]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #41912 - oli-obk:patch-3, r=eddyb
authorMark Simulacrum <mark.simulacrum@gmail.com>
Sat, 13 May 2017 00:57:30 +0000 (18:57 -0600)
committerGitHub <noreply@github.com>
Sat, 13 May 2017 00:57:30 +0000 (18:57 -0600)
Upgrade some comments to doc comments

69 files changed:
src/bootstrap/config.rs
src/ci/docker/android-ndk.sh [new file with mode: 0644]
src/ci/docker/disabled/dist-aarch64-android/Dockerfile [new file with mode: 0644]
src/ci/docker/disabled/dist-armv7-android/Dockerfile [new file with mode: 0644]
src/ci/docker/disabled/dist-i686-android/Dockerfile [new file with mode: 0644]
src/ci/docker/disabled/dist-x86_64-android/Dockerfile [new file with mode: 0644]
src/ci/docker/run.sh
src/librustc/infer/combine.rs
src/librustc/infer/equate.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc/ty/mod.rs
src/librustc/ty/relate.rs
src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
src/librustc_driver/lib.rs
src/librustc_driver/target_features.rs
src/librustc_errors/diagnostic.rs
src/librustc_errors/diagnostic_builder.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_mir/build/cfg.rs
src/librustc_mir/build/expr/as_operand.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/expr/stmt.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/copy_prop.rs
src/librustc_mir/transform/deaggregator.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/simplify_branches.rs
src/librustc_mir/transform/type_check.rs
src/librustc_passes/mir_stats.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_typeck/variance/constraints.rs
src/librustc_typeck/variance/xform.rs
src/libstd/ffi/c_str.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/os.rs
src/libstd/thread/mod.rs
src/libsyntax/json.rs
src/test/compile-fail/crt-static-gated.rs [deleted file]
src/test/compile-fail/issue-35675.rs
src/test/compile-fail/region-invariant-static-error-reporting.rs
src/test/compile-fail/regions-trait-object-subtyping.rs
src/test/compile-fail/variance-contravariant-arg-object.rs
src/test/compile-fail/variance-covariant-arg-object.rs
src/test/compile-fail/variance-invariant-arg-object.rs
src/test/run-pass/issue-41677.rs [new file with mode: 0644]
src/test/run-pass/issue-41849-variance-req.rs [new file with mode: 0644]
src/test/ui/resolve/enums-are-namespaced-xc.stderr
src/test/ui/resolve/issue-16058.stderr
src/test/ui/resolve/issue-17518.stderr
src/test/ui/resolve/issue-21221-1.stderr
src/test/ui/resolve/issue-21221-2.stderr
src/test/ui/resolve/issue-21221-3.stderr
src/test/ui/resolve/issue-21221-4.stderr
src/test/ui/resolve/issue-3907.stderr
src/test/ui/resolve/privacy-struct-ctor.stderr
src/test/ui/span/issue-35987.stderr

index 34fbc33d981afddfdc8af7662b85e2ed82a885d4..9c536111811aab1d41a261c3130e4dc862ddad9c 100644 (file)
@@ -264,7 +264,7 @@ pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
             let table = match p.parse() {
                 Some(table) => table,
                 None => {
-                    println!("failed to parse TOML configuration:");
+                    println!("failed to parse TOML configuration '{}':", file.to_str().unwrap());
                     for err in p.errors.iter() {
                         let (loline, locol) = p.to_linecol(err.lo);
                         let (hiline, hicol) = p.to_linecol(err.hi);
diff --git a/src/ci/docker/android-ndk.sh b/src/ci/docker/android-ndk.sh
new file mode 100644 (file)
index 0000000..4849f84
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Copyright 2017 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.
+
+set -ex
+
+URL=https://dl.google.com/android/repository
+
+download_ndk() {
+    mkdir -p /android/ndk
+    cd /android/ndk
+    curl -O $URL/$1
+    unzip -q $1
+    rm $1
+    mv android-ndk-* ndk
+}
+
+make_standalone_toolchain() {
+    # See https://developer.android.com/ndk/guides/standalone_toolchain.htm
+    python2.7 /android/ndk/ndk/build/tools/make_standalone_toolchain.py \
+        --install-dir /android/ndk/$1-$2 \
+        --arch $1 \
+        --api $2
+}
+
+remove_ndk() {
+    rm -rf /android/ndk/ndk
+}
diff --git a/src/ci/docker/disabled/dist-aarch64-android/Dockerfile b/src/ci/docker/disabled/dist-aarch64-android/Dockerfile
new file mode 100644 (file)
index 0000000..34e112a
--- /dev/null
@@ -0,0 +1,49 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  sudo \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+    download_ndk android-ndk-r13b-linux-x86_64.zip && \
+    make_standalone_toolchain arm64 21 && \
+    remove_ndk
+
+ENV PATH=$PATH:/android/ndk/arm64-21/bin
+
+ENV DEP_Z_ROOT=/android/ndk/arm64-21/sysroot/usr/
+
+ENV HOSTS=aarch64-linux-android
+
+ENV RUST_CONFIGURE_ARGS \
+      --host=$HOSTS \
+      --target=$HOSTS \
+      --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
+      --disable-rpath \
+      --enable-extended \
+      --enable-cargo-openssl-static
+
+ENV SCRIPT python2.7 ../x.py dist --target $HOSTS --host $HOSTS
diff --git a/src/ci/docker/disabled/dist-armv7-android/Dockerfile b/src/ci/docker/disabled/dist-armv7-android/Dockerfile
new file mode 100644 (file)
index 0000000..3446896
--- /dev/null
@@ -0,0 +1,65 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  sudo \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+    download_ndk android-ndk-r13b-linux-x86_64.zip && \
+    make_standalone_toolchain arm 9 && \
+    make_standalone_toolchain arm 21 && \
+    remove_ndk
+
+ENV PATH=$PATH:/android/ndk/arm-9/bin
+
+ENV DEP_Z_ROOT=/android/ndk/arm-9/sysroot/usr/
+
+ENV HOSTS=armv7-linux-androideabi
+
+ENV RUST_CONFIGURE_ARGS \
+      --host=$HOSTS \
+      --target=$HOSTS \
+      --armv7-linux-androideabi-ndk=/android/ndk/arm \
+      --disable-rpath \
+      --enable-extended \
+      --enable-cargo-openssl-static
+
+# We support api level 9, but api level 21 is required to build llvm. To
+# overcome this problem we use a ndk with api level 21 to build llvm and then
+# switch to a ndk with api level 9 to complete the build. When the linker is
+# invoked there are missing symbols (like sigsetempty, not available with api
+# level 9), the default linker behavior is to generate an error, to allow the
+# build to finish we use --warn-unresolved-symbols. Note that the missing
+# symbols does not affect std, only the compiler (llvm) and cargo (openssl).
+RUN chmod 777 /android/ndk && \
+    ln -s /android/ndk/arm-21 /android/ndk/arm
+
+ENV SCRIPT \
+  python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \
+  (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \
+    rm /android/ndk/arm && \
+    ln -s /android/ndk/arm-9 /android/ndk/arm && \
+    python2.7 ../x.py dist --host $HOSTS --target $HOSTS)
diff --git a/src/ci/docker/disabled/dist-i686-android/Dockerfile b/src/ci/docker/disabled/dist-i686-android/Dockerfile
new file mode 100644 (file)
index 0000000..cb9c76b
--- /dev/null
@@ -0,0 +1,65 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  sudo \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+    download_ndk android-ndk-r13b-linux-x86_64.zip && \
+    make_standalone_toolchain x86 9 && \
+    make_standalone_toolchain x86 21 && \
+    remove_ndk
+
+ENV PATH=$PATH:/android/ndk/x86-9/bin
+
+ENV DEP_Z_ROOT=/android/ndk/x86-9/sysroot/usr/
+
+ENV HOSTS=i686-linux-android
+
+ENV RUST_CONFIGURE_ARGS \
+      --host=$HOSTS \
+      --target=$HOSTS \
+      --i686-linux-android-ndk=/android/ndk/x86 \
+      --disable-rpath \
+      --enable-extended \
+      --enable-cargo-openssl-static
+
+# We support api level 9, but api level 21 is required to build llvm. To
+# overcome this problem we use a ndk with api level 21 to build llvm and then
+# switch to a ndk with api level 9 to complete the build. When the linker is
+# invoked there are missing symbols (like sigsetempty, not available with api
+# level 9), the default linker behavior is to generate an error, to allow the
+# build to finish we use --warn-unresolved-symbols. Note that the missing
+# symbols does not affect std, only the compiler (llvm) and cargo (openssl).
+RUN chmod 777 /android/ndk && \
+    ln -s /android/ndk/x86-21 /android/ndk/x86
+
+ENV SCRIPT \
+  python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \
+  (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \
+    rm /android/ndk/x86 && \
+    ln -s /android/ndk/x86-9 /android/ndk/x86 && \
+    python2.7 ../x.py dist --host $HOSTS --target $HOSTS)
diff --git a/src/ci/docker/disabled/dist-x86_64-android/Dockerfile b/src/ci/docker/disabled/dist-x86_64-android/Dockerfile
new file mode 100644 (file)
index 0000000..11a80ab
--- /dev/null
@@ -0,0 +1,49 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  sudo \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+    download_ndk android-ndk-r13b-linux-x86_64.zip && \
+    make_standalone_toolchain x86_64 21 && \
+    remove_ndk
+
+ENV PATH=$PATH:/android/ndk/x86_64-21/bin
+
+ENV DEP_Z_ROOT=/android/ndk/x86_64-21/sysroot/usr/
+
+ENV HOSTS=x86_64-linux-android
+
+ENV RUST_CONFIGURE_ARGS \
+      --host=$HOSTS \
+      --target=$HOSTS \
+      --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
+      --disable-rpath \
+      --enable-extended \
+      --enable-cargo-openssl-static
+
+ENV SCRIPT python2.7 ../x.py dist --target $HOSTS --host $HOSTS
index 59b93b784b2f6f27db319fc06d23c2fa93a4600c..6abbf0530afa69c6ebb333823f8b3d562495bb9f 100755 (executable)
@@ -21,11 +21,27 @@ root_dir="`dirname $src_dir`"
 
 source "$ci_dir/shared.sh"
 
-retry docker \
-  build \
-  --rm \
-  -t rust-ci \
-  "`dirname "$script"`/$image"
+if [ -f "$docker_dir/$image/Dockerfile" ]; then
+    retry docker \
+      build \
+      --rm \
+      -t rust-ci \
+      "$docker_dir/$image"
+elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
+    if [ -n "$TRAVIS_OS_NAME" ]; then
+        echo Cannot run disabled images on travis!
+        exit 1
+    fi
+    retry docker \
+      build \
+      --rm \
+      -t rust-ci \
+      -f "$docker_dir/disabled/$image/Dockerfile" \
+      "$docker_dir"
+else
+    echo Invalid image: $image
+    exit 1
+fi
 
 objdir=$root_dir/obj
 
index 1bac512e20977b087d4fdd09b35e336bbf8e8e9b..82578f6aa61d5a78ca3fb793cc582a1179c2ff87 100644 (file)
@@ -42,9 +42,8 @@
 use ty::{IntType, UintType};
 use ty::{self, Ty, TyCtxt};
 use ty::error::TypeError;
-use ty::fold::TypeFoldable;
-use ty::relate::{RelateResult, TypeRelation};
-use traits::PredicateObligations;
+use ty::relate::{self, Relate, RelateResult, TypeRelation};
+use traits::{Obligation, PredicateObligations};
 
 use syntax::ast;
 use syntax_pos::Span;
@@ -207,11 +206,16 @@ pub fn instantiate(&mut self,
         // `'?2` and `?3` are fresh region/type inference
         // variables. (Down below, we will relate `a_ty <: b_ty`,
         // adding constraints like `'x: '?2` and `?1 <: ?3`.)
-        let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?;
+        let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
         debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
                a_ty, dir, b_vid, b_ty);
         self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty);
 
+        if needs_wf {
+            self.obligations.push(Obligation::new(self.trace.cause.clone(),
+                                                  ty::Predicate::WellFormed(b_ty)));
+        }
+
         // Finally, relate `b_ty` to `a_ty`, as described in previous comment.
         //
         // FIXME(#16847): This code is non-ideal because all these subtype
@@ -230,10 +234,9 @@ pub fn instantiate(&mut self,
 
     /// Attempts to generalize `ty` for the type variable `for_vid`.
     /// This checks for cycle -- that is, whether the type `ty`
-    /// references `for_vid`. If `is_eq_relation` is false, it will
-    /// also replace all regions/unbound-type-variables with fresh
-    /// variables. Returns `TyError` in the case of a cycle, `Ok`
-    /// otherwise.
+    /// references `for_vid`. The `dir` is the "direction" for which we
+    /// a performing the generalization (i.e., are we producing a type
+    /// that can be used as a supertype etc).
     ///
     /// Preconditions:
     ///
@@ -241,22 +244,33 @@ pub fn instantiate(&mut self,
     fn generalize(&self,
                   ty: Ty<'tcx>,
                   for_vid: ty::TyVid,
-                  is_eq_relation: bool)
-                  -> RelateResult<'tcx, Ty<'tcx>>
+                  dir: RelationDir)
+                  -> RelateResult<'tcx, Generalization<'tcx>>
     {
+        // Determine the ambient variance within which `ty` appears.
+        // The surrounding equation is:
+        //
+        //     ty [op] ty2
+        //
+        // where `op` is either `==`, `<:`, or `:>`. This maps quite
+        // naturally.
+        let ambient_variance = match dir {
+            RelationDir::EqTo => ty::Invariant,
+            RelationDir::SubtypeOf => ty::Covariant,
+            RelationDir::SupertypeOf => ty::Contravariant,
+        };
+
         let mut generalize = Generalizer {
             infcx: self.infcx,
             span: self.trace.cause.span,
             for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
-            is_eq_relation: is_eq_relation,
-            cycle_detected: false
+            ambient_variance: ambient_variance,
+            needs_wf: false,
         };
-        let u = ty.fold_with(&mut generalize);
-        if generalize.cycle_detected {
-            Err(TypeError::CyclicTy)
-        } else {
-            Ok(u)
-        }
+
+        let ty = generalize.relate(&ty, &ty)?;
+        let needs_wf = generalize.needs_wf;
+        Ok(Generalization { ty, needs_wf })
     }
 }
 
@@ -264,16 +278,81 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
     span: Span,
     for_vid_sub_root: ty::TyVid,
-    is_eq_relation: bool,
-    cycle_detected: bool,
+    ambient_variance: ty::Variance,
+    needs_wf: bool, // see the field `needs_wf` in `Generalization`
 }
 
-impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
+/// Result from a generalization operation. This includes
+/// not only the generalized type, but also a bool flag
+/// indicating whether further WF checks are needed.q
+struct Generalization<'tcx> {
+    ty: Ty<'tcx>,
+
+    /// If true, then the generalized type may not be well-formed,
+    /// even if the source type is well-formed, so we should add an
+    /// additional check to enforce that it is. This arises in
+    /// particular around 'bivariant' type parameters that are only
+    /// constrained by a where-clause. As an example, imagine a type:
+    ///
+    ///     struct Foo<A, B> where A: Iterator<Item=B> {
+    ///         data: A
+    ///     }
+    ///
+    /// here, `A` will be covariant, but `B` is
+    /// unconstrained. However, whatever it is, for `Foo` to be WF, it
+    /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
+    /// then after generalization we will wind up with a type like
+    /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
+    /// ?D>` (or `>:`), we will wind up with the requirement that `?A
+    /// <: ?C`, but no particular relationship between `?B` and `?D`
+    /// (after all, we do not know the variance of the normalized form
+    /// of `A::Item` with respect to `A`). If we do nothing else, this
+    /// may mean that `?D` goes unconstrained (as in #41677).  So, in
+    /// this scenario where we create a new type variable in a
+    /// bivariant context, we set the `needs_wf` flag to true. This
+    /// will force the calling code to check that `WF(Foo<?C, ?D>)`
+    /// holds, which in turn implies that `?C::Item == ?D`. So once
+    /// `?C` is constrained, that should suffice to restrict `?D`.
+    needs_wf: bool,
+}
+
+impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn tag(&self) -> &'static str {
+        "Generalizer"
+    }
+
+    fn a_is_expected(&self) -> bool {
+        true
+    }
+
+    fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+                  -> RelateResult<'tcx, ty::Binder<T>>
+        where T: Relate<'tcx>
+    {
+        Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?))
+    }
+
+    fn relate_with_variance<T: Relate<'tcx>>(&mut self,
+                                             variance: ty::Variance,
+                                             a: &T,
+                                             b: &T)
+                                             -> RelateResult<'tcx, T>
+    {
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        let result = self.relate(a, b);
+        self.ambient_variance = old_ambient_variance;
+        result
+    }
+
+    fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
+
         // Check to see whether the type we are genealizing references
         // any other type variable related to `vid` via
         // subtyping. This is basically our "occurs check", preventing
@@ -286,41 +365,63 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                 if sub_vid == self.for_vid_sub_root {
                     // If sub-roots are equal, then `for_vid` and
                     // `vid` are related via subtyping.
-                    self.cycle_detected = true;
-                    self.tcx().types.err
+                    return Err(TypeError::CyclicTy);
                 } else {
                     match variables.probe_root(vid) {
                         Some(u) => {
                             drop(variables);
-                            self.fold_ty(u)
+                            self.relate(&u, &u)
                         }
                         None => {
-                            if !self.is_eq_relation {
-                                let origin = variables.origin(vid);
-                                let new_var_id = variables.new_var(false, origin, None);
-                                let u = self.tcx().mk_var(new_var_id);
-                                debug!("generalize: replacing original vid={:?} with new={:?}",
-                                       vid, u);
-                                u
-                            } else {
-                                t
+                            match self.ambient_variance {
+                                // Invariant: no need to make a fresh type variable.
+                                ty::Invariant => return Ok(t),
+
+                                // Bivariant: make a fresh var, but we
+                                // may need a WF predicate. See
+                                // comment on `needs_wf` field for
+                                // more info.
+                                ty::Bivariant => self.needs_wf = true,
+
+                                // Co/contravariant: this will be
+                                // sufficiently constrained later on.
+                                ty::Covariant | ty::Contravariant => (),
                             }
+
+                            let origin = variables.origin(vid);
+                            let new_var_id = variables.new_var(false, origin, None);
+                            let u = self.tcx().mk_var(new_var_id);
+                            debug!("generalize: replacing original vid={:?} with new={:?}",
+                                   vid, u);
+                            return Ok(u);
                         }
                     }
                 }
             }
+            ty::TyInfer(ty::IntVar(_)) |
+            ty::TyInfer(ty::FloatVar(_)) => {
+                // No matter what mode we are in,
+                // integer/floating-point types must be equal to be
+                // relatable.
+                Ok(t)
+            }
             _ => {
-                t.super_fold_with(self)
+                relate::super_relate_tys(self, t, t)
             }
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn regions(&mut self, r: ty::Region<'tcx>, r2: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
+        assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
+
         match *r {
             // Never make variables for regions bound within the type itself,
             // nor for erased regions.
             ty::ReLateBound(..) |
-            ty::ReErased => { return r; }
+            ty::ReErased => {
+                return Ok(r);
+            }
 
             // Early-bound regions should really have been substituted away before
             // we get to this point.
@@ -342,15 +443,16 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
             ty::ReScope(..) |
             ty::ReVar(..) |
             ty::ReFree(..) => {
-                if self.is_eq_relation {
-                    return r;
+                match self.ambient_variance {
+                    ty::Invariant => return Ok(r),
+                    ty::Bivariant | ty::Covariant | ty::Contravariant => (),
                 }
             }
         }
 
         // FIXME: This is non-ideal because we don't give a
         // very descriptive origin for this region variable.
-        self.infcx.next_region_var(MiscVariable(self.span))
+        Ok(self.infcx.next_region_var(MiscVariable(self.span)))
     }
 }
 
index f0b179fa2e4205ac2d8b5f6b1818b71e3d193308..f9ffaee81f1573de6c636e685d0418c45f0e9e33 100644 (file)
 use super::combine::{CombineFields, RelationDir};
 use super::{Subtype};
 
+use hir::def_id::DefId;
+
 use ty::{self, Ty, TyCtxt};
 use ty::TyVar;
-use ty::relate::{Relate, RelateResult, TypeRelation};
+use ty::subst::Substs;
+use ty::relate::{self, Relate, RelateResult, TypeRelation};
 
 /// Ensures `a` is made equal to `b`. Returns `a` on success.
 pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@@ -38,6 +41,22 @@ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
     fn a_is_expected(&self) -> bool { self.a_is_expected }
 
+    fn relate_item_substs(&mut self,
+                          _item_def_id: DefId,
+                          a_subst: &'tcx Substs<'tcx>,
+                          b_subst: &'tcx Substs<'tcx>)
+                          -> RelateResult<'tcx, &'tcx Substs<'tcx>>
+    {
+        // NB: Once we are equating types, we don't care about
+        // variance, so don't try to lookup the variance here. This
+        // also avoids some cycles (e.g. #41849) since looking up
+        // variance requires computing types which can require
+        // performing trait matching (which then performs equality
+        // unification).
+
+        relate::relate_substs(self, None, a_subst, b_subst)
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              _: ty::Variance,
                                              a: &T,
index b517ebabbe767622e9b4ab7e1b1e099a328bf3f1..fe2ad498e99610635faf0a4889717dc7a7422904 100644 (file)
@@ -799,7 +799,7 @@ pub enum StatementKind<'tcx> {
     StorageDead(Lvalue<'tcx>),
 
     InlineAsm {
-        asm: InlineAsm,
+        asm: Box<InlineAsm>,
         outputs: Vec<Lvalue<'tcx>>,
         inputs: Vec<Operand<'tcx>>
     },
@@ -995,7 +995,7 @@ pub struct VisibilityScopeData {
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Operand<'tcx> {
     Consume(Lvalue<'tcx>),
-    Constant(Constant<'tcx>),
+    Constant(Box<Constant<'tcx>>),
 }
 
 impl<'tcx> Debug for Operand<'tcx> {
@@ -1015,7 +1015,7 @@ pub fn function_handle<'a>(
         substs: &'tcx Substs<'tcx>,
         span: Span,
     ) -> Self {
-        Operand::Constant(Constant {
+        Operand::Constant(box Constant {
             span: span,
             ty: tcx.type_of(def_id).subst(tcx, substs),
             literal: Literal::Value { value: ConstVal::Function(def_id, substs) },
@@ -1062,7 +1062,7 @@ pub enum Rvalue<'tcx> {
     /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
     /// that `Foo` has a destructor. These rvalues can be optimized
     /// away after type-checking and before lowering.
-    Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),
+    Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
@@ -1185,7 +1185,7 @@ fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
                     tuple_fmt.finish()
                 }
 
-                match *kind {
+                match **kind {
                     AggregateKind::Array(_) => write!(fmt, "{:?}", lvs),
 
                     AggregateKind::Tuple => {
@@ -1603,7 +1603,7 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             Discriminant(ref lval) => Discriminant(lval.fold_with(folder)),
             Box(ty) => Box(ty.fold_with(folder)),
             Aggregate(ref kind, ref fields) => {
-                let kind = match *kind {
+                let kind = box match **kind {
                     AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
                     AggregateKind::Tuple => AggregateKind::Tuple,
                     AggregateKind::Adt(def, v, substs, n) =>
@@ -1631,7 +1631,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             Discriminant(ref lval) => lval.visit_with(visitor),
             Box(ty) => ty.visit_with(visitor),
             Aggregate(ref kind, ref fields) => {
-                (match *kind {
+                (match **kind {
                     AggregateKind::Array(ty) => ty.visit_with(visitor),
                     AggregateKind::Tuple => false,
                     AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
index b6020df072853631ce43cfa14d2e01403ed8f9f4..7bc1dc58c29d298ed84a42b603973487732efef2 100644 (file)
@@ -183,7 +183,7 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'
                 tcx.mk_box(t)
             }
             Rvalue::Aggregate(ref ak, ref ops) => {
-                match *ak {
+                match **ak {
                     AggregateKind::Array(ty) => {
                         tcx.mk_array(ty, ops.len())
                     }
index 31bdd99ef32210abb0e85e91221396ab14d2e355..557fedadeba62155cb0a6cb1ce5767b68f76b35b 100644 (file)
@@ -515,6 +515,7 @@ fn super_rvalue(&mut self,
 
                     Rvalue::Aggregate(ref $($mutability)* kind,
                                       ref $($mutability)* operands) => {
+                        let kind = &$($mutability)* **kind;
                         match *kind {
                             AggregateKind::Array(ref $($mutability)* ty) => {
                                 self.visit_ty(ty);
index 51cdba56cf10a98c1ab7eeaa65f1beba9ef080bc..f5d510c11ae9dd64d1f48b4c3d021b7f29c6e334 100644 (file)
@@ -330,6 +330,66 @@ pub struct CrateVariancesMap {
     pub empty_variance: Rc<Vec<ty::Variance>>,
 }
 
+impl Variance {
+    /// `a.xform(b)` combines the variance of a context with the
+    /// variance of a type with the following meaning.  If we are in a
+    /// context with variance `a`, and we encounter a type argument in
+    /// a position with variance `b`, then `a.xform(b)` is the new
+    /// variance with which the argument appears.
+    ///
+    /// Example 1:
+    ///
+    ///     *mut Vec<i32>
+    ///
+    /// Here, the "ambient" variance starts as covariant. `*mut T` is
+    /// invariant with respect to `T`, so the variance in which the
+    /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
+    /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
+    /// respect to its type argument `T`, and hence the variance of
+    /// the `i32` here is `Invariant.xform(Covariant)`, which results
+    /// (again) in `Invariant`.
+    ///
+    /// Example 2:
+    ///
+    ///     fn(*const Vec<i32>, *mut Vec<i32)
+    ///
+    /// The ambient variance is covariant. A `fn` type is
+    /// contravariant with respect to its parameters, so the variance
+    /// within which both pointer types appear is
+    /// `Covariant.xform(Contravariant)`, or `Contravariant`.  `*const
+    /// T` is covariant with respect to `T`, so the variance within
+    /// which the first `Vec<i32>` appears is
+    /// `Contravariant.xform(Covariant)` or `Contravariant`.  The same
+    /// is true for its `i32` argument. In the `*mut T` case, the
+    /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
+    /// and hence the outermost type is `Invariant` with respect to
+    /// `Vec<i32>` (and its `i32` argument).
+    ///
+    /// Source: Figure 1 of "Taming the Wildcards:
+    /// Combining Definition- and Use-Site Variance" published in PLDI'11.
+    pub fn xform(self, v: ty::Variance) -> ty::Variance {
+        match (self, v) {
+            // Figure 1, column 1.
+            (ty::Covariant, ty::Covariant) => ty::Covariant,
+            (ty::Covariant, ty::Contravariant) => ty::Contravariant,
+            (ty::Covariant, ty::Invariant) => ty::Invariant,
+            (ty::Covariant, ty::Bivariant) => ty::Bivariant,
+
+            // Figure 1, column 2.
+            (ty::Contravariant, ty::Covariant) => ty::Contravariant,
+            (ty::Contravariant, ty::Contravariant) => ty::Covariant,
+            (ty::Contravariant, ty::Invariant) => ty::Invariant,
+            (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
+
+            // Figure 1, column 3.
+            (ty::Invariant, _) => ty::Invariant,
+
+            // Figure 1, column 4.
+            (ty::Bivariant, _) => ty::Bivariant,
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
 pub struct MethodCallee<'tcx> {
     /// Impl method ID, for inherent methods, or trait method ID, otherwise.
index dfa11b9c71a04c6c038621d4dc63330310fa986b..bbe682e74bc04b6dcfe920808d1faae0df10b883 100644 (file)
@@ -51,6 +51,24 @@ fn relate<T: Relate<'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> {
         Relate::relate(self, a, b)
     }
 
+    /// Relate the two substitutions for the given item. The default
+    /// is to look up the variance for the item and proceed
+    /// accordingly.
+    fn relate_item_substs(&mut self,
+                          item_def_id: DefId,
+                          a_subst: &'tcx Substs<'tcx>,
+                          b_subst: &'tcx Substs<'tcx>)
+                          -> RelateResult<'tcx, &'tcx Substs<'tcx>>
+    {
+        debug!("relate_item_substs(item_def_id={:?}, a_subst={:?}, b_subst={:?})",
+               item_def_id,
+               a_subst,
+               b_subst);
+
+        let opt_variances = self.tcx().variances_of(item_def_id);
+        relate_substs(self, Some(&opt_variances), a_subst, b_subst)
+    }
+
     /// Switch variance for the purpose of relating `a` and `b`.
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              variance: ty::Variance,
@@ -109,25 +127,6 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
     }
 }
 
-// substitutions are not themselves relatable without more context,
-// but they is an important subroutine for things that ARE relatable,
-// like traits etc.
-fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
-                                         item_def_id: DefId,
-                                         a_subst: &'tcx Substs<'tcx>,
-                                         b_subst: &'tcx Substs<'tcx>)
-                                         -> RelateResult<'tcx, &'tcx Substs<'tcx>>
-    where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-{
-    debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
-           item_def_id,
-           a_subst,
-           b_subst);
-
-    let opt_variances = relation.tcx().variances_of(item_def_id);
-    relate_substs(relation, Some(&opt_variances), a_subst, b_subst)
-}
-
 pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
                                         variances: Option<&Vec<ty::Variance>>,
                                         a_subst: &'tcx Substs<'tcx>,
@@ -291,7 +290,7 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
         } else {
-            let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
+            let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
             Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
         }
     }
@@ -308,7 +307,7 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
         } else {
-            let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
+            let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
             Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
         }
     }
@@ -372,7 +371,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
         (&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs))
             if a_def == b_def =>
         {
-            let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
+            let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
             Ok(tcx.mk_adt(a_def, substs))
         }
 
index 4ae8bdc284b226760c17ddcd924f71e715679711..4b7d52c25173a58c9640430a87cfe61a84286977 100644 (file)
@@ -517,11 +517,11 @@ fn elaborate_replace(
     }
 
     fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
-        Rvalue::Use(Operand::Constant(Constant {
+        Rvalue::Use(Operand::Constant(Box::new(Constant {
             span: span,
             ty: self.tcx.types.bool,
             literal: Literal::Value { value: ConstVal::Bool(val) }
-        }))
+        })))
     }
 
     fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
index 889f4dd4b9aac9d3c526ffff8863a0f84e4b0a30..eef3b38a8b5e9bdb32c8b12788c32f68a1308ea9 100644 (file)
@@ -635,11 +635,24 @@ fn print_crate_info(sess: &Session,
                             node: ast::MetaItemKind::Word,
                             span: DUMMY_SP,
                         });
-                        if !allow_unstable_cfg && gated_cfg.is_some() {
-                            continue;
+
+                        // Note that crt-static is a specially recognized cfg
+                        // directive that's printed out here as part of
+                        // rust-lang/rust#37406, but in general the
+                        // `target_feature` cfg is gated under
+                        // rust-lang/rust#29717. For now this is just
+                        // specifically allowing the crt-static cfg and that's
+                        // it, this is intended to get into Cargo and then go
+                        // through to build scripts.
+                        let value = value.as_ref().map(|s| s.as_str());
+                        let value = value.as_ref().map(|s| s.as_ref());
+                        if name != "target_feature" || value != Some("crt-static") {
+                            if !allow_unstable_cfg && gated_cfg.is_some() {
+                                continue;
+                            }
                         }
 
-                        cfgs.push(if let &Some(ref value) = value {
+                        cfgs.push(if let Some(value) = value {
                             format!("{}=\"{}\"", name, value)
                         } else {
                             format!("{}", name)
index 718f2b515068b3415033e2cf578e2cb39fd135e5..61bc7c6eb4c714e81f7b1ab3283e3e261d28a4f3 100644 (file)
@@ -12,7 +12,6 @@
 use llvm::LLVMRustHasFeature;
 use rustc::session::Session;
 use rustc_trans::back::write::create_target_machine;
-use syntax::feature_gate::UnstableFeatures;
 use syntax::symbol::Symbol;
 use libc::c_char;
 
@@ -53,8 +52,6 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
     }
 
     let requested_features = sess.opts.cg.target_feature.split(',');
-    let unstable_options = sess.opts.debugging_opts.unstable_options;
-    let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
     let found_negative = requested_features.clone().any(|r| r == "-crt-static");
     let found_positive = requested_features.clone().any(|r| r == "+crt-static");
 
@@ -68,14 +65,6 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
         found_positive
     };
 
-    // If we switched from the default then that's only allowed on nightly, so
-    // gate that here.
-    if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
-        sess.fatal("specifying the `crt-static` target feature is only allowed \
-                    on the nightly channel with `-Z unstable-options` passed \
-                    as well");
-    }
-
     if crt_static {
         cfg.insert((tf, Some(Symbol::intern("crt-static"))));
     }
index 0822f7134998572349e5c5cecb70fbfcf559bd00..861880aa265ec140a1072f8b25a12bc211c827e6 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use CodeSuggestion;
+use Substitution;
 use Level;
 use RenderSpan;
 use std::fmt;
@@ -23,7 +24,7 @@ pub struct Diagnostic {
     pub code: Option<String>,
     pub span: MultiSpan,
     pub children: Vec<SubDiagnostic>,
-    pub suggestion: Option<CodeSuggestion>,
+    pub suggestions: Vec<CodeSuggestion>,
 }
 
 /// For example a note attached to an error.
@@ -87,7 +88,7 @@ pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self
             code: code,
             span: MultiSpan::new(),
             children: vec![],
-            suggestion: None,
+            suggestions: vec![],
         }
     }
 
@@ -204,10 +205,22 @@ pub fn span_help<S: Into<MultiSpan>>(&mut self,
     ///
     /// See `diagnostic::CodeSuggestion` for more information.
     pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
-        assert!(self.suggestion.is_none());
-        self.suggestion = Some(CodeSuggestion {
-            msp: sp.into(),
-            substitutes: vec![suggestion],
+        self.suggestions.push(CodeSuggestion {
+            substitution_parts: vec![Substitution {
+                span: sp,
+                substitutions: vec![suggestion],
+            }],
+            msg: msg.to_owned(),
+        });
+        self
+    }
+
+    pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
+        self.suggestions.push(CodeSuggestion {
+            substitution_parts: vec![Substitution {
+                span: sp,
+                substitutions: suggestions,
+            }],
             msg: msg.to_owned(),
         });
         self
index a9c2bbeba2aa4ba0486eb4db917c7dcd883be258..d03a4acb9fc580389224d8985ff449ca5f235467 100644 (file)
@@ -148,6 +148,11 @@ pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self
                                     msg: &str,
                                     suggestion: String)
                                     -> &mut Self);
+    forward!(pub fn span_suggestions(&mut self,
+                                     sp: Span,
+                                     msg: &str,
+                                     suggestions: Vec<String>)
+                                     -> &mut Self);
     forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
     forward!(pub fn code(&mut self, s: String) -> &mut Self);
 
index 53999eb9138b6f3b5054f8a0884706fd7e74dad6..d1ec1be47b8ab85f5459b1fd98441801f3c0d04e 100644 (file)
@@ -35,23 +35,32 @@ fn emit(&mut self, db: &DiagnosticBuilder) {
         let mut primary_span = db.span.clone();
         let mut children = db.children.clone();
 
-        if let Some(sugg) = db.suggestion.clone() {
-            assert_eq!(sugg.msp.primary_spans().len(), sugg.substitutes.len());
-            // don't display multispans as labels
-            if sugg.substitutes.len() == 1 &&
+        if let Some((sugg, rest)) = db.suggestions.split_first() {
+            if rest.is_empty() &&
+               // don't display multipart suggestions as labels
+               sugg.substitution_parts.len() == 1 &&
+               // don't display multi-suggestions as labels
+               sugg.substitutions() == 1 &&
                // don't display long messages as labels
                sugg.msg.split_whitespace().count() < 10 &&
                // don't display multiline suggestions as labels
-               sugg.substitutes[0].find('\n').is_none() {
-                let msg = format!("help: {} `{}`", sugg.msg, sugg.substitutes[0]);
-                primary_span.push_span_label(sugg.msp.primary_spans()[0], msg);
+               sugg.substitution_parts[0].substitutions[0].find('\n').is_none() {
+                let substitution = &sugg.substitution_parts[0].substitutions[0];
+                let msg = format!("help: {} `{}`", sugg.msg, substitution);
+                primary_span.push_span_label(sugg.substitution_spans().next().unwrap(), msg);
             } else {
-                children.push(SubDiagnostic {
-                    level: Level::Help,
-                    message: Vec::new(),
-                    span: MultiSpan::new(),
-                    render_span: Some(Suggestion(sugg)),
-                });
+                // if there are multiple suggestions, print them all in full
+                // to be consistent. We could try to figure out if we can
+                // make one (or the first one) inline, but that would give
+                // undue importance to a semi-random suggestion
+                for sugg in &db.suggestions {
+                    children.push(SubDiagnostic {
+                        level: Level::Help,
+                        message: Vec::new(),
+                        span: MultiSpan::new(),
+                        render_span: Some(Suggestion(sugg.clone())),
+                    });
+                }
             }
         }
 
@@ -66,6 +75,10 @@ fn emit(&mut self, db: &DiagnosticBuilder) {
 
 /// maximum number of lines we will print for each error; arbitrary.
 pub const MAX_HIGHLIGHT_LINES: usize = 6;
+/// maximum number of suggestions to be shown
+///
+/// Arbitrary, but taken from trait import suggestion limit
+pub const MAX_SUGGESTIONS: usize = 4;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum ColorConfig {
@@ -1054,38 +1067,44 @@ fn emit_suggestion_default(&mut self,
                                -> io::Result<()> {
         use std::borrow::Borrow;
 
-        let primary_span = suggestion.msp.primary_span().unwrap();
+        let primary_span = suggestion.substitution_spans().next().unwrap();
         if let Some(ref cm) = self.cm {
             let mut buffer = StyledBuffer::new();
 
-            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
-            buffer.append(0, ": ", Style::HeaderMsg);
-            self.msg_to_buffer(&mut buffer,
-                               &[(suggestion.msg.to_owned(), Style::NoStyle)],
-                               max_line_num_len,
-                               "suggestion",
-                               Some(Style::HeaderMsg));
-
             let lines = cm.span_to_lines(primary_span).unwrap();
 
             assert!(!lines.lines.is_empty());
 
-            let complete = suggestion.splice_lines(cm.borrow());
+            buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+            buffer.append(0, ": ", Style::HeaderMsg);
+            self.msg_to_buffer(&mut buffer,
+                            &[(suggestion.msg.to_owned(), Style::NoStyle)],
+                            max_line_num_len,
+                            "suggestion",
+                            Some(Style::HeaderMsg));
 
-            // print the suggestion without any line numbers, but leave
-            // space for them. This helps with lining up with previous
-            // snippets from the actual error being reported.
-            let mut lines = complete.lines();
+            let suggestions = suggestion.splice_lines(cm.borrow());
             let mut row_num = 1;
-            for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
-                draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
-                buffer.append(row_num, line, Style::NoStyle);
-                row_num += 1;
-            }
+            for complete in suggestions.iter().take(MAX_SUGGESTIONS) {
+
+                // print the suggestion without any line numbers, but leave
+                // space for them. This helps with lining up with previous
+                // snippets from the actual error being reported.
+                let mut lines = complete.lines();
+                for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
+                    draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                    buffer.append(row_num, line, Style::NoStyle);
+                    row_num += 1;
+                }
 
-            // if we elided some lines, add an ellipsis
-            if let Some(_) = lines.next() {
-                buffer.append(row_num, "...", Style::NoStyle);
+                // if we elided some lines, add an ellipsis
+                if let Some(_) = lines.next() {
+                    buffer.append(row_num, "...", Style::NoStyle);
+                }
+            }
+            if suggestions.len() > MAX_SUGGESTIONS {
+                let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
+                buffer.append(row_num, &msg, Style::NoStyle);
             }
             emit_to_destination(&buffer.render(), level, &mut self.dst)?;
         }
index db8c9ac306bba718ff4ff9c6a64050289bdda97b..e1ec23479ab8a7ef84249db60c626b04a116787c 100644 (file)
@@ -23,6 +23,7 @@
 #![feature(staged_api)]
 #![feature(range_contains)]
 #![feature(libc)]
+#![feature(conservative_impl_trait)]
 
 extern crate term;
 extern crate libc;
@@ -65,11 +66,35 @@ pub enum RenderSpan {
 
 #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub struct CodeSuggestion {
-    pub msp: MultiSpan,
-    pub substitutes: Vec<String>,
+    /// Each substitute can have multiple variants due to multiple
+    /// applicable suggestions
+    ///
+    /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
+    /// `foo` and `bar` on their own:
+    ///
+    /// ```
+    /// vec![
+    ///     (0..3, vec!["a", "x"]),
+    ///     (4..7, vec!["b", "y"]),
+    /// ]
+    /// ```
+    ///
+    /// or by replacing the entire span:
+    ///
+    /// ```
+    /// vec![(0..7, vec!["a.b", "x.y"])]
+    /// ```
+    pub substitution_parts: Vec<Substitution>,
     pub msg: String,
 }
 
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+/// See the docs on `CodeSuggestion::substitutions`
+pub struct Substitution {
+    pub span: Span,
+    pub substitutions: Vec<String>,
+}
+
 pub trait CodeMapper {
     fn lookup_char_pos(&self, pos: BytePos) -> Loc;
     fn span_to_lines(&self, sp: Span) -> FileLinesResult;
@@ -79,8 +104,18 @@ pub trait CodeMapper {
 }
 
 impl CodeSuggestion {
-    /// Returns the assembled code suggestion.
-    pub fn splice_lines(&self, cm: &CodeMapper) -> String {
+    /// Returns the number of substitutions
+    fn substitutions(&self) -> usize {
+        self.substitution_parts[0].substitutions.len()
+    }
+
+    /// Returns the number of substitutions
+    pub fn substitution_spans<'a>(&'a self) -> impl Iterator<Item = Span> + 'a {
+        self.substitution_parts.iter().map(|sub| sub.span)
+    }
+
+    /// Returns the assembled code suggestions.
+    pub fn splice_lines(&self, cm: &CodeMapper) -> Vec<String> {
         use syntax_pos::{CharPos, Loc, Pos};
 
         fn push_trailing(buf: &mut String,
@@ -102,20 +137,22 @@ fn push_trailing(buf: &mut String,
             }
         }
 
-        let mut primary_spans = self.msp.primary_spans().to_owned();
-
-        assert_eq!(primary_spans.len(), self.substitutes.len());
-        if primary_spans.is_empty() {
-            return format!("");
+        if self.substitution_parts.is_empty() {
+            return vec![String::new()];
         }
 
+        let mut primary_spans: Vec<_> = self.substitution_parts
+            .iter()
+            .map(|sub| (sub.span, &sub.substitutions))
+            .collect();
+
         // Assumption: all spans are in the same file, and all spans
         // are disjoint. Sort in ascending order.
-        primary_spans.sort_by_key(|sp| sp.lo);
+        primary_spans.sort_by_key(|sp| sp.0.lo);
 
         // Find the bounding span.
-        let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
-        let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
+        let lo = primary_spans.iter().map(|sp| sp.0.lo).min().unwrap();
+        let hi = primary_spans.iter().map(|sp| sp.0.hi).min().unwrap();
         let bounding_span = Span {
             lo: lo,
             hi: hi,
@@ -138,33 +175,40 @@ fn push_trailing(buf: &mut String,
         prev_hi.col = CharPos::from_usize(0);
 
         let mut prev_line = fm.get_line(lines.lines[0].line_index);
-        let mut buf = String::new();
+        let mut bufs = vec![String::new(); self.substitutions()];
 
-        for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
+        for (sp, substitutes) in primary_spans {
             let cur_lo = cm.lookup_char_pos(sp.lo);
-            if prev_hi.line == cur_lo.line {
-                push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
-            } else {
-                push_trailing(&mut buf, prev_line, &prev_hi, None);
-                // push lines between the previous and current span (if any)
-                for idx in prev_hi.line..(cur_lo.line - 1) {
-                    if let Some(line) = fm.get_line(idx) {
-                        buf.push_str(line);
-                        buf.push('\n');
+            for (buf, substitute) in bufs.iter_mut().zip(substitutes) {
+                if prev_hi.line == cur_lo.line {
+                    push_trailing(buf, prev_line, &prev_hi, Some(&cur_lo));
+                } else {
+                    push_trailing(buf, prev_line, &prev_hi, None);
+                    // push lines between the previous and current span (if any)
+                    for idx in prev_hi.line..(cur_lo.line - 1) {
+                        if let Some(line) = fm.get_line(idx) {
+                            buf.push_str(line);
+                            buf.push('\n');
+                        }
+                    }
+                    if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
+                        buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
                     }
                 }
-                if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
-                    buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
-                }
+                buf.push_str(substitute);
             }
-            buf.push_str(substitute);
             prev_hi = cm.lookup_char_pos(sp.hi);
             prev_line = fm.get_line(prev_hi.line - 1);
         }
-        push_trailing(&mut buf, prev_line, &prev_hi, None);
-        // remove trailing newline
-        buf.pop();
-        buf
+        for buf in &mut bufs {
+            // if the replacement already ends with a newline, don't print the next line
+            if !buf.ends_with('\n') {
+                push_trailing(buf, prev_line, &prev_hi, None);
+            }
+            // remove trailing newline
+            buf.pop();
+        }
+        bufs
     }
 }
 
index c503b8c7fe06f7bb9c58ed0fce452203e35551e0..40a78933aad2d8e5718f28a25f0fd63f5f2def6e 100644 (file)
@@ -60,7 +60,7 @@ pub fn push_assign_constant(&mut self,
                                 temp: &Lvalue<'tcx>,
                                 constant: Constant<'tcx>) {
         self.push_assign(block, source_info, temp,
-                         Rvalue::Use(Operand::Constant(constant)));
+                         Rvalue::Use(Operand::Constant(box constant)));
     }
 
     pub fn push_assign_unit(&mut self,
@@ -68,7 +68,7 @@ pub fn push_assign_unit(&mut self,
                             source_info: SourceInfo,
                             lvalue: &Lvalue<'tcx>) {
         self.push_assign(block, source_info, lvalue, Rvalue::Aggregate(
-            AggregateKind::Tuple, vec![]
+            box AggregateKind::Tuple, vec![]
         ));
     }
 
index 22a36bb21d8753f6cafc5b285007cdf6e9a69a87..f7534737edc03cb74571bbcd517bda16dfa29a7e 100644 (file)
@@ -66,7 +66,7 @@ fn expr_as_operand(&mut self,
         match category {
             Category::Constant => {
                 let constant = this.as_constant(expr);
-                block.and(Operand::Constant(constant))
+                block.and(Operand::Constant(box constant))
             }
             Category::Lvalue |
             Category::Rvalue(..) => {
index 8dc7745cd9eb998772201cfd2d519b56fdf861ec..46e2408c38d5d6e06a90c0e2dc28cde0c6a871fa 100644 (file)
@@ -166,7 +166,7 @@ fn expr_as_rvalue(&mut self,
                           .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                           .collect();
 
-                block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields))
+                block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
             }
             ExprKind::Tuple { fields } => { // see (*) above
                 // first process the set of fields
@@ -175,14 +175,14 @@ fn expr_as_rvalue(&mut self,
                           .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                           .collect();
 
-                block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields))
+                block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
             ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above
                 let upvars =
                     upvars.into_iter()
                           .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
                           .collect();
-                block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
+                block.and(Rvalue::Aggregate(box AggregateKind::Closure(closure_id, substs), upvars))
             }
             ExprKind::Adt {
                 adt_def, variant_index, substs, fields, base
@@ -215,7 +215,8 @@ fn expr_as_rvalue(&mut self,
                     field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
                 };
 
-                let adt = AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
+                let adt =
+                    box AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
                 block.and(Rvalue::Aggregate(adt, fields))
             }
             ExprKind::Assign { .. } |
index c03432312b0ab6c4adc235e2a3036603c6f3854b..3c7ab373651d2c7983eda3d1c06116d137fbc147 100644 (file)
@@ -129,7 +129,7 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
                 this.cfg.push(block, Statement {
                     source_info: source_info,
                     kind: StatementKind::InlineAsm {
-                        asm: asm.clone(),
+                        asm: box asm.clone(),
                         outputs: outputs,
                         inputs: inputs
                     },
index 0833342927fec9dbbb31bab1164aa70a44080b58..28386fa598ce6c7890ddd6762a44d3e4bb65d369 100644 (file)
@@ -308,7 +308,7 @@ pub fn perform_test(&mut self,
                     let eq_block = self.cfg.start_new_block();
                     let cleanup = self.diverge_cleanup();
                     self.cfg.terminate(block, source_info, TerminatorKind::Call {
-                        func: Operand::Constant(Constant {
+                        func: Operand::Constant(box Constant {
                             span: test.span,
                             ty: mty,
                             literal: method
index 35a8b245f2bb64203a7e19e14d8c891015e02821..6c93e073de6b1953bd56b60de2d9069409b9d390 100644 (file)
@@ -40,7 +40,7 @@ pub fn literal_operand(&mut self,
                            ty: Ty<'tcx>,
                            literal: Literal<'tcx>)
                            -> Operand<'tcx> {
-        let constant = Constant {
+        let constant = box Constant {
             span: span,
             ty: ty,
             literal: literal,
@@ -49,7 +49,7 @@ pub fn literal_operand(&mut self,
     }
 
     pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
-        Rvalue::Aggregate(AggregateKind::Tuple, vec![])
+        Rvalue::Aggregate(box AggregateKind::Tuple, vec![])
     }
 
     // Returns a zero literal operand for the appropriate type, works for
index f9c08f34eaf3f4fde47daac87c75282d3391760b..6043a696183f26eb069171d7514db420be8e038a 100644 (file)
@@ -786,7 +786,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
     let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
     TerminatorKind::Call {
-        func: Operand::Constant(Constant {
+        func: Operand::Constant(box Constant {
             span: data.span,
             ty: tcx.type_of(free_func).subst(tcx, substs),
             literal: Literal::Value {
index 1458ea7fdd6a29fcd9fb5e9b75c5ddf88bf95337..a6f9952b23ca5111d9b25286fd50ff77a3ba5d6e 100644 (file)
@@ -323,7 +323,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
     let (callee, mut args) = match call_kind {
         CallKind::Indirect => (rcvr, vec![]),
         CallKind::Direct(def_id) => (
-            Operand::Constant(Constant {
+            Operand::Constant(box Constant {
                 span: span,
                 ty: tcx.type_of(def_id).subst(tcx, param_env.free_substs),
                 literal: Literal::Value {
@@ -449,7 +449,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
             kind: StatementKind::Assign(
                 Lvalue::Local(RETURN_POINTER),
                 Rvalue::Aggregate(
-                    AggregateKind::Adt(adt_def, variant_no, substs, None),
+                    box AggregateKind::Adt(adt_def, variant_no, substs, None),
                     (1..sig.inputs().len()+1).map(|i| {
                         Operand::Consume(Lvalue::Local(Local::new(i)))
                     }).collect()
index fbb67161bac9d82fb7d5034ccab663d481d9819c..08a4961c6cd1ba40317605a73c95e0110a10d303 100644 (file)
@@ -316,7 +316,7 @@ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
             _ => return,
         }
 
-        *operand = Operand::Constant(self.constant.clone());
+        *operand = Operand::Constant(box self.constant.clone());
         self.uses_replaced += 1
     }
 }
index 4309f91c635bb15bc6f733123354c0d24b733625..d21dbeafb5d0a0b269184aec28b2fcd8942ddfeb 100644 (file)
@@ -49,8 +49,8 @@ fn run_pass<'a, 'tcx>(&self,
                     &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
                     _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
                 };
-                let (adt_def, variant, substs) = match agg_kind {
-                    &AggregateKind::Adt(adt_def, variant, substs, None)
+                let (adt_def, variant, substs) = match **agg_kind {
+                    AggregateKind::Adt(adt_def, variant, substs, None)
                         => (adt_def, variant, substs),
                     _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
                 };
@@ -114,8 +114,8 @@ fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
             &Rvalue::Aggregate(ref kind, ref operands) => (kind, operands),
             _ => continue,
         };
-        let (adt_def, variant) = match kind {
-            &AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
+        let (adt_def, variant) = match **kind {
+            AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
             _ => continue,
         };
         if operands.len() == 0 {
index ed9a0d3809f245886e0aa6e41bee1c7f76ba3d7f..e1c4602b045ebab53404a86b715176f6c4a7c84e 100644 (file)
@@ -230,7 +230,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
                 (if self.keep_original {
                     rhs.clone()
                 } else {
-                    let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]);
+                    let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
                     mem::replace(rhs, unit)
                 }, statement.source_info)
             };
@@ -288,7 +288,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
 
     fn promote_candidate(mut self, candidate: Candidate) {
         let span = self.promoted.span;
-        let new_operand = Operand::Constant(Constant {
+        let new_operand = Operand::Constant(box Constant {
             span: span,
             ty: self.promoted.return_ty,
             literal: Literal::Promoted {
index 0d592b4d72be5b11df3d9ddd232ca0fa39cb921b..df837a32133b37e252d885003c0bc83c2e778c4c 100644 (file)
@@ -730,7 +730,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             }
 
             Rvalue::Aggregate(ref kind, _) => {
-                if let AggregateKind::Adt(def, ..) = *kind {
+                if let AggregateKind::Adt(def, ..) = **kind {
                     if def.has_dtor(self.tcx) {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
index d21a6ddfdfb970c85b57276238399370133ddeff..1dcacb29c3ecc406807630affdfd7e7209b14910 100644 (file)
@@ -37,7 +37,7 @@ fn run_pass<'a, 'tcx>(&self,
         for block in mir.basic_blocks_mut() {
             let terminator = block.terminator_mut();
             terminator.kind = match terminator.kind {
-                TerminatorKind::SwitchInt { discr: Operand::Constant(Constant {
+                TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
                     literal: Literal::Value { ref value }, ..
                 }), ref values, ref targets, .. } => {
                     if let Some(ref constint) = value.to_const_int() {
@@ -54,7 +54,7 @@ fn run_pass<'a, 'tcx>(&self,
                         continue
                     }
                 },
-                TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
+                TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
                     literal: Literal::Value {
                         value: ConstVal::Bool(cond)
                     }, ..
@@ -66,4 +66,3 @@ fn run_pass<'a, 'tcx>(&self,
         }
     }
 }
-
index b325470ec818cadcd33f6dd3309ec408400a5351..be384218a414e0a461393c54eb489d521b155eac 100644 (file)
@@ -534,7 +534,7 @@ fn check_call_inputs(&mut self,
 
     fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
         match operand {
-            &Operand::Constant(Constant {
+            &Operand::Constant(box Constant {
                 literal: Literal::Value {
                     value: ConstVal::Function(def_id, _), ..
                 }, ..
index d9921e62330b95e1fa098a7f39b60540641af3c5..24218725186624525e735628bd03a9fac3b6b07a 100644 (file)
@@ -190,7 +190,7 @@ fn visit_rvalue(&mut self,
             Rvalue::Aggregate(ref kind, ref _operands) => {
                 // AggregateKind is not distinguished by visit API, so
                 // record it. (`super_rvalue` handles `_operands`.)
-                self.record(match *kind {
+                self.record(match **kind {
                     AggregateKind::Array(_) => "AggregateKind::Array",
                     AggregateKind::Tuple => "AggregateKind::Tuple",
                     AggregateKind::Adt(..) => "AggregateKind::Adt",
index c797c151de67c602f2a71a1cd302a8e3d5da6933..57639a1ecef7b17b359436a928f5a815602e22c7 100644 (file)
@@ -150,7 +150,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                                           view_path.span,
                                           ResolutionError::SelfImportsOnlyAllowedWithin);
                         } else if source_name == "$crate" && full_path.segments.len() == 1 {
-                            let crate_root = self.resolve_crate_var(source.ctxt);
+                            let crate_root = self.resolve_crate_var(source.ctxt, item.span);
                             let crate_name = match crate_root.kind {
                                 ModuleKind::Def(_, name) => name,
                                 ModuleKind::Block(..) => unreachable!(),
@@ -247,7 +247,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
 
                 // n.b. we don't need to look at the path option here, because cstore already did
                 let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
-                let module = self.get_extern_crate_root(crate_id);
+                let module = self.get_extern_crate_root(crate_id, item.span);
                 self.populate_module_if_necessary(module);
                 let used = self.process_legacy_macro_imports(item, module, expansion);
                 let binding =
@@ -279,7 +279,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                     no_implicit_prelude: parent.no_implicit_prelude || {
                         attr::contains_name(&item.attrs, "no_implicit_prelude")
                     },
-                    ..ModuleData::new(Some(parent), module_kind, def_id)
+                    ..ModuleData::new(Some(parent), module_kind, def_id, item.span)
                 });
                 self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.module_map.insert(def_id, module);
@@ -314,7 +314,10 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
             ItemKind::Enum(ref enum_definition, _) => {
                 let def = Def::Enum(self.definitions.local_def_id(item.id));
                 let module_kind = ModuleKind::Def(def, ident.name);
-                let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+                let module = self.new_module(parent,
+                                             module_kind,
+                                             parent.normal_ancestor_id,
+                                             item.span);
                 self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
 
                 for variant in &(*enum_definition).variants {
@@ -370,7 +373,10 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
 
                 // Add all the items within to a new module.
                 let module_kind = ModuleKind::Def(Def::Trait(def_id), ident.name);
-                let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+                let module = self.new_module(parent,
+                                             module_kind,
+                                             parent.normal_ancestor_id,
+                                             item.span);
                 self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.current_module = module;
             }
@@ -418,8 +424,10 @@ fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion
     fn build_reduced_graph_for_block(&mut self, block: &Block) {
         let parent = self.current_module;
         if self.block_needs_anonymous_module(block) {
-            let module =
-                self.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id);
+            let module = self.new_module(parent,
+                                         ModuleKind::Block(block.id),
+                                         parent.normal_ancestor_id,
+                                         block.span);
             self.block_map.insert(block.id, module);
             self.current_module = module; // Descend into the block.
         }
@@ -431,10 +439,14 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
         let def = child.def;
         let def_id = def.def_id();
         let vis = self.session.cstore.visibility(def_id);
+        let span = child.span;
 
         match def {
             Def::Mod(..) | Def::Enum(..) => {
-                let module = self.new_module(parent, ModuleKind::Def(def, ident.name), def_id);
+                let module = self.new_module(parent,
+                                             ModuleKind::Def(def, ident.name),
+                                             def_id,
+                                             span);
                 self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
             }
             Def::Variant(..) | Def::TyAlias(..) => {
@@ -454,7 +466,10 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
             }
             Def::Trait(..) => {
                 let module_kind = ModuleKind::Def(def, ident.name);
-                let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+                let module = self.new_module(parent,
+                                             module_kind,
+                                             parent.normal_ancestor_id,
+                                             span);
                 self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
 
                 for child in self.session.cstore.item_children(def_id) {
@@ -483,18 +498,18 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
         }
     }
 
-    fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'a> {
+    fn get_extern_crate_root(&mut self, cnum: CrateNum, span: Span) -> Module<'a> {
         let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
         let name = self.session.cstore.crate_name(cnum);
         let macros_only = self.session.cstore.dep_kind(cnum).macros_only();
         let module_kind = ModuleKind::Def(Def::Mod(def_id), name);
         let arenas = self.arenas;
         *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
-            arenas.alloc_module(ModuleData::new(None, module_kind, def_id))
+            arenas.alloc_module(ModuleData::new(None, module_kind, def_id, span))
         })
     }
 
-    pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
+    pub fn macro_def_scope(&mut self, expansion: Mark, span: Span) -> Module<'a> {
         let def_id = self.macro_defs[&expansion];
         if let Some(id) = self.definitions.as_local_node_id(def_id) {
             self.local_macro_def_scopes[&id]
@@ -503,7 +518,7 @@ pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
             self.graph_root
         } else {
             let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
-            self.get_extern_crate_root(module_def_id.krate)
+            self.get_extern_crate_root(module_def_id.krate, span)
         }
     }
 
@@ -593,7 +608,8 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, expa
         } else {
             for (name, span) in legacy_imports.imports {
                 let ident = Ident::with_empty_ctxt(name);
-                let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
+                let result = self.resolve_ident_in_module(module, ident, MacroNS,
+                                                          false, false, span);
                 if let Ok(binding) = result {
                     let directive = macro_use_directive(span);
                     self.potentially_unused_imports.push(directive);
@@ -607,7 +623,7 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, expa
         for (name, span) in legacy_imports.reexports {
             self.session.cstore.export_macros(module.def_id().unwrap().krate);
             let ident = Ident::with_empty_ctxt(name);
-            let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
+            let result = self.resolve_ident_in_module(module, ident, MacroNS, false, false, span);
             if let Ok(binding) = result {
                 self.macro_exports.push(Export { name: name, def: binding.def(), span: span });
             } else {
index ac556270886ac677dcb0247c2791345f6348e59b..6054f46370e3257ccc98c95ed8f16d9e34206128 100644 (file)
@@ -613,7 +613,7 @@ fn visit_ty(&mut self, ty: &'tcx Ty) {
             self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
         } else if let TyKind::ImplicitSelf = ty.node {
             let self_ty = keywords::SelfType.ident();
-            let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
+            let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
                           .map_or(Def::Err, |d| d.def());
             self.record_def(ty.id, PathResolution::new(def));
         } else if let TyKind::Array(ref element, ref length) = ty.node {
@@ -865,12 +865,18 @@ pub struct ModuleData<'a> {
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
     populated: Cell<bool>,
+
+    /// Span of the module itself. Used for error reporting.
+    span: Span,
 }
 
 pub type Module<'a> = &'a ModuleData<'a>;
 
 impl<'a> ModuleData<'a> {
-    fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId) -> Self {
+    fn new(parent: Option<Module<'a>>,
+           kind: ModuleKind,
+           normal_ancestor_id: DefId,
+           span: Span) -> Self {
         ModuleData {
             parent: parent,
             kind: kind,
@@ -884,6 +890,7 @@ fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId)
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
             populated: Cell::new(normal_ancestor_id.is_local()),
+            span: span,
         }
     }
 
@@ -1260,11 +1267,11 @@ fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
         let namespace = if is_value { ValueNS } else { TypeNS };
         let hir::Path { ref segments, span, ref mut def } = *path;
         let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect();
-        match self.resolve_path(&path, Some(namespace), Some(span)) {
+        match self.resolve_path(&path, Some(namespace), true, span) {
             PathResult::Module(module) => *def = module.def().unwrap(),
             PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
                 *def = path_res.base_def(),
-            PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) {
+            PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) {
                 PathResult::Failed(msg, _) => {
                     resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
                 }
@@ -1298,7 +1305,7 @@ pub fn new(session: &'a Session,
         let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
         let graph_root = arenas.alloc_module(ModuleData {
             no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
-            ..ModuleData::new(None, root_module_kind, root_def_id)
+            ..ModuleData::new(None, root_module_kind, root_def_id, krate.span)
         });
         let mut module_map = FxHashMap();
         module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
@@ -1430,9 +1437,14 @@ pub fn resolve_crate(&mut self, krate: &Crate) {
         self.crate_loader.postprocess(krate);
     }
 
-    fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId)
-                  -> Module<'a> {
-        self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id))
+    fn new_module(
+        &self,
+        parent: Module<'a>,
+        kind: ModuleKind,
+        normal_ancestor_id: DefId,
+        span: Span,
+    ) -> Module<'a> {
+        self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id, span))
     }
 
     fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
@@ -1490,7 +1502,8 @@ fn add_to_glob_map(&mut self, id: NodeId, ident: Ident) {
     fn resolve_ident_in_lexical_scope(&mut self,
                                       mut ident: Ident,
                                       ns: Namespace,
-                                      record_used: Option<Span>)
+                                      record_used: bool,
+                                      path_span: Span)
                                       -> Option<LexicalScopeBinding<'a>> {
         if ns == TypeNS {
             ident = ident.unhygienize();
@@ -1501,12 +1514,13 @@ fn resolve_ident_in_lexical_scope(&mut self,
             if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
                 // The ident resolves to a type parameter or local variable.
                 return Some(LexicalScopeBinding::Def(
-                    self.adjust_local_def(ns, i, def, record_used)
+                    self.adjust_local_def(ns, i, def, record_used, path_span)
                 ));
             }
 
             if let ModuleRibKind(module) = self.ribs[ns][i].kind {
-                let item = self.resolve_ident_in_module(module, ident, ns, false, record_used);
+                let item = self.resolve_ident_in_module(module, ident, ns, false,
+                                                        record_used, path_span);
                 if let Ok(binding) = item {
                     // The ident resolves to an item.
                     return Some(LexicalScopeBinding::Item(binding));
@@ -1515,7 +1529,8 @@ fn resolve_ident_in_lexical_scope(&mut self,
                 if let ModuleKind::Block(..) = module.kind { // We can see through blocks
                 } else if !module.no_implicit_prelude {
                     return self.prelude.and_then(|prelude| {
-                        self.resolve_ident_in_module(prelude, ident, ns, false, None).ok()
+                        self.resolve_ident_in_module(prelude, ident, ns, false,
+                                                     false, path_span).ok()
                     }).map(LexicalScopeBinding::Item)
                 } else {
                     return None;
@@ -1535,12 +1550,12 @@ fn resolve_ident_in_lexical_scope(&mut self,
         None
     }
 
-    fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> {
+    fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext, span: Span) -> Module<'a> {
         let mut ctxt_data = crate_var_ctxt.data();
         while ctxt_data.prev_ctxt != SyntaxContext::empty() {
             ctxt_data = ctxt_data.prev_ctxt.data();
         }
-        let module = self.macro_def_scope(ctxt_data.outer_mark);
+        let module = self.macro_def_scope(ctxt_data.outer_mark, span);
         if module.is_local() { self.graph_root } else { module }
     }
 
@@ -2135,7 +2150,8 @@ fn resolve_pattern(&mut self,
                 PatKind::Ident(bmode, ref ident, ref opt_pat) => {
                     // First try to resolve the identifier as some existing
                     // entity, then fall back to a fresh binding.
-                    let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None)
+                    let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS,
+                                                                      false, pat.span)
                                       .and_then(LexicalScopeBinding::item);
                     let resolution = binding.map(NameBinding::def).and_then(|def| {
                         let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
@@ -2241,7 +2257,7 @@ fn smart_resolve_path_fragment(&mut self,
                     (format!(""), format!("the crate root"))
                 } else {
                     let mod_path = &path[..path.len() - 1];
-                    let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), None) {
+                    let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), false, span) {
                         PathResult::Module(module) => module.def(),
                         _ => None,
                     }.map_or(format!(""), |def| format!("{} ", def.kind_name()));
@@ -2271,8 +2287,10 @@ fn smart_resolve_path_fragment(&mut self,
             let name = path.last().unwrap().name;
             let candidates = this.lookup_import_candidates(name, ns, is_expected);
             if !candidates.is_empty() {
+                let mut module_span = this.current_module.span;
+                module_span.hi = module_span.lo;
                 // Report import candidates as help and proceed searching for labels.
-                show_candidates(&mut err, &candidates, def.is_some());
+                show_candidates(&mut err, module_span, &candidates, def.is_some());
             } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
                 let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant);
                 let mut enum_candidates = enum_candidates.iter()
@@ -2289,9 +2307,9 @@ fn smart_resolve_path_fragment(&mut self,
                     }
                 }
             }
-            if path.len() == 1 && this.self_type_is_available() {
+            if path.len() == 1 && this.self_type_is_available(span) {
                 if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
-                    let self_is_available = this.self_value_is_available(path[0].ctxt);
+                    let self_is_available = this.self_value_is_available(path[0].ctxt, span);
                     match candidate {
                         AssocSuggestion::Field => {
                             err.span_label(span, format!("did you mean `self.{}`?", path_str));
@@ -2315,7 +2333,7 @@ fn smart_resolve_path_fragment(&mut self,
             let mut levenshtein_worked = false;
 
             // Try Levenshtein.
-            if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) {
+            if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected, span) {
                 err.span_label(ident_span, format!("did you mean `{}`?", candidate));
                 levenshtein_worked = true;
             }
@@ -2420,14 +2438,15 @@ fn smart_resolve_path_fragment(&mut self,
         resolution
     }
 
-    fn self_type_is_available(&mut self) -> bool {
-        let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(), TypeNS, None);
+    fn self_type_is_available(&mut self, span: Span) -> bool {
+        let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(),
+                                                          TypeNS, false, span);
         if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
     }
 
-    fn self_value_is_available(&mut self, ctxt: SyntaxContext) -> bool {
+    fn self_value_is_available(&mut self, ctxt: SyntaxContext, span: Span) -> bool {
         let ident = Ident { name: keywords::SelfValue.name(), ctxt: ctxt };
-        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None);
+        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, false, span);
         if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
     }
 
@@ -2491,7 +2510,7 @@ fn resolve_qpath(&mut self,
             ));
         }
 
-        let result = match self.resolve_path(&path, Some(ns), Some(span)) {
+        let result = match self.resolve_path(&path, Some(ns), true, span) {
             PathResult::NonModule(path_res) => path_res,
             PathResult::Module(module) if !module.is_normal() => {
                 PathResolution::new(module.def().unwrap())
@@ -2537,7 +2556,7 @@ fn resolve_qpath(&mut self,
         if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
            path[0].name != keywords::CrateRoot.name() && path[0].name != "$crate" {
             let unqualified_result = {
-                match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
+                match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) {
                     PathResult::NonModule(path_res) => path_res.base_def(),
                     PathResult::Module(module) => module.def().unwrap(),
                     _ => return Some(result),
@@ -2555,7 +2574,8 @@ fn resolve_qpath(&mut self,
     fn resolve_path(&mut self,
                     path: &[Ident],
                     opt_ns: Option<Namespace>, // `None` indicates a module path
-                    record_used: Option<Span>)
+                    record_used: bool,
+                    path_span: Span)
                     -> PathResult<'a> {
         let mut module = None;
         let mut allow_super = true;
@@ -2584,17 +2604,17 @@ fn resolve_path(&mut self,
                 module = Some(self.graph_root);
                 continue
             } else if i == 0 && ns == TypeNS && ident.name == "$crate" {
-                module = Some(self.resolve_crate_var(ident.ctxt));
+                module = Some(self.resolve_crate_var(ident.ctxt, path_span));
                 continue
             }
 
             let binding = if let Some(module) = module {
-                self.resolve_ident_in_module(module, ident, ns, false, record_used)
+                self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span)
             } else if opt_ns == Some(MacroNS) {
-                self.resolve_lexical_macro_path_segment(ident, ns, record_used)
+                self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span)
                     .map(MacroBinding::binding)
             } else {
-                match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
+                match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) {
                     Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
                     Some(LexicalScopeBinding::Def(def))
                             if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
@@ -2602,7 +2622,7 @@ fn resolve_path(&mut self,
                             def, path.len() - 1
                         ));
                     }
-                    _ => Err(if record_used.is_some() { Determined } else { Undetermined }),
+                    _ => Err(if record_used { Determined } else { Undetermined }),
                 }
             };
 
@@ -2659,12 +2679,13 @@ fn adjust_local_def(&mut self,
                         ns: Namespace,
                         rib_index: usize,
                         mut def: Def,
-                        record_used: Option<Span>) -> Def {
+                        record_used: bool,
+                        span: Span) -> Def {
         let ribs = &self.ribs[ns][rib_index + 1..];
 
         // An invalid forward use of a type parameter from a previous default.
         if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
-            if let Some(span) = record_used {
+            if record_used {
                 resolve_error(self, span,
                         ResolutionError::ForwardDeclaredTyParam);
             }
@@ -2674,7 +2695,7 @@ fn adjust_local_def(&mut self,
 
         match def {
             Def::Upvar(..) => {
-                span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
+                span_bug!(span, "unexpected {:?} in bindings", def)
             }
             Def::Local(def_id) => {
                 for rib in ribs {
@@ -2700,7 +2721,7 @@ fn adjust_local_def(&mut self,
                             let depth = vec.len();
                             def = Def::Upvar(def_id, depth, function_id);
 
-                            if let Some(span) = record_used {
+                            if record_used {
                                 vec.push(Freevar {
                                     def: prev_def,
                                     span: span,
@@ -2712,7 +2733,7 @@ fn adjust_local_def(&mut self,
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
-                            if let Some(span) = record_used {
+                            if record_used {
                                 resolve_error(self, span,
                                         ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
                             }
@@ -2720,7 +2741,7 @@ fn adjust_local_def(&mut self,
                         }
                         ConstantItemRibKind => {
                             // Still doesn't deal with upvars
-                            if let Some(span) = record_used {
+                            if record_used {
                                 resolve_error(self, span,
                                         ResolutionError::AttemptToUseNonConstantValueInConstant);
                             }
@@ -2739,7 +2760,7 @@ fn adjust_local_def(&mut self,
                         ItemRibKind => {
                             // This was an attempt to use a type parameter outside
                             // its scope.
-                            if let Some(span) = record_used {
+                            if record_used {
                                 resolve_error(self, span,
                                               ResolutionError::TypeParametersFromOuterFunction);
                             }
@@ -2747,7 +2768,7 @@ fn adjust_local_def(&mut self,
                         }
                         ConstantItemRibKind => {
                             // see #9186
-                            if let Some(span) = record_used {
+                            if record_used {
                                 resolve_error(self, span,
                                               ResolutionError::OuterTypeParameterContext);
                             }
@@ -2843,7 +2864,8 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
     fn lookup_typo_candidate<FilterFn>(&mut self,
                                        path: &[Ident],
                                        ns: Namespace,
-                                       filter_fn: FilterFn)
+                                       filter_fn: FilterFn,
+                                       span: Span)
                                        -> Option<Symbol>
         where FilterFn: Fn(Def) -> bool
     {
@@ -2895,7 +2917,8 @@ fn lookup_typo_candidate<FilterFn>(&mut self,
         } else {
             // Search in module.
             let mod_path = &path[..path.len() - 1];
-            if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) {
+            if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS),
+                                                                  false, span) {
                 add_module_candidates(module, &mut names);
             }
         }
@@ -3396,7 +3419,10 @@ fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) {
                 continue
             }
             let ident = attr.path.segments[0].identifier;
-            let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None);
+            let result = self.resolve_lexical_macro_path_segment(ident,
+                                                                 MacroNS,
+                                                                 false,
+                                                                 attr.path.span);
             if let Ok(binding) = result {
                 if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) {
                     attr::mark_known(attr);
@@ -3463,12 +3489,10 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
 /// When an entity with a given name is not available in scope, we search for
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
-fn show_candidates(session: &mut DiagnosticBuilder,
+fn show_candidates(err: &mut DiagnosticBuilder,
+                   span: Span,
                    candidates: &[ImportSuggestion],
                    better: bool) {
-    // don't show more than MAX_CANDIDATES results, so
-    // we're consistent with the trait suggestions
-    const MAX_CANDIDATES: usize = 4;
 
     // we want consistent results across executions, but candidates are produced
     // by iterating through a hash map, so make sure they are ordered:
@@ -3481,21 +3505,13 @@ fn show_candidates(session: &mut DiagnosticBuilder,
         1 => " is found in another module, you can import it",
         _ => "s are found in other modules, you can import them",
     };
+    let msg = format!("possible {}candidate{} into scope", better, msg_diff);
+
+    for candidate in &mut path_strings {
+        *candidate = format!("use {};\n", candidate);
+    }
 
-    let end = cmp::min(MAX_CANDIDATES, path_strings.len());
-    session.help(&format!("possible {}candidate{} into scope:{}{}",
-                          better,
-                          msg_diff,
-                          &path_strings[0..end].iter().map(|candidate| {
-                              format!("\n  `use {};`", candidate)
-                          }).collect::<String>(),
-                          if path_strings.len() > MAX_CANDIDATES {
-                              format!("\nand {} other candidates",
-                                      path_strings.len() - MAX_CANDIDATES)
-                          } else {
-                              "".to_owned()
-                          }
-                          ));
+    err.span_suggestions(span, &msg, path_strings);
 }
 
 /// A somewhat inefficient routine to obtain the name of a module.
index 106f421f39e75b12a5b65e8da2b9c61f68525fa6..c08421cb9374eb9efa04bf4183762a66c07287cc 100644 (file)
@@ -123,14 +123,14 @@ fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
     }
 
     fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
-        struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>);
+        struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span);
 
         impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
             fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
                 let ident = path.segments[0].identifier;
                 if ident.name == "$crate" {
                     path.segments[0].identifier.name = keywords::CrateRoot.name();
-                    let module = self.0.resolve_crate_var(ident.ctxt);
+                    let module = self.0.resolve_crate_var(ident.ctxt, self.1);
                     if !module.is_local() {
                         let span = path.segments[0].span;
                         path.segments.insert(1, match module.kind {
@@ -149,7 +149,7 @@ fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
             }
         }
 
-        EliminateCrateVar(self).fold_item(item).expect_one("")
+        EliminateCrateVar(self, item.span).fold_item(item).expect_one("")
     }
 
     fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool {
@@ -379,7 +379,7 @@ fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKin
                 return Err(Determinacy::Determined);
             }
 
-            let def = match self.resolve_path(&path, Some(MacroNS), None) {
+            let def = match self.resolve_path(&path, Some(MacroNS), false, span) {
                 PathResult::NonModule(path_res) => match path_res.base_def() {
                     Def::Err => Err(Determinacy::Determined),
                     def @ _ => Ok(def),
@@ -401,7 +401,7 @@ fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKin
         let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
             Ok(Def::Macro(binding.def_id, MacroKind::Bang))
         } else {
-            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
+            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) {
                 Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
                 Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
                 Err(_) => {
@@ -421,18 +421,19 @@ fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKin
     pub fn resolve_lexical_macro_path_segment(&mut self,
                                               ident: Ident,
                                               ns: Namespace,
-                                              record_used: Option<Span>)
+                                              record_used: bool,
+                                              path_span: Span)
                                               -> Result<MacroBinding<'a>, Determinacy> {
         let mut module = Some(self.current_module);
         let mut potential_illegal_shadower = Err(Determinacy::Determined);
         let determinacy =
-            if record_used.is_some() { Determinacy::Determined } else { Determinacy::Undetermined };
+            if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
         loop {
             let result = if let Some(module) = module {
                 // Since expanded macros may not shadow the lexical scope and
                 // globs may not shadow global macros (both enforced below),
                 // we resolve with restricted shadowing (indicated by the penultimate argument).
-                self.resolve_ident_in_module(module, ident, ns, true, record_used)
+                self.resolve_ident_in_module(module, ident, ns, true, record_used, path_span)
                     .map(MacroBinding::Modern)
             } else {
                 self.global_macros.get(&ident.name).cloned().ok_or(determinacy)
@@ -441,15 +442,18 @@ pub fn resolve_lexical_macro_path_segment(&mut self,
 
             match result.map(MacroBinding::binding) {
                 Ok(binding) => {
-                    let span = match record_used {
-                        Some(span) => span,
-                        None => return result,
-                    };
+                    if !record_used {
+                        return result;
+                    }
                     if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
                         if shadower.def() != binding.def() {
                             let name = ident.name;
                             self.ambiguity_errors.push(AmbiguityError {
-                                span: span, name: name, b1: shadower, b2: binding, lexical: true,
+                                span: path_span,
+                                name: name,
+                                b1: shadower,
+                                b2: binding,
+                                lexical: true,
                                 legacy: false,
                             });
                             return potential_illegal_shadower;
@@ -543,7 +547,7 @@ pub fn resolve_legacy_scope(&mut self,
     pub fn finalize_current_module_macro_resolutions(&mut self) {
         let module = self.current_module;
         for &(ref path, span) in module.macro_resolutions.borrow().iter() {
-            match self.resolve_path(path, Some(MacroNS), Some(span)) {
+            match self.resolve_path(path, Some(MacroNS), true, span) {
                 PathResult::NonModule(_) => {},
                 PathResult::Failed(msg, _) => {
                     resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
@@ -555,7 +559,7 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
         for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() {
             let legacy_scope = &self.invocations[&mark].legacy_scope;
             let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true);
-            let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span));
+            let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span);
             match (legacy_resolution, resolution) {
                 (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
                     let msg1 = format!("`{}` could refer to the macro defined here", ident);
@@ -579,7 +583,7 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
                             format!("cannot find derive macro `{}` in this scope", ident),
                     };
                     let mut err = self.session.struct_span_err(span, &msg);
-                    self.suggest_macro_name(&ident.name.as_str(), kind, &mut err);
+                    self.suggest_macro_name(&ident.name.as_str(), kind, &mut err, span);
                     err.emit();
                 },
                 _ => {},
@@ -588,7 +592,7 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
     }
 
     fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
-                          err: &mut DiagnosticBuilder<'a>) {
+                          err: &mut DiagnosticBuilder<'a>, span: Span) {
         // First check if this is a locally-defined bang macro.
         let suggestion = if let MacroKind::Bang = kind {
             find_best_match_for_name(self.macro_names.iter(), name, None)
@@ -619,7 +623,7 @@ fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
                 }
             };
             let ident = Ident::from_str(name);
-            self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro)
+            self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro, span)
         });
 
         if let Some(suggestion) = suggestion {
index 804e1ea740f50e4152c75fbc14a4ad03317ffddd..1d4ba4ed100b72e3139fbcf29b42e70e1e9eed13 100644 (file)
@@ -146,7 +146,8 @@ pub fn resolve_ident_in_module(&mut self,
                                    ident: Ident,
                                    ns: Namespace,
                                    restricted_shadowing: bool,
-                                   record_used: Option<Span>)
+                                   record_used: bool,
+                                   path_span: Span)
                                    -> Result<&'a NameBinding<'a>, Determinacy> {
         self.populate_module_if_necessary(module);
 
@@ -154,7 +155,7 @@ pub fn resolve_ident_in_module(&mut self,
             .try_borrow_mut()
             .map_err(|_| Determined)?; // This happens when there is a cycle of imports
 
-        if let Some(span) = record_used {
+        if record_used {
             if let Some(binding) = resolution.binding {
                 if let Some(shadowed_glob) = resolution.shadows_glob {
                     let name = ident.name;
@@ -164,16 +165,20 @@ pub fn resolve_ident_in_module(&mut self,
                        ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
                        binding.def() != shadowed_glob.def() {
                         self.ambiguity_errors.push(AmbiguityError {
-                            span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob,
+                            span: path_span,
+                            name: name,
+                            lexical: false,
+                            b1: binding,
+                            b2: shadowed_glob,
                             legacy: false,
                         });
                     }
                 }
-                if self.record_use(ident, ns, binding, span) {
+                if self.record_use(ident, ns, binding, path_span) {
                     return Ok(self.dummy_binding);
                 }
                 if !self.is_accessible(binding.vis) {
-                    self.privacy_errors.push(PrivacyError(span, ident.name, binding));
+                    self.privacy_errors.push(PrivacyError(path_span, ident.name, binding));
                 }
             }
 
@@ -205,7 +210,7 @@ pub fn resolve_ident_in_module(&mut self,
                     SingleImport { source, .. } => source,
                     _ => unreachable!(),
                 };
-                match self.resolve_ident_in_module(module, ident, ns, false, None) {
+                match self.resolve_ident_in_module(module, ident, ns, false, false, path_span) {
                     Err(Determined) => {}
                     _ => return Err(Undetermined),
                 }
@@ -230,7 +235,12 @@ pub fn resolve_ident_in_module(&mut self,
         for directive in module.globs.borrow().iter() {
             if self.is_accessible(directive.vis.get()) {
                 if let Some(module) = directive.imported_module.get() {
-                    let result = self.resolve_ident_in_module(module, ident, ns, false, None);
+                    let result = self.resolve_ident_in_module(module,
+                                                              ident,
+                                                              ns,
+                                                              false,
+                                                              false,
+                                                              path_span);
                     if let Err(Undetermined) = result {
                         return Err(Undetermined);
                     }
@@ -499,7 +509,7 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
             // For better failure detection, pretend that the import will not define any names
             // while resolving its module path.
             directive.vis.set(ty::Visibility::Invisible);
-            let result = self.resolve_path(&directive.module_path, None, None);
+            let result = self.resolve_path(&directive.module_path, None, false, directive.span);
             directive.vis.set(vis);
 
             match result {
@@ -523,7 +533,12 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
         let mut indeterminate = false;
         self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
             if let Err(Undetermined) = result[ns].get() {
-                result[ns].set(this.resolve_ident_in_module(module, source, ns, false, None));
+                result[ns].set(this.resolve_ident_in_module(module,
+                                                            source,
+                                                            ns,
+                                                            false,
+                                                            false,
+                                                            directive.span));
             } else {
                 return
             };
@@ -563,14 +578,14 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<Stri
         self.current_module = directive.parent;
 
         let ImportDirective { ref module_path, span, .. } = *directive;
-        let module_result = self.resolve_path(&module_path, None, Some(span));
+        let module_result = self.resolve_path(&module_path, None, true, span);
         let module = match module_result {
             PathResult::Module(module) => module,
             PathResult::Failed(msg, _) => {
                 let (mut self_path, mut self_result) = (module_path.clone(), None);
                 if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
                     self_path[0].name = keywords::SelfValue.name();
-                    self_result = Some(self.resolve_path(&self_path, None, None));
+                    self_result = Some(self.resolve_path(&self_path, None, false, span));
                 }
                 return if let Some(PathResult::Module(..)) = self_result {
                     Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
@@ -609,7 +624,12 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<Stri
                         Some(this.dummy_binding);
                 }
             }
-        } else if let Ok(binding) = this.resolve_ident_in_module(module, ident, ns, false, None) {
+        } else if let Ok(binding) = this.resolve_ident_in_module(module,
+                                                                 ident,
+                                                                 ns,
+                                                                 false,
+                                                                 false,
+                                                                 directive.span) {
             legacy_self_import = Some(directive);
             let binding = this.arenas.alloc_name_binding(NameBinding {
                 kind: NameBindingKind::Import {
@@ -630,7 +650,7 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<Stri
             }
             let mut all_ns_failed = true;
             self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
-                match this.resolve_ident_in_module(module, ident, ns, false, Some(span)) {
+                match this.resolve_ident_in_module(module, ident, ns, false, true, span) {
                     Ok(_) => all_ns_failed = false,
                     _ => {}
                 }
index 889f9dc4cded5880f85a9c2171a7b24e708d350c..96ef26d3f6f833aa87a2a56c2eef37ac01d8c74f 100644 (file)
@@ -108,7 +108,7 @@ fn visit_terminator_kind(&mut self,
                              location: Location) {
         match *kind {
             mir::TerminatorKind::Call {
-                func: mir::Operand::Constant(mir::Constant {
+                func: mir::Operand::Constant(box mir::Constant {
                     literal: Literal::Value {
                         value: ConstVal::Function(def_id, _), ..
                     }, ..
index 040194e63d07e0ec6f549244ec495d3f3951abae..6ba00c7e103317cf1afcafa0827b1353e5de9417 100644 (file)
@@ -537,7 +537,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                 }
                 failure?;
 
-                match *kind {
+                match **kind {
                     mir::AggregateKind::Array(_) => {
                         self.const_array(dest_ty, &fields)
                     }
index b8e9a490b0e7cffa36b0ce40812131c19ebd8382..667075e6970e184c010e55ef7f9c6ab1de8f4ac8 100644 (file)
@@ -104,7 +104,7 @@ pub fn trans_rvalue(&mut self,
             }
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
-                match *kind {
+                match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
                         let discr = adt_def.discriminant_for_variant(bcx.tcx(), variant_index)
                            .to_u128_unchecked() as u64;
index e986a381cd963df034968e27a66fa463c2a5c2e6..cb2ee7dd1bcda5c7b89bcc4fda7a95e6d543f81c 100644 (file)
@@ -27,7 +27,6 @@
 
 use super::terms::*;
 use super::terms::VarianceTerm::*;
-use super::xform::*;
 
 pub struct ConstraintContext<'a, 'tcx: 'a> {
     pub terms_cx: TermsContext<'a, 'tcx>,
index 507734ce35e44fdcf1695911ac48b7c7190b6293..7106ca4d420a86100bebc22a21d4e64a8f98dd81 100644 (file)
 
 use rustc::ty;
 
-pub trait Xform {
-    fn xform(self, v: Self) -> Self;
-}
-
-impl Xform for ty::Variance {
-    fn xform(self, v: ty::Variance) -> ty::Variance {
-        // "Variance transformation", Figure 1 of The Paper
-        match (self, v) {
-            // Figure 1, column 1.
-            (ty::Covariant, ty::Covariant) => ty::Covariant,
-            (ty::Covariant, ty::Contravariant) => ty::Contravariant,
-            (ty::Covariant, ty::Invariant) => ty::Invariant,
-            (ty::Covariant, ty::Bivariant) => ty::Bivariant,
-
-            // Figure 1, column 2.
-            (ty::Contravariant, ty::Covariant) => ty::Contravariant,
-            (ty::Contravariant, ty::Contravariant) => ty::Covariant,
-            (ty::Contravariant, ty::Invariant) => ty::Invariant,
-            (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
-
-            // Figure 1, column 3.
-            (ty::Invariant, _) => ty::Invariant,
-
-            // Figure 1, column 4.
-            (ty::Bivariant, _) => ty::Bivariant,
-        }
-    }
-}
-
 pub fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
     // Greatest lower bound of the variance lattice as
     // defined in The Paper:
index 29f977ecd8c33101c655425c565e6c491a4cf969..44b62593fa3a69add0ce5065004b12fca4098f77 100644 (file)
 /// type is a static guarantee that the underlying bytes contain no interior 0
 /// bytes and the final byte is 0.
 ///
-/// A `CString` is created from either a byte slice or a byte vector. After
-/// being created, a `CString` predominately inherits all of its methods from
-/// the `Deref` implementation to `[c_char]`. Note that the underlying array
-/// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice
-/// can be obtained with the `as_bytes` method.  Slices produced from a `CString`
-/// do *not* contain the trailing nul terminator unless otherwise specified.
+/// A `CString` is created from either a byte slice or a byte vector.  A `u8`
+/// slice can be obtained with the `as_bytes` method.  Slices produced from a
+/// `CString` do *not* contain the trailing nul terminator unless otherwise
+/// specified.
 ///
 /// # Examples
 ///
index 5e46069cf7ddfb2257eb8d4f5423cb1d153f83fb..1646f8cce72326e05c778bf88933b892479f6695 100644 (file)
@@ -199,7 +199,10 @@ fn clone(&self) -> Self { *self }
 
 pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
 
+pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
+
 pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
+pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800;
 pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
 
 pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
index 7e28dd1e259c8c1551e7f73fc97d2daaecc09501..a51b458451e8623ff3fd397956f276cf6e5e4604 100644 (file)
@@ -32,7 +32,7 @@ pub fn errno() -> i32 {
 }
 
 /// Gets a detailed string description for the given error number.
-pub fn error_string(errnum: i32) -> String {
+pub fn error_string(mut errnum: i32) -> String {
     // This value is calculated from the macro
     // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
     let langId = 0x0800 as c::DWORD;
@@ -40,9 +40,27 @@ pub fn error_string(errnum: i32) -> String {
     let mut buf = [0 as c::WCHAR; 2048];
 
     unsafe {
-        let res = c::FormatMessageW(c::FORMAT_MESSAGE_FROM_SYSTEM |
+        let mut module = ptr::null_mut();
+        let mut flags = 0;
+
+        // NTSTATUS errors may be encoded as HRESULT, which may returned from
+        // GetLastError. For more information about Windows error codes, see
+        // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx
+        if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
+            // format according to https://support.microsoft.com/en-us/help/259693
+            const NTDLL_DLL: &'static [u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _,
+                                                '.' as _, 'D' as _, 'L' as _, 'L' as _, 0];
+            module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());
+
+            if module != ptr::null_mut() {
+                errnum ^= c::FACILITY_NT_BIT as i32;
+                flags = c::FORMAT_MESSAGE_FROM_HMODULE;
+            }
+        }
+
+        let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM |
                                         c::FORMAT_MESSAGE_IGNORE_INSERTS,
-                                    ptr::null_mut(),
+                                    module,
                                     errnum as c::DWORD,
                                     langId,
                                     buf.as_mut_ptr(),
@@ -299,3 +317,17 @@ pub fn home_dir() -> Option<PathBuf> {
 pub fn exit(code: i32) -> ! {
     unsafe { c::ExitProcess(code as c::UINT) }
 }
+
+#[cfg(test)]
+mod tests {
+    use io::Error;
+    use sys::c;
+
+    // tests `error_string` above
+    #[test]
+    fn ntstatus_error() {
+        const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
+        assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
+            .to_string().contains("FormatMessageW() returned error"));
+    }
+}
index 230c60baf8bb49a95b123d4c29b4c4a90caeb660..200368be275c335e81b03e6b986fb6a8ded6c800 100644 (file)
@@ -210,8 +210,8 @@ impl Builder {
     /// configuration methods can be chained.
     ///
     /// If the [`stack_size`] field is not specified, the stack size
-    /// will be the `RUST_MIN_STACK` environment variable, if it is
-    /// not specified either, a sensible default size will be set (2MB as
+    /// will be the `RUST_MIN_STACK` environment variable.  If it is
+    /// not specified either, a sensible default will be set (2MB as
     /// of the writting of this doc).
     ///
     /// # Examples
index 0271ddbccbf38a75248ed418b39d4065511ba2bb..06335584c96108571e0136a1ba84a052270820e9 100644 (file)
@@ -22,9 +22,8 @@
 use codemap::{CodeMap, FilePathMapping};
 use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
 use errors::registry::Registry;
-use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
+use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
 use errors::emitter::Emitter;
-use errors::snippet::Style;
 
 use std::rc::Rc;
 use std::io::{self, Write};
@@ -154,23 +153,26 @@ impl Diagnostic {
     fn from_diagnostic_builder(db: &DiagnosticBuilder,
                                je: &JsonEmitter)
                                -> Diagnostic {
-        let sugg = db.suggestion.as_ref().map(|sugg| {
-            SubDiagnostic {
-                level: Level::Help,
-                message: vec![(sugg.msg.clone(), Style::NoStyle)],
-                span: MultiSpan::new(),
-                render_span: Some(RenderSpan::Suggestion(sugg.clone())),
-            }
+        let sugg = db.suggestions.iter().flat_map(|sugg| {
+            je.render(sugg).into_iter().map(move |rendered| {
+                Diagnostic {
+                    message: sugg.msg.clone(),
+                    code: None,
+                    level: "help",
+                    spans: DiagnosticSpan::from_suggestion(sugg, je),
+                    children: vec![],
+                    rendered: Some(rendered),
+                }
+            })
         });
-        let sugg = sugg.as_ref();
         Diagnostic {
             message: db.message(),
             code: DiagnosticCode::map_opt_string(db.code.clone(), je),
             level: db.level.to_str(),
             spans: DiagnosticSpan::from_multispan(&db.span, je),
-            children: db.children.iter().chain(sugg).map(|c| {
+            children: db.children.iter().map(|c| {
                 Diagnostic::from_sub_diagnostic(c, je)
-            }).collect(),
+            }).chain(sugg).collect(),
             rendered: None,
         }
     }
@@ -184,8 +186,7 @@ fn from_sub_diagnostic(db: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
                      .map(|sp| DiagnosticSpan::from_render_span(sp, je))
                      .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)),
             children: vec![],
-            rendered: db.render_span.as_ref()
-                                    .and_then(|rsp| je.render(rsp)),
+            rendered: None,
         }
     }
 }
@@ -278,14 +279,19 @@ fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
 
     fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
                        -> Vec<DiagnosticSpan> {
-        assert_eq!(suggestion.msp.span_labels().len(), suggestion.substitutes.len());
-        suggestion.msp.span_labels()
-                      .into_iter()
-                      .zip(&suggestion.substitutes)
-                      .map(|(span_label, suggestion)| {
-                          DiagnosticSpan::from_span_label(span_label,
-                                                          Some(suggestion),
-                                                          je)
+        suggestion.substitution_parts
+                      .iter()
+                      .flat_map(|substitution| {
+                          substitution.substitutions.iter().map(move |suggestion| {
+                              let span_label = SpanLabel {
+                                  span: substitution.span,
+                                  is_primary: true,
+                                  label: None,
+                              };
+                              DiagnosticSpan::from_span_label(span_label,
+                                                              Some(suggestion),
+                                                              je)
+                          })
                       })
                       .collect()
     }
@@ -294,8 +300,9 @@ fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
         match *rsp {
             RenderSpan::FullSpan(ref msp) =>
                 DiagnosticSpan::from_multispan(msp, je),
-            RenderSpan::Suggestion(ref suggestion) =>
-                DiagnosticSpan::from_suggestion(suggestion, je),
+            // regular diagnostics don't produce this anymore
+            // FIXME(oli_obk): remove it entirely
+            RenderSpan::Suggestion(_) => unreachable!(),
         }
     }
 }
@@ -351,17 +358,8 @@ fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode>
 }
 
 impl JsonEmitter {
-    fn render(&self, render_span: &RenderSpan) -> Option<String> {
-        use std::borrow::Borrow;
-
-        match *render_span {
-            RenderSpan::FullSpan(_) => {
-                None
-            }
-            RenderSpan::Suggestion(ref suggestion) => {
-                Some(suggestion.splice_lines(self.cm.borrow()))
-            }
-        }
+    fn render(&self, suggestion: &CodeSuggestion) -> Vec<String> {
+        suggestion.splice_lines(&*self.cm)
     }
 }
 
diff --git a/src/test/compile-fail/crt-static-gated.rs b/src/test/compile-fail/crt-static-gated.rs
deleted file mode 100644 (file)
index 6c7c60b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2016 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.
-
-// compile-flags:-C target-feature=+crt-static
-// error-pattern: specifying the `crt-static` target feature is only allowed
-
-fn main() {}
index f990c2c42fe1431a266970a5837e9b7f2646dc40..001c1f2eddca1e3ccbeabaf58450b6296547847c 100644 (file)
@@ -8,7 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum Fruit {
+// these two HELPs are actually in a new line between this line and the `enum Fruit` line
+enum Fruit { //~ HELP possible candidate is found in another module, you can import it into scope
+    //~^ HELP possible candidate is found in another module, you can import it into scope
     Apple(i64),
     //~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
     //~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
@@ -21,7 +23,6 @@ fn should_return_fruit() -> Apple {
     Apple(5)
     //~^ ERROR cannot find function `Apple` in this scope
     //~| NOTE not found in this scope
-    //~| HELP possible candidate is found in another module, you can import it into scope
 }
 
 fn should_return_fruit_too() -> Fruit::Apple {
@@ -30,7 +31,6 @@ fn should_return_fruit_too() -> Fruit::Apple {
     Apple(5)
     //~^ ERROR cannot find function `Apple` in this scope
     //~| NOTE not found in this scope
-    //~| HELP possible candidate is found in another module, you can import it into scope
 }
 
 fn foo() -> Ok {
index d25674a74b1d37e563adcbe82728b269e3a70626..646ae8183a20ce8c93047a4dfc4d5203162f97e6 100644 (file)
@@ -13,9 +13,8 @@
 // over time, but this test used to exhibit some pretty bogus messages
 // that were not remotely helpful.
 
-// error-pattern:cannot infer
-// error-pattern:cannot outlive the lifetime 'a
-// error-pattern:must be valid for the static lifetime
+// error-pattern:the lifetime 'a
+// error-pattern:the static lifetime
 
 struct Invariant<'a>(Option<&'a mut &'a mut ()>);
 
index e8ada6a1755719205422e74f43591b9bf8ea138f..948fb7e1ef6c29759aed6ba0ddd3ac5db4349471 100644 (file)
@@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
 
 fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
     // Without knowing 'a:'b, we can't coerce
-    x //~ ERROR cannot infer an appropriate lifetime
+    x //~ ERROR lifetime bound not satisfied
      //~^ ERROR cannot infer an appropriate lifetime
 }
 
index d3bf92e85f411a5207e03786dc844487d7417dcf..1795ac95358d7c6c29c2bde494f0212b16ad6076 100644 (file)
@@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
                                 -> Box<Get<&'min i32>>
     where 'max : 'min
 {
-    v //~ ERROR cannot infer an appropriate lifetime
+    v //~ ERROR mismatched types
 }
 
 fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
@@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
     where 'max : 'min
 {
     // Previously OK:
-    v //~ ERROR cannot infer an appropriate lifetime
+    v //~ ERROR mismatched types
 }
 
 fn main() { }
index 0e94e35df2839895fdc389f970eeb6396db708e0..ad059a467f570bb2d4b9e5ef872d907ff1f8522c 100644 (file)
@@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
     where 'max : 'min
 {
     // Previously OK, now an error as traits are invariant.
-    v //~ ERROR cannot infer an appropriate lifetime
+    v //~ ERROR mismatched types
 }
 
 fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
                                    -> Box<Get<&'max i32>>
     where 'max : 'min
 {
-    v //~ ERROR cannot infer an appropriate lifetime
+    v //~ ERROR mismatched types
 }
 
 fn main() { }
index aa3e06c015d503829e89c839c2beb07e52a40e4e..9edb510b826a12df92df2fe2ea40966ca9ac98fa 100644 (file)
@@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
                                 -> Box<Get<&'min i32>>
     where 'max : 'min
 {
-    v //~ ERROR cannot infer an appropriate lifetime
+    v //~ ERROR mismatched types
 }
 
 fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
                                    -> Box<Get<&'max i32>>
     where 'max : 'min
 {
-    v //~ ERROR cannot infer an appropriate lifetime
+    v //~ ERROR mismatched types
 }
 
 fn main() { }
diff --git a/src/test/run-pass/issue-41677.rs b/src/test/run-pass/issue-41677.rs
new file mode 100644 (file)
index 0000000..d014382
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2016 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.
+
+// Regression test for #41677. The local variable was winding up with
+// a type `Receiver<?T, H>` where `?T` was unconstrained, because we
+// failed to enforce the WF obligations and `?T` is a bivariant type
+// parameter position.
+
+#![allow(unused_variables, dead_code)]
+
+use std::marker::PhantomData;
+
+trait Handle {
+    type Inner;
+}
+
+struct ResizingHandle<H>(PhantomData<H>);
+impl<H> Handle for ResizingHandle<H> {
+    type Inner = H;
+}
+
+struct Receiver<T, H: Handle<Inner=T>>(PhantomData<H>);
+
+fn channel<T>(size: usize) -> Receiver<T, ResizingHandle<T>> {
+    let rx = Receiver(PhantomData);
+    rx
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-41849-variance-req.rs b/src/test/run-pass/issue-41849-variance-req.rs
new file mode 100644 (file)
index 0000000..0557a6e
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2016 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.
+
+// Regression test for #41849.
+
+use std::ops::Mul;
+
+const C: usize = 1;
+const CAPACITY: usize = 1 * C;
+
+struct A<X> {
+    f: [X; CAPACITY],
+}
+
+struct B<T> {
+    f: T,
+}
+
+impl<T> Mul for B<T> {
+    type Output = Self;
+    fn mul(self, _rhs: B<T>) -> Self::Output {
+        self
+    }
+}
+
+impl<T> Mul<usize> for B<T> {
+    type Output = Self;
+    fn mul(self, _rhs: usize) -> Self::Output {
+        self
+    }
+}
+
+fn main() {
+    let a = A { f: [1] };
+    let _ = B { f: a };
+}
index dd04c5ce356c626224f5eda92cbc93e69edc4d5c..17c5d5d15d40479415e0c5503c248ace94e25045 100644 (file)
@@ -4,8 +4,8 @@ error[E0425]: cannot find value `A` in module `namespaced_enums`
 15 |     let _ = namespaced_enums::A;
    |                               ^ not found in `namespaced_enums`
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use namespaced_enums::Foo::A;`
+help: possible candidate is found in another module, you can import it into scope
+   | use namespaced_enums::Foo::A;
 
 error[E0425]: cannot find function `B` in module `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:18:31
@@ -13,8 +13,8 @@ error[E0425]: cannot find function `B` in module `namespaced_enums`
 18 |     let _ = namespaced_enums::B(10);
    |                               ^ not found in `namespaced_enums`
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use namespaced_enums::Foo::B;`
+help: possible candidate is found in another module, you can import it into scope
+   | use namespaced_enums::Foo::B;
 
 error[E0422]: cannot find struct, variant or union type `C` in module `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:21:31
@@ -22,8 +22,8 @@ error[E0422]: cannot find struct, variant or union type `C` in module `namespace
 21 |     let _ = namespaced_enums::C { a: 10 };
    |                               ^ not found in `namespaced_enums`
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use namespaced_enums::Foo::C;`
+help: possible candidate is found in another module, you can import it into scope
+   | use namespaced_enums::Foo::C;
 
 error: aborting due to 3 previous errors
 
index 69c48cc1f3241b9bbd0658c0119eabdb0410014a..63d2ce109142c70116181304aad38511fcb51325 100644 (file)
@@ -4,10 +4,10 @@ error[E0574]: expected struct, variant or union type, found enum `Result`
 19 |         Result {
    |         ^^^^^^ not a struct, variant or union type
    |
-   = help: possible better candidates are found in other modules, you can import them into scope:
-             `use std::fmt::Result;`
-             `use std::io::Result;`
-             `use std::thread::Result;`
+help: possible better candidates are found in other modules, you can import them into scope
+   | use std::fmt::Result;
+   | use std::io::Result;
+   | use std::thread::Result;
 
 error: aborting due to previous error
 
index ea6841e600972e78c4f376da98d3b388f4cc56fb..c0438abfe43b45cd5458eb302868063ff96c15df 100644 (file)
@@ -4,8 +4,8 @@ error[E0422]: cannot find struct, variant or union type `E` in this scope
 16 |     E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
    |     ^ not found in this scope
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use SomeEnum::E;`
+help: possible candidate is found in another module, you can import it into scope
+   | use SomeEnum::E;
 
 error: aborting due to previous error
 
index f38491d5362587200e7b7df5eca3ca0640604b79..7315d295f7b8427a9c84cafe3cfa3a37539d3d89 100644 (file)
@@ -4,10 +4,10 @@ error[E0405]: cannot find trait `Mul` in this scope
 53 | impl Mul for Foo {
    |      ^^^ not found in this scope
    |
-   = help: possible candidates are found in other modules, you can import them into scope:
-             `use mul1::Mul;`
-             `use mul2::Mul;`
-             `use std::ops::Mul;`
+help: possible candidates are found in other modules, you can import them into scope
+   | use mul1::Mul;
+   | use mul2::Mul;
+   | use std::ops::Mul;
 
 error[E0412]: cannot find type `Mul` in this scope
   --> $DIR/issue-21221-1.rs:72:16
@@ -15,12 +15,12 @@ error[E0412]: cannot find type `Mul` in this scope
 72 | fn getMul() -> Mul {
    |                ^^^ not found in this scope
    |
-   = help: possible candidates are found in other modules, you can import them into scope:
-             `use mul1::Mul;`
-             `use mul2::Mul;`
-             `use mul3::Mul;`
-             `use mul4::Mul;`
-           and 2 other candidates
+help: possible candidates are found in other modules, you can import them into scope
+   | use mul1::Mul;
+   | use mul2::Mul;
+   | use mul3::Mul;
+   | use mul4::Mul;
+and 2 other candidates
 
 error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
   --> $DIR/issue-21221-1.rs:83:6
@@ -34,8 +34,8 @@ error[E0405]: cannot find trait `Div` in this scope
 88 | impl Div for Foo {
    |      ^^^ not found in this scope
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use std::ops::Div;`
+help: possible candidate is found in another module, you can import it into scope
+   | use std::ops::Div;
 
 error: cannot continue compilation due to previous error
 
index 14dac7de4b2e13af1aa4796bdcc75fa3830b189c..f0b22754e6444607af28f16310bbe92a490c5f7e 100644 (file)
@@ -4,8 +4,8 @@ error[E0405]: cannot find trait `T` in this scope
 28 | impl T for Foo { }
    |      ^ not found in this scope
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use foo::bar::T;`
+help: possible candidate is found in another module, you can import it into scope
+   | use foo::bar::T;
 
 error: main function not found
 
index e1e00571e5d4a1bb5d110828db316c98df5c828f..a4a2496b19ae4c0b85c070945fa4fff4d35e0f54 100644 (file)
@@ -4,8 +4,8 @@ error[E0405]: cannot find trait `OuterTrait` in this scope
 25 | impl OuterTrait for Foo {}
    |      ^^^^^^^^^^ not found in this scope
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use issue_21221_3::outer::OuterTrait;`
+help: possible candidate is found in another module, you can import it into scope
+   | use issue_21221_3::outer::OuterTrait;
 
 error: cannot continue compilation due to previous error
 
index 569315a59cf34c8d9d1a8e89f3840bd633f5d307..dc2f22717313320616be267464421c8f15841708 100644 (file)
@@ -4,8 +4,8 @@ error[E0405]: cannot find trait `T` in this scope
 20 | impl T for Foo {}
    |      ^ not found in this scope
    |
-   = help: possible candidate is found in another module, you can import it into scope:
-             `use issue_21221_4::T;`
+help: possible candidate is found in another module, you can import it into scope
+   | use issue_21221_4::T;
 
 error: cannot continue compilation due to previous error
 
index a7dd494d75b0df694304d8f1b2f3279e588a7f58..0bf39dc55cee76a5b30d073f3c532380d2b7c5af 100644 (file)
@@ -4,8 +4,8 @@ error[E0404]: expected trait, found type alias `Foo`
 20 | impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
    |      ^^^ type aliases cannot be used for traits
    |
-   = help: possible better candidate is found in another module, you can import it into scope:
-             `use issue_3907::Foo;`
+help: possible better candidate is found in another module, you can import it into scope
+   | use issue_3907::Foo;
 
 error: cannot continue compilation due to previous error
 
index 940e4acabb2c16b8016f45733a08a724e6b033c9..19940ff4586d2e3baf028f71ebecec7ba96804f9 100644 (file)
@@ -8,8 +8,8 @@ error[E0423]: expected value, found struct `Z`
    |         did you mean `S`?
    |         constructor is not visible here due to private fields
    |
-   = help: possible better candidate is found in another module, you can import it into scope:
-             `use m::n::Z;`
+help: possible better candidate is found in another module, you can import it into scope
+   | use m::n::Z;
 
 error[E0423]: expected value, found struct `S`
   --> $DIR/privacy-struct-ctor.rs:36:5
@@ -20,8 +20,8 @@ error[E0423]: expected value, found struct `S`
    |     did you mean `S { /* fields */ }`?
    |     constructor is not visible here due to private fields
    |
-   = help: possible better candidate is found in another module, you can import it into scope:
-             `use m::S;`
+help: possible better candidate is found in another module, you can import it into scope
+   | use m::S;
 
 error[E0423]: expected value, found struct `xcrate::S`
   --> $DIR/privacy-struct-ctor.rs:42:5
@@ -32,8 +32,8 @@ error[E0423]: expected value, found struct `xcrate::S`
    |     did you mean `xcrate::S { /* fields */ }`?
    |     constructor is not visible here due to private fields
    |
-   = help: possible better candidate is found in another module, you can import it into scope:
-             `use m::S;`
+help: possible better candidate is found in another module, you can import it into scope
+   | use m::S;
 
 error: tuple struct `Z` is private
   --> $DIR/privacy-struct-ctor.rs:25:9
index 9dab2f77898153eea02c08e92d5ca9bc2089b71a..e53ea6a55afb5dc3a9b1028bba5f5d89312fe0e9 100644 (file)
@@ -4,8 +4,8 @@ error[E0404]: expected trait, found type parameter `Add`
 15 | impl<T: Clone, Add> Add for Foo<T> {
    |                     ^^^ not a trait
    |
-   = help: possible better candidate is found in another module, you can import it into scope:
-             `use std::ops::Add;`
+help: possible better candidate is found in another module, you can import it into scope
+   | use std::ops::Add;
 
 error: main function not found