From 31b240d6bcb81836fca2c2aa4076daa2aea587fe Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 11 Dec 2014 12:11:39 -0500 Subject: [PATCH 01/59] Add comments with type annotations. This will hopefully help people with their first steps in Rust. Fixes #16143. --- src/doc/guide.md | 72 +++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 21043cfef14..a054038ac89 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -417,6 +417,19 @@ let x: int = 5; If I asked you to read this out loud to the rest of the class, you'd say "`x` is a binding with the type `int` and the value `five`." +In future examples, we may annotate the type in a comment. The examples will +look like this: + +```{rust} +fn main() { + let x = 5i; // x: int +} +``` + +Note the similarities between this annotation and the syntax you use with `let`. +Including these kinds of comments is not idiomatic Rust, but we'll occasionally +include them to help you understand what the types that Rust infers are. + By default, bindings are **immutable**. This code will not compile: ```{ignore} @@ -435,7 +448,7 @@ error: re-assignment of immutable variable `x` If you want a binding to be mutable, you can use `mut`: ```{rust} -let mut x = 5i; +let mut x = 5i; // mut x: int x = 10i; ``` @@ -583,7 +596,7 @@ let y = if x == 5i { 10i } else { 15i -}; +}; // y: int ``` Which we can (and probably should) write like this: @@ -591,7 +604,7 @@ Which we can (and probably should) write like this: ```{rust} let x = 5i; -let y = if x == 5i { 10i } else { 15i }; +let y = if x == 5i { 10i } else { 15i }; // y: int ``` This reveals two interesting things about Rust: it is an expression-based @@ -927,8 +940,8 @@ destructuring. You can assign one tuple into another, if they have the same arity and contained types. ```rust -let mut x = (1i, 2i); -let y = (2i, 3i); +let mut x = (1i, 2i); // x: (int, int) +let y = (2i, 3i); // y: (int, int) x = y; ``` @@ -980,7 +993,7 @@ struct Point { } fn main() { - let origin = Point { x: 0i, y: 0i }; + let origin = Point { x: 0i, y: 0i }; // origin: Point println!("The origin is at ({}, {})", origin.x, origin.y); } @@ -1100,7 +1113,7 @@ fn main() { let x = 5i; let y = 10i; - let ordering = cmp(x, y); + let ordering = cmp(x, y); // ordering: Ordering if ordering == Less { println!("less"); @@ -1387,7 +1400,7 @@ Instead, it looks like this: ```{rust} for x in range(0i, 10i) { - println!("{}", x); + println!("{}", x); // x: int } ``` @@ -1422,8 +1435,8 @@ The other kind of looping construct in Rust is the `while` loop. It looks like this: ```{rust} -let mut x = 5u; -let mut done = false; +let mut x = 5u; // mut x: uint +let mut done = false; // mut done: bool while !done { x += x - 3; @@ -1519,7 +1532,7 @@ The first kind is a `&str`. This is pronounced a 'string slice.' String literals are of the type `&str`: ```{rust} -let string = "Hello there."; +let string = "Hello there."; // string: &str ``` This string is statically allocated, meaning that it's saved inside our @@ -1531,7 +1544,7 @@ A `String`, on the other hand, is an in-memory string. This string is growable, and is also guaranteed to be UTF-8. ```{rust} -let mut s = "Hello".to_string(); +let mut s = "Hello".to_string(); // mut s: String println!("{}", s); s.push_str(", world."); @@ -1587,16 +1600,19 @@ things. The most basic is the **array**, a fixed-size list of elements of the same type. By default, arrays are immutable. ```{rust} -let a = [1i, 2i, 3i]; -let mut m = [1i, 2i, 3i]; +let a = [1i, 2i, 3i]; // a: [int, ..3] +let mut m = [1i, 2i, 3i]; // mut m: [int, ..3] ``` You can create an array with a given number of elements, all initialized to the same value, with `[val, ..N]` syntax. The compiler ensures that arrays are always initialized. +There's a shorthand for initializing each element of an array to the same +value. In this example, each element of `a` will be initialized to `0i`: + ```{rust} -let a = [0i, ..20]; // Shorthand for array of 20 elements all initialized to 0 +let a = [0i, ..20]; // a: [int, ..20] ``` Arrays have type `[T,..N]`. We'll talk about this `T` notation later, when we @@ -1607,7 +1623,7 @@ You can get the number of elements in an array `a` with `a.len()`, and use number in order: ```{rust} -let a = [1i, 2, 3]; // Only the first item needs a type suffix +let a = [1i, 2, 3]; // Only the first item needs a type suffix println!("a has {} elements", a.len()); for e in a.iter() { @@ -1618,7 +1634,7 @@ for e in a.iter() { You can access a particular element of an array with **subscript notation**: ```{rust} -let names = ["Graydon", "Brian", "Niko"]; +let names = ["Graydon", "Brian", "Niko"]; // names: [&str, 3] println!("The second name is: {}", names[1]); ``` @@ -1636,7 +1652,7 @@ later). Vectors are to arrays what `String` is to `&str`. You can create them with the `vec!` macro: ```{rust} -let v = vec![1i, 2, 3]; +let v = vec![1i, 2, 3]; // v: Vec ``` (Notice that unlike the `println!` macro we've used in the past, we use square @@ -1647,8 +1663,10 @@ You can get the length of, iterate over, and subscript vectors just like arrays. In addition, (mutable) vectors can grow automatically: ```{rust} -let mut nums = vec![1i, 2, 3]; +let mut nums = vec![1i, 2, 3]; // mut nums: Vec + nums.push(4); + println!("The length of nums is now {}", nums.len()); // Prints 4 ``` @@ -1822,10 +1840,12 @@ use std::io; fn main() { println!("Type something!"); - let input = io::stdin() - .read_line() - .ok() - .expect("Failed to read line"); + // here, we'll show the types at each step + + let input = io::stdin() // std::io::stdio::StdinReader + .read_line() // IoResult + .ok() // Option + .expect("Failed to read line"); // String println!("{}", input); } @@ -1968,7 +1988,7 @@ use std::rand; fn main() { println!("Guess the number!"); - let secret_number = (rand::random() % 100i) + 1i; + let secret_number = (rand::random() % 100i) + 1i; // secret_number: int println!("The secret number is: {}", secret_number); @@ -2261,8 +2281,8 @@ In this case, we say `x` is a `uint` explicitly, so Rust is able to properly tell `random()` what to generate. In a similar fashion, both of these work: ```{rust,ignore} -let input_num = from_str::("5"); -let input_num: Option = from_str("5"); +let input_num = from_str::("5"); // input_num: Option +let input_num: Option = from_str("5"); // input_num: Option ``` Anyway, with us now converting our input to a number, our code looks like this: From e92e8ac36521b2057b5239aef552136ef4d316b2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 21 Nov 2014 14:45:45 -0800 Subject: [PATCH 02/59] Use rust-installer for installation This is just a refactoring of the current installer so that Rust and Cargo use the same codebase. cc #16456 --- .gitmodules | 3 + mk/dist.mk | 22 +- mk/install.mk | 4 +- src/etc/install.sh | 519 --------------------------------------------- src/rust-installer | 1 + 5 files changed, 21 insertions(+), 528 deletions(-) delete mode 100644 src/etc/install.sh create mode 160000 src/rust-installer diff --git a/.gitmodules b/.gitmodules index 987791ac9db..6cd704b3703 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git +[submodule "src/rust-installer"] + path = src/rust-installer + url = https://github.com/rust-lang/rust-installer diff --git a/mk/dist.mk b/mk/dist.mk index 00f6e861739..2db26f819df 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -58,6 +58,7 @@ PKG_FILES := \ rt \ rustllvm \ snapshots.txt \ + rust-installer \ test) \ $(PKG_GITMODULES) \ $(filter-out config.stamp, \ @@ -209,33 +210,40 @@ distcheck-osx: dist-osx # Unix binary installer tarballs ###################################################################### +NON_INSTALLED_PREFIXES=COPYRIGHT,LICENSE-APACHE,LICENSE-MIT,README.md,doc + define DEF_INSTALLER $$(eval $$(call DEF_PREPARE,dir-$(1))) dist-install-dir-$(1): PREPARE_HOST=$(1) dist-install-dir-$(1): PREPARE_TARGETS=$(2) -dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1) +dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD) dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD) dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD) dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD) dist-install-dir-$(1): PREPARE_CLEAN=true dist-install-dir-$(1): prepare-base-dir-$(1) docs compiler-docs - $$(Q)(cd $$(PREPARE_DEST_DIR)/ && find . -type f | sed 's/^\.\///') \ - > tmp/dist/manifest-$(1).in - $$(Q)mv tmp/dist/manifest-$(1).in $$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)/rustlib/manifest.in -# Add remaining non-installed files $$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR) $$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR) $$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-MIT $$(PREPARE_DEST_DIR) $$(Q)$$(PREPARE_MAN_CMD) $$(S)README.md $$(PREPARE_DEST_DIR) $$(Q)cp -r doc $$(PREPARE_DEST_DIR) - $$(Q)$$(PREPARE_BIN_CMD) $$(S)src/etc/install.sh $$(PREPARE_DEST_DIR) dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1) @$(call E, build: $$@) - $$(Q)tar -czf dist/$$(PKG_NAME)-$(1).tar.gz -C tmp/dist $$(PKG_NAME)-$(1) + $$(Q)$$(S)src/rust-installer/gen-installer.sh \ + --product-name=Rust \ + --verify-bin=rustc \ + --rel-manifest-dir=rustlib \ + --success-message=Rust-is-ready-to-roll. \ + --image-dir=tmp/dist/$$(PKG_NAME)-$(1)-image \ + --work-dir=tmp/dist \ + --output-dir=dist \ + --non-installed-prefixes=$$(NON_INSTALLED_PREFIXES) \ + --package-name=$$(PKG_NAME)-$(1) + $$(Q)rm -R tmp/dist/$$(PKG_NAME)-$(1)-image endef diff --git a/mk/install.mk b/mk/install.mk index 88b451f661a..632df3c754b 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -25,7 +25,7 @@ endif # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist -prepare_install: dist-install-dir-$(CFG_BUILD) | tmp/empty_dir +prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir uninstall: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) @@ -38,7 +38,7 @@ endif # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist -prepare_uninstall: dist-install-dir-$(CFG_BUILD) | tmp/empty_dir +prepare_uninstall: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir .PHONY: install prepare_install uninstall prepare_uninstall diff --git a/src/etc/install.sh b/src/etc/install.sh deleted file mode 100644 index 8bc48fc7934..00000000000 --- a/src/etc/install.sh +++ /dev/null @@ -1,519 +0,0 @@ -#!/bin/sh -# Copyright 2014 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -msg() { - echo "install: $1" -} - -step_msg() { - msg - msg "$1" - msg -} - -warn() { - echo "install: WARNING: $1" -} - -err() { - echo "install: error: $1" - exit 1 -} - -need_ok() { - if [ $? -ne 0 ] - then - err "$1" - fi -} - -need_cmd() { - if command -v $1 >/dev/null 2>&1 - then msg "found $1" - else err "need $1" - fi -} - -putvar() { - local T - eval T=\$$1 - eval TLEN=\${#$1} - if [ $TLEN -gt 35 ] - then - printf "install: %-20s := %.35s ...\n" $1 "$T" - else - printf "install: %-20s := %s %s\n" $1 "$T" "$2" - fi -} - -valopt() { - VAL_OPTIONS="$VAL_OPTIONS $1" - - local OP=$1 - local DEFAULT=$2 - shift - shift - local DOC="$*" - if [ $HELP -eq 0 ] - then - local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') - local V="CFG_${UOP}" - eval $V="$DEFAULT" - for arg in $CFG_ARGS - do - if echo "$arg" | grep -q -- "--$OP=" - then - val=$(echo "$arg" | cut -f2 -d=) - eval $V=$val - fi - done - putvar $V - else - if [ -z "$DEFAULT" ] - then - DEFAULT="" - fi - OP="${OP}=[${DEFAULT}]" - printf " --%-30s %s\n" "$OP" "$DOC" - fi -} - -opt() { - BOOL_OPTIONS="$BOOL_OPTIONS $1" - - local OP=$1 - local DEFAULT=$2 - shift - shift - local DOC="$*" - local FLAG="" - - if [ $DEFAULT -eq 0 ] - then - FLAG="enable" - else - FLAG="disable" - DOC="don't $DOC" - fi - - if [ $HELP -eq 0 ] - then - for arg in $CFG_ARGS - do - if [ "$arg" = "--${FLAG}-${OP}" ] - then - OP=$(echo $OP | tr 'a-z-' 'A-Z_') - FLAG=$(echo $FLAG | tr 'a-z' 'A-Z') - local V="CFG_${FLAG}_${OP}" - eval $V=1 - putvar $V - fi - done - else - if [ ! -z "$META" ] - then - OP="$OP=<$META>" - fi - printf " --%-30s %s\n" "$FLAG-$OP" "$DOC" - fi -} - -flag() { - BOOL_OPTIONS="$BOOL_OPTIONS $1" - - local OP=$1 - shift - local DOC="$*" - - if [ $HELP -eq 0 ] - then - for arg in $CFG_ARGS - do - if [ "$arg" = "--${OP}" ] - then - OP=$(echo $OP | tr 'a-z-' 'A-Z_') - local V="CFG_${OP}" - eval $V=1 - putvar $V - fi - done - else - if [ ! -z "$META" ] - then - OP="$OP=<$META>" - fi - printf " --%-30s %s\n" "$OP" "$DOC" - fi -} - -validate_opt () { - for arg in $CFG_ARGS - do - isArgValid=0 - for option in $BOOL_OPTIONS - do - if test --disable-$option = $arg - then - isArgValid=1 - fi - if test --enable-$option = $arg - then - isArgValid=1 - fi - if test --$option = $arg - then - isArgValid=1 - fi - done - for option in $VAL_OPTIONS - do - if echo "$arg" | grep -q -- "--$option=" - then - isArgValid=1 - fi - done - if [ "$arg" = "--help" ] - then - echo - echo "No more help available for Configure options," - echo "check the Wiki or join our IRC channel" - break - else - if test $isArgValid -eq 0 - then - err "Option '$arg' is not recognized" - fi - fi - done -} - -absolutify() { - FILE_PATH="${1}" - FILE_PATH_DIRNAME="$(dirname ${FILE_PATH})" - FILE_PATH_BASENAME="$(basename ${FILE_PATH})" - FILE_ABS_PATH="$(cd ${FILE_PATH_DIRNAME} && pwd)" - FILE_PATH="${FILE_ABS_PATH}/${FILE_PATH_BASENAME}" - # This is the return value - ABSOLUTIFIED="${FILE_PATH}" -} - -msg "looking for install programs" -need_cmd mkdir -need_cmd printf -need_cmd cut -need_cmd grep -need_cmd uname -need_cmd tr -need_cmd sed - -CFG_SRC_DIR="$(cd $(dirname $0) && pwd)" -CFG_SELF="$0" -CFG_ARGS="$@" - -HELP=0 -if [ "$1" = "--help" ] -then - HELP=1 - shift - echo - echo "Usage: $CFG_SELF [options]" - echo - echo "Options:" - echo -else - step_msg "processing $CFG_SELF args" -fi - -# Check for mingw or cygwin in order to special case $CFG_LIBDIR_RELATIVE. -# This logic is duplicated from configure in order to get the correct libdir -# for Windows installs. -CFG_OSTYPE=$(uname -s) - -case $CFG_OSTYPE in - - MINGW32*) - CFG_OSTYPE=pc-mingw32 - ;; - - MINGW64*) - # msys2, MSYSTEM=MINGW64 - CFG_OSTYPE=w64-mingw32 - ;; - -# Thad's Cygwin identifers below - -# Vista 32 bit - CYGWIN_NT-6.0) - CFG_OSTYPE=pc-mingw32 - ;; - -# Vista 64 bit - CYGWIN_NT-6.0-WOW64) - CFG_OSTYPE=w64-mingw32 - ;; - -# Win 7 32 bit - CYGWIN_NT-6.1) - CFG_OSTYPE=pc-mingw32 - ;; - -# Win 7 64 bit - CYGWIN_NT-6.1-WOW64) - CFG_OSTYPE=w64-mingw32 - ;; -esac - -OPTIONS="" -BOOL_OPTIONS="" -VAL_OPTIONS="" - -# On windows we just store the libraries in the bin directory because -# there's no rpath. This is where the build system itself puts libraries; -# --libdir is used to configure the installation directory. -# FIXME: Thise needs to parameterized over target triples. Do it in platform.mk -CFG_LIBDIR_RELATIVE=lib -if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ] -then - CFG_LIBDIR_RELATIVE=bin -fi - -if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ] -then - CFG_LD_PATH_VAR=PATH - CFG_OLD_LD_PATH_VAR=$PATH -elif [ "$CFG_OSTYPE" = "Darwin" ] -then - CFG_LD_PATH_VAR=DYLD_LIBRARY_PATH - CFG_OLD_LD_PATH_VAR=$DYLD_LIBRARY_PATH -else - CFG_LD_PATH_VAR=LD_LIBRARY_PATH - CFG_OLD_LD_PATH_VAR=$LD_LIBRARY_PATH -fi - -flag uninstall "only uninstall from the installation prefix" -opt verify 1 "verify that the installed binaries run correctly" -valopt prefix "/usr/local" "set installation prefix" -# NB This is exactly the same definition as in `configure`. -valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries" -case "$CFG_LIBDIR" in - "$CFG_PREFIX"/*) CAT_INC=2;; - "$CFG_PREFIX"*) CAT_INC=1;; - *) - err "libdir must begin with the prefix. Use --prefix to set it accordingly.";; -esac -CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-` - -valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" - -if [ $HELP -eq 1 ] -then - echo - exit 0 -fi - -step_msg "validating $CFG_SELF args" -validate_opt - - -# OK, let's get installing ... - -# Sanity check: can we run the binaries? -if [ -z "${CFG_DISABLE_VERIFY}" ] -then - # Don't do this if uninstalling. Failure here won't help in any way. - if [ -z "${CFG_UNINSTALL}" ] - then - msg "verifying platform can run binaries" - export $CFG_LD_PATH_VAR="${CFG_SRC_DIR}/lib:$CFG_OLD_LD_PATH_VAR" - "${CFG_SRC_DIR}/bin/rustc" --version > /dev/null - if [ $? -ne 0 ] - then - err "can't execute rustc binary on this platform" - fi - export $CFG_LD_PATH_VAR=$CFG_OLD_LD_PATH_VAR - fi -fi - -# Sanity check: can we can write to the destination? -msg "verifying destination is writable" -umask 022 && mkdir -p "${CFG_LIBDIR}" -need_ok "can't write to destination. consider \`sudo\`." -touch "${CFG_LIBDIR}/rust-install-probe" > /dev/null -if [ $? -ne 0 ] -then - err "can't write to destination. consider \`sudo\`." -fi -rm -f "${CFG_LIBDIR}/rust-install-probe" -need_ok "failed to remove install probe" - -# Sanity check: don't install to the directory containing the installer. -# That would surely cause chaos. -msg "verifying destination is not the same as source" -INSTALLER_DIR="$(cd $(dirname $0) && pwd)" -PREFIX_DIR="$(cd ${CFG_PREFIX} && pwd)" -if [ "${INSTALLER_DIR}" = "${PREFIX_DIR}" ] -then - err "can't install to same directory as installer" -fi - -# Using an absolute path to libdir in a few places so that the status -# messages are consistently using absolute paths. -absolutify "${CFG_LIBDIR}" -ABS_LIBDIR="${ABSOLUTIFIED}" - -# The file name of the manifest we're going to create during install -INSTALLED_MANIFEST="${ABS_LIBDIR}/rustlib/manifest" - -# First, uninstall from the installation prefix. -# Errors are warnings - try to rm everything in the manifest even if some fail. -if [ -f "${INSTALLED_MANIFEST}" ] -then - # Iterate through installed manifest and remove files - while read p; do - # The installed manifest contains absolute paths - msg "removing $p" - if [ -f "$p" ] - then - rm -f "$p" - if [ $? -ne 0 ] - then - warn "failed to remove $p" - fi - else - warn "supposedly installed file $p does not exist!" - fi - done < "${INSTALLED_MANIFEST}" - - # If we fail to remove rustlib below, then the installed manifest will - # still be full; the installed manifest needs to be empty before install. - msg "removing ${INSTALLED_MANIFEST}" - rm -f "${INSTALLED_MANIFEST}" - # For the above reason, this is a hard error - need_ok "failed to remove installed manifest" - - # Remove 'rustlib' directory - msg "removing ${ABS_LIBDIR}/rustlib" - rm -Rf "${ABS_LIBDIR}/rustlib" - if [ $? -ne 0 ] - then - warn "failed to remove rustlib" - fi -else - # There's no manifest. If we were asked to uninstall, then that's a problem. - if [ -n "${CFG_UNINSTALL}" ] - then - err "unable to find installation manifest at ${CFG_LIBDIR}/rustlib" - fi -fi - -# If we're only uninstalling then exit -if [ -n "${CFG_UNINSTALL}" ] -then - echo - echo " Rust is uninstalled. Have a nice day." - echo - exit 0 -fi - -# Create the installed manifest, which we will fill in with absolute file paths -mkdir -p "${CFG_LIBDIR}/rustlib" -need_ok "failed to create rustlib" -touch "${INSTALLED_MANIFEST}" -need_ok "failed to create installed manifest" - -# Now install, iterate through the new manifest and copy files -while read p; do - - # Decide the destination of the file - FILE_INSTALL_PATH="${CFG_PREFIX}/$p" - - if echo "$p" | grep "^${CFG_LIBDIR_RELATIVE}/" > /dev/null - then - pp=`echo $p | sed "s%^${CFG_LIBDIR_RELATIVE}/%%"` - FILE_INSTALL_PATH="${CFG_LIBDIR}/$pp" - fi - - if echo "$p" | grep "^share/man/" > /dev/null - then - pp=`echo $p | sed 's/^share\/man\///'` - FILE_INSTALL_PATH="${CFG_MANDIR}/$pp" - fi - - # Make sure there's a directory for it - umask 022 && mkdir -p "$(dirname ${FILE_INSTALL_PATH})" - need_ok "directory creation failed" - - # Make the path absolute so we can uninstall it later without - # starting from the installation cwd - absolutify "${FILE_INSTALL_PATH}" - FILE_INSTALL_PATH="${ABSOLUTIFIED}" - - # Install the file - msg "${FILE_INSTALL_PATH}" - if echo "$p" | grep "^bin/" > /dev/null - then - install -m755 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}" - else - install -m644 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}" - fi - need_ok "file creation failed" - - # Update the manifest - echo "${FILE_INSTALL_PATH}" >> "${INSTALLED_MANIFEST}" - need_ok "failed to update manifest" - -# The manifest lists all files to install -done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in" - -# Run ldconfig to make dynamic libraries available to the linker -if [ "$CFG_OSTYPE" = "Linux" ] - then - ldconfig - if [ $? -ne 0 ] - then - warn "failed to run ldconfig." - warn "this may happen when not installing as root and may be fine" - fi -fi - -# Sanity check: can we run the installed binaries? -# -# As with the verification above, make sure the right LD_LIBRARY_PATH-equivalent -# is in place. Try first without this variable, and if that fails try again with -# the variable. If the second time tries, print a hopefully helpful message to -# add something to the appropriate environment variable. -if [ -z "${CFG_DISABLE_VERIFY}" ] -then - msg "verifying installed binaries are executable" - "${CFG_PREFIX}/bin/rustc" --version 2> /dev/null 1> /dev/null - if [ $? -ne 0 ] - then - export $CFG_LD_PATH_VAR="${CFG_PREFIX}/lib:$CFG_OLD_LD_PATH_VAR" - "${CFG_PREFIX}/bin/rustc" --version > /dev/null - if [ $? -ne 0 ] - then - ERR="can't execute installed rustc binary. " - ERR="${ERR}installation may be broken. " - ERR="${ERR}if this is expected then rerun install.sh with \`--disable-verify\` " - ERR="${ERR}or \`make install\` with \`--disable-verify-install\`" - err "${ERR}" - else - echo - echo " Note: please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}" - fi - fi -fi - -echo -echo " Rust is ready to roll." -echo - - diff --git a/src/rust-installer b/src/rust-installer new file mode 160000 index 00000000000..aed73472416 --- /dev/null +++ b/src/rust-installer @@ -0,0 +1 @@ +Subproject commit aed73472416064642911af790b25d57c9390b6c7 From 577f742d7a8a593e8134056259f195a7c897eeb9 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Fri, 12 Dec 2014 11:34:01 +0900 Subject: [PATCH 03/59] serialize: Avoid stray nul characters when auto-serializing char. Fixes #19719. --- src/libserialize/json.rs | 54 +++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 7919ac0eff1..e26366ce3a6 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -367,8 +367,8 @@ fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> { fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> { let mut buf = [0, .. 4]; - v.encode_utf8(&mut buf); - escape_bytes(writer, &mut buf) + let len = v.encode_utf8(&mut buf).unwrap(); + escape_bytes(writer, buf[mut ..len]) } fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> { @@ -2694,37 +2694,39 @@ mod tests { ); } + macro_rules! check_encoder_for_simple( + ($value:expr, $expected:expr) => ({ + let s = with_str_writer(|writer| { + let mut encoder = Encoder::new(writer); + $value.encode(&mut encoder).unwrap(); + }); + assert_eq!(s, $expected); + + let s = with_str_writer(|writer| { + let mut encoder = PrettyEncoder::new(writer); + $value.encode(&mut encoder).unwrap(); + }); + assert_eq!(s, $expected); + }) + ) + #[test] fn test_write_some() { - let value = Some("jodhpurs".into_string()); - let s = with_str_writer(|writer| { - let mut encoder = Encoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "\"jodhpurs\""); - - let value = Some("jodhpurs".into_string()); - let s = with_str_writer(|writer| { - let mut encoder = PrettyEncoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "\"jodhpurs\""); + check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\""); } #[test] fn test_write_none() { - let value: Option = None; - let s = with_str_writer(|writer| { - let mut encoder = Encoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "null"); + check_encoder_for_simple!(None::, "null"); + } - let s = with_str_writer(|writer| { - let mut encoder = Encoder::new(writer); - value.encode(&mut encoder).unwrap(); - }); - assert_eq!(s, "null"); + #[test] + fn test_write_char() { + check_encoder_for_simple!('a', "\"a\""); + check_encoder_for_simple!('\t', "\"\\t\""); + check_encoder_for_simple!('\u00a0', "\"\u00a0\""); + check_encoder_for_simple!('\uabcd', "\"\uabcd\""); + check_encoder_for_simple!('\U0010ffff', "\"\U0010ffff\""); } #[test] From 19eb4bf0b2d59c1d1dc78fe52fb98fe61a9a2783 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 12 Dec 2014 16:54:57 +1300 Subject: [PATCH 04/59] Add coercions from *mut to *const and from &mut to *const. --- src/librustc/middle/infer/coercion.rs | 9 ++++--- src/test/compile-fail/ptr-coercion.rs | 24 ++++++++++++++++++ src/test/run-pass/ptr-coercion.rs | 35 +++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/ptr-coercion.rs create mode 100644 src/test/run-pass/ptr-coercion.rs diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index f04c519badc..babef6bae3d 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -549,17 +549,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { b.repr(self.get_ref().infcx.tcx)); let mt_a = match *sty_a { - ty::ty_rptr(_, mt) => mt, + ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt, _ => { return self.subtype(a, b); } }; // Check that the types which they point at are compatible. - // Note that we don't adjust the mutability here. We cannot change - // the mutability and the kind of pointer in a single coercion. - let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a); + let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ mutbl: mutbl_b, ty: mt_a.ty }); try!(self.subtype(a_unsafe, b)); + if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) { + return Err(ty::terr_mutability); + } // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that diff --git a/src/test/compile-fail/ptr-coercion.rs b/src/test/compile-fail/ptr-coercion.rs new file mode 100644 index 00000000000..d9b20748a7a --- /dev/null +++ b/src/test/compile-fail/ptr-coercion.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test coercions between pointers which don't do anything fancy like unsizing. +// These are testing that we don't lose mutability when converting to raw pointers. + +pub fn main() { + // *const -> *mut + let x: *const int = &42i; + let x: *mut int = x; //~ERROR values differ in mutability + + // & -> *mut + let x: *mut int = &42; //~ERROR values differ in mutability + + let x: *const int = &42; + let x: *mut int = x; //~ERROR values differ in mutability +} diff --git a/src/test/run-pass/ptr-coercion.rs b/src/test/run-pass/ptr-coercion.rs new file mode 100644 index 00000000000..1b77c1316ed --- /dev/null +++ b/src/test/run-pass/ptr-coercion.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test coercions between pointers which don't do anything fancy like unsizing. + +pub fn main() { + // &mut -> & + let x: &mut int = &mut 42i; + let x: &int = x; + + let x: &int = &mut 42i; + + // & -> *const + let x: &int = &42i; + let x: *const int = x; + + let x: *const int = &42i; + + // &mut -> *const + let x: &mut int = &mut 42i; + let x: *const int = x; + + let x: *const int = &mut 42i; + + // *mut -> *const + let x: *mut int = &mut 42i; + let x: *const int = x; +} From 8abe7846d6c32bf06fd8bb79d76e658b6770bd7b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 13 Dec 2014 14:18:44 -0800 Subject: [PATCH 05/59] Deprecate more in-tree libs for crates.io This commit deprecates a few more in-tree libs for their crates.io counterparts. Note that this commit does not make use of the #[deprecated] tag to prevent warnings from being generated for in-tree usage. Once #[unstable] warnings are turned on then all external users will be warned to move. These crates have all been duplicated in rust-lang/$crate repositories so development can happen independently of the in-tree copies. We can explore at a later date replacing the in-tree copies with the external copies, but at this time the libraries have changed very little over the past few months so it's unlikely for changes to be sent to both repos. cc #19260 --- src/libgetopts/lib.rs | 2 +- src/liblog/lib.rs | 2 +- src/libregex/lib.rs | 2 +- src/libregex_macros/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index b809138c451..a5a84b22c19 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -79,7 +79,7 @@ //! ``` #![crate_name = "getopts"] -#![experimental] +#![experimental = "use the crates.io `getopts` library instead"] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 8b79078eac6..498fa2b5e74 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -158,7 +158,7 @@ //! if logging is disabled, none of the components of the log will be executed. #![crate_name = "log"] -#![experimental] +#![experimental = "use the crates.io `log` library instead"] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs index b35c3879783..2d64aac6f79 100644 --- a/src/libregex/lib.rs +++ b/src/libregex/lib.rs @@ -362,7 +362,7 @@ #![crate_name = "regex"] #![crate_type = "rlib"] #![crate_type = "dylib"] -#![experimental] +#![experimental = "use the crates.io `regex` library instead"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/", diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs index 4df88197743..11976b11c7e 100644 --- a/src/libregex_macros/lib.rs +++ b/src/libregex_macros/lib.rs @@ -13,7 +13,7 @@ #![crate_name = "regex_macros"] #![crate_type = "dylib"] -#![experimental] +#![experimental = "use the crates.io `regex_macros` library instead"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] From 81f9a319265ddbe6b7823b50c29e3aff076d82c1 Mon Sep 17 00:00:00 2001 From: Chase Southwood Date: Wed, 10 Dec 2014 23:12:31 -0600 Subject: [PATCH 06/59] Change `VecMap`'s iterators to use wrapper structs instead of typedefs. Using a type alias for iterator implementations is fragile since this exposes the implementation to users of the iterator, and any changes could break existing code. This commit changes the iterators of `VecMap` to use proper new types, rather than type aliases. However, since it is fair-game to treat a type-alias as the aliased type, this is a: [breaking-change]. --- src/libcollections/vec_map.rs | 59 ++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index cc2fd0a6646..fab595c2e05 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -18,7 +18,7 @@ use core::prelude::*; use core::default::Default; use core::fmt; use core::iter; -use core::iter::{Enumerate, FilterMap}; +use core::iter::{Enumerate, FilterMap, Map}; use core::mem::replace; use core::ops::FnOnce; @@ -144,7 +144,7 @@ impl VecMap { pub fn keys<'r>(&'r self) -> Keys<'r, V> { fn first((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { iter: self.iter().map(first) } } /// Returns an iterator visiting all values in ascending order by the keys. @@ -153,7 +153,7 @@ impl VecMap { pub fn values<'r>(&'r self) -> Values<'r, V> { fn second((_, b): (A, B)) -> B { b } - self.iter().map(second) + Values { iter: self.iter().map(second) } } /// Returns an iterator visiting all key-value pairs in ascending order by the keys. @@ -240,7 +240,7 @@ impl VecMap { } let values = replace(&mut self.v, vec!()); - values.into_iter().enumerate().filter_map(filter) + MoveItems { iter: values.into_iter().enumerate().filter_map(filter) } } /// Return the number of elements in the map. @@ -603,7 +603,7 @@ macro_rules! double_ended_iterator { } } -/// Forward iterator over a map. +/// An iterator over the key-value pairs of a map. pub struct Entries<'a, V:'a> { front: uint, back: uint, @@ -613,7 +613,7 @@ pub struct Entries<'a, V:'a> { iterator!(impl Entries -> (uint, &'a V), as_ref) double_ended_iterator!(impl Entries -> (uint, &'a V), as_ref) -/// Forward iterator over the key-value pairs of a map, with the +/// An iterator over the key-value pairs of a map, with the /// values being mutable. pub struct MutEntries<'a, V:'a> { front: uint, @@ -624,19 +624,50 @@ pub struct MutEntries<'a, V:'a> { iterator!(impl MutEntries -> (uint, &'a mut V), as_mut) double_ended_iterator!(impl MutEntries -> (uint, &'a mut V), as_mut) -/// Forward iterator over the keys of a map -pub type Keys<'a, V> = iter::Map<(uint, &'a V), uint, Entries<'a, V>, fn((uint, &'a V)) -> uint>; +/// An iterator over the keys of a map. +pub struct Keys<'a, V: 'a> { + iter: Map<(uint, &'a V), uint, Entries<'a, V>, fn((uint, &'a V)) -> uint> +} -/// Forward iterator over the values of a map -pub type Values<'a, V> = - iter::Map<(uint, &'a V), &'a V, Entries<'a, V>, fn((uint, &'a V)) -> &'a V>; +/// An iterator over the values of a map. +pub struct Values<'a, V: 'a> { + iter: Map<(uint, &'a V), &'a V, Entries<'a, V>, fn((uint, &'a V)) -> &'a V> +} -/// Iterator over the key-value pairs of a map, the iterator consumes the map -pub type MoveItems = FilterMap< +/// A consuming iterator over the key-value pairs of a map. +pub struct MoveItems { + iter: FilterMap< (uint, Option), (uint, V), Enumerate>>, - fn((uint, Option)) -> Option<(uint, V)>>; + fn((uint, Option)) -> Option<(uint, V)>> +} + +impl<'a, V> Iterator for Keys<'a, V> { + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl<'a, V> DoubleEndedIterator for Keys<'a, V> { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + + +impl<'a, V> Iterator<&'a V> for Values<'a, V> { + fn next(&mut self) -> Option<(&'a V)> { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl<'a, V> DoubleEndedIterator<&'a V> for Values<'a, V> { + fn next_back(&mut self) -> Option<(&'a V)> { self.iter.next_back() } +} + + +impl Iterator<(uint, V)> for MoveItems { + fn next(&mut self) -> Option<(uint, V)> { self.iter.next() } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl DoubleEndedIterator<(uint, V)> for MoveItems { + fn next_back(&mut self) -> Option<(uint, V)> { self.iter.next_back() } +} #[cfg(test)] mod test_map { From 7d1fa4ebea3cb29d76d04199e3a015ab11974914 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Dec 2014 12:16:30 -0800 Subject: [PATCH 07/59] rustc: Start the deprecation of libserialize The primary focus of Rust's stability story at 1.0 is the standard library. All other libraries distributed with the Rust compiler are planned to be #[unstable] and therfore only accessible on the nightly channel of Rust. One of the more widely used libraries today is libserialize, Rust's current solution for encoding and decoding types. The current libserialize library, however, has a number of drawbacks: * The API is not ready to be stabilize as-is and we will likely not have enough resources to stabilize the API for 1.0. * The library is not necessarily the speediest implementations with alternatives being developed out-of-tree (e.g. serde from erickt). * It is not clear how the API of Encodable/Decodable can evolve over time while maintaining backwards compatibility. One of the major pros to the current libserialize, however, is `deriving(Encodable, Decodable)` as short-hands for enabling serializing and deserializing a type. This is unambiguously useful functionality, so we cannot simply deprecate the in-tree libserialize in favor of an external crates.io implementation. For these reasons, this commit starts off a stability story for libserialize by following these steps: 1. The deriving(Encodable, Decodable) modes will be deprecated in favor of a renamed deriving(RustcEncodable, RustcDecodable). 2. The in-tree libserialize will be deprecated in favor of an external rustc-serialize crate shipped on crates.io. The contents of the crate will be the same for now (but they can evolve separately). 3. At 1.0 serialization will be performed through deriving(RustcEncodable, RustcDecodable) and the rustc-serialize crate. The expansions for each deriving mode will change from `::serialize::foo` to `::rustc_serialize::foo`. This story will require that the compiler freezes its implementation of `RustcEncodable` deriving for all of time, but this should be a fairly minimal maintenance burden. Otherwise the crate in crates.io must always maintain the exact definition of its traits, but the implementation of json, for example, can continue to evolve in the semver-sense. The major goal for this stabilization effort is to pave the road for a new official serialization crate which can replace the current one, solving many of its downsides in the process. We are not assuming that this will exist for 1.0, hence the above measures. Some possibilities for replacing libserialize include: * If plugins have a stable API, then any crate can provide a custom `deriving` mode (will require some compiler work). This means that any new serialization crate can provide its own `deriving` with its own backing implementation, entirely obsoleting the current libserialize and fully replacing it. * Erick is exploring the possibility of code generation via preprocessing Rust source files in the near term until plugins are stable. This strategy would provide the same ergonomic benefit that `deriving` does today in theory. So, in summary, the current libserialize crate is being deprecated in favor of the crates.io-based rustc-serialize crate where the `deriving` modes are appropriately renamed. This opens up space for a later implementation of serialization in a more official capacity while allowing alternative implementations to be explored in the meantime. Concretely speaking, this change adds support for the `RustcEncodable` and `RustcDecodable` deriving modes. After a snapshot is made warnings will be turned on for usage of `Encodable` and `Decodable` as well as deprecating the in-tree libserialize crate to encurage users to use rustc-serialize instead. --- src/libsyntax/ext/deriving/mod.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index fccef47d1ea..5fb320b9136 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -70,8 +70,28 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt, "Hash" => expand!(hash::expand_deriving_hash), - "Encodable" => expand!(encodable::expand_deriving_encodable), - "Decodable" => expand!(decodable::expand_deriving_decodable), + "RustcEncodable" => { + expand!(encodable::expand_deriving_encodable) + } + "RustcDecodable" => { + expand!(decodable::expand_deriving_decodable) + } + "Encodable" => { + // NOTE: uncomment after a stage0 snap + // cx.span_warn(titem.span, + // "deriving(Encodable) is deprecated \ + // in favor of deriving(RustcEncodable)"); + + expand!(encodable::expand_deriving_encodable) + } + "Decodable" => + // NOTE: uncomment after a stage0 snap + // cx.span_warn(titem.span, + // "deriving(Decodable) is deprecated \ + // in favor of deriving(RustcDecodable)"); + + expand!(decodable::expand_deriving_decodable) + } "PartialEq" => expand!(eq::expand_deriving_eq), "Eq" => expand!(totaleq::expand_deriving_totaleq), From f053f29ff5469ff955221d1ea8d6154ef276ce10 Mon Sep 17 00:00:00 2001 From: mchaput Date: Sun, 14 Dec 2014 00:48:09 -0500 Subject: [PATCH 08/59] Fix mispelling in char.rs error message Error message has wrong spelling ("radix is to high"). --- src/libcore/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 75f7991df02..07db32bcc2b 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -141,7 +141,7 @@ pub fn to_digit(c: char, radix: uint) -> Option { #[unstable = "pending decisions about costructors for primitives"] pub fn from_digit(num: uint, radix: uint) -> Option { if radix > 36 { - panic!("from_digit: radix is to high (maximum 36)"); + panic!("from_digit: radix is too high (maximum 36)"); } if num < radix { unsafe { From ac7dc03a52d94fe62c367e4783d0a8b915554b75 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 14 Dec 2014 00:35:35 -0500 Subject: [PATCH 09/59] libsyntax: Make deriving also respect where bounds. --- src/libsyntax/ext/deriving/generic/mod.rs | 30 +++++++++++++++++++---- src/test/run-pass/issue-19358.rs | 29 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/issue-19358.rs diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index a75be40604e..fd0fa9a70d4 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -388,7 +388,7 @@ impl<'a> TraitDef<'a> { methods: Vec>) -> P { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - let Generics { mut lifetimes, ty_params, where_clause: _ } = + let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics.to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); @@ -420,13 +420,33 @@ impl<'a> TraitDef<'a> { ty_param.unbound.clone(), None) })); + + // and similarly for where clauses + where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { + match *clause { + ast::WherePredicate::BoundPredicate(ref wb) => { + ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + id: ast::DUMMY_NODE_ID, + span: self.span, + ident: wb.ident, + bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect()) + }) + } + ast::WherePredicate::EqPredicate(ref we) => { + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { + id: ast::DUMMY_NODE_ID, + span: self.span, + path: we.path.clone(), + ty: we.ty.clone() + }) + } + } + })); + let trait_generics = Generics { lifetimes: lifetimes, ty_params: OwnedSlice::from_vec(ty_params), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, + where_clause: where_clause }; // Create the reference to the trait. diff --git a/src/test/run-pass/issue-19358.rs b/src/test/run-pass/issue-19358.rs new file mode 100644 index 00000000000..e4c190f4116 --- /dev/null +++ b/src/test/run-pass/issue-19358.rs @@ -0,0 +1,29 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait {} + +#[deriving(Show)] +struct Foo { + foo: T, +} + +#[deriving(Show)] +struct Bar where T: Trait { + bar: T, +} + +impl Trait for int {} + +fn main() { + let a = Foo { foo: 12i }; + let b = Bar { bar: 12i }; + println!("{} {}", a, b); +} From ab1bdde536668e752aaf4e9dbfa0acf058d0240b Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 14 Dec 2014 00:51:42 -0500 Subject: [PATCH 10/59] libsyntax: Output where clauses in pretty printer for structs. --- src/libsyntax/print/pprust.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6d8b8dcb8ba..d01b5a0fee2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1070,6 +1070,7 @@ impl<'a> State<'a> { span: codemap::Span) -> IoResult<()> { try!(self.print_ident(ident)); try!(self.print_generics(generics)); + try!(self.print_where_clause(generics)); if ast_util::struct_def_is_tuple_like(struct_def) { if !struct_def.fields.is_empty() { try!(self.popen()); From c2b0d7dd8818a0dca9b1fa7af6873375907f05ca Mon Sep 17 00:00:00 2001 From: Eric Kidd Date: Sat, 13 Dec 2014 13:33:18 -0500 Subject: [PATCH 11/59] Modify `regex::Captures::{at,name}` to return `Option` Closes #14602. As discussed in that issue, the existing `at` and `name` functions represent two different results with the empty string: 1. Matched the empty string. 2. Did not match anything. Consider the following example. This regex has two named matched groups, `key` and `value`. `value` is optional: ```rust // Matches "foo", "foo;v=bar" and "foo;v=". regex!(r"(?P[a-z]+)(;v=(?P[a-z]*))?"); ``` We can access `value` using `caps.name("value")`, but there's no way for us to distinguish between the `"foo"` and `"foo;v="` cases. Early this year, @BurntSushi recommended modifying the existing `at` and `name` functions to return `Option`, instead of adding new functions to the API. This is a [breaking-change], but the fix is easy: - `refs.at(1)` becomes `refs.at(1).unwrap_or("")`. - `refs.name(name)` becomes `refs.name(name).unwrap_or("")`. --- src/compiletest/compiletest.rs | 4 +-- src/compiletest/errors.rs | 8 +++--- src/grammar/verify.rs | 8 +++--- src/libregex/lib.rs | 6 +++-- src/libregex/re.rs | 49 +++++++++++++++++----------------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 47ab675aff9..375dd138c22 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -393,7 +393,7 @@ fn extract_gdb_version(full_version_line: Option) -> Option { match re.captures(full_version_line) { Some(captures) => { - Some(captures.at(2).to_string()) + Some(captures.at(2).unwrap_or("").to_string()) } None => { println!("Could not extract GDB version from line '{}'", @@ -427,7 +427,7 @@ fn extract_lldb_version(full_version_line: Option) -> Option { match re.captures(full_version_line) { Some(captures) => { - Some(captures.at(1).to_string()) + Some(captures.at(1).unwrap_or("").to_string()) } None => { println!("Could not extract LLDB version from line '{}'", diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index f15db7d9371..b7df43aabdd 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -66,10 +66,10 @@ fn parse_expected(last_nonfollow_error: Option, line: &str, re: &Regex) -> Option<(WhichLine, ExpectedError)> { re.captures(line).and_then(|caps| { - let adjusts = caps.name("adjusts").len(); - let kind = caps.name("kind").to_ascii_lower(); - let msg = caps.name("msg").trim().to_string(); - let follow = caps.name("follow").len() > 0; + let adjusts = caps.name("adjusts").unwrap_or("").len(); + let kind = caps.name("kind").unwrap_or("").to_ascii_lower(); + let msg = caps.name("msg").unwrap_or("").trim().to_string(); + let follow = caps.name("follow").unwrap_or("").len() > 0; let (which, line) = if follow { assert!(adjusts == 0, "use either //~| or //~^, not both."); diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index e3ff20f7874..f7b19cf6fbf 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -173,10 +173,10 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAn ); let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice()); - let start = m.name("start"); - let end = m.name("end"); - let toknum = m.name("toknum"); - let content = m.name("content"); + let start = m.name("start").unwrap_or(""); + let end = m.name("end").unwrap_or(""); + let toknum = m.name("toknum").unwrap_or(""); + let content = m.name("content").unwrap_or(""); let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map", toknum).as_slice()); diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs index 05f853a851e..3fadba9583e 100644 --- a/src/libregex/lib.rs +++ b/src/libregex/lib.rs @@ -103,7 +103,9 @@ //! let re = regex!(r"(\d{4})-(\d{2})-(\d{2})"); //! let text = "2012-03-14, 2013-01-01 and 2014-07-05"; //! for cap in re.captures_iter(text) { -//! println!("Month: {} Day: {} Year: {}", cap.at(2), cap.at(3), cap.at(1)); +//! println!("Month: {} Day: {} Year: {}", +//! cap.at(2).unwrap_or(""), cap.at(3).unwrap_or(""), +//! cap.at(1).unwrap_or("")); //! } //! // Output: //! // Month: 03 Day: 14 Year: 2012 @@ -285,7 +287,7 @@ //! # fn main() { //! let re = regex!(r"(?i)a+(?-i)b+"); //! let cap = re.captures("AaAaAbbBBBb").unwrap(); -//! assert_eq!(cap.at(0), "AaAaAbb"); +//! assert_eq!(cap.at(0), Some("AaAaAbb")); //! # } //! ``` //! diff --git a/src/libregex/re.rs b/src/libregex/re.rs index 1504e191985..53181bfbb7e 100644 --- a/src/libregex/re.rs +++ b/src/libregex/re.rs @@ -273,9 +273,9 @@ impl Regex { /// let re = regex!(r"'([^']+)'\s+\((\d{4})\)"); /// let text = "Not my favorite movie: 'Citizen Kane' (1941)."; /// let caps = re.captures(text).unwrap(); - /// assert_eq!(caps.at(1), "Citizen Kane"); - /// assert_eq!(caps.at(2), "1941"); - /// assert_eq!(caps.at(0), "'Citizen Kane' (1941)"); + /// assert_eq!(caps.at(1), Some("Citizen Kane")); + /// assert_eq!(caps.at(2), Some("1941")); + /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)")); /// # } /// ``` /// @@ -291,9 +291,9 @@ impl Regex { /// let re = regex!(r"'(?P[^']+)'\s+\((?P<year>\d{4})\)"); /// let text = "Not my favorite movie: 'Citizen Kane' (1941)."; /// let caps = re.captures(text).unwrap(); - /// assert_eq!(caps.name("title"), "Citizen Kane"); - /// assert_eq!(caps.name("year"), "1941"); - /// assert_eq!(caps.at(0), "'Citizen Kane' (1941)"); + /// assert_eq!(caps.name("title"), Some("Citizen Kane")); + /// assert_eq!(caps.name("year"), Some("1941")); + /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)")); /// # } /// ``` /// @@ -434,7 +434,7 @@ impl Regex { /// # use regex::Captures; fn main() { /// let re = regex!(r"([^,\s]+),\s+(\S+)"); /// let result = re.replace("Springsteen, Bruce", |&: caps: &Captures| { - /// format!("{} {}", caps.at(2), caps.at(1)) + /// format!("{} {}", caps.at(2).unwrap_or(""), caps.at(1).unwrap_or("")) /// }); /// assert_eq!(result.as_slice(), "Bruce Springsteen"); /// # } @@ -712,27 +712,25 @@ impl<'t> Captures<'t> { Some((self.locs[s].unwrap(), self.locs[e].unwrap())) } - /// Returns the matched string for the capture group `i`. - /// If `i` isn't a valid capture group or didn't match anything, then the - /// empty string is returned. - pub fn at(&self, i: uint) -> &'t str { + /// Returns the matched string for the capture group `i`. If `i` isn't + /// a valid capture group or didn't match anything, then `None` is + /// returned. + pub fn at(&self, i: uint) -> Option<&'t str> { match self.pos(i) { - None => "", - Some((s, e)) => { - self.text.slice(s, e) - } + None => None, + Some((s, e)) => Some(self.text.slice(s, e)) } } - /// Returns the matched string for the capture group named `name`. - /// If `name` isn't a valid capture group or didn't match anything, then - /// the empty string is returned. - pub fn name(&self, name: &str) -> &'t str { + /// Returns the matched string for the capture group named `name`. If + /// `name` isn't a valid capture group or didn't match anything, then + /// `None` is returned. + pub fn name(&self, name: &str) -> Option<&'t str> { match self.named { - None => "", + None => None, Some(ref h) => { match h.get(name) { - None => "", + None => None, Some(i) => self.at(*i), } } @@ -769,11 +767,12 @@ impl<'t> Captures<'t> { // FIXME: Don't use regexes for this. It's completely unnecessary. let re = Regex::new(r"(^|[^$]|\b)\$(\w+)").unwrap(); let text = re.replace_all(text, |&mut: refs: &Captures| -> String { - let (pre, name) = (refs.at(1), refs.at(2)); + let pre = refs.at(1).unwrap_or(""); + let name = refs.at(2).unwrap_or(""); format!("{}{}", pre, match from_str::<uint>(name.as_slice()) { - None => self.name(name).to_string(), - Some(i) => self.at(i).to_string(), + None => self.name(name).unwrap_or("").to_string(), + Some(i) => self.at(i).unwrap_or("").to_string(), }) }); let re = Regex::new(r"\$\$").unwrap(); @@ -802,7 +801,7 @@ impl<'t> Iterator<&'t str> for SubCaptures<'t> { fn next(&mut self) -> Option<&'t str> { if self.idx < self.caps.len() { self.idx += 1; - Some(self.caps.at(self.idx - 1)) + Some(self.caps.at(self.idx - 1).unwrap_or("")) } else { None } From 5966815abea77bd4497634fcb06c7bbdecf5e08a Mon Sep 17 00:00:00 2001 From: Jake Goulding <jake.goulding@gmail.com> Date: Sun, 14 Dec 2014 09:48:56 -0500 Subject: [PATCH 12/59] InvariantLifetime is Copy-able Both ContravariantLifetime and CovariantLifetime are marked as Copy, so it makes sense for InvariantLifetime to be as well. --- src/libcore/kinds.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index 2b92ae8af0a..c0673c46142 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -259,6 +259,8 @@ pub mod marker { #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct InvariantLifetime<'a>; + impl<'a> Copy for InvariantLifetime<'a> {} + /// A type which is considered "not sendable", meaning that it cannot /// be safely sent between tasks, even if it is owned. This is /// typically embedded in other types, such as `Gc`, to ensure that From 2f7a5f49029279bd734ef87fd65ae992b2ad9f40 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <japaricious@gmail.com> Date: Sat, 13 Dec 2014 22:04:23 -0500 Subject: [PATCH 13/59] libcore: make iterator adaptors `Clone`able --- src/libcore/iter.rs | 124 +++++++++++++++++++++++++++++++ src/libcore/slice.rs | 11 +++ src/test/run-pass/issue-12677.rs | 17 +++++ 3 files changed, 152 insertions(+) create mode 100644 src/test/run-pass/issue-12677.rs diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 8ee2a8874bb..1eac8a39eba 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1388,6 +1388,19 @@ pub struct Map<A, B, I: Iterator<A>, F: FnMut(A) -> B> { f: F, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, B, I, F> Clone for Map<A, B, I, F> where + I: Clone + Iterator<A>, + F: Clone + FnMut(A) -> B, +{ + fn clone(&self) -> Map<A, B, I, F> { + Map { + iter: self.iter.clone(), + f: self.f.clone(), + } + } +} + impl<A, B, I, F> Map<A, B, I, F> where I: Iterator<A>, F: FnMut(A) -> B { #[inline] fn do_map(&mut self, elt: Option<A>) -> Option<B> { @@ -1449,6 +1462,19 @@ pub struct Filter<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { predicate: P, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, I, P> Clone for Filter<A, I, P> where + I: Clone + Iterator<A>, + P: Clone + FnMut(&A) -> bool, +{ + fn clone(&self) -> Filter<A, I, P> { + Filter { + iter: self.iter.clone(), + predicate: self.predicate.clone(), + } + } +} + #[unstable = "trait is unstable"] impl<A, I, P> Iterator<A> for Filter<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { #[inline] @@ -1494,6 +1520,19 @@ pub struct FilterMap<A, B, I, F> where I: Iterator<A>, F: FnMut(A) -> Option<B> f: F, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, B, I, F> Clone for FilterMap<A, B, I, F> where + I: Clone + Iterator<A>, + F: Clone + FnMut(A) -> Option<B>, +{ + fn clone(&self) -> FilterMap<A, B, I, F> { + FilterMap { + iter: self.iter.clone(), + f: self.f.clone(), + } + } +} + #[unstable = "trait is unstable"] impl<A, B, I, F> Iterator<B> for FilterMap<A, B, I, F> where I: Iterator<A>, @@ -1657,6 +1696,20 @@ pub struct SkipWhile<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { predicate: P, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, I, P> Clone for SkipWhile<A, I, P> where + I: Clone + Iterator<A>, + P: Clone + FnMut(&A) -> bool, +{ + fn clone(&self) -> SkipWhile<A, I, P> { + SkipWhile { + iter: self.iter.clone(), + flag: self.flag, + predicate: self.predicate.clone(), + } + } +} + #[unstable = "trait is unstable"] impl<A, I, P> Iterator<A> for SkipWhile<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { #[inline] @@ -1686,6 +1739,20 @@ pub struct TakeWhile<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { predicate: P, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, I, P> Clone for TakeWhile<A, I, P> where + I: Clone + Iterator<A>, + P: Clone + FnMut(&A) -> bool, +{ + fn clone(&self) -> TakeWhile<A, I, P> { + TakeWhile { + iter: self.iter.clone(), + flag: self.flag, + predicate: self.predicate.clone(), + } + } +} + #[unstable = "trait is unstable"] impl<A, I, P> Iterator<A> for TakeWhile<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { #[inline] @@ -1847,6 +1914,21 @@ pub struct Scan<A, B, I, St, F> where I: Iterator<A>, F: FnMut(&mut St, A) -> Op pub state: St, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, B, I, St, F> Clone for Scan<A, B, I, St, F> where + I: Clone + Iterator<A>, + St: Clone, + F: Clone + FnMut(&mut St, A) -> Option<B>, +{ + fn clone(&self) -> Scan<A, B, I, St, F> { + Scan { + iter: self.iter.clone(), + f: self.f.clone(), + state: self.state.clone(), + } + } +} + #[unstable = "trait is unstable"] impl<A, B, I, St, F> Iterator<B> for Scan<A, B, I, St, F> where I: Iterator<A>, @@ -1876,6 +1958,22 @@ pub struct FlatMap<A, B, I, U, F> where I: Iterator<A>, U: Iterator<B>, F: FnMut backiter: Option<U>, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, B, I, U, F> Clone for FlatMap<A, B, I, U, F> where + I: Clone + Iterator<A>, + U: Clone + Iterator<B>, + F: Clone + FnMut(A) -> U, +{ + fn clone(&self) -> FlatMap<A, B, I, U, F> { + FlatMap { + iter: self.iter.clone(), + f: self.f.clone(), + frontiter: self.frontiter.clone(), + backiter: self.backiter.clone(), + } + } +} + #[unstable = "trait is unstable"] impl<A, B, I, U, F> Iterator<B> for FlatMap<A, B, I, U, F> where I: Iterator<A>, @@ -2020,6 +2118,19 @@ pub struct Inspect<A, I, F> where I: Iterator<A>, F: FnMut(&A) { f: F, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, I, F> Clone for Inspect<A, I, F> where + I: Clone + Iterator<A>, + F: Clone + FnMut(&A), +{ + fn clone(&self) -> Inspect<A, I, F> { + Inspect { + iter: self.iter.clone(), + f: self.f.clone(), + } + } +} + impl<A, I, F> Inspect<A, I, F> where I: Iterator<A>, F: FnMut(&A) { #[inline] fn do_inspect(&mut self, elt: Option<A>) -> Option<A> { @@ -2114,6 +2225,19 @@ pub struct Unfold<A, St, F> where F: FnMut(&mut St) -> Option<A> { pub state: St, } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<A, St, F> Clone for Unfold<A, St, F> where + F: Clone + FnMut(&mut St) -> Option<A>, + St: Clone, +{ + fn clone(&self) -> Unfold<A, St, F> { + Unfold { + f: self.f.clone(), + state: self.state.clone(), + } + } +} + #[experimental] impl<A, St, F> Unfold<A, St, F> where F: FnMut(&mut St) -> Option<A> { /// Creates a new iterator with the specified closure as the "iterator diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 27a4328ba80..059292c11f2 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1291,6 +1291,17 @@ pub struct Splits<'a, T:'a, P> where P: FnMut(&T) -> bool { finished: bool } +// FIXME(#19839) Remove in favor of `#[deriving(Clone)]` +impl<'a, T, P> Clone for Splits<'a, T, P> where P: Clone + FnMut(&T) -> bool { + fn clone(&self) -> Splits<'a, T, P> { + Splits { + v: self.v, + pred: self.pred.clone(), + finished: self.finished, + } + } +} + #[experimental = "needs review"] impl<'a, T, P> Iterator<&'a [T]> for Splits<'a, T, P> where P: FnMut(&T) -> bool { #[inline] diff --git a/src/test/run-pass/issue-12677.rs b/src/test/run-pass/issue-12677.rs new file mode 100644 index 00000000000..ef68daa8ce5 --- /dev/null +++ b/src/test/run-pass/issue-12677.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let s = "Hello"; + let first = s.bytes(); + let second = first.clone(); + + assert_eq!(first.collect::<Vec<u8>>(), second.collect::<Vec<u8>>()) +} From 5c29df6b28a82d1c74c9d799f82daac81f0304d8 Mon Sep 17 00:00:00 2001 From: jbranchaud <jbranchaud@gmail.com> Date: Sun, 14 Dec 2014 12:09:42 -0600 Subject: [PATCH 14/59] Fix indentation in a code example in the ownership guide. --- src/doc/guide-ownership.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index aebafebf98e..613eb7bbfdb 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -341,7 +341,7 @@ fn main() { { // | let y = &5i; // ---+ y goes into scope let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here + x = &f.x; // | | error here } // ---+ f & y go out of scope // | println!("{}", x); // | From a333e013fc939a933f2cdc951da0ec442abeebd9 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop <nicholasbishop@gmail.com> Date: Sun, 14 Dec 2014 13:38:46 -0500 Subject: [PATCH 15/59] Fix typo: intuitive -> unintuitive --- src/doc/guide-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide-macros.md b/src/doc/guide-macros.md index 65b6014b496..a7f4d103aca 100644 --- a/src/doc/guide-macros.md +++ b/src/doc/guide-macros.md @@ -195,7 +195,7 @@ early_return!(input_2, [T::SpecialB]); As the above example demonstrates, `$(...)*` is also valid on the right-hand side of a macro definition. The behavior of `*` in transcription, especially in cases where multiple `*`s are nested, and multiple different -names are involved, can seem somewhat magical and intuitive at first. The +names are involved, can seem somewhat magical and unintuitive at first. The system that interprets them is called "Macro By Example". The two rules to keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer" of repetitions for all of the `$name`s it contains in lockstep, and (2) each From 1fbca8824a6b6018191b7ee998d2c97f30c481d7 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Sun, 14 Dec 2014 10:34:23 -0800 Subject: [PATCH 16/59] std: Fully stabilize Option<T> This commit takes a second pass through the `std::option` module to fully stabilize any lingering methods inside of it. These items were made stable as-is * Some * None * as_mut * expect * unwrap * unwrap_or * unwrap_or_else * map * map_or * map_or_else * and_then * or_else * unwrap_or_default * Default implementation * FromIterator implementation * Copy implementation These items were made stable with modifications * iter - now returns a struct called Iter * iter_mut - now returns a struct called IterMut * into_iter - now returns a struct called IntoIter, Clone is never implemented This is a breaking change due to the modifications to the names of the iterator types returned. Code referencing the old names should updated to referencing the newer names instead. This is also a breaking change due to the fact that `IntoIter` no longer implements the `Clone` trait. These items were explicitly not stabilized * as_slice - waiting on indexing conventions * as_mut_slice - waiting on conventions with as_slice as well * cloned - the API was still just recently added * ok_or - API remains experimental * ok_or_else - API remains experimental [breaking-change] --- src/libcore/option.rs | 113 ++++++++++++++++++++++++------- src/librustc/metadata/encoder.rs | 10 +-- src/librustc_driver/pretty.rs | 2 +- 3 files changed, 93 insertions(+), 32 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 7be47f73e9e..58d71e0ed08 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -168,8 +168,10 @@ use ops::{Deref, FnOnce}; #[stable] pub enum Option<T> { /// No value + #[stable] None, /// Some value `T` + #[stable] Some(T) } @@ -261,7 +263,7 @@ impl<T> Option<T> { /// assert_eq!(x, Some(42u)); /// ``` #[inline] - #[unstable = "waiting for mut conventions"] + #[stable] pub fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> { match *self { Some(ref mut x) => Some(x), @@ -321,7 +323,7 @@ impl<T> Option<T> { /// x.expect("the world is ending"); // panics with `world is ending` /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn expect(self, msg: &str) -> T { match self { Some(val) => val, @@ -353,7 +355,7 @@ impl<T> Option<T> { /// assert_eq!(x.unwrap(), "air"); // fails /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap(self) -> T { match self { Some(val) => val, @@ -370,7 +372,7 @@ impl<T> Option<T> { /// assert_eq!(None.unwrap_or("bike"), "bike"); /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap_or(self, def: T) -> T { match self { Some(x) => x, @@ -388,7 +390,7 @@ impl<T> Option<T> { /// assert_eq!(None.unwrap_or_else(|| 2 * k), 20u); /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T { match self { Some(x) => x, @@ -412,7 +414,7 @@ impl<T> Option<T> { /// let num_as_int: Option<uint> = num_as_str.map(|n| n.len()); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { match self { Some(x) => Some(f(x)), @@ -432,7 +434,7 @@ impl<T> Option<T> { /// assert_eq!(x.map_or(42u, |v| v.len()), 42u); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U { match self { Some(t) => f(t), @@ -454,7 +456,7 @@ impl<T> Option<T> { /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42u); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, def: D, f: F) -> U { match self { Some(t) => f(t), @@ -520,9 +522,9 @@ impl<T> Option<T> { /// assert_eq!(x.iter().next(), None); /// ``` #[inline] - #[unstable = "waiting for iterator conventions"] - pub fn iter<'r>(&'r self) -> Item<&'r T> { - Item{opt: self.as_ref()} + #[stable] + pub fn iter(&self) -> Iter<T> { + Iter { inner: Item { opt: self.as_ref() } } } /// Returns a mutable iterator over the possibly contained value. @@ -542,8 +544,8 @@ impl<T> Option<T> { /// ``` #[inline] #[unstable = "waiting for iterator conventions"] - pub fn iter_mut<'r>(&'r mut self) -> Item<&'r mut T> { - Item{opt: self.as_mut()} + pub fn iter_mut(&mut self) -> IterMut<T> { + IterMut { inner: Item { opt: self.as_mut() } } } /// Returns a consuming iterator over the possibly contained value. @@ -560,9 +562,9 @@ impl<T> Option<T> { /// assert!(v.is_empty()); /// ``` #[inline] - #[unstable = "waiting for iterator conventions"] - pub fn into_iter(self) -> Item<T> { - Item{opt: self} + #[stable] + pub fn into_iter(self) -> IntoIter<T> { + IntoIter { inner: Item { opt: self } } } ///////////////////////////////////////////////////////////////////////// @@ -614,7 +616,7 @@ impl<T> Option<T> { /// assert_eq!(None.and_then(sq).and_then(sq), None); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> { match self { Some(x) => f(x), @@ -666,7 +668,7 @@ impl<T> Option<T> { /// assert_eq!(None.or_else(nobody), None); /// ``` #[inline] - #[unstable = "waiting for unboxed closures"] + #[stable] pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> { match self { Some(_) => self, @@ -731,7 +733,7 @@ impl<T: Default> Option<T> { /// assert_eq!(0i, bad_year); /// ``` #[inline] - #[unstable = "waiting for conventions"] + #[stable] pub fn unwrap_or_default(self) -> T { match self { Some(x) => x, @@ -744,6 +746,7 @@ impl<T: Default> Option<T> { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[unstable = "waiting on the stability of the trait itself"] impl<T> AsSlice<T> for Option<T> { /// Convert from `Option<T>` to `&[T]` (without copying) #[inline] @@ -761,20 +764,16 @@ impl<T> AsSlice<T> for Option<T> { #[stable] impl<T> Default for Option<T> { #[inline] + #[stable] fn default() -> Option<T> { None } } ///////////////////////////////////////////////////////////////////////////// -// The Option Iterator +// The Option Iterators ///////////////////////////////////////////////////////////////////////////// -/// An `Option` iterator that yields either one or zero elements -/// -/// The `Item` iterator is returned by the `iter`, `iter_mut` and `into_iter` -/// methods on `Option`. #[deriving(Clone)] -#[unstable = "waiting for iterator conventions"] -pub struct Item<A> { +struct Item<A> { opt: Option<A> } @@ -802,6 +801,66 @@ impl<A> DoubleEndedIterator<A> for Item<A> { impl<A> ExactSizeIterator<A> for Item<A> {} +/// An iterator over a reference of the contained item in an Option. +#[stable] +pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } + +impl<'a, A> Iterator<&'a A> for Iter<'a, A> { + #[inline] + fn next(&mut self) -> Option<&'a A> { self.inner.next() } + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<'a, A> DoubleEndedIterator<&'a A> for Iter<'a, A> { + #[inline] + fn next_back(&mut self) -> Option<&'a A> { self.inner.next_back() } +} + +impl<'a, A> ExactSizeIterator<&'a A> for Iter<'a, A> {} + +impl<'a, A> Clone for Iter<'a, A> { + fn clone(&self) -> Iter<'a, A> { + Iter { inner: self.inner.clone() } + } +} + +/// An iterator over a mutable reference of the contained item in an Option. +#[stable] +pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } + +impl<'a, A> Iterator<&'a mut A> for IterMut<'a, A> { + #[inline] + fn next(&mut self) -> Option<&'a mut A> { self.inner.next() } + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<'a, A> DoubleEndedIterator<&'a mut A> for IterMut<'a, A> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut A> { self.inner.next_back() } +} + +impl<'a, A> ExactSizeIterator<&'a mut A> for IterMut<'a, A> {} + +/// An iterator over the item contained inside an Option. +#[stable] +pub struct IntoIter<A> { inner: Item<A> } + +impl<A> Iterator<A> for IntoIter<A> { + #[inline] + fn next(&mut self) -> Option<A> { self.inner.next() } + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<A> DoubleEndedIterator<A> for IntoIter<A> { + #[inline] + fn next_back(&mut self) -> Option<A> { self.inner.next_back() } +} + +impl<A> ExactSizeIterator<A> for IntoIter<A> {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// @@ -826,6 +885,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { /// assert!(res == Some(vec!(2u, 3u))); /// ``` #[inline] + #[stable] fn from_iter<I: Iterator<Option<A>>>(iter: I) -> Option<V> { // FIXME(#11084): This could be replaced with Iterator::scan when this // performance bug is closed. @@ -860,5 +920,6 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { } } +#[stable] impl<T:Copy> Copy for Option<T> {} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 9804e3c20aa..9381c97d49d 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -364,12 +364,12 @@ fn encode_enum_variant_info(ecx: &EncodeContext, } } -fn encode_path<PI: Iterator<PathElem> + Clone>(rbml_w: &mut Encoder, - mut path: PI) { +fn encode_path<PI: Iterator<PathElem>>(rbml_w: &mut Encoder, path: PI) { + let path = path.collect::<Vec<_>>(); rbml_w.start_tag(tag_path); - rbml_w.wr_tagged_u32(tag_path_len, path.clone().count() as u32); - for pe in path { - let tag = match pe { + rbml_w.wr_tagged_u32(tag_path_len, path.len() as u32); + for pe in path.iter() { + let tag = match *pe { ast_map::PathMod(_) => tag_path_elem_mod, ast_map::PathName(_) => tag_path_elem_name }; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 7ec05b6a030..57004d71c75 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -325,7 +325,7 @@ impl FromStr for UserIdentifiedItem { } enum NodesMatchingUII<'a, 'ast: 'a> { - NodesMatchingDirect(option::Item<ast::NodeId>), + NodesMatchingDirect(option::IntoIter<ast::NodeId>), NodesMatchingSuffix(ast_map::NodesMatchingSuffix<'a, 'ast, String>), } From 0a968ef199c99b9c1a3420029ca8bc5af5b249ec Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <japaricious@gmail.com> Date: Sun, 14 Dec 2014 21:10:51 -0500 Subject: [PATCH 17/59] Add test for #19129 Closes #19129 --- src/test/run-pass/issue-19129-1.rs | 25 +++++++++++++++++++++++++ src/test/run-pass/issue-19129-2.rs | 19 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/run-pass/issue-19129-1.rs create mode 100644 src/test/run-pass/issue-19129-2.rs diff --git a/src/test/run-pass/issue-19129-1.rs b/src/test/run-pass/issue-19129-1.rs new file mode 100644 index 00000000000..eecc073b047 --- /dev/null +++ b/src/test/run-pass/issue-19129-1.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Trait<Input> { + type Output; + + fn method() -> <Self as Trait<Input>>::Output; +} + +impl<T> Trait<T> for () { + type Output = (); + + fn method() {} +} + +fn main() {} diff --git a/src/test/run-pass/issue-19129-2.rs b/src/test/run-pass/issue-19129-2.rs new file mode 100644 index 00000000000..aeaf5e37644 --- /dev/null +++ b/src/test/run-pass/issue-19129-2.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Trait<Input> { + type Output; + + fn method() -> bool { false } +} + +fn main() {} From 0d38cae0b9e23f1557ce96fd7a9677f1040fab54 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Sun, 14 Dec 2014 18:56:19 -0800 Subject: [PATCH 18/59] std: Bind port early to make a test more reliable This test would read with a timeout and then send a UDP message, expecting the message to be received. The receiving port, however, was bound in the child thread so it could be the case that the timeout and send happens before the child thread runs. To remedy this we just bind the port before the child thread runs, moving it into the child later on. cc #19120 --- src/libstd/io/net/udp.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index 78951b8dae2..ce7e5ca5f5e 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -557,11 +557,12 @@ mod test { let addr1 = next_test_ip4(); let addr2 = next_test_ip4(); let mut a = UdpSocket::bind(addr1).unwrap(); + let a2 = UdpSocket::bind(addr2).unwrap(); let (tx, rx) = channel(); let (tx2, rx2) = channel(); spawn(move|| { - let mut a = UdpSocket::bind(addr2).unwrap(); + let mut a = a2; assert_eq!(a.recv_from(&mut [0]), Ok((1, addr1))); assert_eq!(a.send_to(&[0], addr1), Ok(())); rx.recv(); From f63784f4e279facc881c51451d5cd8315336585e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <japaricious@gmail.com> Date: Sun, 14 Dec 2014 22:21:43 -0500 Subject: [PATCH 19/59] impl `Copy` for `NoSend`/`NoSync` --- src/libcore/kinds.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index 2b92ae8af0a..5d122e83116 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -264,8 +264,7 @@ pub mod marker { /// typically embedded in other types, such as `Gc`, to ensure that /// their instances remain thread-local. #[lang="no_send_bound"] - #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] - #[allow(missing_copy_implementations)] + #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct NoSend; /// A type which is considered "not POD", meaning that it is not @@ -280,8 +279,7 @@ pub mod marker { /// its contents are not threadsafe, hence they cannot be /// shared between tasks. #[lang="no_sync_bound"] - #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] - #[allow(missing_copy_implementations)] + #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct NoSync; /// A type which is considered managed by the GC. This is typically From c270390f1b7d2489644f30445e35e25a1595f256 Mon Sep 17 00:00:00 2001 From: Martin Pool <mbp@sourcefrog.net> Date: Sun, 14 Dec 2014 22:26:09 -0800 Subject: [PATCH 20/59] Fix Markdown syntax in docs for OsRng --- src/libstd/rand/os.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 5405892535c..fcd73379667 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -117,7 +117,8 @@ mod imp { /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// /// This does not block. pub struct OsRng { inner: OsRngInner, @@ -184,7 +185,8 @@ mod imp { /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// /// This does not block. pub struct OsRng { marker: marker::NoCopy @@ -254,7 +256,8 @@ mod imp { /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// /// This does not block. pub struct OsRng { hcryptprov: HCRYPTPROV From 8d6895a9c097a90bb00459eccacb6ba06c6437f9 Mon Sep 17 00:00:00 2001 From: Steven Fackler <sfackler@gmail.com> Date: Sun, 14 Dec 2014 23:36:50 -0800 Subject: [PATCH 21/59] Free stdin on exit --- src/libstd/io/stdio.rs | 7 +++++++ src/test/run-pass-valgrind/cleanup-stdin.rs | 13 +++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/run-pass-valgrind/cleanup-stdin.rs diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 344012a09a0..548dfdd6273 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -41,6 +41,7 @@ use option::Option; use option::Option::{Some, None}; use ops::{Deref, DerefMut, FnOnce}; use result::Result::{Ok, Err}; +use rt; use rustrt; use rustrt::local::Local; use rustrt::task::Task; @@ -224,6 +225,12 @@ pub fn stdin() -> StdinReader { inner: Arc::new(Mutex::new(stdin)) }; STDIN = mem::transmute(box stdin); + + // Make sure to free it at exit + rt::at_exit(|| { + mem::transmute::<_, Box<StdinReader>>(STDIN); + STDIN = 0 as *const _; + }); }); (*STDIN).clone() diff --git a/src/test/run-pass-valgrind/cleanup-stdin.rs b/src/test/run-pass-valgrind/cleanup-stdin.rs new file mode 100644 index 00000000000..21160553f79 --- /dev/null +++ b/src/test/run-pass-valgrind/cleanup-stdin.rs @@ -0,0 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _ = std::io::stdin(); +} From 8fcc832198e86c4f3ff2912c5cfc91dc0896098b Mon Sep 17 00:00:00 2001 From: Andrew Wagner <drewm1980@gmail.com> Date: Mon, 15 Dec 2014 10:22:49 +0100 Subject: [PATCH 22/59] Standardize some usages of "which" in docstrings In US english, "that" is used in restrictive clauses in place of "which", and often affects the meaning of sentences. In UK english and many dialects, no distinction is made. While Rust devs want to avoid unproductive pedanticism, it is worth at least being uniform in documentation such as: http://doc.rust-lang.org/std/iter/index.html and also in cases where correct usage of US english clarifies the sentence. --- src/doc/guide.md | 2 +- src/libcollections/ring_buf.rs | 2 +- src/libcore/iter.rs | 52 +++++++++++++++++----------------- src/librand/lib.rs | 4 +-- src/libstd/comm/mod.rs | 12 ++++---- src/libstd/io/fs.rs | 10 +++---- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 6e178a2648d..c44cc86a8a2 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -4418,7 +4418,7 @@ for i in range(0u, nums.len()) { ``` This is strictly worse than using an actual iterator. The `.iter()` method on -vectors returns an iterator which iterates through a reference to each element +vectors returns an iterator that iterates through a reference to each element of the vector in turn. So write this: ```{rust} diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 084b585d7b9..b5f37219f7e 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -377,7 +377,7 @@ impl<T> RingBuf<T> { } } - /// Returns a front-to-back iterator which returns mutable references. + /// Returns a front-to-back iterator that returns mutable references. /// /// # Examples /// diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 8ee2a8874bb..25e012b71c1 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -110,8 +110,8 @@ pub trait Iterator<A> { #[unstable = "new convention for extension traits"] /// An extension trait providing numerous methods applicable to all iterators. pub trait IteratorExt<A>: Iterator<A> { - /// Chain this iterator with another, returning a new iterator which will - /// finish iterating over the current iterator, and then it will iterate + /// Chain this iterator with another, returning a new iterator that will + /// finish iterating over the current iterator, and then iterate /// over the other specified iterator. /// /// # Example @@ -130,7 +130,7 @@ pub trait IteratorExt<A>: Iterator<A> { Chain{a: self, b: other, flag: false} } - /// Creates an iterator which iterates over both this and the specified + /// Creates an iterator that iterates over both this and the specified /// iterators simultaneously, yielding the two elements as pairs. When /// either iterator returns None, all further invocations of next() will /// return None. @@ -151,7 +151,7 @@ pub trait IteratorExt<A>: Iterator<A> { Zip{a: self, b: other} } - /// Creates a new iterator which will apply the specified function to each + /// Creates a new iterator that will apply the specified function to each /// element returned by the first, yielding the mapped element instead. /// /// # Example @@ -169,8 +169,8 @@ pub trait IteratorExt<A>: Iterator<A> { Map{iter: self, f: f} } - /// Creates an iterator which applies the predicate to each element returned - /// by this iterator. Only elements which have the predicate evaluate to + /// Creates an iterator that applies the predicate to each element returned + /// by this iterator. Only elements that have the predicate evaluate to /// `true` will be yielded. /// /// # Example @@ -187,7 +187,7 @@ pub trait IteratorExt<A>: Iterator<A> { Filter{iter: self, predicate: predicate} } - /// Creates an iterator which both filters and maps elements. + /// Creates an iterator that both filters and maps elements. /// If the specified function returns None, the element is skipped. /// Otherwise the option is unwrapped and the new value is yielded. /// @@ -205,7 +205,7 @@ pub trait IteratorExt<A>: Iterator<A> { FilterMap { iter: self, f: f } } - /// Creates an iterator which yields a pair of the value returned by this + /// Creates an iterator that yields a pair of the value returned by this /// iterator plus the current index of iteration. /// /// # Example @@ -248,7 +248,7 @@ pub trait IteratorExt<A>: Iterator<A> { Peekable{iter: self, peeked: None} } - /// Creates an iterator which invokes the predicate on elements until it + /// Creates an iterator that invokes the predicate on elements until it /// returns false. Once the predicate returns false, all further elements are /// yielded. /// @@ -268,7 +268,7 @@ pub trait IteratorExt<A>: Iterator<A> { SkipWhile{iter: self, flag: false, predicate: predicate} } - /// Creates an iterator which yields elements so long as the predicate + /// Creates an iterator that yields elements so long as the predicate /// returns true. After the predicate returns false for the first time, no /// further elements will be yielded. /// @@ -287,8 +287,8 @@ pub trait IteratorExt<A>: Iterator<A> { TakeWhile{iter: self, flag: false, predicate: predicate} } - /// Creates an iterator which skips the first `n` elements of this iterator, - /// and then it yields all further items. + /// Creates an iterator that skips the first `n` elements of this iterator, + /// and then yields all further items. /// /// # Example /// @@ -305,8 +305,8 @@ pub trait IteratorExt<A>: Iterator<A> { Skip{iter: self, n: n} } - /// Creates an iterator which yields the first `n` elements of this - /// iterator, and then it will always return None. + /// Creates an iterator that yields the first `n` elements of this + /// iterator, and then will always return None. /// /// # Example /// @@ -324,7 +324,7 @@ pub trait IteratorExt<A>: Iterator<A> { Take{iter: self, n: n} } - /// Creates a new iterator which behaves in a similar fashion to fold. + /// Creates a new iterator that behaves in a similar fashion to fold. /// There is a state which is passed between each iteration and can be /// mutated as necessary. The yielded values from the closure are yielded /// from the Scan instance when not None. @@ -1223,7 +1223,7 @@ impl<A, T: Clone + RandomAccessIterator<A>> RandomAccessIterator<A> for Cycle<T> } } -/// An iterator which strings two iterators together +/// An iterator that strings two iterators together #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1297,7 +1297,7 @@ for Chain<T, U> { } } -/// An iterator which iterates two other iterators simultaneously +/// An iterator that iterates two other iterators simultaneously #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1380,7 +1380,7 @@ RandomAccessIterator<(A, B)> for Zip<T, U> { } } -/// An iterator which maps the values of `iter` with `f` +/// An iterator that maps the values of `iter` with `f` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct Map<A, B, I: Iterator<A>, F: FnMut(A) -> B> { @@ -1441,7 +1441,7 @@ impl<A, B, I, F> RandomAccessIterator<B> for Map<A, B, I, F> where } } -/// An iterator which filters the elements of `iter` with `predicate` +/// An iterator that filters the elements of `iter` with `predicate` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct Filter<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { @@ -1486,7 +1486,7 @@ impl<A, I, P> DoubleEndedIterator<A> for Filter<A, I, P> where } } -/// An iterator which uses `f` to both filter and map elements from `iter` +/// An iterator that uses `f` to both filter and map elements from `iter` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct FilterMap<A, B, I, F> where I: Iterator<A>, F: FnMut(A) -> Option<B> { @@ -1534,7 +1534,7 @@ impl<A, B, I, F> DoubleEndedIterator<B> for FilterMap<A, B, I, F> where } } -/// An iterator which yields the current count and the element during iteration +/// An iterator that yields the current count and the element during iteration #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1648,7 +1648,7 @@ impl<'a, A, T: Iterator<A>> Peekable<A, T> { } } -/// An iterator which rejects elements while `predicate` is true +/// An iterator that rejects elements while `predicate` is true #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct SkipWhile<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { @@ -1677,7 +1677,7 @@ impl<A, I, P> Iterator<A> for SkipWhile<A, I, P> where I: Iterator<A>, P: FnMut( } } -/// An iterator which only accepts elements while `predicate` is true +/// An iterator that only accepts elements while `predicate` is true #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct TakeWhile<A, I, P> where I: Iterator<A>, P: FnMut(&A) -> bool { @@ -1714,7 +1714,7 @@ impl<A, I, P> Iterator<A> for TakeWhile<A, I, P> where I: Iterator<A>, P: FnMut( } } -/// An iterator which skips over `n` elements of `iter`. +/// An iterator that skips over `n` elements of `iter`. #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -1782,7 +1782,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> { } } -/// An iterator which only iterates over the first `n` iterations of `iter`. +/// An iterator that only iterates over the first `n` iterations of `iter`. #[deriving(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] @@ -2075,7 +2075,7 @@ impl<A, I, F> RandomAccessIterator<A> for Inspect<A, I, F> where } } -/// An iterator which passes mutable state to a closure and yields the result. +/// An iterator that passes mutable state to a closure and yields the result. /// /// # Example: The Fibonacci Sequence /// diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 4fba3707703..dfcdad481a9 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -185,7 +185,7 @@ pub trait Rng { Rand::rand(self) } - /// Return an iterator which will yield an infinite number of randomly + /// Return an iterator that will yield an infinite number of randomly /// generated items. /// /// # Example diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 0a5b3e5771b..72ddbe19f54 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -81,7 +81,7 @@ //! Shared usage: //! //! ``` -//! // Create a shared channel which can be sent along from many tasks +//! // Create a shared channel that can be sent along from many tasks //! // where tx is the sending half (tx for transmission), and rx is the receiving //! // half (rx for receiving). //! let (tx, rx) = channel(); @@ -176,7 +176,7 @@ // The choice of implementation of all channels is to be built on lock-free data // structures. The channels themselves are then consequently also lock-free data // structures. As always with lock-free code, this is a very "here be dragons" -// territory, especially because I'm unaware of any academic papers which have +// territory, especially because I'm unaware of any academic papers that have // gone into great length about channels of these flavors. // // ## Flavors of channels @@ -190,7 +190,7 @@ // They contain as few atomics as possible and involve one and // exactly one allocation. // * Streams - these channels are optimized for the non-shared use case. They -// use a different concurrent queue which is more tailored for this +// use a different concurrent queue that is more tailored for this // use case. The initial allocation of this flavor of channel is not // optimized. // * Shared - this is the most general form of channel that this module offers, @@ -205,7 +205,7 @@ // shared and concurrent queue holding all of the actual data. // // With two flavors of channels, two flavors of queues are also used. We have -// chosen to use queues from a well-known author which are abbreviated as SPSC +// chosen to use queues from a well-known author that are abbreviated as SPSC // and MPSC (single producer, single consumer and multiple producer, single // consumer). SPSC queues are used for streams while MPSC queues are used for // shared channels. @@ -309,7 +309,7 @@ // // Sadly this current implementation requires multiple allocations, so I have // seen the throughput of select() be much worse than it should be. I do not -// believe that there is anything fundamental which needs to change about these +// believe that there is anything fundamental that needs to change about these // channels, however, in order to support a more efficient select(). // // # Conclusion @@ -910,7 +910,7 @@ impl<T: Send> Receiver<T> { } } - /// Returns an iterator which will block waiting for messages, but never + /// Returns an iterator that will block waiting for messages, but never /// `panic!`. It will return `None` when the channel has hung up. #[unstable] pub fn iter<'a>(&'a self) -> Messages<'a, T> { diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index da0834dc9ef..32f62427216 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -200,7 +200,7 @@ impl File { .update_desc("couldn't create file") } - /// Returns the original path which was used to open this file. + /// Returns the original path that was used to open this file. pub fn path<'a>(&'a self) -> &'a Path { &self.path } @@ -215,7 +215,7 @@ impl File { } /// This function is similar to `fsync`, except that it may not synchronize - /// file metadata to the filesystem. This is intended for use case which + /// file metadata to the filesystem. This is intended for use cases that /// must synchronize content, but don't need the metadata on disk. The goal /// of this method is to reduce disk operations. pub fn datasync(&mut self) -> IoResult<()> { @@ -456,7 +456,7 @@ pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { /// # Error /// /// This function will return an error on failure. Failure conditions include -/// reading a file that does not exist or reading a file which is not a symlink. +/// reading a file that does not exist or reading a file that is not a symlink. pub fn readlink(path: &Path) -> IoResult<Path> { fs_imp::readlink(path) .update_err("couldn't resolve symlink for path", |e| @@ -546,7 +546,7 @@ pub fn readdir(path: &Path) -> IoResult<Vec<Path>> { |e| format!("{}; path={}", e, path.display())) } -/// Returns an iterator which will recursively walk the directory structure +/// Returns an iterator that will recursively walk the directory structure /// rooted at `path`. The path given will not be iterated over, and this will /// perform iteration in some top-down order. The contents of unreadable /// subdirectories are ignored. @@ -557,7 +557,7 @@ pub fn walk_dir(path: &Path) -> IoResult<Directories> { }) } -/// An iterator which walks over a directory +/// An iterator that walks over a directory pub struct Directories { stack: Vec<Path>, } From 4df66cd014409042f1ddbc2f2130c81e4bdc941f Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Mon, 15 Dec 2014 22:31:38 +0900 Subject: [PATCH 23/59] Resolve lifetimes in associated types --- src/libsyntax/visit.rs | 19 +++++++++------- .../associated-types-resolve-lifetime.rs | 22 +++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/associated-types-resolve-lifetime.rs diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3535c6e267e..cf3efeeeb8f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -555,14 +555,18 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, } } +pub fn walk_ty_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v TyParam) { + visitor.visit_ident(param.span, param.ident); + walk_ty_param_bounds_helper(visitor, ¶m.bounds); + match param.default { + Some(ref ty) => visitor.visit_ty(&**ty), + None => {} + } +} + pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { for type_parameter in generics.ty_params.iter() { - visitor.visit_ident(type_parameter.span, type_parameter.ident); - walk_ty_param_bounds_helper(visitor, &type_parameter.bounds); - match type_parameter.default { - Some(ref ty) => visitor.visit_ty(&**ty), - None => {} - } + walk_ty_param(visitor, type_parameter); } walk_lifetime_decls_helper(visitor, &generics.lifetimes); for predicate in generics.where_clause.predicates.iter() { @@ -665,8 +669,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v Tr RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type), ProvidedMethod(ref method) => walk_method_helper(visitor, &**method), TypeTraitItem(ref associated_type) => { - visitor.visit_ident(associated_type.ty_param.span, - associated_type.ty_param.ident) + walk_ty_param(visitor, &associated_type.ty_param); } } } diff --git a/src/test/run-pass/associated-types-resolve-lifetime.rs b/src/test/run-pass/associated-types-resolve-lifetime.rs new file mode 100644 index 00000000000..1be09e1e068 --- /dev/null +++ b/src/test/run-pass/associated-types-resolve-lifetime.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get<T> { + fn get(&self) -> T; +} + +trait Trait<'a> { + type T: 'static; + type U: Get<&'a int>; +} + +fn main() {} From 2e74291290c23f60428917b0449aa1d0656263eb Mon Sep 17 00:00:00 2001 From: Pedro Larroy <pedro.larroy@here.com> Date: Mon, 15 Dec 2014 15:01:26 +0100 Subject: [PATCH 24/59] remove explicit if_let and tuple_indexing feature enables as they now trigger warnings --- src/libcollections/lib.rs | 2 +- src/librustc_borrowck/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 039bbcd2b70..274fa13d074 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -24,7 +24,7 @@ #![allow(unknown_features)] #![feature(macro_rules, default_type_params, phase, globs)] #![feature(unsafe_destructor, import_shadowing, slicing_syntax)] -#![feature(tuple_indexing, unboxed_closures)] +#![feature(unboxed_closures)] #![no_std] #[phase(plugin, link)] extern crate core; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index db19a09deba..ffc5a3919b6 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -16,8 +16,8 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)] -#![feature(slicing_syntax, tuple_indexing, unsafe_destructor)] +#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)] +#![feature(slicing_syntax, unsafe_destructor)] #![feature(rustc_diagnostic_macros)] #![feature(unboxed_closures)] #![allow(non_camel_case_types)] From c9ea7c9a58bc2bcfe77d264cedaeca5a3296634a Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Mon, 15 Dec 2014 09:06:06 -0800 Subject: [PATCH 25/59] serialize: Change some FnOnce bounds to FnMut Relax some of the bounds on the decoder methods back to FnMut to help accomodate some more flavorful variants of decoders which may need to run the closure more than once when it, for example, attempts to find the first successful enum to decode. This a breaking change due to the bounds for the trait switching, and clients will need to update from `FnOnce` to `FnMut` as well as likely making the local function binding mutable in order to call the function. [breaking-change] --- src/librbml/lib.rs | 14 ++++++++------ src/libserialize/json.rs | 11 ++++++----- src/libserialize/serialize.rs | 6 +++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 28d5e1812f0..bbedbc75395 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -499,8 +499,9 @@ pub mod reader { Ok(result) } - fn read_enum_variant<T, F>(&mut self, _: &[&str], f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult<T>, + fn read_enum_variant<T, F>(&mut self, _: &[&str], + mut f: F) -> DecodeResult<T> + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult<T>, { debug!("read_enum_variant()"); let idx = try!(self._next_uint(EsEnumVid)); @@ -526,8 +527,9 @@ pub mod reader { f(self) } - fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult<T>, + fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], + mut f: F) -> DecodeResult<T> + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult<T>, { debug!("read_enum_struct_variant()"); let idx = try!(self._next_uint(EsEnumVid)); @@ -610,8 +612,8 @@ pub mod reader { self.read_tuple_arg(idx, f) } - fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder<'doc>, bool) -> DecodeResult<T>, + fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where + F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult<T>, { debug!("read_option()"); self.read_enum("Option", move |this| { diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index d34828ccee3..6047c76d093 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2082,8 +2082,9 @@ impl ::Decoder<DecoderError> for Decoder { f(self) } - fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>, + fn read_enum_variant<T, F>(&mut self, names: &[&str], + mut f: F) -> DecodeResult<T> + where F: FnMut(&mut Decoder, uint) -> DecodeResult<T>, { debug!("read_enum_variant(names={})", names); let name = match self.pop() { @@ -2133,7 +2134,7 @@ impl ::Decoder<DecoderError> for Decoder { } fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>, + F: FnMut(&mut Decoder, uint) -> DecodeResult<T>, { debug!("read_enum_struct_variant(names={})", names); self.read_enum_variant(names, f) @@ -2230,8 +2231,8 @@ impl ::Decoder<DecoderError> for Decoder { self.read_tuple_arg(idx, f) } - fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where - F: FnOnce(&mut Decoder, bool) -> DecodeResult<T>, + fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where + F: FnMut(&mut Decoder, bool) -> DecodeResult<T>, { debug!("read_option()"); match self.pop() { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 98bd2f6bc93..0e0d3b4115b 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -120,12 +120,12 @@ pub trait Decoder<E> { F: FnOnce(&mut Self) -> Result<T, E>; fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where - F: FnOnce(&mut Self, uint) -> Result<T, E>; + F: FnMut(&mut Self, uint) -> Result<T, E>; fn read_enum_variant_arg<T, F>(&mut self, a_idx: uint, f: F) -> Result<T, E> where F: FnOnce(&mut Self) -> Result<T, E>; fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, E> where - F: FnOnce(&mut Self, uint) -> Result<T, E>; + F: FnMut(&mut Self, uint) -> Result<T, E>; fn read_enum_struct_variant_field<T, F>(&mut self, &f_name: &str, f_idx: uint, @@ -154,7 +154,7 @@ pub trait Decoder<E> { // Specialized types: fn read_option<T, F>(&mut self, f: F) -> Result<T, E> where - F: FnOnce(&mut Self, bool) -> Result<T, E>; + F: FnMut(&mut Self, bool) -> Result<T, E>; fn read_seq<T, F>(&mut self, f: F) -> Result<T, E> where F: FnOnce(&mut Self, uint) -> Result<T, E>; From 556d971f83ea5950444b0a5b5392cd0040f077f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <japaricious@gmail.com> Date: Sat, 13 Dec 2014 23:06:44 -0500 Subject: [PATCH 26/59] Remove internal uses of `marker::NoCopy` --- src/libcollections/btree/node.rs | 4 ---- src/libcollections/ring_buf.rs | 2 -- src/libcore/atomic.rs | 19 +++++++------------ src/libcore/cell.rs | 2 -- src/libcore/slice.rs | 7 ++----- src/librustc/util/snapshot_vec.rs | 9 +++------ src/librustrt/task.rs | 4 +--- src/libstd/rand/os.rs | 7 +++---- src/libstd/sys/common/thread_local.rs | 3 --- src/libstd/task.rs | 6 ++---- src/libstd/thread_local/mod.rs | 5 ----- 11 files changed, 18 insertions(+), 50 deletions(-) diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index ae23f38c929..a7250b862c2 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -18,7 +18,6 @@ pub use self::TraversalItem::*; use core::prelude::*; use core::{slice, mem, ptr, cmp, num, raw}; -use core::kinds::marker; use core::iter::Zip; use core::borrow::BorrowFrom; use alloc::heap; @@ -175,7 +174,6 @@ fn calculate_offsets_generic<K, V>(capacity: uint, is_leaf: bool) -> (uint, uint struct RawItems<T> { head: *const T, tail: *const T, - marker: marker::NoCopy } impl<T> RawItems<T> { @@ -188,13 +186,11 @@ impl<T> RawItems<T> { RawItems { head: ptr, tail: (ptr as uint + len) as *const T, - marker: marker::NoCopy } } else { RawItems { head: ptr, tail: ptr.offset(len as int), - marker: marker::NoCopy } } } diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 084b585d7b9..e8dc3aeb52c 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -402,7 +402,6 @@ impl<T> RingBuf<T> { cap: self.cap, ptr: self.ptr, marker: marker::ContravariantLifetime::<'a>, - marker2: marker::NoCopy } } @@ -952,7 +951,6 @@ pub struct MutItems<'a, T:'a> { head: uint, cap: uint, marker: marker::ContravariantLifetime<'a>, - marker2: marker::NoCopy } impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> { diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 748f5d774a4..bb2fed19e2a 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -15,7 +15,6 @@ pub use self::Ordering::*; use intrinsics; -use std::kinds::marker; use cell::UnsafeCell; use kinds::Copy; @@ -23,28 +22,24 @@ use kinds::Copy; #[stable] pub struct AtomicBool { v: UnsafeCell<uint>, - nocopy: marker::NoCopy } /// A signed integer type which can be safely shared between threads. #[stable] pub struct AtomicInt { v: UnsafeCell<int>, - nocopy: marker::NoCopy } /// An unsigned integer type which can be safely shared between threads. #[stable] pub struct AtomicUint { v: UnsafeCell<uint>, - nocopy: marker::NoCopy } /// A raw pointer type which can be safely shared between threads. #[stable] pub struct AtomicPtr<T> { p: UnsafeCell<uint>, - nocopy: marker::NoCopy } /// Atomic memory orderings @@ -87,15 +82,15 @@ impl Copy for Ordering {} /// An `AtomicBool` initialized to `false`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_BOOL: AtomicBool = - AtomicBool { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy }; + AtomicBool { v: UnsafeCell { value: 0 } }; /// An `AtomicInt` initialized to `0`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_INT: AtomicInt = - AtomicInt { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy }; + AtomicInt { v: UnsafeCell { value: 0 } }; /// An `AtomicUint` initialized to `0`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_UINT: AtomicUint = - AtomicUint { v: UnsafeCell { value: 0, }, nocopy: marker::NoCopy }; + AtomicUint { v: UnsafeCell { value: 0, } }; // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly const UINT_TRUE: uint = -1; @@ -115,7 +110,7 @@ impl AtomicBool { #[stable] pub fn new(v: bool) -> AtomicBool { let val = if v { UINT_TRUE } else { 0 }; - AtomicBool { v: UnsafeCell::new(val), nocopy: marker::NoCopy } + AtomicBool { v: UnsafeCell::new(val) } } /// Loads a value from the bool. @@ -355,7 +350,7 @@ impl AtomicInt { #[inline] #[stable] pub fn new(v: int) -> AtomicInt { - AtomicInt {v: UnsafeCell::new(v), nocopy: marker::NoCopy} + AtomicInt {v: UnsafeCell::new(v)} } /// Loads a value from the int. @@ -541,7 +536,7 @@ impl AtomicUint { #[inline] #[stable] pub fn new(v: uint) -> AtomicUint { - AtomicUint { v: UnsafeCell::new(v), nocopy: marker::NoCopy } + AtomicUint { v: UnsafeCell::new(v) } } /// Loads a value from the uint. @@ -728,7 +723,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable] pub fn new(p: *mut T) -> AtomicPtr<T> { - AtomicPtr { p: UnsafeCell::new(p as uint), nocopy: marker::NoCopy } + AtomicPtr { p: UnsafeCell::new(p as uint) } } /// Loads a value from the pointer. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1ec2efaf801..afb6249e7ae 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -234,7 +234,6 @@ impl<T:PartialEq + Copy> PartialEq for Cell<T> { pub struct RefCell<T> { value: UnsafeCell<T>, borrow: Cell<BorrowFlag>, - nocopy: marker::NoCopy, noshare: marker::NoSync, } @@ -251,7 +250,6 @@ impl<T> RefCell<T> { RefCell { value: UnsafeCell::new(value), borrow: Cell::new(UNUSED), - nocopy: marker::NoCopy, noshare: marker::NoSync, } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 27a4328ba80..1b57bec0733 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -611,13 +611,11 @@ impl<T> SlicePrelude<T> for [T] { if mem::size_of::<T>() == 0 { MutItems{ptr: p, end: (p as uint + self.len()) as *mut T, - marker: marker::ContravariantLifetime::<'a>, - marker2: marker::NoCopy} + marker: marker::ContravariantLifetime::<'a>} } else { MutItems{ptr: p, end: p.offset(self.len() as int), - marker: marker::ContravariantLifetime::<'a>, - marker2: marker::NoCopy} + marker: marker::ContravariantLifetime::<'a>} } } } @@ -1215,7 +1213,6 @@ pub struct MutItems<'a, T: 'a> { ptr: *mut T, end: *mut T, marker: marker::ContravariantLifetime<'a>, - marker2: marker::NoCopy } #[experimental] diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs index 519cd6b1675..e80e8dc5351 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc/util/snapshot_vec.rs @@ -20,7 +20,6 @@ //! those changes. use self::UndoLog::*; -use std::kinds::marker; use std::mem; #[deriving(PartialEq)] @@ -47,10 +46,9 @@ pub struct SnapshotVec<T,U,D> { delegate: D } +// Snapshots are tokens that should be created/consumed linearly. +#[allow(missing_copy_implementations)] pub struct Snapshot { - // Snapshots are tokens that should be created/consumed linearly. - marker: marker::NoCopy, - // Length of the undo log at the time the snapshot was taken. length: uint, } @@ -112,8 +110,7 @@ impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> { pub fn start_snapshot(&mut self) -> Snapshot { let length = self.undo_log.len(); self.undo_log.push(OpenSnapshot); - Snapshot { length: length, - marker: marker::NoCopy } + Snapshot { length: length } } fn assert_open_snapshot(&self, snapshot: &Snapshot) { diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index 37632f509c1..b942a3819cc 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -20,7 +20,6 @@ use alloc::boxed::Box; use core::any::Any; use core::atomic::{AtomicUint, SeqCst}; use core::iter::{IteratorExt, Take}; -use core::kinds::marker; use core::ops::FnOnce; use core::mem; use core::ops::FnMut; @@ -95,7 +94,6 @@ pub enum BlockedTask { /// Per-task state related to task death, killing, panic, etc. pub struct Death { pub on_exit: Option<Thunk<Result>>, - marker: marker::NoCopy, } pub struct BlockedTasks { @@ -499,7 +497,7 @@ impl BlockedTask { impl Death { pub fn new() -> Death { - Death { on_exit: None, marker: marker::NoCopy } + Death { on_exit: None } } } diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 5405892535c..c0eebe135c3 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -186,9 +186,8 @@ mod imp { /// service provider with the `PROV_RSA_FULL` type. /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed /// This does not block. - pub struct OsRng { - marker: marker::NoCopy - } + #[allow(missing_copy_implementations)] + pub struct OsRng; #[repr(C)] struct SecRandom; @@ -205,7 +204,7 @@ mod imp { impl OsRng { /// Create a new `OsRng`. pub fn new() -> IoResult<OsRng> { - Ok(OsRng {marker: marker::NoCopy} ) + Ok(OsRng) } } diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 3eb0e3f46cb..cf56a71d67a 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -58,7 +58,6 @@ use prelude::*; -use kinds::marker; use rustrt::exclusive::Exclusive; use sync::atomic::{mod, AtomicUint}; use sync::{Once, ONCE_INIT}; @@ -100,7 +99,6 @@ pub struct StaticKey { /// Inner contents of `StaticKey`, created by the `INIT_INNER` constant. pub struct StaticKeyInner { key: AtomicUint, - nc: marker::NoCopy, } /// A type for a safely managed OS-based TLS slot. @@ -141,7 +139,6 @@ pub const INIT: StaticKey = StaticKey { /// This value allows specific configuration of the destructor for a TLS key. pub const INIT_INNER: StaticKeyInner = StaticKeyInner { key: atomic::INIT_ATOMIC_UINT, - nc: marker::NoCopy, }; static INIT_KEYS: Once = ONCE_INIT; diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 562afd33e2f..324b594209a 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -49,7 +49,7 @@ use boxed::Box; use comm::channel; use core::ops::FnOnce; use io::{Writer, stdio}; -use kinds::{Send, marker}; +use kinds::Send; use option::Option; use option::Option::{None, Some}; use result::Result; @@ -83,7 +83,6 @@ pub struct TaskBuilder { stderr: Option<Box<Writer + Send>>, // Optionally wrap the eventual task body gen_body: Option<Thunk<Thunk, Thunk>>, - nocopy: marker::NoCopy, } impl TaskBuilder { @@ -96,7 +95,6 @@ impl TaskBuilder { stdout: None, stderr: None, gen_body: None, - nocopy: marker::NoCopy, } } } @@ -137,7 +135,7 @@ impl TaskBuilder { on_exit: Option<Thunk<task::Result>>) { let TaskBuilder { - name, stack_size, stdout, stderr, mut gen_body, nocopy: _ + name, stack_size, stdout, stderr, mut gen_body } = self; let f = match gen_body.take() { diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 2d5766c2393..76fb703514b 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -185,7 +185,6 @@ macro_rules! __thread_local_inner( inner: ::std::cell::UnsafeCell { value: $init }, dtor_registered: ::std::cell::UnsafeCell { value: false }, dtor_running: ::std::cell::UnsafeCell { value: false }, - marker: ::std::kinds::marker::NoCopy, } }; @@ -247,7 +246,6 @@ mod imp { use cell::UnsafeCell; use intrinsics; - use kinds::marker; use ptr; #[doc(hidden)] @@ -264,9 +262,6 @@ mod imp { // these variables are thread-local, not global. pub dtor_registered: UnsafeCell<bool>, // should be Cell pub dtor_running: UnsafeCell<bool>, // should be Cell - - // These shouldn't be copied around. - pub marker: marker::NoCopy, } #[doc(hidden)] From c3778fae6f57d30381476ea0110cb445e52b407a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <japaricious@gmail.com> Date: Mon, 15 Dec 2014 15:35:34 -0500 Subject: [PATCH 27/59] libstd: add a dummy field to `OsRng` to avoid out of module construction --- src/libstd/rand/os.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index c0eebe135c3..c1e42660269 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -187,7 +187,10 @@ mod imp { /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed /// This does not block. #[allow(missing_copy_implementations)] - pub struct OsRng; + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside of this module + _dummy: (), + } #[repr(C)] struct SecRandom; @@ -204,7 +207,7 @@ mod imp { impl OsRng { /// Create a new `OsRng`. pub fn new() -> IoResult<OsRng> { - Ok(OsRng) + Ok(OsRng { _dummy: () }) } } From c500b63e717261bc6cb80231936eca8f1233bc82 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" <pnkfelix@pnkfx.org> Date: Mon, 15 Dec 2014 12:32:54 +0100 Subject: [PATCH 28/59] libgraphviz: add `label` and `escaped` ctors taking any `str::IntoMaybeOwned`. --- src/libgraphviz/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index fa048346e99..9e4b7a6a4cc 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -421,6 +421,14 @@ pub trait Labeller<'a,N,E> { } impl<'a> LabelText<'a> { + pub fn label<S:IntoCow<'a, String, str>>(s: S) -> LabelText<'a> { + LabelStr(s.into_cow()) + } + + pub fn escaped<S:IntoCow<'a, String, str>>(s: S) -> LabelText<'a> { + EscStr(s.into_cow()) + } + fn escape_char<F>(c: char, mut f: F) where F: FnMut(char) { match c { // not escaping \\, since Graphviz escString needs to From a5e0624a3216a9cf155370a71c9901e56638fa0d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" <pnkfelix@pnkfx.org> Date: Mon, 15 Dec 2014 12:37:42 +0100 Subject: [PATCH 29/59] libgraphviz: extend API with flags to indicate options like "do not include labels". --- src/libgraphviz/lib.rs | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 9e4b7a6a4cc..0576c46d3bd 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -513,11 +513,29 @@ pub trait GraphWalk<'a, N, E> { fn target(&'a self, edge: &E) -> N; } +#[deriving(Copy, PartialEq, Eq, Show)] +pub enum RenderOption { + NoEdgeLabels, + NoNodeLabels, +} + +/// Returns vec holding all the default render options. +pub fn default_options() -> Vec<RenderOption> { vec![] } + /// Renders directed graph `g` into the writer `w` in DOT syntax. -/// (Main entry point for the library.) +/// (Simple wrapper around `render_opts` that passes a default set of options.) pub fn render<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>( g: &'a G, - w: &mut W) -> io::IoResult<()> + w: &mut W) -> io::IoResult<()> { + render_opts(g, w, &[]) +} + +/// Renders directed graph `g` into the writer `w` in DOT syntax. +/// (Main entry point for the library.) +pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>( + g: &'a G, + w: &mut W, + options: &[RenderOption]) -> io::IoResult<()> { fn writeln<W:Writer>(w: &mut W, arg: &[&str]) -> io::IoResult<()> { for &s in arg.iter() { try!(w.write_str(s)); } @@ -532,9 +550,13 @@ pub fn render<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, for n in g.nodes().iter() { try!(indent(w)); let id = g.node_id(n); - let escaped = g.node_label(n).escape(); - try!(writeln(w, &[id.as_slice(), - "[label=\"", escaped.as_slice(), "\"];"])); + if options.contains(&RenderOption::NoNodeLabels) { + try!(writeln(w, &[id.as_slice(), ";"])); + } else { + let escaped = g.node_label(n).escape(); + try!(writeln(w, &[id.as_slice(), + "[label=\"", escaped.as_slice(), "\"];"])); + } } for e in g.edges().iter() { @@ -544,8 +566,14 @@ pub fn render<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, let target = g.target(e); let source_id = g.node_id(&source); let target_id = g.node_id(&target); - try!(writeln(w, &[source_id.as_slice(), " -> ", target_id.as_slice(), - "[label=\"", escaped_label.as_slice(), "\"];"])); + if options.contains(&RenderOption::NoEdgeLabels) { + try!(writeln(w, &[source_id.as_slice(), + " -> ", target_id.as_slice(), ";"])); + } else { + try!(writeln(w, &[source_id.as_slice(), + " -> ", target_id.as_slice(), + "[label=\"", escaped_label.as_slice(), "\"];"])); + } } writeln(w, &["}"]) From d6d0bb2030f870c0b4b942da793beb4edb82c191 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" <pnkfelix@pnkfx.org> Date: Mon, 15 Dec 2014 17:17:52 +0100 Subject: [PATCH 30/59] Added `-Z print-region-graph` debugging option; produces graphviz visualization of region inference constraint graph. Optionally uses environment variables `RUST_REGION_GRAPH=<path_template>` and `RUST_REGION_GRAPH_NODE=<node-id>` to select which file to output to and which AST node to print. Note that in some cases of method AST's, the identification of AST node is based on the id for the *body* of the method; this is largely due to having the body node-id already available at the relevant point in the control-flow of rustc in its current incarnation. Ideally we would handle identifying AST's by name in addition to node-id, e.g. the same way that the pretty-printer supports path suffixes as well as node-ids for identifying subtrees to print. --- src/librustc/middle/infer/mod.rs | 4 +- .../middle/infer/region_inference/graphviz.rs | 227 ++++++++++++++++++ .../middle/infer/region_inference/mod.rs | 12 +- src/librustc/session/config.rs | 8 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/regionck.rs | 41 +++- src/librustc_typeck/collect.rs | 2 +- 7 files changed, 277 insertions(+), 19 deletions(-) create mode 100644 src/librustc/middle/infer/region_inference/graphviz.rs diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 2b1d8776365..3a84712016e 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -814,8 +814,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.new_bound(debruijn) } - pub fn resolve_regions_and_report_errors(&self) { - let errors = self.region_vars.resolve_regions(); + pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) { + let errors = self.region_vars.resolve_regions(subject_node_id); self.report_region_errors(&errors); // see error_reporting.rs } diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs new file mode 100644 index 00000000000..7be3ec15862 --- /dev/null +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -0,0 +1,227 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module provides linkage between libgraphviz traits and +//! `rustc::middle::typeck::infer::region_inference`, generating a +//! rendering of the graph represented by the list of `Constraint` +//! instances (which make up the edges of the graph), as well as the +//! origin for each constraint (which are attached to the labels on +//! each edge). + +/// For clarity, rename the graphviz crate locally to dot. +use graphviz as dot; + +use middle::ty; +use super::Constraint; +use middle::typeck::infer::SubregionOrigin; +use middle::typeck::infer::region_inference::RegionVarBindings; +use session::config; +use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::ppaux::Repr; + +use std::collections::hash_map::Vacant; +use std::io::{mod, File}; +use std::os; +use std::sync::atomic; +use syntax::ast; + +fn print_help_message() { + println!("\ +-Z print-region-graph by default prints a region constraint graph for every \n\ +function body, to the path `/tmp/constraints.nodeXXX.dot`, where the XXX is \n\ +replaced with the node id of the function under analysis. \n\ + \n\ +To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ +where XXX is the node id desired. \n\ + \n\ +To generate output to some path other than the default \n\ +`/tmp/constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ +occurrences of the character `%` in the requested path will be replaced with\n\ +the node id of the function under analysis. \n\ + \n\ +(Since you requested help via RUST_REGION_GRAPH=help, no region constraint \n\ +graphs will be printed. \n\ +"); +} + +pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, 'tcx>, + subject_node: ast::NodeId) { + let tcx = region_vars.tcx; + + if !region_vars.tcx.sess.debugging_opt(config::PRINT_REGION_GRAPH) { + return; + } + + let requested_node : Option<ast::NodeId> = + os::getenv("RUST_REGION_GRAPH_NODE").and_then(|s|from_str(s.as_slice())); + + if requested_node.is_some() && requested_node != Some(subject_node) { + return; + } + + let requested_output = os::getenv("RUST_REGION_GRAPH"); + debug!("requested_output: {} requested_node: {}", + requested_output, requested_node); + + let output_path = { + let output_template = match requested_output { + Some(ref s) if s.as_slice() == "help" => { + static PRINTED_YET : atomic::AtomicBool = atomic::INIT_ATOMIC_BOOL; + if !PRINTED_YET.load(atomic::SeqCst) { + print_help_message(); + PRINTED_YET.store(true, atomic::SeqCst); + } + return; + } + + Some(other_path) => other_path, + None => "/tmp/constraints.node%.dot".to_string(), + }; + + if output_template.len() == 0 { + tcx.sess.bug("empty string provided as RUST_REGION_GRAPH"); + } + + if output_template.contains_char('%') { + let mut new_str = String::new(); + for c in output_template.chars() { + if c == '%' { + new_str.push_str(subject_node.to_string().as_slice()); + } else { + new_str.push(c); + } + } + new_str + } else { + output_template + } + }; + + let constraints = &*region_vars.constraints.borrow(); + match dump_region_constraints_to(tcx, constraints, output_path.as_slice()) { + Ok(()) => {} + Err(e) => { + let msg = format!("io error dumping region constraints: {}", e); + region_vars.tcx.sess.err(msg.as_slice()) + } + } +} + +struct ConstraintGraph<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, + graph_name: String, + map: &'a FnvHashMap<Constraint, SubregionOrigin<'tcx>>, + node_ids: FnvHashMap<Node, uint>, +} + +#[deriving(Clone, Hash, PartialEq, Eq, Show)] +enum Node { + RegionVid(ty::RegionVid), + Region(ty::Region), +} + +type Edge = Constraint; + +impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { + fn new(tcx: &'a ty::ctxt<'tcx>, + name: String, + map: &'a ConstraintMap<'tcx>) -> ConstraintGraph<'a, 'tcx> { + let mut i = 0; + let mut node_ids = FnvHashMap::new(); + { + let add_node = |node| { + if let Vacant(e) = node_ids.entry(node) { + e.set(i); + i += 1; + } + }; + + for (n1, n2) in map.keys().map(|c|constraint_to_nodes(c)) { + add_node(n1); + add_node(n2); + } + } + + ConstraintGraph { tcx: tcx, + graph_name: name, + map: map, + node_ids: node_ids } + } +} + +impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> { + fn graph_id(&self) -> dot::Id { + dot::Id::new(self.graph_name.as_slice()).unwrap() + } + fn node_id(&self, n: &Node) -> dot::Id { + dot::Id::new(format!("node_{}", self.node_ids.get(n).unwrap())).unwrap() + } + fn node_label(&self, n: &Node) -> dot::LabelText { + match *n { + Node::RegionVid(n_vid) => + dot::LabelText::label(format!("{}", n_vid)), + Node::Region(n_rgn) => + dot::LabelText::label(format!("{}", n_rgn.repr(self.tcx))), + } + } + fn edge_label(&self, e: &Edge) -> dot::LabelText { + dot::LabelText::label(format!("{}", self.map.get(e).unwrap().repr(self.tcx))) + } +} + +fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { + match *c { + Constraint::ConstrainVarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), + Node::RegionVid(rv_2)), + Constraint::ConstrainRegSubVar(r_1, rv_2) => (Node::Region(r_1), + Node::RegionVid(rv_2)), + Constraint::ConstrainVarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), + Node::Region(r_2)), + } +} + +impl<'a, 'tcx> dot::GraphWalk<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> { + fn nodes(&self) -> dot::Nodes<Node> { + let mut set = FnvHashSet::new(); + for constraint in self.map.keys() { + let (n1, n2) = constraint_to_nodes(constraint); + set.insert(n1); + set.insert(n2); + } + debug!("constraint graph has {} nodes", set.len()); + set.into_iter().collect() + } + fn edges(&self) -> dot::Edges<Edge> { + debug!("constraint graph has {} edges", self.map.len()); + self.map.keys().map(|e|*e).collect() + } + fn source(&self, edge: &Edge) -> Node { + let (n1, _) = constraint_to_nodes(edge); + debug!("edge {} has source {}", edge, n1); + n1 + } + fn target(&self, edge: &Edge) -> Node { + let (_, n2) = constraint_to_nodes(edge); + debug!("edge {} has target {}", edge, n2); + n2 + } +} + +pub type ConstraintMap<'tcx> = FnvHashMap<Constraint, SubregionOrigin<'tcx>>; + +fn dump_region_constraints_to<'a, 'tcx:'a >(tcx: &'a ty::ctxt<'tcx>, + map: &ConstraintMap<'tcx>, + path: &str) -> io::IoResult<()> { + debug!("dump_region_constraints map (len: {}) path: {}", map.len(), path); + let g = ConstraintGraph::new(tcx, format!("region_constraints"), map); + let mut f = File::create(&Path::new(path)); + debug!("dump_region_constraints calling render"); + dot::render(&g, &mut f) +} diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 98f69f66b27..acd49f3f8df 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -37,9 +37,10 @@ use std::uint; use syntax::ast; mod doc; +mod graphviz; // A constraint that influences the inference process. -#[deriving(PartialEq, Eq, Hash)] +#[deriving(PartialEq, Eq, Hash, Show)] pub enum Constraint { // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), @@ -706,10 +707,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// fixed-point iteration to find region values which satisfy all /// constraints, assuming such values can be found; if they cannot, /// errors are reported. - pub fn resolve_regions(&self) -> Vec<RegionResolutionError<'tcx>> { + pub fn resolve_regions(&self, subject_node: ast::NodeId) -> Vec<RegionResolutionError<'tcx>> { debug!("RegionVarBindings: resolve_regions()"); let mut errors = vec!(); - let v = self.infer_variable_values(&mut errors); + let v = self.infer_variable_values(&mut errors, subject_node); *self.values.borrow_mut() = Some(v); errors } @@ -958,14 +959,15 @@ type RegionGraph = graph::Graph<(), Constraint>; impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn infer_variable_values(&self, - errors: &mut Vec<RegionResolutionError<'tcx>>) - -> Vec<VarValue> + errors: &mut Vec<RegionResolutionError<'tcx>>, + subject: ast::NodeId) -> Vec<VarValue> { let mut var_data = self.construct_var_data(); // Dorky hack to cause `dump_constraints` to only get called // if debug mode is enabled: debug!("----() End constraint listing {}---", self.dump_constraints()); + graphviz::maybe_print_constraints_for(self, subject); self.expansion(var_data.as_mut_slice()); self.contraction(var_data.as_mut_slice()); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index c7b5e1e8de9..b3b44b60b6e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -276,7 +276,8 @@ debugging_opts!( FLOWGRAPH_PRINT_MOVES, FLOWGRAPH_PRINT_ASSIGNS, FLOWGRAPH_PRINT_ALL, - PRINT_SYSROOT + PRINT_SYSROOT, + PRINT_REGION_GRAPH ] 0 ) @@ -322,7 +323,10 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> { ("flowgraph-print-all", "Include all dataflow analysis data in \ --pretty flowgraph output", FLOWGRAPH_PRINT_ALL), ("print-sysroot", "Print the sysroot as used by this rustc invocation", - PRINT_SYSROOT)] + PRINT_SYSROOT), + ("print-region-graph", "Prints region inference graph. \ + Use with RUST_REGION_GRAPH=help for more info", + PRINT_REGION_GRAPH)] } #[deriving(Clone)] diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e0df94745d6..ad0046a1ad4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1190,7 +1190,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Finally, resolve all regions. This catches wily misuses of lifetime // parameters. - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(impl_m_body_id); /// Check that region bounds on impl method are the same as those on the trait. In principle, /// it could be ok for there to be fewer region bounds on the impl method, but this leads to an diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9f75b9764eb..501b9775f7f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -139,27 +139,31 @@ use syntax::visit::Visitor; use std::cell::{RefCell}; use std::collections::hash_map::{Vacant, Occupied}; +use self::RepeatingScope::Repeating; +use self::SubjectNode::Subject; + + /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { - let mut rcx = Rcx::new(fcx, e.id); + let mut rcx = Rcx::new(fcx, Repeating(e.id), Subject(e.id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_expr(e); rcx.visit_region_obligations(e.id); } - fcx.infcx().resolve_regions_and_report_errors(); + rcx.resolve_regions_and_report_errors(); } pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { - let mut rcx = Rcx::new(fcx, item.id); + let mut rcx = Rcx::new(fcx, Repeating(item.id), Subject(item.id)); rcx.visit_region_obligations(item.id); - fcx.infcx().resolve_regions_and_report_errors(); + rcx.resolve_regions_and_report_errors(); } pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast::Block) { - let mut rcx = Rcx::new(fcx, blk.id); + let mut rcx = Rcx::new(fcx, Repeating(blk.id), Subject(id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_fn_body(id, decl, blk); @@ -169,7 +173,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast: // particularly around closure bounds. vtable::select_all_fcx_obligations_or_error(fcx); - fcx.infcx().resolve_regions_and_report_errors(); + rcx.resolve_regions_and_report_errors(); } /// Checks that the types in `component_tys` are well-formed. This will add constraints into the @@ -177,7 +181,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast: pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, component_tys: &[Ty<'tcx>]) { - let mut rcx = Rcx::new(fcx, 0); + let mut rcx = Rcx::new(fcx, Repeating(0), SubjectNode::None); for &component_ty in component_tys.iter() { // Check that each type outlives the empty region. Since the // empty region is a subregion of all others, this can't fail @@ -225,6 +229,9 @@ pub struct Rcx<'a, 'tcx: 'a> { // id of innermost fn or loop repeating_scope: ast::NodeId, + // id of AST node being analyzed (the subject of the analysis). + subject: SubjectNode, + // Possible region links we will establish if an upvar // turns out to be unique/mutable maybe_links: MaybeLinkMap<'tcx> @@ -251,11 +258,17 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { } } +pub enum RepeatingScope { Repeating(ast::NodeId) } +pub enum SubjectNode { Subject(ast::NodeId), None } + impl<'a, 'tcx> Rcx<'a, 'tcx> { pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, - initial_repeating_scope: ast::NodeId) -> Rcx<'a, 'tcx> { + initial_repeating_scope: RepeatingScope, + subject: SubjectNode) -> Rcx<'a, 'tcx> { + let Repeating(initial_repeating_scope) = initial_repeating_scope; Rcx { fcx: fcx, repeating_scope: initial_repeating_scope, + subject: subject, region_param_pairs: Vec::new(), maybe_links: RefCell::new(FnvHashMap::new()) } } @@ -425,6 +438,18 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { debug!("<< relate_free_regions"); } + + fn resolve_regions_and_report_errors(&self) { + let subject_node_id = match self.subject { + Subject(s) => s, + SubjectNode::None => { + self.tcx().sess.bug("cannot resolve_regions_and_report_errors \ + without subject node"); + } + }; + + self.fcx.infcx().resolve_regions_and_report_errors(subject_node_id); + } } impl<'fcx, 'tcx> mc::Typer<'tcx> for Rcx<'fcx, 'tcx> { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 61b8e6c956c..962bb575dc8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2237,6 +2237,6 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( format!("mismatched self type: expected `{}`", ppaux::ty_to_string(crate_context.tcx, required_type)) })); - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(body_id); } } From 72608eba434281361f51484c28525c85a51b9aff Mon Sep 17 00:00:00 2001 From: Jacob Edelman <edelman.jd@gmail.com> Date: Mon, 15 Dec 2014 17:07:49 -0500 Subject: [PATCH 31/59] Fixed a small spelling mistake --- src/etc/make-win-dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py index 7fb86f904a2..95e647c91cf 100644 --- a/src/etc/make-win-dist.py +++ b/src/etc/make-win-dist.py @@ -107,7 +107,7 @@ def make_win_dist(rust_root, gcc_root, target_triple): for src in target_tools: shutil.copy(src, target_bin_dir) - # Copy platform libs to platform-spcific lib directory + # Copy platform libs to platform-specific lib directory target_lib_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "lib") if not os.path.exists(target_lib_dir): os.makedirs(target_lib_dir) From a9dbb7908dd851dff81f613452518db3ba04887c Mon Sep 17 00:00:00 2001 From: jbranchaud <jbranchaud@gmail.com> Date: Mon, 15 Dec 2014 16:40:27 -0600 Subject: [PATCH 32/59] Add a doctest for the string Add function. --- src/libcollections/string.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index c4659f86680..3dd24fc33ae 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -857,6 +857,16 @@ impl<'a, S: Str> Equiv<S> for String { #[experimental = "waiting on Add stabilization"] impl<S: Str> Add<S, String> for String { + /// Concatenates `self` and `other` as a new mutable `String`. + /// + /// # Examples + /// + /// ``` + /// let string1 = "foo".to_string(); + /// let string2 = "bar".to_string(); + /// let string3 = string1 + string2; + /// assert_eq!(string3, "foobar".to_string()); + /// ``` fn add(&self, other: &S) -> String { let mut s = String::from_str(self.as_slice()); s.push_str(other.as_slice()); From 765806ef1ee93b352b724aa76870d23d82894e4e Mon Sep 17 00:00:00 2001 From: Chase Southwood <chase.southwood@gmail.com> Date: Fri, 12 Dec 2014 00:04:47 -0600 Subject: [PATCH 33/59] Use wrapper structs for `BTreeMap`'s iterators. Using a type alias for iterator implementations is fragile since this exposes the implementation to users of the iterator, and any changes could break existing code. This commit changes the keys and values iterators of `BTreeMap` to use proper new types, rather than type aliases. However, since it is fair-game to treat a type-alias as the aliased type, this is a: [breaking-change]. --- src/libcollections/btree/map.rs | 34 +++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index e49a8ddbe5a..e45e91b93ba 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -26,6 +26,7 @@ use std::hash::{Writer, Hash}; use core::default::Default; use core::{iter, fmt, mem}; use core::fmt::Show; +use core::iter::Map; use ring_buf::RingBuf; @@ -107,12 +108,14 @@ pub struct MoveEntries<K, V> { } /// An iterator over a BTreeMap's keys. -pub type Keys<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>; +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> +} /// An iterator over a BTreeMap's values. -pub type Values<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>; +pub struct Values<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> +} /// A view into a single entry in a map, which may either be vacant or occupied. pub enum Entry<'a, K:'a, V:'a> { @@ -1061,6 +1064,25 @@ impl<K, V> DoubleEndedIterator<(K, V)> for MoveEntries<K, V> { impl<K, V> ExactSizeIterator<(K, V)> for MoveEntries<K, V> {} +impl<'a, K, V> Iterator<&'a K> for Keys<'a, K, V> { + fn next(&mut self) -> Option<(&'a K)> { self.inner.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} +impl<'a, K, V> DoubleEndedIterator<&'a K> for Keys<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K)> { self.inner.next_back() } +} +impl<'a, K, V> ExactSizeIterator<&'a K> for Keys<'a, K, V> {} + + +impl<'a, K, V> Iterator<&'a V> for Values<'a, K, V> { + fn next(&mut self) -> Option<(&'a V)> { self.inner.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} +impl<'a, K, V> DoubleEndedIterator<&'a V> for Values<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a V)> { self.inner.next_back() } +} +impl<'a, K, V> ExactSizeIterator<&'a V> for Values<'a, K, V> {} + impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Sets the value of the entry with the VacantEntry's key, @@ -1211,7 +1233,7 @@ impl<K, V> BTreeMap<K, V> { pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { fn first<A, B>((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { inner: self.iter().map(first) } } /// Gets an iterator over the values of the map. @@ -1232,7 +1254,7 @@ impl<K, V> BTreeMap<K, V> { pub fn values<'a>(&'a self) -> Values<'a, K, V> { fn second<A, B>((_, b): (A, B)) -> B { b } - self.iter().map(second) + Values { inner: self.iter().map(second) } } /// Return the number of elements in the map. From a81c3ab468ad7aebcab8a545b196e74c2fb3ac32 Mon Sep 17 00:00:00 2001 From: Chase Southwood <chase.southwood@gmail.com> Date: Fri, 12 Dec 2014 23:14:57 -0600 Subject: [PATCH 34/59] Use wrapper structs for `BTreeSet`'s iterators. Using a type alias for iterator implementations is fragile since this exposes the implementation to users of the iterator, and any changes could break existing code. This commit changes the iterators of `BTreeSet` to use proper new types, rather than type aliases. However, since it is fair-game to treat a type-alias as the aliased type, this is a: [breaking-change]. --- src/libcollections/btree/set.rs | 36 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index c6d1898b87e..dbba5ebdc99 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -17,8 +17,8 @@ use btree_map::{BTreeMap, Keys, MoveEntries}; use std::hash::Hash; use core::borrow::BorrowFrom; use core::default::Default; -use core::{iter, fmt}; -use core::iter::Peekable; +use core::fmt; +use core::iter::{Peekable, Map}; use core::fmt::Show; // FIXME(conventions): implement bounded iterators @@ -33,11 +33,14 @@ pub struct BTreeSet<T>{ } /// An iterator over a BTreeSet's items. -pub type Items<'a, T> = Keys<'a, T, ()>; +pub struct Items<'a, T: 'a> { + iter: Keys<'a, T, ()> +} /// An owning iterator over a BTreeSet's items. -pub type MoveItems<T> = - iter::Map<(T, ()), T, MoveEntries<T, ()>, fn((T, ())) -> T>; +pub struct MoveItems<T> { + iter: Map<(T, ()), T, MoveEntries<T, ()>, fn((T, ())) -> T> +} /// A lazy iterator producing elements in the set difference (in-order). pub struct DifferenceItems<'a, T:'a> { @@ -105,7 +108,7 @@ impl<T> BTreeSet<T> { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn iter<'a>(&'a self) -> Items<'a, T> { - self.map.keys() + Items { iter: self.map.keys() } } /// Gets an iterator for moving out the BtreeSet's contents. @@ -124,7 +127,7 @@ impl<T> BTreeSet<T> { pub fn into_iter(self) -> MoveItems<T> { fn first<A, B>((a, _): (A, B)) -> A { a } - self.map.into_iter().map(first) + MoveItems { iter: self.map.into_iter().map(first) } } } @@ -635,6 +638,25 @@ impl<T: Show> Show for BTreeSet<T> { } } +impl<'a, T> Iterator<&'a T> for Items<'a, T> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} +impl<'a, T> DoubleEndedIterator<&'a T> for Items<'a, T> { + fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back() } +} +impl<'a, T> ExactSizeIterator<&'a T> for Items<'a, T> {} + + +impl<T> Iterator<T> for MoveItems<T> { + fn next(&mut self) -> Option<T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} +impl<T> DoubleEndedIterator<T> for MoveItems<T> { + fn next_back(&mut self) -> Option<T> { self.iter.next_back() } +} +impl<T> ExactSizeIterator<T> for MoveItems<T> {} + /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { From 85fe141fb7c066e88a6872e74347c5f34d0223a7 Mon Sep 17 00:00:00 2001 From: Chase Southwood <chase.southwood@gmail.com> Date: Fri, 12 Dec 2014 01:02:19 -0600 Subject: [PATCH 35/59] Use wrapper structs for `HashMap`'s iterators. Using a type alias for iterator implementations is fragile since this exposes the implementation to users of the iterator, and any changes could break existing code. This commit changes the keys and values iterators of `HashMap` to use proper new types, rather than type aliases. However, since it is fair-game to treat a type-alias as the aliased type, this is a: [breaking-change]. --- src/libstd/collections/hash/map.rs | 64 ++++++++++++++---------------- src/libstd/collections/hash/set.rs | 5 +-- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a8d97eed05..d22e7b2f764 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -20,7 +20,7 @@ use cmp::{max, Eq, Equiv, PartialEq}; use default::Default; use fmt::{mod, Show}; use hash::{Hash, Hasher, RandomSipHasher}; -use iter::{mod, Iterator, IteratorExt, FromIterator, Extend}; +use iter::{mod, Iterator, IteratorExt, FromIterator, Extend, Map}; use kinds::Sized; use mem::{mod, replace}; use num::{Int, UnsignedInt}; @@ -859,7 +859,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn keys(&self) -> Keys<K, V> { fn first<A, B>((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { inner: self.iter().map(first) } } /// An iterator visiting all values in arbitrary order. @@ -883,7 +883,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn values(&self) -> Values<K, V> { fn second<A, B>((_, b): (A, B)) -> B { b } - self.iter().map(second) + Values { inner: self.iter().map(second) } } /// An iterator visiting all key-value pairs in arbitrary order. @@ -1335,6 +1335,16 @@ pub struct MoveEntries<K, V> { > } +/// HashMap keys iterator +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> +} + +/// HashMap values iterator +pub struct Values<'a, K: 'a, V: 'a> { + inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> +} + /// A view into a single occupied location in a HashMap pub struct OccupiedEntry<'a, K:'a, V:'a> { elem: FullBucket<K, V, &'a mut RawTable<K, V>>, @@ -1365,36 +1375,28 @@ enum VacantEntryState<K, V, M> { } impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } } impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } } impl<K, V> Iterator<(K, V)> for MoveEntries<K, V> { - #[inline] - fn next(&mut self) -> Option<(K, V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<'a, K, V> Iterator<&'a K> for Keys<'a, K, V> { + #[inline] fn next(&mut self) -> Option<(&'a K)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } +} + +impl<'a, K, V> Iterator<&'a V> for Values<'a, K, V> { + #[inline] fn next(&mut self) -> Option<(&'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() } } impl<'a, K, V> OccupiedEntry<'a, K, V> { @@ -1448,14 +1450,6 @@ impl<'a, K, V> VacantEntry<'a, K, V> { } } -/// HashMap keys iterator -pub type Keys<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>; - -/// HashMap values iterator -pub type Values<'a, K, V> = - iter::Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>; - impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> { fn from_iter<T: Iterator<(K, V)>>(iter: T) -> HashMap<K, V, H> { let (lower, _) = iter.size_hint(); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 745a8298ee8..3993a23140b 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -22,7 +22,7 @@ use iter; use option::Option::{Some, None, mod}; use result::Result::{Ok, Err}; -use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY}; +use super::map::{HashMap, MoveEntries, Keys, INITIAL_CAPACITY}; // FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub @@ -617,8 +617,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> { } /// HashSet iterator -pub type SetItems<'a, K> = - iter::Map<(&'a K, &'a ()), &'a K, Entries<'a, K, ()>, fn((&'a K, &'a ())) -> &'a K>; +pub type SetItems<'a, K> = Keys<'a, K, ()>; /// HashSet move iterator pub type SetMoveItems<K> = iter::Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K>; From 341cf405e5be56b9b1c8f3be6d0fe9a014eeff26 Mon Sep 17 00:00:00 2001 From: Chase Southwood <chase.southwood@gmail.com> Date: Sat, 13 Dec 2014 12:36:05 -0600 Subject: [PATCH 36/59] Use wrapper structs for `HashSet`'s iterators. Using a type alias for iterator implementations is fragile since this exposes the implementation to users of the iterator, and any changes could break existing code. This commit changes the iterators of `HashSet` to use proper new types, rather than type aliases. However, since it is fair-game to treat a type-alias as the aliased type, this is a: [breaking-change]. --- src/libstd/collections/hash/set.rs | 79 ++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 3993a23140b..865d8840c52 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -17,8 +17,7 @@ use default::Default; use fmt::Show; use fmt; use hash::{Hash, Hasher, RandomSipHasher}; -use iter::{Iterator, IteratorExt, FromIterator, FilterMap, Chain, Repeat, Zip, Extend, repeat}; -use iter; +use iter::{Iterator, IteratorExt, FromIterator, Map, FilterMap, Chain, Repeat, Zip, Extend, repeat}; use option::Option::{Some, None, mod}; use result::Result::{Ok, Err}; @@ -252,7 +251,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn iter<'a>(&'a self) -> SetItems<'a, T> { - self.map.keys() + SetItems { iter: self.map.keys() } } /// Creates a consuming iterator, that is, one that moves each value out @@ -279,7 +278,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { pub fn into_iter(self) -> SetMoveItems<T> { fn first<A, B>((a, _): (A, B)) -> A { a } - self.map.into_iter().map(first) + SetMoveItems { iter: self.map.into_iter().map(first) } } /// Visit the values representing the difference. @@ -312,7 +311,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { if !other.contains(elt) { Some(elt) } else { None } } - repeat(other).zip(self.iter()).filter_map(filter) + SetAlgebraItems { iter: repeat(other).zip(self.iter()).filter_map(filter) } } /// Visit the values representing the symmetric difference. @@ -337,8 +336,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>) - -> Chain<SetAlgebraItems<'a, T, H>, SetAlgebraItems<'a, T, H>> { - self.difference(other).chain(other.difference(self)) + -> SymDifferenceItems<'a, T, H> { + SymDifferenceItems { iter: self.difference(other).chain(other.difference(self)) } } /// Visit the values representing the intersection. @@ -366,7 +365,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { if other.contains(elt) { Some(elt) } else { None } } - repeat(other).zip(self.iter()).filter_map(filter) + SetAlgebraItems { iter: repeat(other).zip(self.iter()).filter_map(filter) } } /// Visit the values representing the union. @@ -387,9 +386,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) - -> Chain<SetItems<'a, T>, SetAlgebraItems<'a, T, H>> { - self.iter().chain(other.difference(self)) + pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> UnionItems<'a, T, H> { + UnionItems { iter: self.iter().chain(other.difference(self)) } } /// Return the number of elements in the set @@ -617,20 +615,61 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> { } /// HashSet iterator -pub type SetItems<'a, K> = Keys<'a, K, ()>; +pub struct SetItems<'a, K: 'a> { + iter: Keys<'a, K, ()> +} /// HashSet move iterator -pub type SetMoveItems<K> = iter::Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K>; +pub struct SetMoveItems<K> { + iter: Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K> +} // `Repeat` is used to feed the filter closure an explicit capture // of a reference to the other set -/// Set operations iterator -pub type SetAlgebraItems<'a, T, H> = FilterMap< - (&'a HashSet<T, H>, &'a T), - &'a T, - Zip<Repeat<&'a HashSet<T, H>>, SetItems<'a, T>>, - for<'b> fn((&HashSet<T, H>, &'b T)) -> Option<&'b T>, ->; +/// Set operations iterator, used directly for intersection and difference +pub struct SetAlgebraItems<'a, T: 'a, H: 'a> { + iter: FilterMap< + (&'a HashSet<T, H>, &'a T), + &'a T, + Zip<Repeat<&'a HashSet<T, H>>, SetItems<'a, T>>, + for<'b> fn((&HashSet<T, H>, &'b T)) -> Option<&'b T>, + > +} + +/// Symmetric difference iterator. +pub struct SymDifferenceItems<'a, T: 'a, H: 'a> { + iter: Chain<SetAlgebraItems<'a, T, H>, SetAlgebraItems<'a, T, H>> +} + +/// Set union iterator. +pub struct UnionItems<'a, T: 'a, H: 'a> { + iter: Chain<SetItems<'a, T>, SetAlgebraItems<'a, T, H>> +} + +impl<'a, K> Iterator<&'a K> for SetItems<'a, K> { + fn next(&mut self) -> Option<&'a K> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<K> Iterator<K> for SetMoveItems<K> { + fn next(&mut self) -> Option<K> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<'a, T, H> Iterator<&'a T> for SetAlgebraItems<'a, T, H> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<'a, T, H> Iterator<&'a T> for SymDifferenceItems<'a, T, H> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} + +impl<'a, T, H> Iterator<&'a T> for UnionItems<'a, T, H> { + fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } +} #[cfg(test)] mod test_set { From 13e7f9c0a7ced7c20ea909e46bc6c520a9a2b260 Mon Sep 17 00:00:00 2001 From: Brian Koropoff <bkoropoff@gmail.com> Date: Sat, 13 Dec 2014 14:40:38 -0800 Subject: [PATCH 37/59] Handle higher-rank lifetimes when generating type IDs Normalize late-bound regions in bare functions, stack closures, and traits and include them in the generated hash. Closes #19791 --- src/librustc/middle/ty.rs | 272 ++++++++++++++++++++++---------------- 1 file changed, 158 insertions(+), 114 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 50c324c49c3..3a59fb50160 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5825,126 +5825,153 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { let mut state = sip::SipState::new(); - macro_rules! byte( ($b:expr) => { ($b as u8).hash(&mut state) } ); - macro_rules! hash( ($e:expr) => { $e.hash(&mut state) } ); + helper(tcx, ty, svh, &mut state); + return state.result(); - let region = |_state: &mut sip::SipState, r: Region| { - match r { - ReStatic => {} + fn helper(tcx: &ctxt, ty: Ty, svh: &Svh, state: &mut sip::SipState) { + macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } ); + macro_rules! hash( ($e:expr) => { $e.hash(state) } ); - ReEmpty | - ReEarlyBound(..) | - ReLateBound(..) | - ReFree(..) | - ReScope(..) | - ReInfer(..) => { - tcx.sess.bug("non-static region found when hashing a type") - } - } - }; - let did = |state: &mut sip::SipState, did: DefId| { - let h = if ast_util::is_local(did) { - svh.clone() - } else { - tcx.sess.cstore.get_crate_hash(did.krate) - }; - h.as_str().hash(state); - did.node.hash(state); - }; - let mt = |state: &mut sip::SipState, mt: mt| { - mt.mutbl.hash(state); - }; - ty::walk_ty(ty, |ty| { - match ty.sty { - ty_bool => byte!(2), - ty_char => byte!(3), - ty_int(i) => { - byte!(4); - hash!(i); - } - ty_uint(u) => { - byte!(5); - hash!(u); - } - ty_float(f) => { - byte!(6); - hash!(f); - } - ty_str => { - byte!(7); - } - ty_enum(d, _) => { - byte!(8); - did(&mut state, d); - } - ty_uniq(_) => { - byte!(9); - } - ty_vec(_, Some(n)) => { - byte!(10); - n.hash(&mut state); - } - ty_vec(_, None) => { - byte!(11); - } - ty_ptr(m) => { - byte!(12); - mt(&mut state, m); - } - ty_rptr(r, m) => { - byte!(13); - region(&mut state, r); - mt(&mut state, m); - } - ty_bare_fn(ref b) => { - byte!(14); - hash!(b.unsafety); - hash!(b.abi); - } - ty_closure(ref c) => { - byte!(15); - hash!(c.unsafety); - hash!(c.onceness); - hash!(c.bounds); - match c.store { - UniqTraitStore => byte!(0), - RegionTraitStore(r, m) => { - byte!(1) - region(&mut state, r); - assert_eq!(m, ast::MutMutable); - } + let region = |state: &mut sip::SipState, r: Region| { + match r { + ReStatic => {} + ReLateBound(db, BrAnon(i)) => { + db.hash(state); + i.hash(state); + } + ReEmpty | + ReEarlyBound(..) | + ReLateBound(..) | + ReFree(..) | + ReScope(..) | + ReInfer(..) => { + tcx.sess.bug("unexpected region found when hashing a type") } } - ty_trait(box TyTrait { ref principal, bounds }) => { - byte!(17); - did(&mut state, principal.def_id); - hash!(bounds); + }; + let did = |state: &mut sip::SipState, did: DefId| { + let h = if ast_util::is_local(did) { + svh.clone() + } else { + tcx.sess.cstore.get_crate_hash(did.krate) + }; + h.as_str().hash(state); + did.node.hash(state); + }; + let mt = |state: &mut sip::SipState, mt: mt| { + mt.mutbl.hash(state); + }; + let fn_sig = |state: &mut sip::SipState, sig: &FnSig| { + let sig = anonymize_late_bound_regions(tcx, sig); + for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } + if let ty::FnConverging(output) = sig.output { + helper(tcx, output, svh, state); } - ty_struct(d, _) => { - byte!(18); - did(&mut state, d); - } - ty_tup(ref inner) => { - byte!(19); - hash!(inner.len()); - } - ty_param(p) => { - byte!(20); - hash!(p.idx); - did(&mut state, p.def_id); - } - ty_open(_) => byte!(22), - ty_infer(_) => unreachable!(), - ty_err => byte!(23), - ty_unboxed_closure(d, r, _) => { - byte!(24); - did(&mut state, d); - region(&mut state, r); - } - } - }); + }; + maybe_walk_ty(ty, |ty| { + match ty.sty { + ty_bool => byte!(2), + ty_char => byte!(3), + ty_int(i) => { + byte!(4); + hash!(i); + } + ty_uint(u) => { + byte!(5); + hash!(u); + } + ty_float(f) => { + byte!(6); + hash!(f); + } + ty_str => { + byte!(7); + } + ty_enum(d, _) => { + byte!(8); + did(state, d); + } + ty_uniq(_) => { + byte!(9); + } + ty_vec(_, Some(n)) => { + byte!(10); + n.hash(state); + } + ty_vec(_, None) => { + byte!(11); + } + ty_ptr(m) => { + byte!(12); + mt(state, m); + } + ty_rptr(r, m) => { + byte!(13); + region(state, r); + mt(state, m); + } + ty_bare_fn(ref b) => { + byte!(14); + hash!(b.unsafety); + hash!(b.abi); + fn_sig(state, &b.sig); + return false; + } + ty_closure(ref c) => { + byte!(15); + hash!(c.unsafety); + hash!(c.onceness); + hash!(c.bounds); + match c.store { + UniqTraitStore => byte!(0), + RegionTraitStore(r, m) => { + byte!(1); + region(state, r); + assert_eq!(m, ast::MutMutable); + } + } - state.result() + fn_sig(state, &c.sig); + + return false; + } + ty_trait(box TyTrait { ref principal, bounds }) => { + byte!(17); + did(state, principal.def_id); + hash!(bounds); + + let principal = anonymize_late_bound_regions(tcx, principal); + for subty in principal.substs.types.iter() { + helper(tcx, *subty, svh, state); + } + + return false; + } + ty_struct(d, _) => { + byte!(18); + did(state, d); + } + ty_tup(ref inner) => { + byte!(19); + hash!(inner.len()); + } + ty_param(p) => { + byte!(20); + hash!(p.idx); + did(state, p.def_id); + } + ty_open(_) => byte!(22), + ty_infer(_) => unreachable!(), + ty_err => byte!(23), + ty_unboxed_closure(d, r, _) => { + byte!(24); + did(state, d); + region(state, r); + } + } + true + }); + } } impl Variance { @@ -6284,6 +6311,23 @@ pub fn erase_late_bound_regions<'tcx, HR>( replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0 } +/// Rewrite any late-bound regions so that they are anonymous. Region numbers are +/// assigned starting at 1 and increasing monotonically in the order traversed +/// by the fold operation. +/// +/// The chief purpose of this function is to canonicalize regions so that two +/// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become +/// structurally identical. For example, `for<'a, 'b> fn(&'a int, &'b int)` and +/// `for<'a, 'b> fn(&'b int, &'a int)` will become identical after anonymization. +pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR + where HR: HigherRankedFoldable<'tcx> { + let mut counter = 0; + replace_late_bound_regions(tcx, sig, |_, db| { + counter += 1; + ReLateBound(db, BrAnon(counter)) + }).0 +} + /// Replaces the late-bound-regions in `value` that are bound by `value`. pub fn replace_late_bound_regions<'tcx, HR, F>( tcx: &ty::ctxt<'tcx>, From 3925b4d5c94c10f6e3cff05afcb5866d62a7235c Mon Sep 17 00:00:00 2001 From: Brian Koropoff <bkoropoff@gmail.com> Date: Sat, 13 Dec 2014 14:42:38 -0800 Subject: [PATCH 38/59] Add regression test for #19791 --- src/test/run-pass/type-id-higher-rank.rs | 85 ++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/test/run-pass/type-id-higher-rank.rs diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs new file mode 100644 index 00000000000..efda7771403 --- /dev/null +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -0,0 +1,85 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that type IDs correctly account for higher-rank lifetimes +// Also acts as a regression test for an ICE (issue #19791) + +#![feature(unboxed_closures)] + +use std::intrinsics::TypeId; + +fn main() { + // Bare fns + { + let a = TypeId::of::<fn(&'static int, &'static int)>(); + let b = TypeId::of::<for<'a> fn(&'static int, &'a int)>(); + let c = TypeId::of::<for<'a, 'b> fn(&'a int, &'b int)>(); + let d = TypeId::of::<for<'a, 'b> fn(&'b int, &'a int)>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<for<'a> fn(fn(&'a int) -> &'a int)>(); + let f = TypeId::of::<fn(for<'a> fn(&'a int) -> &'a int)>(); + assert!(e != f); + } + // Stack closures + { + let a = TypeId::of::<|&'static int, &'static int|>(); + let b = TypeId::of::<for<'a> |&'static int, &'a int|>(); + let c = TypeId::of::<for<'a, 'b> |&'a int, &'b int|>(); + let d = TypeId::of::<for<'a, 'b> |&'b int, &'a int|>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<for<'a> |(|&'a int| -> &'a int)|>(); + let f = TypeId::of::<|for<'a> |&'a int| -> &'a int|>(); + assert!(e != f); + } + // Boxed unboxed closures + { + let a = TypeId::of::<Box<Fn(&'static int, &'static int)>>(); + let b = TypeId::of::<Box<for<'a> Fn(&'static int, &'a int)>>(); + let c = TypeId::of::<Box<for<'a, 'b> Fn(&'a int, &'b int)>>(); + let d = TypeId::of::<Box<for<'a, 'b> Fn(&'b int, &'a int)>>(); + assert!(a != b); + assert!(a != c); + assert!(a != d); + assert!(b != c); + assert!(b != d); + assert_eq!(c, d); + + // Make sure De Bruijn indices are handled correctly + let e = TypeId::of::<Box<for<'a> Fn(Box<Fn(&'a int) -> &'a int>)>>(); + let f = TypeId::of::<Box<Fn(Box<for<'a> Fn(&'a int) -> &'a int>)>>(); + assert!(e != f); + } + // Raw unboxed closures + // Note that every unboxed closure has its own anonymous type, + // so no two IDs should equal each other, even when compatible + { + let a = id(|&: _: &int, _: &int| {}); + let b = id(|&: _: &int, _: &int| {}); + assert!(a != b); + } + + fn id<T:'static>(_: T) -> TypeId { + TypeId::of::<T>() + } +} From 0a1798dd1e7fad9f04a99c58623661ffb1747de0 Mon Sep 17 00:00:00 2001 From: Brian Koropoff <bkoropoff@gmail.com> Date: Sat, 13 Dec 2014 19:11:04 -0800 Subject: [PATCH 39/59] Fix pretty printing of HRTB syntax --- src/libsyntax/print/pprust.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index db122f271a9..b08cf1112fb 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1005,8 +1005,13 @@ impl<'a> State<'a> { fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> { if !t.bound_lifetimes.is_empty() { try!(word(&mut self.s, "for<")); + let mut comma = false; for lifetime_def in t.bound_lifetimes.iter() { + if comma { + try!(self.word_space(",")) + } try!(self.print_lifetime_def(lifetime_def)); + comma = true; } try!(word(&mut self.s, ">")); } From 23bae856b7f3a037caffbf6af6f376a7d48058cd Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Mon, 15 Dec 2014 19:40:25 -0800 Subject: [PATCH 40/59] std: Second-pass stabilization of `mem` This commit takes a second pass through the `std::mem` module for stabilization. The only remaining non-stable items in this module were `forget`, `transmute`, `copy_lifetime`, and `copy_lifetime_mut`. The `forget` and `transmute` intrinsics themselves were marked `#[stable]` to propgate into the `core::mem` module so they would be marked stable. The `copy_lifetime` functions were left `unstable`, but `Sized?` annotations were added to the parameters to allow more general use with DSTs. The `size_of_val`, `min_align_of_val`, and `align_of_val` functions would like to grow `Sized?` bounds, but this is a backwards compatible change that currently ICEs the compiler, so this change was not made at this time. Finally, the module itself was declared `#![stable]` in this pass. --- src/libcore/intrinsics.rs | 2 ++ src/libcore/mem.rs | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2fc4d23e7fd..e2afee9905d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -217,6 +217,7 @@ extern "rust-intrinsic" { /// /// `forget` is unsafe because the caller is responsible for /// ensuring the argument is deallocated already. + #[stable] pub fn forget<T>(_: T) -> (); /// Unsafely transforms a value of one type into a value of another type. @@ -232,6 +233,7 @@ extern "rust-intrinsic" { /// let v: &[u8] = unsafe { mem::transmute("L") }; /// assert!(v == [76u8]); /// ``` + #[stable] pub fn transmute<T,U>(e: T) -> U; /// Gives the address for the return value of the enclosing function. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 937f73a3262..6747d12e028 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -13,9 +13,13 @@ //! This module contains functions for querying the size and alignment of //! types, initializing and manipulating memory. +#![stable] + +use kinds::Sized; use intrinsics; use ptr; +#[stable] pub use intrinsics::transmute; /// Moves a thing into the void. @@ -223,7 +227,8 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U { #[inline] #[unstable = "this function may be removed in the future due to its \ questionable utility"] -pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T { +pub unsafe fn copy_lifetime<'a, Sized? S, Sized? T: 'a>(_ptr: &'a S, + ptr: &T) -> &'a T { transmute(ptr) } @@ -231,7 +236,8 @@ pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T { #[inline] #[unstable = "this function may be removed in the future due to its \ questionable utility"] -pub unsafe fn copy_mut_lifetime<'a, S, T:'a>(_ptr: &'a mut S, - ptr: &mut T) -> &'a mut T { +pub unsafe fn copy_mut_lifetime<'a, Sized? S, Sized? T: 'a>(_ptr: &'a mut S, + ptr: &mut T) + -> &'a mut T { transmute(ptr) } From 9021f61ef7979cb146c5786e1c54c6d928cc0483 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Mon, 15 Dec 2014 20:04:52 -0800 Subject: [PATCH 41/59] std: Second pass stabilization of `default` This commit performs a second pass stabilization of the `std::default` module. The module was already marked `#[stable]`, and the inheritance of `#[stable]` was removed since this attribute was applied. This commit adds the `#[stable]` attribute to the trait definition and one method name, along with all implementations found in the standard distribution. --- src/liballoc/arc.rs | 2 ++ src/liballoc/boxed.rs | 4 ++++ src/liballoc/rc.rs | 1 + src/libcollections/binary_heap.rs | 2 ++ src/libcollections/bit.rs | 2 ++ src/libcollections/btree/map.rs | 2 ++ src/libcollections/btree/set.rs | 2 ++ src/libcollections/dlist.rs | 2 ++ src/libcollections/hash/sip.rs | 2 ++ src/libcollections/ring_buf.rs | 2 ++ src/libcollections/string.rs | 1 + src/libcollections/tree/map.rs | 2 ++ src/libcollections/tree/set.rs | 2 ++ src/libcollections/trie/map.rs | 2 ++ src/libcollections/trie/set.rs | 2 ++ src/libcollections/vec.rs | 1 + src/libcollections/vec_map.rs | 2 ++ src/libcore/cell.rs | 6 ++++-- src/libcore/default.rs | 4 ++++ src/libcore/option.rs | 1 + src/libcore/slice.rs | 3 ++- src/libcore/str.rs | 2 ++ src/libcore/tuple/mod.rs | 1 + src/librand/reseeding.rs | 2 ++ src/libstd/collections/hash/map.rs | 2 ++ src/libstd/collections/hash/set.rs | 2 ++ src/libstd/hash.rs | 2 ++ src/libstd/io/mod.rs | 2 ++ 28 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 1f1909fd33c..876f335406f 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -316,7 +316,9 @@ impl<T: fmt::Show> fmt::Show for Arc<T> { } } +#[stable] impl<T: Default + Sync + Send> Default for Arc<T> { + #[stable] fn default() -> Arc<T> { Arc::new(Default::default()) } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index b0ba20b0133..8fb441c374f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -44,11 +44,15 @@ pub static HEAP: () = (); #[unstable = "custom allocators will add an additional type parameter (with default)"] pub struct Box<T>(*mut T); +#[stable] impl<T: Default> Default for Box<T> { + #[stable] fn default() -> Box<T> { box Default::default() } } +#[stable] impl<T> Default for Box<[T]> { + #[stable] fn default() -> Box<[T]> { box [] } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 217c898e661..636bf48e876 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -447,6 +447,7 @@ impl<T: Default> Default for Rc<T> { /// let x: Rc<int> = Default::default(); /// ``` #[inline] + #[stable] fn default() -> Rc<T> { Rc::new(Default::default()) } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b107d6640a3..94211592698 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -172,8 +172,10 @@ pub struct BinaryHeap<T> { data: Vec<T>, } +#[stable] impl<T: Ord> Default for BinaryHeap<T> { #[inline] + #[stable] fn default() -> BinaryHeap<T> { BinaryHeap::new() } } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index a0c4f6e7ee8..5d8d1084169 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -824,8 +824,10 @@ pub fn from_fn<F>(len: uint, mut f: F) -> Bitv where F: FnMut(uint) -> bool { bitv } +#[stable] impl Default for Bitv { #[inline] + #[stable] fn default() -> Bitv { Bitv::new() } } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index e49a8ddbe5a..dff2c070b57 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -836,7 +836,9 @@ impl<S: Writer, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> { } } +#[stable] impl<K: Ord, V> Default for BTreeMap<K, V> { + #[stable] fn default() -> BTreeMap<K, V> { BTreeMap::new() } diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index c6d1898b87e..172d7ea02ee 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -436,7 +436,9 @@ impl<T: Ord> Extend<T> for BTreeSet<T> { } } +#[stable] impl<T: Ord> Default for BTreeSet<T> { + #[stable] fn default() -> BTreeSet<T> { BTreeSet::new() } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index df86ac96424..bc4bd64092a 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -192,8 +192,10 @@ impl<T> DList<T> { } } +#[stable] impl<T> Default for DList<T> { #[inline] + #[stable] fn default() -> DList<T> { DList::new() } } diff --git a/src/libcollections/hash/sip.rs b/src/libcollections/hash/sip.rs index 9a7aa8c20d3..60042b5ebd8 100644 --- a/src/libcollections/hash/sip.rs +++ b/src/libcollections/hash/sip.rs @@ -204,8 +204,10 @@ impl Clone for SipState { } } +#[stable] impl Default for SipState { #[inline] + #[stable] fn default() -> SipState { SipState::new() } diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 084b585d7b9..5a29d7c085e 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -68,7 +68,9 @@ impl<T> Drop for RingBuf<T> { } } +#[stable] impl<T> Default for RingBuf<T> { + #[stable] #[inline] fn default() -> RingBuf<T> { RingBuf::new() } } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index f3a9e7b1867..505b6367d88 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -826,6 +826,7 @@ impl StrAllocating for String { #[stable] impl Default for String { + #[stable] fn default() -> String { String::new() } diff --git a/src/libcollections/tree/map.rs b/src/libcollections/tree/map.rs index 5c2cf4a8180..2b14f9569b0 100644 --- a/src/libcollections/tree/map.rs +++ b/src/libcollections/tree/map.rs @@ -185,8 +185,10 @@ impl<K: Ord + Show, V: Show> Show for TreeMap<K, V> { } } +#[stable] impl<K: Ord, V> Default for TreeMap<K,V> { #[inline] + #[stable] fn default() -> TreeMap<K, V> { TreeMap::new() } } diff --git a/src/libcollections/tree/set.rs b/src/libcollections/tree/set.rs index 6a0986d3283..c3aebc2736c 100644 --- a/src/libcollections/tree/set.rs +++ b/src/libcollections/tree/set.rs @@ -134,8 +134,10 @@ impl<T: Ord + Show> Show for TreeSet<T> { } } +#[stable] impl<T: Ord> Default for TreeSet<T> { #[inline] + #[stable] fn default() -> TreeSet<T> { TreeSet::new() } } diff --git a/src/libcollections/trie/map.rs b/src/libcollections/trie/map.rs index a4dee807648..67c5407eb6e 100644 --- a/src/libcollections/trie/map.rs +++ b/src/libcollections/trie/map.rs @@ -150,8 +150,10 @@ impl<T: Show> Show for TrieMap<T> { } } +#[stable] impl<T> Default for TrieMap<T> { #[inline] + #[stable] fn default() -> TrieMap<T> { TrieMap::new() } } diff --git a/src/libcollections/trie/set.rs b/src/libcollections/trie/set.rs index 7b7b4d8280b..5d24673ae75 100644 --- a/src/libcollections/trie/set.rs +++ b/src/libcollections/trie/set.rs @@ -69,8 +69,10 @@ impl Show for TrieSet { } } +#[stable] impl Default for TrieSet { #[inline] + #[stable] fn default() -> TrieSet { TrieSet::new() } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 275825da3b5..d6ab2c9a75f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1322,6 +1322,7 @@ impl<T> Drop for Vec<T> { #[stable] impl<T> Default for Vec<T> { + #[stable] fn default() -> Vec<T> { Vec::new() } diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index cc2fd0a6646..d3f28e4a8c8 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -66,7 +66,9 @@ pub struct VecMap<V> { v: Vec<Option<V>>, } +#[stable] impl<V> Default for VecMap<V> { + #[stable] #[inline] fn default() -> VecMap<V> { VecMap::new() } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1ec2efaf801..1e09cf9d5c2 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -215,8 +215,9 @@ impl<T:Copy> Clone for Cell<T> { } } -#[unstable] +#[stable] impl<T:Default + Copy> Default for Cell<T> { + #[stable] fn default() -> Cell<T> { Cell::new(Default::default()) } @@ -349,8 +350,9 @@ impl<T: Clone> Clone for RefCell<T> { } } -#[unstable] +#[stable] impl<T:Default> Default for RefCell<T> { + #[stable] fn default() -> RefCell<T> { RefCell::new(Default::default()) } diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 269a456542c..10facfe4750 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -97,6 +97,7 @@ /// bar: f32, /// } /// ``` +#[stable] pub trait Default { /// Returns the "default value" for a type. /// @@ -130,13 +131,16 @@ pub trait Default { /// fn default() -> Kind { Kind::A } /// } /// ``` + #[stable] fn default() -> Self; } macro_rules! default_impl( ($t:ty, $v:expr) => { + #[stable] impl Default for $t { #[inline] + #[stable] fn default() -> $t { $v } } } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 7be47f73e9e..51f19d8f906 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -760,6 +760,7 @@ impl<T> AsSlice<T> for Option<T> { #[stable] impl<T> Default for Option<T> { + #[stable] #[inline] fn default() -> Option<T> { None } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 27a4328ba80..22d40797f71 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1044,8 +1044,9 @@ impl<'a, T, Sized? U: AsSlice<T>> AsSlice<T> for &'a mut U { fn as_slice<'a>(&'a self) -> &'a [T] { AsSlice::as_slice(*self) } } -#[unstable = "waiting for DST"] +#[stable] impl<'a, T> Default for &'a [T] { + #[stable] fn default() -> &'a [T] { &[] } } diff --git a/src/libcore/str.rs b/src/libcore/str.rs index e632934782c..e85d5a3e315 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -2349,7 +2349,9 @@ impl StrPrelude for str { fn len(&self) -> uint { self.repr().len } } +#[stable] impl<'a> Default for &'a str { + #[stable] fn default() -> &'a str { "" } } diff --git a/src/libcore/tuple/mod.rs b/src/libcore/tuple/mod.rs index 8160424be29..5ea84f7db91 100644 --- a/src/libcore/tuple/mod.rs +++ b/src/libcore/tuple/mod.rs @@ -182,6 +182,7 @@ macro_rules! tuple_impls { #[stable] impl<$($T:Default),+> Default for ($($T,)+) { + #[stable] #[inline] fn default() -> ($($T,)+) { ($({ let x: $T = Default::default(); x},)+) diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 88c870579e6..46ee67940f2 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -142,7 +142,9 @@ impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault { *rng = Default::default(); } } +#[stable] impl Default for ReseedWithDefault { + #[stable] fn default() -> ReseedWithDefault { ReseedWithDefault } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a8d97eed05..b245f167e9d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1288,7 +1288,9 @@ impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> } } +#[stable] impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H> { + #[stable] fn default() -> HashMap<K, V, H> { HashMap::with_hasher(Default::default()) } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 745a8298ee8..ca8d2df4651 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -610,7 +610,9 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Extend<T> for HashSet<T, H> { } } +#[stable] impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> { + #[stable] fn default() -> HashSet<T, H> { HashSet::with_hasher(Default::default()) } diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index ac68e1ef121..b2fac31853d 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -95,7 +95,9 @@ impl Hasher<sip::SipState> for RandomSipHasher { } } +#[stable] impl Default for RandomSipHasher { + #[stable] #[inline] fn default() -> RandomSipHasher { RandomSipHasher::new() diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 4baeaabc6c6..b9139c5d0e2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1911,7 +1911,9 @@ bitflags! { } +#[stable] impl Default for FilePermission { + #[stable] #[inline] fn default() -> FilePermission { FilePermission::empty() } } From 4ecad89636dc7d15dd593776b342b01c7bdf2f50 Mon Sep 17 00:00:00 2001 From: Aaron Friel <mayreply@aaronfriel.com> Date: Mon, 15 Dec 2014 22:45:12 -0600 Subject: [PATCH 42/59] Add probe and var for file Was testing rustup on a very minimal Debian installation and got errors during the install process (error occurred in `install.sh` of the Rust nightly.) Noticed that Rustup was downloading the i686 nightly instead of x86-64. Installing `file` fixed the problem, and this patch adds the probe to ensure file is installed before attempting to use it. There may still be an issue with the i686 installation, I did not investigate further. --- src/etc/rustup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/etc/rustup.sh b/src/etc/rustup.sh index b610bc65b09..5b8ccf924eb 100755 --- a/src/etc/rustup.sh +++ b/src/etc/rustup.sh @@ -231,6 +231,7 @@ validate_opt() { probe_need CFG_CURL curl probe_need CFG_TAR tar +probe_need CFG_FILE file CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/" CFG_SELF="$0" @@ -359,7 +360,7 @@ esac # Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] then - file -L "$SHELL" | grep -q "x86[_-]64" + "${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64" if [ $? != 0 ]; then CFG_CPUTYPE=i686 fi From 3a073e3127363c6b553eda83e0803353f2a95777 Mon Sep 17 00:00:00 2001 From: mdinger <mdinger.bugzilla@gmail.com> Date: Tue, 16 Dec 2014 02:42:25 -0500 Subject: [PATCH 43/59] Tuple test no longer needed. Is already in run-pass tests --- src/libcoretest/tuple.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/libcoretest/tuple.rs b/src/libcoretest/tuple.rs index c53d82de23c..f7b714757f8 100644 --- a/src/libcoretest/tuple.rs +++ b/src/libcoretest/tuple.rs @@ -15,32 +15,6 @@ fn test_clone() { assert_eq!(a, b); } -#[test] -fn test_getters() { - macro_rules! test_getter( - ($x:expr, $valN:ident, $refN:ident, $mutN:ident, - $init:expr, $incr:expr, $result:expr) => ({ - assert_eq!($x.$valN(), $init); - assert_eq!(*$x.$refN(), $init); - *$x.$mutN() += $incr; - assert_eq!(*$x.$refN(), $result); - }) - ) - let mut x = (0u8, 1u16, 2u32, 3u64, 4u, 5i8, 6i16, 7i32, 8i64, 9i, 10f32, 11f64); - test_getter!(x, val0, ref0, mut0, 0, 1, 1); - test_getter!(x, val1, ref1, mut1, 1, 1, 2); - test_getter!(x, val2, ref2, mut2, 2, 1, 3); - test_getter!(x, val3, ref3, mut3, 3, 1, 4); - test_getter!(x, val4, ref4, mut4, 4, 1, 5); - test_getter!(x, val5, ref5, mut5, 5, 1, 6); - test_getter!(x, val6, ref6, mut6, 6, 1, 7); - test_getter!(x, val7, ref7, mut7, 7, 1, 8); - test_getter!(x, val8, ref8, mut8, 8, 1, 9); - test_getter!(x, val9, ref9, mut9, 9, 1, 10); - test_getter!(x, val10, ref10, mut10, 10.0, 1.0, 11.0); - test_getter!(x, val11, ref11, mut11, 11.0, 1.0, 12.0); -} - #[test] fn test_tuple_cmp() { let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u)); From 127dac4990ec14d47a9f5a78db7d7363b038574f Mon Sep 17 00:00:00 2001 From: Flavio Percoco <flaper87@gmail.com> Date: Mon, 15 Dec 2014 21:49:49 +0100 Subject: [PATCH 44/59] Don't make unboxed closures implicitly copiable The fix just checks if the bound is `Copy` and returns an `Err` if so. Closes: #19817 --- src/librustc/middle/traits/select.rs | 7 +++++++ .../unboxed-closer-non-implicit-copyable.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 8b31132f736..f551ff06165 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1209,6 +1209,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is reserve judgement and then intertwine this // analysis with closure inference. assert_eq!(def_id.krate, ast::LOCAL_CRATE); + + // Unboxed closures shouldn't be + // implicitly copyable + if bound == ty::BoundCopy { + return Ok(ParameterBuiltin); + } + match self.tcx().freevars.borrow().get(&def_id.node) { None => { // No upvars. diff --git a/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs new file mode 100644 index 00000000000..182c632d062 --- /dev/null +++ b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +fn main() { + let f = move|:| (); + f(); + f(); //~ ERROR use of moved value +} From 7d4e7f079552a524440d8b5fb656d52661592aee Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" <pnkfelix@pnkfx.org> Date: Tue, 16 Dec 2014 14:30:30 +0100 Subject: [PATCH 45/59] AST refactor: make the place in ExprBox an option. This is to allow us to migrate away from UnUniq in a followup commit, and thus unify the code paths related to all forms of `box`. --- src/librustc/middle/cfg/construct.rs | 6 ++---- src/librustc/middle/expr_use_visitor.rs | 5 ++++- src/librustc/middle/liveness.rs | 3 ++- src/librustc/middle/ty.rs | 3 ++- src/librustc_trans/trans/debuginfo.rs | 3 ++- src/librustc_typeck/check/mod.rs | 27 ++++++++++++++----------- src/libsyntax/ast.rs | 2 +- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 5 ++++- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/visit.rs | 2 +- 11 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 5c39c9fa74d..0e10155beb4 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -462,15 +462,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) } + ast::ExprBox(Some(ref l), ref r) | ast::ExprIndex(ref l, ref r) | ast::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) } - ast::ExprBox(ref p, ref e) => { - self.straightline(expr, pred, [p, e].iter().map(|&e| &**e)) - } - + ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 746a6fc6e70..2cb78beff4c 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -631,7 +631,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprBox(ref place, ref base) => { - self.consume_expr(&**place); + match *place { + Some(ref place) => self.consume_expr(&**place), + None => {} + } self.consume_expr(&**base); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 31bcdff9cd5..c76d9bc6b1f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1199,7 +1199,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprIndex(ref l, ref r) | ast::ExprBinary(_, ref l, ref r) | - ast::ExprBox(ref l, ref r) => { + ast::ExprBox(Some(ref l), ref r) => { let r_succ = self.propagate_through_expr(&**r, succ); self.propagate_through_expr(&**l, r_succ) } @@ -1210,6 +1210,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&**e1, succ) } + ast::ExprBox(None, ref e) | ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 50c324c49c3..b5a8f4869e2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4320,12 +4320,13 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLit(_) | // Note: LitStr is carved out above ast::ExprUnary(..) | + ast::ExprBox(None, _) | ast::ExprAddrOf(..) | ast::ExprBinary(..) => { RvalueDatumExpr } - ast::ExprBox(ref place, _) => { + ast::ExprBox(Some(ref place), _) => { // Special case `Box<T>` for now: let definition = match tcx.def_map.borrow().get(&place.id) { Some(&def) => def, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 3f8c951786d..c97e6a09529 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3472,7 +3472,8 @@ fn populate_scope_map(cx: &CrateContext, walk_expr(cx, &**sub_exp, scope_stack, scope_map), ast::ExprBox(ref place, ref sub_expr) => { - walk_expr(cx, &**place, scope_stack, scope_map); + place.as_ref().map( + |e| walk_expr(cx, &**e, scope_stack, scope_map)); walk_expr(cx, &**sub_expr, scope_stack, scope_map); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 482284c07dc..4b2e91977fb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3658,22 +3658,25 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.ccx.tcx; let id = expr.id; match expr.node { - ast::ExprBox(ref place, ref subexpr) => { - check_expr(fcx, &**place); + ast::ExprBox(ref opt_place, ref subexpr) => { + opt_place.as_ref().map(|place|check_expr(fcx, &**place)); check_expr(fcx, &**subexpr); let mut checked = false; - if let ast::ExprPath(ref path) = place.node { - // FIXME(pcwalton): For now we hardcode the two permissible - // places: the exchange heap and the managed heap. - let definition = lookup_def(fcx, path.span, place.id); - let def_id = definition.def_id(); - let referent_ty = fcx.expr_ty(&**subexpr); - if tcx.lang_items.exchange_heap() == Some(def_id) { - fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); - checked = true + opt_place.as_ref().map(|place| match place.node { + ast::ExprPath(ref path) => { + // FIXME(pcwalton): For now we hardcode the two permissible + // places: the exchange heap and the managed heap. + let definition = lookup_def(fcx, path.span, place.id); + let def_id = definition.def_id(); + let referent_ty = fcx.expr_ty(&**subexpr); + if tcx.lang_items.exchange_heap() == Some(def_id) { + fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); + checked = true + } } - } + _ => {} + }); if !checked { span_err!(tcx.sess, expr.span, E0066, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 206fb26eb55..98d858babb1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -696,7 +696,7 @@ pub struct Expr { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Expr_ { /// First expr is the place; second expr is the value. - ExprBox(P<Expr>, P<Expr>), + ExprBox(Option<P<Expr>>, P<Expr>), ExprVec(Vec<P<Expr>>), ExprCall(P<Expr>, Vec<P<Expr>>), ExprMethodCall(SpannedIdent, Vec<P<Ty>>, Vec<P<Expr>>), diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8a578c2cb05..7d2acd08d94 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1282,7 +1282,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) -> id: folder.new_id(id), node: match node { ExprBox(p, e) => { - ExprBox(folder.fold_expr(p), folder.fold_expr(e)) + ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e)) } ExprVec(exprs) => { ExprVec(exprs.move_map(|x| folder.fold_expr(x))) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b9ef3fdbd49..6e3cfe5854a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2888,7 +2888,7 @@ impl<'a> Parser<'a> { } let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; - ex = ExprBox(place, subexpression); + ex = ExprBox(Some(place), subexpression); return self.mk_expr(lo, hi, ex); } } @@ -2896,6 +2896,9 @@ impl<'a> Parser<'a> { // Otherwise, we use the unique pointer default. let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; + // FIXME (pnkfelix): After working out kinks with box + // desugaring, should be `ExprBox(None, subexpression)` + // instead. ex = self.mk_unary(UnUniq, subexpression); } _ => return self.parse_dot_or_call_expr() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index db122f271a9..4f45b69883b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1495,7 +1495,7 @@ impl<'a> State<'a> { ast::ExprBox(ref p, ref e) => { try!(word(&mut self.s, "box")); try!(word(&mut self.s, "(")); - try!(self.print_expr(&**p)); + try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); try!(self.word_space(")")); try!(self.print_expr(&**e)); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3535c6e267e..f5a86bafea1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -739,7 +739,7 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) { pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { match expression.node { ExprBox(ref place, ref subexpression) => { - visitor.visit_expr(&**place); + place.as_ref().map(|e|visitor.visit_expr(&**e)); visitor.visit_expr(&**subexpression) } ExprVec(ref subexpressions) => { From b7ba69d4ddec0b502e091982ff22d2523d44b367 Mon Sep 17 00:00:00 2001 From: Valerii Hiora <valerii.hiora@gmail.com> Date: Thu, 11 Dec 2014 11:51:25 +0200 Subject: [PATCH 46/59] Fixed iOS build after oibit --- src/librustrt/lib.rs | 2 +- src/librustrt/libunwind.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs index 066e8c51aef..47e00174c78 100644 --- a/src/librustrt/lib.rs +++ b/src/librustrt/lib.rs @@ -126,5 +126,5 @@ pub mod shouldnt_be_public { #[cfg(not(test))] mod std { - pub use core::{fmt, option, cmp}; + pub use core::{fmt, option, cmp, kinds}; } diff --git a/src/librustrt/libunwind.rs b/src/librustrt/libunwind.rs index e4565be284f..2feea7fa0a4 100644 --- a/src/librustrt/libunwind.rs +++ b/src/librustrt/libunwind.rs @@ -25,6 +25,7 @@ use libc; #[cfg(any(not(target_arch = "arm"), target_os = "ios"))] #[repr(C)] +#[deriving(Copy)] pub enum _Unwind_Action { _UA_SEARCH_PHASE = 1, _UA_CLEANUP_PHASE = 2, From 375b79a0fb0a4f9dfc1edfed1154cda97c1f2bc3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" <pnkfelix@pnkfx.org> Date: Tue, 16 Dec 2014 17:07:26 +0100 Subject: [PATCH 47/59] Followup fixes that I missed during an earlier rebase. --- src/librustc/middle/infer/region_inference/graphviz.rs | 4 ++-- src/librustc/middle/infer/region_inference/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs index 7be3ec15862..720de357a27 100644 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -20,8 +20,8 @@ use graphviz as dot; use middle::ty; use super::Constraint; -use middle::typeck::infer::SubregionOrigin; -use middle::typeck::infer::region_inference::RegionVarBindings; +use middle::infer::SubregionOrigin; +use middle::infer::region_inference::RegionVarBindings; use session::config; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::Repr; diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index acd49f3f8df..a284dddc323 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -40,7 +40,7 @@ mod doc; mod graphviz; // A constraint that influences the inference process. -#[deriving(PartialEq, Eq, Hash, Show)] +#[deriving(Clone, PartialEq, Eq, Hash, Show)] pub enum Constraint { // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), From 8f4e9c2357a953a7aa01570de4a00f4cac34d0b0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" <pnkfelix@pnkfx.org> Date: Tue, 16 Dec 2014 17:08:49 +0100 Subject: [PATCH 48/59] Fix `make TAGS.emacs`. --- mk/ctags.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/ctags.mk b/mk/ctags.mk index 39b1c4d4d59..c7a3406a9e7 100644 --- a/mk/ctags.mk +++ b/mk/ctags.mk @@ -27,7 +27,7 @@ CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/llvm,, \ $(patsubst ${CFG_SRC_DIR}src/rt/msvc,, \ $(patsubst ${CFG_SRC_DIR}src/rt/vg,, \ $(wildcard ${CFG_SRC_DIR}src/*) $(wildcard ${CFG_SRC_DIR}src/rt/*) \ - ))))))))) + )))))))) CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=-javascript --recurse ${CTAGS_LOCATIONS} # We could use `--languages=Rust`, but there is value in producing tags for the # C++ parts of the code base too (at the time of writing, those are .h and .cpp From df5404cfa837907405427e3aa4adf1d969e208c9 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Mon, 15 Dec 2014 08:49:01 -0800 Subject: [PATCH 49/59] std: Change escape_unicode to use new escapes This changes the `escape_unicode` method on a `char` to use the new style of unicode escapes in the language. Closes #19811 Closes #19879 --- src/libcollections/str.rs | 36 +++-- src/libcore/char.rs | 143 +++++++++--------- src/libcoretest/char.rs | 41 +++-- .../macro-crate-cannot-read-embedded-ident.rs | 2 +- 4 files changed, 111 insertions(+), 111 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 3c3a1291ba0..4a5132f1c75 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1597,17 +1597,24 @@ mod tests { #[test] fn test_escape_unicode() { - assert_eq!("abc".escape_unicode(), String::from_str("\\x61\\x62\\x63")); - assert_eq!("a c".escape_unicode(), String::from_str("\\x61\\x20\\x63")); - assert_eq!("\r\n\t".escape_unicode(), String::from_str("\\x0d\\x0a\\x09")); - assert_eq!("'\"\\".escape_unicode(), String::from_str("\\x27\\x22\\x5c")); + assert_eq!("abc".escape_unicode(), + String::from_str("\\u{61}\\u{62}\\u{63}")); + assert_eq!("a c".escape_unicode(), + String::from_str("\\u{61}\\u{20}\\u{63}")); + assert_eq!("\r\n\t".escape_unicode(), + String::from_str("\\u{d}\\u{a}\\u{9}")); + assert_eq!("'\"\\".escape_unicode(), + String::from_str("\\u{27}\\u{22}\\u{5c}")); assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), - String::from_str("\\x00\\x01\\u00fe\\u00ff")); - assert_eq!("\u{100}\u{ffff}".escape_unicode(), String::from_str("\\u0100\\uffff")); + String::from_str("\\u{0}\\u{1}\\u{fe}\\u{ff}")); + assert_eq!("\u{100}\u{ffff}".escape_unicode(), + String::from_str("\\u{100}\\u{ffff}")); assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), - String::from_str("\\U00010000\\U0010ffff")); - assert_eq!("ab\u{fb00}".escape_unicode(), String::from_str("\\x61\\x62\\ufb00")); - assert_eq!("\u{1d4ea}\r".escape_unicode(), String::from_str("\\U0001d4ea\\x0d")); + String::from_str("\\u{10000}\\u{10ffff}")); + assert_eq!("ab\u{fb00}".escape_unicode(), + String::from_str("\\u{61}\\u{62}\\u{fb00}")); + assert_eq!("\u{1d4ea}\r".escape_unicode(), + String::from_str("\\u{1d4ea}\\u{d}")); } #[test] @@ -1616,11 +1623,14 @@ mod tests { assert_eq!("a c".escape_default(), String::from_str("a c")); assert_eq!("\r\n\t".escape_default(), String::from_str("\\r\\n\\t")); assert_eq!("'\"\\".escape_default(), String::from_str("\\'\\\"\\\\")); - assert_eq!("\u{100}\u{ffff}".escape_default(), String::from_str("\\u0100\\uffff")); + assert_eq!("\u{100}\u{ffff}".escape_default(), + String::from_str("\\u{100}\\u{ffff}")); assert_eq!("\u{10000}\u{10ffff}".escape_default(), - String::from_str("\\U00010000\\U0010ffff")); - assert_eq!("ab\u{fb00}".escape_default(), String::from_str("ab\\ufb00")); - assert_eq!("\u{1d4ea}\r".escape_default(), String::from_str("\\U0001d4ea\\r")); + String::from_str("\\u{10000}\\u{10ffff}")); + assert_eq!("ab\u{fb00}".escape_default(), + String::from_str("ab\\u{fb00}")); + assert_eq!("\u{1d4ea}\r".escape_default(), + String::from_str("\\u{1d4ea}\\r")); } #[test] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index fbc444c2be3..268d763dcda 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -15,11 +15,11 @@ #![allow(non_snake_case)] #![doc(primitive = "char")] +use iter::Iterator; use mem::transmute; use ops::FnMut; -use option::Option; use option::Option::{None, Some}; -use iter::{range_step, Iterator, RangeStep}; +use option::Option; use slice::SliceExt; // UTF-8 ranges and tags for encoding characters @@ -156,15 +156,7 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> { } } -/// -/// Returns the hexadecimal Unicode escape of a `char` -/// -/// The rules are as follows: -/// -/// - chars in [0,0xff] get 2-digit escapes: `\\xNN` -/// - chars in [0x100,0xffff] get 4-digit escapes: `\\u{NNNN}` -/// - chars above 0x10000 get 8-digit escapes: `\\u{{NNN}NNNNN}` -/// +/// Deprecated, call the escape_unicode method instead. #[deprecated = "use the Char::escape_unicode method"] pub fn escape_unicode<F>(c: char, mut f: F) where F: FnMut(char) { for char in c.escape_unicode() { @@ -172,18 +164,7 @@ pub fn escape_unicode<F>(c: char, mut f: F) where F: FnMut(char) { } } -/// -/// Returns a 'default' ASCII and C++11-like literal escape of a `char` -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex Unicode escapes; see `escape_unicode`. -/// +/// Deprecated, call the escape_default method instead. #[deprecated = "use the Char::escape_default method"] pub fn escape_default<F>(c: char, mut f: F) where F: FnMut(char) { for c in c.escape_default() { @@ -267,13 +248,11 @@ pub trait Char { /// Returns an iterator that yields the hexadecimal Unicode escape /// of a character, as `char`s. /// - /// The rules are as follows: - /// - /// * Characters in [0,0xff] get 2-digit escapes: `\\xNN` - /// * Characters in [0x100,0xffff] get 4-digit escapes: `\\u{NNNN}`. - /// * Characters above 0x10000 get 8-digit escapes: `\\u{{NNN}NNNNN}`. + /// All characters are escaped with Rust syntax of the form `\\u{NNNN}` + /// where `NNNN` is the shortest hexadecimal representation of the code + /// point. #[unstable = "pending error conventions, trait organization"] - fn escape_unicode(self) -> UnicodeEscapedChars; + fn escape_unicode(self) -> EscapeUnicode; /// Returns an iterator that yields the 'default' ASCII and /// C++11-like literal escape of a character, as `char`s. @@ -288,7 +267,7 @@ pub trait Char { /// * Any other chars in the range [0x20,0x7e] are not escaped. /// * Any other chars are given hex Unicode escapes; see `escape_unicode`. #[unstable = "pending error conventions, trait organization"] - fn escape_default(self) -> DefaultEscapedChars; + fn escape_default(self) -> EscapeDefault; /// Returns the amount of bytes this character would need if encoded in /// UTF-8. @@ -358,23 +337,23 @@ impl Char for char { fn from_u32(i: u32) -> Option<char> { from_u32(i) } #[unstable = "pending error conventions, trait organization"] - fn escape_unicode(self) -> UnicodeEscapedChars { - UnicodeEscapedChars { c: self, state: UnicodeEscapedCharsState::Backslash } + fn escape_unicode(self) -> EscapeUnicode { + EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash } } #[unstable = "pending error conventions, trait organization"] - fn escape_default(self) -> DefaultEscapedChars { + fn escape_default(self) -> EscapeDefault { let init_state = match self { - '\t' => DefaultEscapedCharsState::Backslash('t'), - '\r' => DefaultEscapedCharsState::Backslash('r'), - '\n' => DefaultEscapedCharsState::Backslash('n'), - '\\' => DefaultEscapedCharsState::Backslash('\\'), - '\'' => DefaultEscapedCharsState::Backslash('\''), - '"' => DefaultEscapedCharsState::Backslash('"'), - '\x20' ... '\x7e' => DefaultEscapedCharsState::Char(self), - _ => DefaultEscapedCharsState::Unicode(self.escape_unicode()) + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' => EscapeDefaultState::Backslash('\\'), + '\'' => EscapeDefaultState::Backslash('\''), + '"' => EscapeDefaultState::Backslash('"'), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; - DefaultEscapedChars { state: init_state } + EscapeDefault { state: init_state } } #[inline] @@ -451,72 +430,86 @@ impl Char for char { /// An iterator over the characters that represent a `char`, as escaped by /// Rust's unicode escaping rules. -pub struct UnicodeEscapedChars { +pub struct EscapeUnicode { c: char, - state: UnicodeEscapedCharsState + state: EscapeUnicodeState } -enum UnicodeEscapedCharsState { +enum EscapeUnicodeState { Backslash, Type, - Value(RangeStep<i32>), + LeftBrace, + Value(uint), + RightBrace, + Done, } -impl Iterator<char> for UnicodeEscapedChars { +impl Iterator<char> for EscapeUnicode { fn next(&mut self) -> Option<char> { match self.state { - UnicodeEscapedCharsState::Backslash => { - self.state = UnicodeEscapedCharsState::Type; + EscapeUnicodeState::Backslash => { + self.state = EscapeUnicodeState::Type; Some('\\') } - UnicodeEscapedCharsState::Type => { - let (typechar, pad) = if self.c <= '\x7f' { ('x', 2) } - else if self.c <= '\u{ffff}' { ('u', 4) } - else { ('U', 8) }; - self.state = UnicodeEscapedCharsState::Value(range_step(4 * (pad - 1), -1, -4i32)); - Some(typechar) + EscapeUnicodeState::Type => { + self.state = EscapeUnicodeState::LeftBrace; + Some('u') } - UnicodeEscapedCharsState::Value(ref mut range_step) => match range_step.next() { - Some(offset) => { - let offset = offset as uint; - let v = match ((self.c as i32) >> offset) & 0xf { - i @ 0 ... 9 => '0' as i32 + i, - i => 'a' as i32 + (i - 10) - }; - Some(unsafe { transmute(v) }) + EscapeUnicodeState::LeftBrace => { + let mut n = 0u; + while (self.c as u32) >> (4 * (n + 1)) != 0 { + n += 1; } - None => None + self.state = EscapeUnicodeState::Value(n); + Some('{') } + EscapeUnicodeState::Value(offset) => { + let v = match ((self.c as i32) >> (offset * 4)) & 0xf { + i @ 0 ... 9 => '0' as i32 + i, + i => 'a' as i32 + (i - 10) + }; + if offset == 0 { + self.state = EscapeUnicodeState::RightBrace; + } else { + self.state = EscapeUnicodeState::Value(offset - 1); + } + Some(unsafe { transmute(v) }) + } + EscapeUnicodeState::RightBrace => { + self.state = EscapeUnicodeState::Done; + Some('}') + } + EscapeUnicodeState::Done => None, } } } /// An iterator over the characters that represent a `char`, escaped /// for maximum portability. -pub struct DefaultEscapedChars { - state: DefaultEscapedCharsState +pub struct EscapeDefault { + state: EscapeDefaultState } -enum DefaultEscapedCharsState { +enum EscapeDefaultState { Backslash(char), Char(char), Done, - Unicode(UnicodeEscapedChars), + Unicode(EscapeUnicode), } -impl Iterator<char> for DefaultEscapedChars { +impl Iterator<char> for EscapeDefault { fn next(&mut self) -> Option<char> { match self.state { - DefaultEscapedCharsState::Backslash(c) => { - self.state = DefaultEscapedCharsState::Char(c); + EscapeDefaultState::Backslash(c) => { + self.state = EscapeDefaultState::Char(c); Some('\\') } - DefaultEscapedCharsState::Char(c) => { - self.state = DefaultEscapedCharsState::Done; + EscapeDefaultState::Char(c) => { + self.state = EscapeDefaultState::Done; Some(c) } - DefaultEscapedCharsState::Done => None, - DefaultEscapedCharsState::Unicode(ref mut iter) => iter.next() + EscapeDefaultState::Done => None, + EscapeDefaultState::Unicode(ref mut iter) => iter.next() } } } diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index e5561bebb22..bed38f8c296 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -135,38 +135,35 @@ fn test_escape_default() { let s = string('~'); assert_eq!(s, "~"); let s = string('\x00'); - assert_eq!(s, "\\x00"); + assert_eq!(s, "\\u{0}"); let s = string('\x1f'); - assert_eq!(s, "\\x1f"); + assert_eq!(s, "\\u{1f}"); let s = string('\x7f'); - assert_eq!(s, "\\x7f"); - let s = string('\u00ff'); - assert_eq!(s, "\\u00ff"); - let s = string('\u011b'); - assert_eq!(s, "\\u011b"); - let s = string('\U0001d4b6'); - assert_eq!(s, "\\U0001d4b6"); + assert_eq!(s, "\\u{7f}"); + let s = string('\u{ff}'); + assert_eq!(s, "\\u{ff}"); + let s = string('\u{11b}'); + assert_eq!(s, "\\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\\u{1d4b6}"); } #[test] fn test_escape_unicode() { - fn string(c: char) -> String { - let mut result = String::new(); - escape_unicode(c, |c| { result.push(c); }); - return result; - } + fn string(c: char) -> String { c.escape_unicode().collect() } + let s = string('\x00'); - assert_eq!(s, "\\x00"); + assert_eq!(s, "\\u{0}"); let s = string('\n'); - assert_eq!(s, "\\x0a"); + assert_eq!(s, "\\u{a}"); let s = string(' '); - assert_eq!(s, "\\x20"); + assert_eq!(s, "\\u{20}"); let s = string('a'); - assert_eq!(s, "\\x61"); - let s = string('\u011b'); - assert_eq!(s, "\\u011b"); - let s = string('\U0001d4b6'); - assert_eq!(s, "\\U0001d4b6"); + assert_eq!(s, "\\u{61}"); + let s = string('\u{11b}'); + assert_eq!(s, "\\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\\u{1d4b6}"); } #[test] diff --git a/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs b/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs index 268b6e6aa0f..fc7664c480f 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs @@ -11,7 +11,7 @@ // aux-build:macro_crate_test.rs // ignore-stage1 // ignore-android -// error-pattern: unknown start of token: \x00 +// error-pattern: unknown start of token: \u{0} // Issue #15750 and #15962 : this test is checking that the standard // parser rejects embedded idents. pnkfelix did not want to attempt From 73d395e6dbde3e720544a660c95f407378b5be70 Mon Sep 17 00:00:00 2001 From: Sean Collins <sean@cllns.com> Date: Tue, 16 Dec 2014 12:57:51 -0500 Subject: [PATCH 50/59] Change 'if' to lowercase, so it displays better on the site --- src/doc/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index da111cbe6b4..79b2d129766 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -538,7 +538,7 @@ format in a more detailed manner, there are a [wide number of options available](std/fmt/index.html). For now, we'll just stick to the default: integers aren't very complicated to print. -# If +# `if` Rust's take on `if` is not particularly complex, but it's much more like the `if` you'll find in a dynamically typed language than in a more traditional From 570325dd3c6b7958ccfe008fb0c68f531fd51ed1 Mon Sep 17 00:00:00 2001 From: P1start <rewi-github@whanau.org> Date: Tue, 16 Dec 2014 13:38:34 +1300 Subject: [PATCH 51/59] Use the sugary syntax to print the `Fn` traits in error messages --- src/librustc/util/ppaux.rs | 25 +++++++++++++------- src/test/compile-fail/fn-trait-formatting.rs | 24 +++++++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/fn-trait-formatting.rs diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 74e312803f3..13b5c262bf7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -428,17 +428,19 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let base = ty::item_path_str(cx, did); let generics = ty::lookup_item_type(cx, did).generics; - parameterized(cx, base.as_slice(), substs, &generics) + parameterized(cx, base.as_slice(), substs, &generics, did) } ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { let base = ty::item_path_str(cx, principal.def_id); let trait_def = ty::lookup_trait_def(cx, principal.def_id); + let did = trait_def.trait_ref.def_id; let ty = parameterized(cx, base.as_slice(), - &principal.substs, &trait_def.generics); + &principal.substs, &trait_def.generics, + did); let bound_str = bounds.user_string(cx); - let bound_sep = if bound_str.is_empty() { "" } else { "+" }; + let bound_sep = if bound_str.is_empty() { "" } else { " + " }; format!("{}{}{}", ty, bound_sep, @@ -484,7 +486,8 @@ pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory) pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, base: &str, substs: &subst::Substs<'tcx>, - generics: &ty::Generics<'tcx>) + generics: &ty::Generics<'tcx>, + did: ast::DefId) -> String { if cx.sess.verbose() { @@ -537,7 +540,12 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, strs.push(ty_to_string(cx, *t)) } - if strs.len() > 0u { + if cx.lang_items.fn_trait_kind(did).is_some() { + format!("{}({}){}", + base, + strs[0][1 .. strs[0].len() - (strs[0].ends_with(",)") as uint+1)], + if &*strs[1] == "()" { String::new() } else { format!(" -> {}", strs[1]) }) + } else if strs.len() > 0 { format!("{}<{}>", base, strs.connect(", ")) } else { format!("{}", base) @@ -743,7 +751,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { let trait_def = ty::lookup_trait_def(tcx, self.def_id); format!("<{} : {}>", self.substs.self_ty().repr(tcx), - parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)) + parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics, self.def_id)) } } @@ -1116,7 +1124,7 @@ impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> { for n in self.trait_bounds.iter() { result.push(n.user_string(tcx)); } - result.connect("+") + result.connect(" + ") } } @@ -1189,7 +1197,8 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { }; let trait_def = ty::lookup_trait_def(tcx, self.def_id); - parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics) + let did = trait_def.trait_ref.def_id; + parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics, did) } } diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs new file mode 100644 index 00000000000..3eeb4c177ca --- /dev/null +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +fn needs_fn<F>(x: F) where F: Fn(int) -> int {} + +fn main() { + let _: () = (box |:_: int| {}) as Box<FnOnce(int)>; //~ ERROR object-safe + //~^ ERROR Box<core::ops::FnOnce(int)> + let _: () = (box |&:_: int, int| {}) as Box<Fn(int, int)>; + //~^ ERROR Box<core::ops::Fn(int, int)> + let _: () = (box |&mut:| -> int unimplemented!()) as Box<FnMut() -> int>; + //~^ ERROR Box<core::ops::FnMut() -> int> + + needs_fn(1i); //~ ERROR `core::ops::Fn(int) -> int` +} From c42e2f604ef2f43e9b8adbf1fc7a40944bfcb668 Mon Sep 17 00:00:00 2001 From: Clark Gaebel <cg.wowus.cg@gmail.com> Date: Tue, 16 Dec 2014 16:00:37 -0500 Subject: [PATCH 52/59] Small cleanups in HashMap based off of new rust features. --- src/libstd/collections/hash/map.rs | 123 +++++++++------------------ src/libstd/collections/hash/set.rs | 2 +- src/libstd/collections/hash/table.rs | 4 +- 3 files changed, 41 insertions(+), 88 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a8d97eed05..7d9c9b92460 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -297,7 +297,7 @@ pub struct HashMap<K, V, H = RandomSipHasher> { /// Search for a pre-hashed key. fn search_hashed<K, V, M, F>(table: M, - hash: &SafeHash, + hash: SafeHash, mut is_match: F) -> SearchResult<K, V, M> where M: Deref<RawTable<K, V>>, @@ -320,14 +320,9 @@ fn search_hashed<K, V, M, F>(table: M, } // If the hash doesn't match, it can't be this one.. - if *hash == full.hash() { - let matched = { - let (k, _) = full.read(); - is_match(k) - }; - + if hash == full.hash() { // If the key doesn't match, it can't be this one.. - if matched { + if is_match(full.read().0) { return FoundExisting(full); } } @@ -353,7 +348,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) { } // Now we've done all our shifting. Return the value we grabbed earlier. - return (retkey, retval); + (retkey, retval) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -389,10 +384,11 @@ fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>, let b = bucket.put(old_hash, old_key, old_val); // Now that it's stolen, just read the value's pointer // right out of the table! - let (_, v) = Bucket::at_index(b.into_table(), starting_index).peek() - .expect_full() - .into_mut_refs(); - return v; + return Bucket::at_index(b.into_table(), starting_index) + .peek() + .expect_full() + .into_mut_refs() + .1; }, table::Full(bucket) => bucket }; @@ -441,14 +437,14 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { fn search_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>> { let hash = self.make_hash(q); - search_hashed(&self.table, &hash, |k| q.equiv(k)).into_option() + search_hashed(&self.table, hash, |k| q.equiv(k)).into_option() } #[allow(deprecated)] fn search_equiv_mut<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>> { let hash = self.make_hash(q); - search_hashed(&mut self.table, &hash, |k| q.equiv(k)).into_option() + search_hashed(&mut self.table, hash, |k| q.equiv(k)).into_option() } /// Search for a key, yielding the index if it's found in the hashtable. @@ -458,7 +454,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { where Q: BorrowFrom<K> + Eq + Hash<S> { let hash = self.make_hash(q); - search_hashed(&self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) .into_option() } @@ -466,14 +462,14 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { where Q: BorrowFrom<K> + Eq + Hash<S> { let hash = self.make_hash(q); - search_hashed(&mut self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&mut self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) .into_option() } // The caller should ensure that invariants by Robin Hood Hashing hold. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { let cap = self.table.capacity(); - let mut buckets = Bucket::new(&mut self.table, &hash); + let mut buckets = Bucket::new(&mut self.table, hash); let ib = buckets.index(); while buckets.index() != ib + cap { @@ -762,26 +758,22 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { { // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = self.table.size(); - let mut probe = Bucket::new(&mut self.table, &hash); + let mut probe = Bucket::new(&mut self.table, hash); let ib = probe.index(); loop { let mut bucket = match probe.peek() { Empty(bucket) => { // Found a hole! - let bucket = bucket.put(hash, k, v); - let (_, val) = bucket.into_mut_refs(); - return val; - }, + return bucket.put(hash, k, v).into_mut_refs().1; + } Full(bucket) => bucket }; + // hash matches? if bucket.hash() == hash { - let found_match = { - let (bucket_k, _) = bucket.read_mut(); - k == *bucket_k - }; - if found_match { + // key matches? + if k == *bucket.read_mut().0 { let (bucket_k, bucket_v) = bucket.into_mut_refs(); debug_assert!(k == *bucket_k); // Key already exists. Get its reference. @@ -811,13 +803,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// Deprecated: use `get` and `BorrowFrom` instead. #[deprecated = "use get and BorrowFrom instead"] pub fn find_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> { - match self.search_equiv(k) { - None => None, - Some(bucket) => { - let (_, v_ref) = bucket.into_refs(); - Some(v_ref) - } - } + self.search_equiv(k).map(|bucket| bucket.into_refs().1) } /// Deprecated: use `remove` and `BorrowFrom` instead. @@ -829,13 +815,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { self.reserve(1); - match self.search_equiv_mut(k) { - Some(bucket) => { - let (_k, val) = pop_internal(bucket); - Some(val) - } - _ => None - } + self.search_equiv_mut(k).map(|bucket| pop_internal(bucket).1) } /// An iterator visiting all keys in arbitrary order. @@ -1022,11 +1002,8 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { while buckets.index() != cap { buckets = match buckets.peek() { - Empty(b) => b.next(), - Full(full) => { - let (b, _, _) = full.take(); - b.next() - } + Empty(b) => b.next(), + Full(full) => full.take().0.next(), }; } } @@ -1057,10 +1034,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn get<Sized? Q>(&self, k: &Q) -> Option<&V> where Q: Hash<S> + Eq + BorrowFrom<K> { - self.search(k).map(|bucket| { - let (_, v) = bucket.into_refs(); - v - }) + self.search(k).map(|bucket| bucket.into_refs().1) } /// Returns true if the map contains a value for the specified key. @@ -1115,13 +1089,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { pub fn get_mut<Sized? Q>(&mut self, k: &Q) -> Option<&mut V> where Q: Hash<S> + Eq + BorrowFrom<K> { - match self.search_mut(k) { - Some(bucket) => { - let (_, v) = bucket.into_mut_refs(); - Some(v) - } - _ => None - } + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Deprecated: Renamed to `insert`. @@ -1189,10 +1157,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { return None } - self.search_mut(k).map(|bucket| { - let (_k, val) = pop_internal(bucket); - val - }) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } } @@ -1200,7 +1165,7 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas -> Entry<'a, K, V> { // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = table.size(); - let mut probe = Bucket::new(table, &hash); + let mut probe = Bucket::new(table, hash); let ib = probe.index(); loop { @@ -1216,13 +1181,10 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas Full(bucket) => bucket }; + // hash matches? if bucket.hash() == hash { - let is_eq = { - let (bucket_k, _) = bucket.read(); - k == *bucket_k - }; - - if is_eq { + // key matches? + if k == *bucket.read().0 { return Occupied(OccupiedEntry{ elem: bucket, }); @@ -1308,10 +1270,7 @@ impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q, V> for HashMap<K { #[inline] fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { - match self.get_mut(index) { - Some(v) => v, - None => panic!("no entry found for key") - } + self.get_mut(index).expect("no entry found for key") } } @@ -1400,21 +1359,18 @@ impl<K, V> Iterator<(K, V)> for MoveEntries<K, V> { impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the value in the entry pub fn get(&self) -> &V { - let (_, v) = self.elem.read(); - v + self.elem.read().1 } /// Gets a mutable reference to the value in the entry pub fn get_mut(&mut self) -> &mut V { - let (_, v) = self.elem.read_mut(); - v + self.elem.read_mut().1 } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut V { - let (_, v) = self.elem.into_mut_refs(); - v + self.elem.into_mut_refs().1 } /// Sets the value of the entry, and returns the entry's old value @@ -1426,8 +1382,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Takes the value out of the entry, and returns it pub fn take(self) -> V { - let (_, v) = pop_internal(self.elem); - v + pop_internal(self.elem).1 } } @@ -1440,9 +1395,7 @@ impl<'a, K, V> VacantEntry<'a, K, V> { robin_hood(bucket, ib, self.hash, self.key, value) } NoElem(bucket) => { - let full = bucket.put(self.hash, self.key, value); - let (_, v) = full.into_mut_refs(); - v + bucket.put(self.hash, self.key, value).into_mut_refs().1 } } } @@ -1458,7 +1411,7 @@ pub type Values<'a, K, V> = impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> { fn from_iter<T: Iterator<(K, V)>>(iter: T) -> HashMap<K, V, H> { - let (lower, _) = iter.size_hint(); + let lower = iter.size_hint().0; let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); map.extend(iter); map diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index c71f0d5b935..262bbf094ec 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -595,7 +595,7 @@ impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> { impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, H> { fn from_iter<I: Iterator<T>>(iter: I) -> HashSet<T, H> { - let (lower, _) = iter.size_hint(); + let lower = iter.size_hint().0; let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); set.extend(iter); set diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index ef4cabedc47..da06387e9a5 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -124,7 +124,7 @@ struct GapThenFull<K, V, M> { /// A hash that is not zero, since we use a hash of zero to represent empty /// buckets. -#[deriving(PartialEq)] +#[deriving(PartialEq, Copy)] pub struct SafeHash { hash: u64, } @@ -211,7 +211,7 @@ impl<K, V, M> Bucket<K, V, M> { } impl<K, V, M: Deref<RawTable<K, V>>> Bucket<K, V, M> { - pub fn new(table: M, hash: &SafeHash) -> Bucket<K, V, M> { + pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> { Bucket::at_index(table, hash.inspect() as uint) } From c1b69c7a82b1a138dd1bb1954cd308fa97d15115 Mon Sep 17 00:00:00 2001 From: Philipp Gesang <phg42.2a@gmail.com> Date: Sun, 7 Dec 2014 22:02:17 +0100 Subject: [PATCH 53/59] guide-ownership.md, guide-testing.md: fix typos Signed-off-by: Philipp Gesang <phg@phi-gamma.net> --- src/doc/guide-ownership.md | 2 +- src/doc/guide-testing.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index ddabb1de765..88139a1a513 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -416,7 +416,7 @@ note: `car` moved here because it has type `Car`, which is non-copyable ``` We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with -`Box<T>`, because it has a single owner. We can do t with `Rc<T>` instead: +`Box<T>`, because it has a single owner. We can do it with `Rc<T>` instead: ```rust use std::rc::Rc; diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 0452ed0bfeb..682c89fcc53 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -357,7 +357,7 @@ Let's finally check out that third section: documentation tests. Nothing is better than documentation with examples. Nothing is worse than examples that don't actually work, because the code has changed since the -documentation has been written. To this end, Rust supports automaticaly +documentation has been written. To this end, Rust supports automatically running examples in your documentation. Here's a fleshed-out `src/lib.rs` with examples: From 033a79203e48ec4ae51d79f3642372bf662ecffb Mon Sep 17 00:00:00 2001 From: Steve Klabnik <steve@steveklabnik.com> Date: Tue, 16 Dec 2014 18:23:55 -0500 Subject: [PATCH 54/59] Document std::mem --- src/libcore/mem.rs | 185 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 46 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 937f73a3262..11c3f7c289d 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -29,6 +29,14 @@ pub use intrinsics::transmute; pub use intrinsics::forget; /// Returns the size of a type in bytes. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of::<i32>()); +/// ``` #[inline] #[stable] pub fn size_of<T>() -> uint { @@ -36,6 +44,14 @@ pub fn size_of<T>() -> uint { } /// Returns the size of the type that `_val` points to in bytes. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// ``` #[inline] #[stable] pub fn size_of_val<T>(_val: &T) -> uint { @@ -44,16 +60,30 @@ pub fn size_of_val<T>(_val: &T) -> uint { /// Returns the ABI-required minimum alignment of a type /// -/// This is the alignment used for struct fields. It may be smaller -/// than the preferred alignment. +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of::<i32>()); +/// ``` #[inline] #[stable] pub fn min_align_of<T>() -> uint { unsafe { intrinsics::min_align_of::<T>() } } -/// Returns the ABI-required minimum alignment of the type of the value that -/// `_val` points to +/// Returns the ABI-required minimum alignment of the type of the value that `_val` points to +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of_val(&5i32)); +/// ``` #[inline] #[stable] pub fn min_align_of_val<T>(_val: &T) -> uint { @@ -62,9 +92,16 @@ pub fn min_align_of_val<T>(_val: &T) -> uint { /// Returns the alignment in memory for a type. /// -/// This function will return the alignment, in bytes, of a type in memory. If -/// the alignment returned is adhered to, then the type is guaranteed to -/// function properly. +/// This function will return the alignment, in bytes, of a type in memory. If the alignment +/// returned is adhered to, then the type is guaranteed to function properly. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of::<i32>()); +/// ``` #[inline] #[stable] pub fn align_of<T>() -> uint { @@ -77,9 +114,16 @@ pub fn align_of<T>() -> uint { /// Returns the alignment of the type of the value that `_val` points to. /// -/// This is similar to `align_of`, but function will properly handle types such -/// as trait objects (in the future), returning the alignment for an arbitrary -/// value at runtime. +/// This is similar to `align_of`, but function will properly handle types such as trait objects +/// (in the future), returning the alignment for an arbitrary value at runtime. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of_val(&5i32)); +/// ``` #[inline] #[stable] pub fn align_of_val<T>(_val: &T) -> uint { @@ -88,15 +132,22 @@ pub fn align_of_val<T>(_val: &T) -> uint { /// Create a value initialized to zero. /// -/// This function is similar to allocating space for a local variable and -/// zeroing it out (an unsafe operation). +/// This function is similar to allocating space for a local variable and zeroing it out (an unsafe +/// operation). /// -/// Care must be taken when using this function, if the type `T` has a -/// destructor and the value falls out of scope (due to unwinding or returning) -/// before being initialized, then the destructor will run on zeroed -/// data, likely leading to crashes. +/// Care must be taken when using this function, if the type `T` has a destructor and the value +/// falls out of scope (due to unwinding or returning) before being initialized, then the +/// destructor will run on zeroed data, likely leading to crashes. /// /// This is useful for FFI functions sometimes, but should generally be avoided. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let x: int = unsafe { mem::zeroed() }; +/// ``` #[inline] #[stable] pub unsafe fn zeroed<T>() -> T { @@ -105,20 +156,41 @@ pub unsafe fn zeroed<T>() -> T { /// Create an uninitialized value. /// -/// Care must be taken when using this function, if the type `T` has a -/// destructor and the value falls out of scope (due to unwinding or returning) -/// before being initialized, then the destructor will run on uninitialized -/// data, likely leading to crashes. +/// Care must be taken when using this function, if the type `T` has a destructor and the value +/// falls out of scope (due to unwinding or returning) before being initialized, then the +/// destructor will run on uninitialized data, likely leading to crashes. /// /// This is useful for FFI functions sometimes, but should generally be avoided. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let x: int = unsafe { mem::uninitialized() }; +/// ``` #[inline] #[stable] pub unsafe fn uninitialized<T>() -> T { intrinsics::uninit() } -/// Swap the values at two mutable locations of the same type, without -/// deinitialising or copying either one. +/// Swap the values at two mutable locations of the same type, without deinitialising or copying +/// either one. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let x = &mut 5i; +/// let y = &mut 42i; +/// +/// mem::swap(x, y); +/// +/// assert_eq!(42i, *x); +/// assert_eq!(5i, *y); +/// ``` #[inline] #[stable] pub fn swap<T>(x: &mut T, y: &mut T) { @@ -137,13 +209,26 @@ pub fn swap<T>(x: &mut T, y: &mut T) { } } -/// Replace the value at a mutable location with a new one, returning the old -/// value, without deinitialising or copying either one. +/// Replace the value at a mutable location with a new one, returning the old value, without +/// deinitialising or copying either one. /// -/// This is primarily used for transferring and swapping ownership of a value -/// in a mutable location. For example, this function allows consumption of -/// one field of a struct by replacing it with another value. The normal approach -/// doesn't always work: +/// This is primarily used for transferring and swapping ownership of a value in a mutable +/// location. +/// +/// # Examples +/// +/// A simple example: +/// +/// ``` +/// use std::mem; +/// +/// let mut v: Vec<i32> = Vec::new(); +/// +/// mem::replace(&mut v, Vec::new()); +/// ``` +/// +/// This function allows consumption of one field of a struct by replacing it with another value. +/// The normal approach doesn't always work: /// /// ```rust,ignore /// struct Buffer<T> { buf: Vec<T> } @@ -158,16 +243,16 @@ pub fn swap<T>(x: &mut T, y: &mut T) { /// } /// ``` /// -/// Note that `T` does not necessarily implement `Clone`, so it can't even -/// clone and reset `self.buf`. But `replace` can be used to disassociate -/// the original value of `self.buf` from `self`, allowing it to be returned: +/// Note that `T` does not necessarily implement `Clone`, so it can't even clone and reset +/// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from +/// `self`, allowing it to be returned: /// /// ```rust +/// use std::mem; /// # struct Buffer<T> { buf: Vec<T> } /// impl<T> Buffer<T> { /// fn get_and_reset(&mut self) -> Vec<T> { -/// use std::mem::replace; -/// replace(&mut self.buf, Vec::new()) +/// mem::replace(&mut self.buf, Vec::new()) /// } /// } /// ``` @@ -180,10 +265,10 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// This function can be used to destroy any value by allowing `drop` to take -/// ownership of its argument. +/// This function can be used to destroy any value by allowing `drop` to take ownership of its +/// argument. /// -/// # Example +/// # Examples /// /// ``` /// use std::cell::RefCell; @@ -192,6 +277,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { /// /// let mut mutable_borrow = x.borrow_mut(); /// *mutable_borrow = 1; +/// /// drop(mutable_borrow); // relinquish the mutable borrow on this slot /// /// let borrow = x.borrow(); @@ -201,18 +287,25 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { #[stable] pub fn drop<T>(_x: T) { } -/// Interprets `src` as `&U`, and then reads `src` without moving the contained -/// value. +/// Interprets `src` as `&U`, and then reads `src` without moving the contained value. /// -/// This function will unsafely assume the pointer `src` is valid for -/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It -/// will also unsafely create a copy of the contained value instead of moving -/// out of `src`. +/// This function will unsafely assume the pointer `src` is valid for `sizeof(U)` bytes by +/// transmuting `&T` to `&U` and then reading the `&U`. It will also unsafely create a copy of the +/// contained value instead of moving out of `src`. /// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers undefined behavior if `U` is larger than -/// `T`. +/// It is not a compile-time error if `T` and `U` have different sizes, but it is highly encouraged +/// to only invoke this function where `T` and `U` have the same size. This function triggers +/// undefined behavior if `U` is larger than `T`. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let one = unsafe { mem::transmute_copy(&1i) }; +/// +/// assert_eq!(1u, one); +/// ``` #[inline] #[stable] pub unsafe fn transmute_copy<T, U>(src: &T) -> U { From 59d41534573fceea2df0b5f5b16ce4ffbe345d18 Mon Sep 17 00:00:00 2001 From: Piotr Czarnecki <pioczarn@gmail.com> Date: Wed, 17 Dec 2014 00:37:55 +0100 Subject: [PATCH 55/59] Implement remove for RingBuf --- src/libcollections/ring_buf.rs | 300 +++++++++++++++++++++++++++------ 1 file changed, 250 insertions(+), 50 deletions(-) diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 084b585d7b9..7413978f087 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -102,17 +102,15 @@ impl<T> RingBuf<T> { /// Copies a contiguous block of memory len long from src to dst #[inline] - fn copy(&self, dst: uint, src: uint, len: uint) { - unsafe { - debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); - debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); - ptr::copy_memory( - self.ptr.offset(dst as int), - self.ptr.offset(src as int) as *const T, - len); - } + unsafe fn copy(&self, dst: uint, src: uint, len: uint) { + debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, + self.cap); + debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, + self.cap); + ptr::copy_memory( + self.ptr.offset(dst as int), + self.ptr.offset(src as int) as *const T, + len); } } @@ -732,7 +730,7 @@ impl<T> RingBuf<T> { self.tail = self.wrap_index(self.tail - 1); }, - (true, true, _) => { + (true, true, _) => unsafe { // contiguous, insert closer to tail: // // T I H @@ -752,13 +750,15 @@ impl<T> RingBuf<T> { // [o I A o o o o o . . . . . . . o] // M M - let old_tail = self.tail; - self.tail = self.wrap_index(self.tail - 1); + let new_tail = self.wrap_index(self.tail - 1); - self.copy(self.tail, old_tail, 1); - self.copy(old_tail, old_tail + 1, i); + self.copy(new_tail, self.tail, 1); + // Already moved the tail, so we only copy `i - 1` elements. + self.copy(self.tail, self.tail + 1, i - 1); + + self.tail = new_tail; }, - (true, false, _) => { + (true, false, _) => unsafe { // contiguous, insert closer to head: // // T I H @@ -768,12 +768,11 @@ impl<T> RingBuf<T> { // [. . . o o o o I A o o . . . . .] // M M M - let old_head = self.head; + self.copy(idx + 1, idx, self.head - idx); self.head = self.wrap_index(self.head + 1); - self.copy(idx + 1, idx, old_head - idx); }, - (false, true, true) => { - // discontiguous, tail section, insert closer to tail: + (false, true, true) => unsafe { + // discontiguous, insert closer to tail, tail section: // // H T I // [o o o o o o . . . . . o o A o o] @@ -782,12 +781,11 @@ impl<T> RingBuf<T> { // [o o o o o o . . . . o o I A o o] // M M - let old_tail = self.tail; - self.tail = self.tail - 1; - self.copy(self.tail, old_tail, i); + self.copy(self.tail - 1, self.tail, i); + self.tail -= 1; }, - (false, false, true) => { - // discontiguous, tail section, insert closer to head: + (false, false, true) => unsafe { + // discontiguous, insert closer to head, tail section: // // H T I // [o o . . . . . . . o o o o o A o] @@ -796,20 +794,19 @@ impl<T> RingBuf<T> { // [o o o . . . . . . o o o o o I A] // M M M M - let old_head = self.head; - self.head = self.head + 1; - // copy elements up to new head - self.copy(1, 0, old_head); + self.copy(1, 0, self.head); // copy last element into empty spot at bottom of buffer self.copy(0, self.cap - 1, 1); // move elements from idx to end forward not including ^ element self.copy(idx + 1, idx, self.cap - 1 - idx); + + self.head += 1; }, - (false, true, false) if idx == 0 => { - // discontiguous, head section, insert is closer to tail, + (false, true, false) if idx == 0 => unsafe { + // discontiguous, insert is closer to tail, head section, // and is at index zero in the internal buffer: // // I H T @@ -819,16 +816,16 @@ impl<T> RingBuf<T> { // [A o o o o o o o o o . . o o o I] // M M M - let old_tail = self.tail; - self.tail = self.tail - 1; // copy elements up to new tail - self.copy(old_tail - 1, old_tail, i); + self.copy(self.tail - 1, self.tail, self.cap - self.tail); // copy last element into empty spot at bottom of buffer self.copy(self.cap - 1, 0, 1); + + self.tail -= 1; }, - (false, true, false) => { - // discontiguous, head section, insert closer to tail: + (false, true, false) => unsafe { + // discontiguous, insert closer to tail, head section: // // I H T // [o o o A o o o o o o . . . o o o] @@ -837,19 +834,19 @@ impl<T> RingBuf<T> { // [o o I A o o o o o o . . o o o o] // M M M M M M - let old_tail = self.tail; - self.tail = self.tail - 1; // copy elements up to new tail - self.copy(old_tail - 1, old_tail, i); + self.copy(self.tail - 1, self.tail, self.cap - self.tail); // copy last element into empty spot at bottom of buffer self.copy(self.cap - 1, 0, 1); // move elements from idx-1 to end forward not including ^ element self.copy(0, 1, idx - 1); - } - (false, false, false) => { - // discontiguous, head section, insert closer to head: + + self.tail -= 1; + }, + (false, false, false) => unsafe { + // discontiguous, insert closer to head, head section: // // I H T // [o o o o A o o . . . . . . o o o] @@ -858,9 +855,8 @@ impl<T> RingBuf<T> { // [o o o o I A o o . . . . . o o o] // M M M - let old_head = self.head; - self.head = self.head + 1; - self.copy(idx + 1, idx, old_head - idx); + self.copy(idx + 1, idx, self.head - idx); + self.head += 1; } } @@ -870,6 +866,170 @@ impl<T> RingBuf<T> { self.buffer_write(new_idx, t); } } + + /// Removes and returns the element at position `i` from the ringbuf. + /// Whichever end is closer to the removal point will be moved to make + /// room, and all the affected elements will be moved to new positions. + /// Returns `None` if `i` is out of bounds. + /// + /// # Example + /// ```rust + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// buf.push_back(5i); + /// buf.push_back(10i); + /// buf.push_back(12i); + /// buf.push_back(15); + /// buf.remove(2); + /// assert_eq!(Some(&15), buf.get(2)); + /// ``` + #[unstable = "matches collection reform specification; waiting on panic semantics"] + pub fn remove(&mut self, i: uint) -> Option<T> { + if self.is_empty() || self.len() <= i { + return None; + } + + // There are three main cases: + // Elements are contiguous + // Elements are discontiguous and the removal is in the tail section + // Elements are discontiguous and the removal is in the head section + // - special case when elements are technically contiguous, + // but self.head = 0 + // + // For each of those there are two more cases: + // Insert is closer to tail + // Insert is closer to head + // + // Key: H - self.head + // T - self.tail + // o - Valid element + // x - Element marked for removal + // R - Indicates element that is being removed + // M - Indicates element was moved + + let idx = self.wrap_index(self.tail + i); + + let elem = unsafe { + Some(self.buffer_read(idx)) + }; + + let distance_to_tail = i; + let distance_to_head = self.len() - i; + + let contiguous = self.tail <= self.head; + + match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { + (true, true, _) => unsafe { + // contiguous, remove closer to tail: + // + // T R H + // [. . . o o x o o o o . . . . . .] + // + // T H + // [. . . . o o o o o o . . . . . .] + // M M + + self.copy(self.tail + 1, self.tail, i); + self.tail += 1; + }, + (true, false, _) => unsafe { + // contiguous, remove closer to head: + // + // T R H + // [. . . o o o o x o o . . . . . .] + // + // T H + // [. . . o o o o o o . . . . . . .] + // M M + + self.copy(idx, idx + 1, self.head - idx - 1); + self.head -= 1; + }, + (false, true, true) => unsafe { + // discontiguous, remove closer to tail, tail section: + // + // H T R + // [o o o o o o . . . . . o o x o o] + // + // H T + // [o o o o o o . . . . . . o o o o] + // M M + + self.copy(self.tail + 1, self.tail, i); + self.tail = self.wrap_index(self.tail + 1); + }, + (false, false, false) => unsafe { + // discontiguous, remove closer to head, head section: + // + // R H T + // [o o o o x o o . . . . . . o o o] + // + // H T + // [o o o o o o . . . . . . . o o o] + // M M + + self.copy(idx, idx + 1, self.head - idx - 1); + self.head -= 1; + }, + (false, false, true) => unsafe { + // discontiguous, remove closer to head, tail section: + // + // H T R + // [o o o . . . . . . o o o o o x o] + // + // H T + // [o o . . . . . . . o o o o o o o] + // M M M M + // + // or quasi-discontiguous, remove next to head, tail section: + // + // H T R + // [. . . . . . . . . o o o o o x o] + // + // T H + // [. . . . . . . . . o o o o o o .] + // M + + // draw in elements in the tail section + self.copy(idx, idx + 1, self.cap - idx - 1); + + // Prevents underflow. + if self.head != 0 { + // copy first element into empty spot + self.copy(self.cap - 1, 0, 1); + + // move elements in the head section backwards + self.copy(0, 1, self.head - 1); + } + + self.head = self.wrap_index(self.head - 1); + }, + (false, true, false) => unsafe { + // discontiguous, remove closer to tail, head section: + // + // R H T + // [o o x o o o o o o o . . . o o o] + // + // H T + // [o o o o o o o o o o . . . . o o] + // M M M M M + + // draw in elements up to idx + self.copy(1, 0, idx); + + // copy last element into empty spot + self.copy(0, self.cap - 1, 1); + + // move elements from tail to end forward, excluding the last one + self.copy(self.tail + 1, self.tail, self.cap - self.tail - 1); + + self.tail = self.wrap_index(self.tail + 1); + } + } + + return elem; + } } /// Returns the index in the underlying buffer for a given logical element index. @@ -1103,6 +1263,7 @@ mod tests { use core::iter; use self::Taggy::*; use self::Taggypar::*; + use std::cmp; use std::fmt::Show; use std::prelude::*; use std::hash; @@ -1892,11 +2053,11 @@ mod tests { #[test] fn test_insert() { // This test checks that every single combination of tail position, length, and - // insertion position is tested. Capacity 7 should be large enough to cover every case. + // insertion position is tested. Capacity 15 should be large enough to cover every case. - let mut tester = RingBuf::with_capacity(7); - // can't guarantee we got 7, so have to get what we got. - // 7 would be great, but we will definitely get 2^k - 1, for k >= 3, or else + let mut tester = RingBuf::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else // this test isn't covering what it wants to let cap = tester.capacity(); @@ -1915,6 +2076,45 @@ mod tests { } } tester.insert(to_insert, to_insert); + assert!(tester.tail < tester.cap); + assert!(tester.head < tester.cap); + assert_eq!(tester, expected); + } + } + } + } + + #[test] + fn test_remove() { + // This test checks that every single combination of tail position, length, and + // removal position is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = RingBuf::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + + // len is the length *after* removal + for len in range(0, cap - 1) { + // 0, 1, 2, .., len - 1 + let expected = iter::count(0, 1).take(len).collect(); + for tail_pos in range(0, cap) { + for to_remove in range(0, len + 1) { + tester.tail = tail_pos; + tester.head = tail_pos; + for i in range(0, len) { + if i == to_remove { + tester.push_back(1234); + } + tester.push_back(i); + } + if to_remove == len { + tester.push_back(1234); + } + tester.remove(to_remove); + assert!(tester.tail < tester.cap); + assert!(tester.head < tester.cap); assert_eq!(tester, expected); } } From 18c420ed6250f605d3a67739d5513ffe4f2914d6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik <steve@steveklabnik.com> Date: Tue, 16 Dec 2014 20:12:30 -0500 Subject: [PATCH 56/59] Improve docs for std::vec --- src/libcollections/vec.rs | 179 ++++++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 74 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 932366d77ad..866147b1409 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -11,6 +11,38 @@ //! A growable list type, written `Vec<T>` but pronounced 'vector.' //! //! Vectors have `O(1)` indexing, push (to the end) and pop (from the end). +//! +//! # Examples +//! +//! Explicitly creating a `Vec<T>` with `new()`: +//! +//! ``` +//! let xs: Vec<i32> = Vec::new(); +//! ``` +//! +//! Using the `vec!` macro: +//! +//! ``` +//! let ys: Vec<i32> = vec![]; +//! +//! let zs = vec![1i32, 2, 3, 4, 5]; +//! ``` +//! +//! Push: +//! +//! ``` +//! let mut xs = vec![1i32, 2]; +//! +//! xs.push(3); +//! ``` +//! +//! And pop: +//! +//! ``` +//! let mut xs = vec![1i32, 2]; +//! +//! let two = xs.pop(); +//! ``` use core::prelude::*; @@ -31,7 +63,7 @@ use core::uint; use slice::CloneSliceExt; -/// An owned, growable vector. +/// A growable list type, written `Vec<T>` but pronounced 'vector.' /// /// # Examples /// @@ -65,7 +97,7 @@ use slice::CloneSliceExt; /// assert_eq!(vec, vec![1, 2, 3, 4]); /// ``` /// -/// Use a `Vec` as an efficient stack: +/// Use a `Vec<T>` as an efficient stack: /// /// ``` /// let mut stack = Vec::new(); @@ -86,20 +118,17 @@ use slice::CloneSliceExt; /// /// # Capacity and reallocation /// -/// The capacity of a vector is the amount of space allocated for any future -/// elements that will be added onto the vector. This is not to be confused -/// with the *length* of a vector, which specifies the number of actual -/// elements within the vector. If a vector's length exceeds its capacity, -/// its capacity will automatically be increased, but its elements will -/// have to be reallocated. +/// The capacity of a vector is the amount of space allocated for any future elements that will be +/// added onto the vector. This is not to be confused with the *length* of a vector, which +/// specifies the number of actual elements within the vector. If a vector's length exceeds its +/// capacity, its capacity will automatically be increased, but its elements will have to be +/// reallocated. /// -/// For example, a vector with capacity 10 and length 0 would be an empty -/// vector with space for 10 more elements. Pushing 10 or fewer elements onto -/// the vector will not change its capacity or cause reallocation to occur. -/// However, if the vector's length is increased to 11, it will have to -/// reallocate, which can be slow. For this reason, it is recommended -/// to use `Vec::with_capacity` whenever possible to specify how big the vector -/// is expected to get. +/// For example, a vector with capacity 10 and length 0 would be an empty vector with space for 10 +/// more elements. Pushing 10 or fewer elements onto the vector will not change its capacity or +/// cause reallocation to occur. However, if the vector's length is increased to 11, it will have +/// to reallocate, which can be slow. For this reason, it is recommended to use +/// `Vec::with_capacity` whenever possible to specify how big the vector is expected to get. #[unsafe_no_drop_flag] #[stable] pub struct Vec<T> { @@ -130,7 +159,7 @@ impl<'a, T> IntoCow<'a, Vec<T>, [T]> for &'a [T] where T: Clone { } impl<T> Vec<T> { - /// Constructs a new, empty `Vec`. + /// Constructs a new, empty `Vec<T>`. /// /// The vector will not allocate until elements are pushed onto it. /// @@ -149,16 +178,15 @@ impl<T> Vec<T> { Vec { ptr: EMPTY as *mut T, len: 0, cap: 0 } } - /// Constructs a new, empty `Vec` with the specified capacity. + /// Constructs a new, empty `Vec<T>` with the specified capacity. /// - /// The vector will be able to hold exactly `capacity` elements without - /// reallocating. If `capacity` is 0, the vector will not allocate. + /// The vector will be able to hold exactly `capacity` elements without reallocating. If + /// `capacity` is 0, the vector will not allocate. /// - /// It is important to note that this function does not specify the - /// *length* of the returned vector, but only the *capacity*. (For an - /// explanation of the difference between length and capacity, see - /// the main `Vec` docs above, 'Capacity and reallocation'.) To create - /// a vector of a given length, use `Vec::from_elem` or `Vec::from_fn`. + /// It is important to note that this function does not specify the *length* of the returned + /// vector, but only the *capacity*. (For an explanation of the difference between length and + /// capacity, see the main `Vec<T>` docs above, 'Capacity and reallocation'.) To create a + /// vector of a given length, use `Vec::from_elem` or `Vec::from_fn`. /// /// # Examples /// @@ -192,10 +220,10 @@ impl<T> Vec<T> { } } - /// Creates and initializes a `Vec`. + /// Creates and initializes a `Vec<T>`. /// - /// Creates a `Vec` of size `length` and initializes the elements to the - /// value returned by the closure `op`. + /// Creates a `Vec<T>` of size `length` and initializes the elements to the value returned by + /// the closure `op`. /// /// # Examples /// @@ -260,10 +288,9 @@ impl<T> Vec<T> { /// Creates a vector by copying the elements from a raw pointer. /// - /// This function will copy `elts` contiguous elements starting at `ptr` - /// into a new allocation owned by the returned `Vec`. The elements of the - /// buffer are copied into the vector without cloning, as if `ptr::read()` - /// were called on them. + /// This function will copy `elts` contiguous elements starting at `ptr` into a new allocation + /// owned by the returned `Vec<T>`. The elements of the buffer are copied into the vector + /// without cloning, as if `ptr::read()` were called on them. #[inline] #[unstable = "just renamed from raw::from_buf"] pub unsafe fn from_raw_buf(ptr: *const T, elts: uint) -> Vec<T> { @@ -273,11 +300,10 @@ impl<T> Vec<T> { dst } - /// Consumes the `Vec`, partitioning it based on a predicate. + /// Consumes the `Vec<T>`, partitioning it based on a predicate. /// - /// Partitions the `Vec` into two `Vec`s `(A,B)`, where all elements of `A` - /// satisfy `f` and all elements of `B` do not. The order of elements is - /// preserved. + /// Partitions the `Vec<T>` into two `Vec<T>`s `(A,B)`, where all elements of `A` satisfy `f` + /// and all elements of `B` do not. The order of elements is preserved. /// /// # Examples /// @@ -306,9 +332,9 @@ impl<T> Vec<T> { } impl<T: Clone> Vec<T> { - /// Constructs a `Vec` with copies of a value. + /// Constructs a `Vec<T>` with copies of a value. /// - /// Creates a `Vec` with `length` copies of `value`. + /// Creates a `Vec<T>` with `length` copies of `value`. /// /// # Examples /// @@ -331,10 +357,10 @@ impl<T: Clone> Vec<T> { } } - /// Appends all elements in a slice to the `Vec`. + /// Appends all elements in a slice to the `Vec<T>`. /// /// Iterates over the slice `other`, clones each element, and then appends - /// it to this `Vec`. The `other` vector is traversed in-order. + /// it to this `Vec<T>`. The `other` vector is traversed in-order. /// /// # Examples /// @@ -363,9 +389,9 @@ impl<T: Clone> Vec<T> { } } - /// Grows the `Vec` in-place. + /// Grows the `Vec<T>` in-place. /// - /// Adds `n` copies of `value` to the `Vec`. + /// Adds `n` copies of `value` to the `Vec<T>`. /// /// # Examples /// @@ -387,7 +413,7 @@ impl<T: Clone> Vec<T> { /// Partitions a vector based on a predicate. /// - /// Clones the elements of the vector, partitioning them into two `Vec`s + /// Clones the elements of the vector, partitioning them into two `Vec<T>`s /// `(a, b)`, where all elements of `a` satisfy `f` and all elements of `b` /// do not. The order of elements is preserved. /// @@ -639,8 +665,7 @@ unsafe fn dealloc<T>(ptr: *mut T, len: uint) { } impl<T> Vec<T> { - /// Returns the number of elements the vector can hold without - /// reallocating. + /// Returns the number of elements the vector can hold without reallocating. /// /// # Examples /// @@ -661,7 +686,7 @@ impl<T> Vec<T> { } /// Reserves capacity for at least `additional` more elements to be inserted in the given - /// `Vec`. The collection may reserve more space to avoid frequent reallocations. + /// `Vec<T>`. The collection may reserve more space to avoid frequent reallocations. /// /// # Panics /// @@ -695,7 +720,7 @@ impl<T> Vec<T> { } /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the - /// given `Vec`. Does nothing if the capacity is already sufficient. + /// given `Vec<T>`. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it requests. Therefore /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future @@ -722,16 +747,19 @@ impl<T> Vec<T> { } } - /// Shrinks the capacity of the vector as much as possible. It will drop - /// down as close as possible to the length but the allocator may still - /// inform the vector that there is space for a few more elements. + /// Shrinks the capacity of the vector as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator may still inform the + /// vector that there is space for a few more elements. /// /// # Examples /// /// ``` /// let mut vec: Vec<int> = Vec::with_capacity(10); + /// /// vec.push_all(&[1, 2, 3]); /// assert_eq!(vec.capacity(), 10); + /// /// vec.shrink_to_fit(); /// assert!(vec.capacity() >= 3); /// ``` @@ -820,14 +848,14 @@ impl<T> Vec<T> { } } - /// Creates a consuming iterator, that is, one that moves each - /// value out of the vector (from start to end). The vector cannot - /// be used after calling this. + /// Creates a consuming iterator, that is, one that moves each value out of the vector (from + /// start to end). The vector cannot be used after calling this. /// /// # Examples /// /// ``` /// let v = vec!["a".to_string(), "b".to_string()]; + /// /// for s in v.into_iter() { /// // s has type String, not &String /// println!("{}", s); @@ -852,9 +880,8 @@ impl<T> Vec<T> { /// Sets the length of a vector. /// - /// This will explicitly set the size of the vector, without actually - /// modifying its buffers, so it is up to the caller to ensure that the - /// vector is actually the specified size. + /// This will explicitly set the size of the vector, without actually modifying its buffers, so + /// it is up to the caller to ensure that the vector is actually the specified size. /// /// # Examples /// @@ -870,8 +897,10 @@ impl<T> Vec<T> { self.len = len; } - /// Removes an element from anywhere in the vector and return it, replacing - /// it with the last element. This does not preserve ordering, but is O(1). + /// Removes an element from anywhere in the vector and return it, replacing it with the last + /// element. + /// + /// This does not preserve ordering, but is O(1). /// /// Returns `None` if `index` is out of bounds. /// @@ -900,13 +929,12 @@ impl<T> Vec<T> { self.pop() } - /// Inserts an element at position `index` within the vector, shifting all - /// elements after position `i` one position to the right. + /// Inserts an element at position `index` within the vector, shifting all elements after + /// position `i` one position to the right. /// /// # Panics /// - /// Panics if `index` is not between `0` and the vector's length (both - /// bounds inclusive). + /// Panics if `index` is not between `0` and the vector's length (both bounds inclusive). /// /// # Examples /// @@ -939,9 +967,9 @@ impl<T> Vec<T> { } } - /// Removes and returns the element at position `index` within the vector, - /// shifting all elements after position `index` one position to the left. - /// Returns `None` if `i` is out of bounds. + /// Removes and returns the element at position `index` within the vector, shifting all + /// elements after position `index` one position to the left. Returns `None` if `i` is out of + /// bounds. /// /// # Examples /// @@ -980,8 +1008,8 @@ impl<T> Vec<T> { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` such that `f(&e)` returns false. - /// This method operates in place and preserves the order of the retained elements. + /// In other words, remove all elements `e` such that `f(&e)` returns false. This method + /// operates in place and preserves the order of the retained elements. /// /// # Examples /// @@ -1070,8 +1098,7 @@ impl<T> Vec<T> { } } - /// Removes the last element from a vector and returns it, or `None` if - /// it is empty. + /// Removes the last element from a vector and returns it, or `None` if it is empty. /// /// # Examples /// @@ -1099,7 +1126,9 @@ impl<T> Vec<T> { /// /// ``` /// let mut v = vec![1i, 2, 3]; + /// /// v.clear(); + /// /// assert!(v.is_empty()); /// ``` #[inline] @@ -1108,7 +1137,7 @@ impl<T> Vec<T> { self.truncate(0) } - /// Return the number of elements in the vector + /// Returns the number of elements in the vector. /// /// # Examples /// @@ -1120,13 +1149,14 @@ impl<T> Vec<T> { #[stable] pub fn len(&self) -> uint { self.len } - /// Returns true if the vector contains no elements + /// Returns `true` if the vector contains no elements. /// /// # Examples /// /// ``` /// let mut v = Vec::new(); /// assert!(v.is_empty()); + /// /// v.push(1i); /// assert!(!v.is_empty()); /// ``` @@ -1161,7 +1191,9 @@ impl<T: PartialEq> Vec<T> { /// /// ``` /// let mut vec = vec![1i, 2, 2, 3, 2]; + /// /// vec.dedup(); + /// /// assert_eq!(vec, vec![1i, 2, 3, 2]); /// ``` #[unstable = "this function may be renamed"] @@ -1433,10 +1465,9 @@ impl<T> Drop for MoveItems<T> { /// Converts an iterator of pairs into a pair of vectors. /// -/// Returns a tuple containing two vectors where the i-th element of the first -/// vector contains the first element of the i-th tuple of the input iterator, -/// and the i-th element of the second vector contains the second element -/// of the i-th tuple of the input iterator. +/// Returns a tuple containing two vectors where the i-th element of the first vector contains the +/// first element of the i-th tuple of the input iterator, and the i-th element of the second +/// vector contains the second element of the i-th tuple of the input iterator. #[unstable = "this functionality may become more generic over time"] pub fn unzip<T, U, V: Iterator<(T, U)>>(mut iter: V) -> (Vec<T>, Vec<U>) { let (lo, _) = iter.size_hint(); From 2ba2843b49ad237d669e0e2e4993b12b1be8a240 Mon Sep 17 00:00:00 2001 From: Kevin Yap <me@kevinyap.ca> Date: Sun, 14 Dec 2014 18:10:34 -0800 Subject: [PATCH 57/59] Minor changes to Rust Language FAQ - Change long inline code to code block - Replace double-hyphens with en dash - Miscellaneous rephrasings for clarity --- src/doc/complement-lang-faq.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 62faecede55..9e73863239f 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -24,7 +24,7 @@ Some examples that demonstrate different aspects of the language: [HashMap]: https://github.com/rust-lang/rust/blob/master/src/libcollections/hashmap.rs [json]: https://github.com/rust-lang/rust/blob/master/src/libserialize/json.rs -You may also be interested in browsing [GitHub's Rust][github-rust] page. +You may also be interested in browsing [trending Rust repositories][github-rust] on GitHub. [github-rust]: https://github.com/trending?l=rust @@ -42,7 +42,7 @@ Let the fact that this is an easily countable number be a warning. ## Does it run on Windows? -Yes. All development happens in lock-step on all 3 target platforms. Using MinGW, not Cygwin. Note that the windows implementation currently has some limitations: in particular 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc]. +Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin). Note that the Windows implementation currently has some limitations; in particular, the 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc]. [win64]: https://github.com/rust-lang/rust/issues/1237 [libgcc]: https://github.com/rust-lang/rust/issues/11782 @@ -104,7 +104,7 @@ Similar to the reasoning about default-sync: it wires fewer assumptions into the ## Why are strings UTF-8 by default? Why not UCS2 or UCS4? -The `str` type is UTF-8 because we observe more text in the wild in this encoding -- particularly in network transmissions, which are endian-agnostic -- and we think it's best that the default treatment of I/O not involve having to recode codepoints in each direction. +The `str` type is UTF-8 because we observe more text in the wild in this encoding – particularly in network transmissions, which are endian-agnostic – and we think it's best that the default treatment of I/O not involve having to recode codepoints in each direction. This does mean that indexed access to a Unicode codepoint inside a `str` value is an O(n) operation. On the one hand, this is clearly undesirable; on the other hand, this problem is full of trade-offs and we'd like to point a few important qualifications: @@ -145,7 +145,7 @@ For simplicity, we do not plan to do so. Implementing automatic semicolon insert ## How do I get my program to display the output of logging macros? -**Short answer** set the RUST_LOG environment variable to the name of your source file, sans extension. +**Short Answer**: Set the `RUST_LOG` environment variable to the name of your source file, sans extension. ```sh rustc hello.rs @@ -153,15 +153,19 @@ export RUST_LOG=hello ./hello ``` -**Long answer** RUST_LOG takes a 'logging spec' that consists of a +**Long Answer**: `RUST_LOG` takes a 'logging spec' that consists of a comma-separated list of paths, where a path consists of the crate name and -sequence of module names, each separated by double-colons. For standalone .rs -files the crate is implicitly named after the source file, so in the above -example we were setting RUST_LOG to the name of the hello crate. Multiple paths +sequence of module names, each separated by double-colons. For standalone `.rs` +files, the crate is implicitly named after the source file, so in the above +example we were setting `RUST_LOG` to the name of the hello crate. Multiple paths can be combined to control the exact logging you want to see. For example, when -debugging linking in the compiler you might set -`RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath` -For a full description see [the logging crate][1]. +debugging linking in the compiler, you might set the following: + +```sh +RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath +``` + +For a full description, see [the logging crate][1]. ## How fast is Rust? @@ -172,6 +176,6 @@ performance. That said, it is an explicit goal of Rust to be as fast as C++ for most things. Language decisions are made with performance in mind, and we want Rust to be as fast as possible. Given that Rust is built on top of LLVM, any performance -improvements in it also help us be faster. +improvements in it also help Rust become faster. [1]:log/index.html From 9caa66f9c8facbe462ce10505c47a98fc2b6f5a0 Mon Sep 17 00:00:00 2001 From: Chase Southwood <chase.southwood@gmail.com> Date: Tue, 16 Dec 2014 22:12:40 -0600 Subject: [PATCH 58/59] Implement BorrowFrom<Arc<T>> for T --- src/liballoc/arc.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 1f1909fd33c..e419d4b0041 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -14,6 +14,7 @@ //! between tasks. use core::atomic; +use core::borrow::BorrowFrom; use core::clone::Clone; use core::fmt::{mod, Show}; use core::cmp::{Eq, Ord, PartialEq, PartialOrd, Ordering}; @@ -155,6 +156,12 @@ impl<T> Clone for Arc<T> { } } +impl<T> BorrowFrom<Arc<T>> for T { + fn borrow_from(owned: &Arc<T>) -> &T { + &**owned + } +} + #[experimental = "Deref is experimental."] impl<T> Deref<T> for Arc<T> { #[inline] From 5c98952409c9123b5f26b3c620029cd1914a07b6 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Wed, 17 Dec 2014 11:26:52 -0800 Subject: [PATCH 59/59] Test fixes and rebase conflicts --- src/librustc_driver/test.rs | 2 +- src/libsyntax/ext/deriving/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 6a50af3bc79..508af4c28e6 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -139,7 +139,7 @@ fn test_env<F>(source_string: &str, stability_index); let infcx = infer::new_infer_ctxt(&tcx); body(Env { infcx: &infcx }); - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID); assert_eq!(tcx.sess.err_count(), expected_err_count); } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 5fb320b9136..839e99c81d1 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -84,7 +84,7 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt, expand!(encodable::expand_deriving_encodable) } - "Decodable" => + "Decodable" => { // NOTE: uncomment after a stage0 snap // cx.span_warn(titem.span, // "deriving(Decodable) is deprecated \