]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #55134 - davidtwco:issue-55118, r=pnkfelix
authorbors <bors@rust-lang.org>
Wed, 17 Oct 2018 23:16:10 +0000 (23:16 +0000)
committerbors <bors@rust-lang.org>
Wed, 17 Oct 2018 23:16:10 +0000 (23:16 +0000)
NLL: change compare-mode=nll to use borrowck=migrate

Fixes #55118.

This PR is split into two parts:

The first commit is a minor change that fixes a flaw in the existing `borrowck=migrate` implementation whereby a lint that was promoted to an error in the AST borrow checker would result in the same lint from the NLL borrow checker being downgraded to a warning in migrate mode. This PR fixes this by ensuring lints are exempt from buffering in the NLL borrow checker.

The second commit updates `compiletest` to make the NLL compare mode use `-Z borrowck=migrate` rather than `-Z borrowck=mir`. The third commit shows all the test output changes that result from this.

r? @pnkfelix

136 files changed:
src/Cargo.lock
src/libcore/iter/iterator.rs
src/librustc/ich/impls_mir.rs
src/librustc/ich/impls_ty.rs
src/librustc/infer/canonical/mod.rs
src/librustc/infer/mod.rs
src/librustc/infer/nll_relate/mod.rs [new file with mode: 0644]
src/librustc/lint/context.rs
src/librustc/mir/mod.rs
src/librustc/mir/visit.rs
src/librustc/session/mod.rs
src/librustc/traits/error_reporting.rs
src/librustc/ty/context.rs
src/librustc/ty/item_path.rs
src/librustc/ty/mod.rs
src/librustc/ty/subst.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/lib.rs
src/librustc_data_structures/obligation_forest/graphviz.rs [new file with mode: 0644]
src/librustc_data_structures/obligation_forest/mod.rs
src/librustc_driver/driver.rs
src/librustc_lint/lib.rs
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/constraint_generation.rs
src/librustc_mir/borrow_check/nll/renumber.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/hair/cx/block.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_mir/hair/util.rs
src/librustc_resolve/error_reporting.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check_unused.rs
src/librustdoc/core.rs
src/librustdoc/test.rs
src/test/mir-opt/basic_assignment.rs
src/test/run-pass/issues/issue-26996.rs
src/test/run-pass/issues/issue-27021.rs
src/test/run-pass/issues/issue-49298.rs
src/test/rustdoc-ui/failed-doctest-output.stdout
src/test/ui/borrowck/assign_mutable_fields.nll.stderr
src/test/ui/borrowck/borrowck-field-sensitivity.nll.stderr
src/test/ui/borrowck/borrowck-init-in-fru.ast.nll.stderr
src/test/ui/borrowck/borrowck-init-in-fru.mir.stderr
src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr
src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr
src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.nll.stderr
src/test/ui/borrowck/borrowck-uninit-ref-chain.mir.stderr
src/test/ui/borrowck/borrowck-uninit-ref-chain.rs
src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr
src/test/ui/borrowck/borrowck-union-move.nll.stderr
src/test/ui/borrowck/borrowck-union-uninitialized.nll.stderr
src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.nll.stderr
src/test/ui/borrowck/borrowck-use-in-index-lvalue.mir.stderr
src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.nll.stderr
src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.mir.stderr
src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.nll.stderr
src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.mir.stderr
src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.ast.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.nll.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.ast.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.ast.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.ast.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.nll.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs [new file with mode: 0644]
src/test/ui/borrowck/reassignment_immutable_fields.nll.stderr
src/test/ui/borrowck/reassignment_immutable_fields_overlapping.nll.stderr
src/test/ui/borrowck/reassignment_immutable_fields_twice.nll.stderr
src/test/ui/conservative_impl_trait.rs
src/test/ui/conservative_impl_trait.stderr
src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
src/test/ui/for/for-c-in-str.rs
src/test/ui/for/for-c-in-str.stderr
src/test/ui/for/for-loop-bogosity.rs
src/test/ui/for/for-loop-bogosity.stderr
src/test/ui/issues/issue-17385.nll.stderr
src/test/ui/issues/issue-22872.rs [new file with mode: 0644]
src/test/ui/issues/issue-22872.stderr [new file with mode: 0644]
src/test/ui/issues/issue-27282-move-match-input-into-guard.rs
src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr
src/test/ui/issues/issue-28098.rs
src/test/ui/issues/issue-28098.stderr
src/test/ui/issues/issue-50480.rs
src/test/ui/issues/issue-50480.stderr
src/test/ui/iterators/array-of-ranges.rs [new file with mode: 0644]
src/test/ui/iterators/array-of-ranges.stderr [new file with mode: 0644]
src/test/ui/iterators/array.rs [new file with mode: 0644]
src/test/ui/iterators/array.stderr [new file with mode: 0644]
src/test/ui/iterators/bound.rs [new file with mode: 0644]
src/test/ui/iterators/bound.stderr [new file with mode: 0644]
src/test/ui/iterators/integral.rs [new file with mode: 0644]
src/test/ui/iterators/integral.stderr [new file with mode: 0644]
src/test/ui/iterators/ranges.rs [new file with mode: 0644]
src/test/ui/iterators/ranges.stderr [new file with mode: 0644]
src/test/ui/iterators/string.rs [new file with mode: 0644]
src/test/ui/iterators/string.stderr [new file with mode: 0644]
src/test/ui/liveness/liveness-use-after-move.nll.stderr
src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs [new file with mode: 0644]
src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr [new file with mode: 0644]
src/test/ui/nll/issue-21232-partial-init-and-use.rs [new file with mode: 0644]
src/test/ui/nll/issue-21232-partial-init-and-use.stderr [new file with mode: 0644]
src/test/ui/nll/issue-51512.rs
src/test/ui/nll/issue-51512.stderr
src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
src/test/ui/nll/user-annotations/dump-fn-method.stderr
src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr [new file with mode: 0644]
src/test/ui/rust-2018/issue-54006.stderr
src/test/ui/suggestions/suggest-remove-refs-1.rs
src/test/ui/suggestions/suggest-remove-refs-1.stderr
src/test/ui/suggestions/suggest-remove-refs-2.rs
src/test/ui/suggestions/suggest-remove-refs-2.stderr
src/test/ui/suggestions/suggest-remove-refs-3.rs
src/test/ui/suggestions/suggest-remove-refs-3.stderr
src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr
src/test/ui/use/use-after-move-self-based-on-type.nll.stderr [new file with mode: 0644]
src/test/ui/use/use-after-move-self.nll.stderr
src/test/ui/walk-struct-literal-with.nll.stderr

index 52314b0ac8998360869c5501a21dbafe6f2e536a..d519522a1b0d2fb88ef174fa70eb84f352d0fdeb 100644 (file)
@@ -2161,6 +2161,7 @@ version = "0.0.0"
 dependencies = [
  "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "graphviz 0.0.0",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
index 4ed4ddb5b656f92b83e26fd304828a723576cf1a..5b6d9e2033caa74078f804e2dbdf70d24414fb37 100644 (file)
@@ -30,11 +30,72 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item=()>) {}
 /// [impl]: index.html#implementing-iterator
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
+    on(
+        _Self="[std::ops::Range<Idx>; 1]",
+        label="if you meant to iterate between two values, remove the square brackets",
+        note="`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \
+              without the brackets: `start..end`"
+    ),
+    on(
+        _Self="[std::ops::RangeFrom<Idx>; 1]",
+        label="if you meant to iterate from a value onwards, remove the square brackets",
+        note="`[start..]` is an array of one `RangeFrom`; you might have meant to have a \
+              `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \
+              unbounded iterator will run forever unless you `break` or `return` from within the \
+              loop"
+    ),
+    on(
+        _Self="[std::ops::RangeTo<Idx>; 1]",
+        label="if you meant to iterate until a value, remove the square brackets and add a \
+               starting value",
+        note="`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \
+              `Range` without the brackets: `0..end`"
+    ),
+    on(
+        _Self="[std::ops::RangeInclusive<Idx>; 1]",
+        label="if you meant to iterate between two values, remove the square brackets",
+        note="`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \
+              `RangeInclusive` without the brackets: `start..=end`"
+    ),
+    on(
+        _Self="[std::ops::RangeToInclusive<Idx>; 1]",
+        label="if you meant to iterate until a value (including it), remove the square brackets \
+               and add a starting value",
+        note="`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \
+              bounded `RangeInclusive` without the brackets: `0..=end`"
+    ),
+    on(
+        _Self="std::ops::RangeTo<Idx>",
+        label="if you meant to iterate until a value, add a starting value",
+        note="`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
+              bounded `Range`: `0..end`"
+    ),
+    on(
+        _Self="std::ops::RangeToInclusive<Idx>",
+        label="if you meant to iterate until a value (including it), add a starting value",
+        note="`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
+              to have a bounded `RangeInclusive`: `0..=end`"
+    ),
     on(
         _Self="&str",
         label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
-    label="`{Self}` is not an iterator; maybe try calling `.iter()` or a similar method"
+    on(
+        _Self="std::string::String",
+        label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
+    ),
+    on(
+        _Self="[]",
+        label="borrow the array with `&` or call `.iter()` on it to iterate over it",
+        note="arrays are not an iterators, but slices like the following are: `&[1, 2, 3]`"
+    ),
+    on(
+        _Self="{integral}",
+        note="if you want to iterate between `start` until a value `end`, use the exclusive range \
+              syntax `start..end` or the inclusive range syntax `start..=end`"
+    ),
+    label="`{Self}` is not an iterator",
+    message="`{Self}` is not an iterator"
 )]
 #[doc(spotlight)]
 pub trait Iterator {
index 337cc0fc627649ff22a29c90a38fe34e3281c001..b660187945cdbb26cf2298f5a21fd8ab92014ffa 100644 (file)
@@ -587,3 +587,24 @@ fn hash_stable<W: StableHasherResult>(&self,
 }
 
 impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });
+
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::UserTypeAnnotation::Ty(ref ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::UserTypeAnnotation::FnDef(ref def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
index dd2c41dda640300ca78b72ed743bba2320dd9e58..e54968c5274bf130fea0d97d1baeb22f629bf69c 100644 (file)
@@ -1417,3 +1417,8 @@ fn hash_stable<W: StableHasherResult>(&self,
     Universal,
     Existential
 });
+
+impl_stable_hash_for!(struct ty::subst::UserSubsts<'tcx> { substs, user_self_ty });
+
+impl_stable_hash_for!(struct ty::subst::UserSelfTy<'tcx> { impl_def_id, self_ty });
+
index a78b5b7d072644f91a10189cc20dbd246d39cf05..1863f08930f5f55b04b1f24fd13ff6b3ecc0c375 100644 (file)
@@ -241,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// canonicalized) then represents the values that you computed
     /// for each of the canonical inputs to your query.
 
-    pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
+    pub fn instantiate_canonical_with_fresh_inference_vars<T>(
         &self,
         span: Span,
         canonical: &Canonical<'tcx, T>,
@@ -249,9 +249,6 @@ pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
     where
         T: TypeFoldable<'tcx>,
     {
-        assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created");
-        assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created");
-
         let canonical_inference_vars =
             self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
         let result = canonical.substitute(self.tcx, &canonical_inference_vars);
index ef9886e06d4be51c616beead21cf9aa749c5d7b9..fbd38ebd78cedcf8f33f60c04110d6650fa5a4e9 100644 (file)
@@ -62,6 +62,7 @@
 pub mod lattice;
 mod lexical_region_resolve;
 mod lub;
+pub mod nll_relate;
 pub mod opaque_types;
 pub mod outlives;
 pub mod region_constraints;
diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs
new file mode 100644 (file)
index 0000000..e003c19
--- /dev/null
@@ -0,0 +1,736 @@
+// 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.
+
+//! This code is kind of an alternate way of doing subtyping,
+//! supertyping, and type equating, distinct from the `combine.rs`
+//! code but very similar in its effect and design. Eventually the two
+//! ought to be merged. This code is intended for use in NLL.
+//!
+//! Here are the key differences:
+//!
+//! - This code generally assumes that there are no unbound type
+//!   inferences variables, because at NLL
+//!   time types are fully inferred up-to regions.
+//!   - Actually, to support user-given type annotations like
+//!     `Vec<_>`, we do have some measure of support for type
+//!     inference variables, but we impose some simplifying
+//!     assumptions on them that would not be suitable for the infer
+//!     code more generally. This could be fixed.
+//! - This code uses "universes" to handle higher-ranked regions and
+//!   not the leak-check. This is "more correct" than what rustc does
+//!   and we are generally migrating in this direction, but NLL had to
+//!   get there first.
+
+use crate::infer::InferCtxt;
+use crate::ty::fold::{TypeFoldable, TypeVisitor};
+use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use crate::ty::subst::Kind;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_data_structures::fx::FxHashMap;
+
+pub struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
+
+    /// Callback to use when we deduce an outlives relationship
+    delegate: D,
+
+    /// How are we relating `a` and `b`?
+    ///
+    /// - covariant means `a <: b`
+    /// - contravariant means `b <: a`
+    /// - invariant means `a == b
+    /// - bivariant means that it doesn't matter
+    ambient_variance: ty::Variance,
+
+    /// When we pass through a set of binders (e.g., when looking into
+    /// a `fn` type), we push a new bound region scope onto here.  This
+    /// will contain the instantiated region for each region in those
+    /// binders. When we then encounter a `ReLateBound(d, br)`, we can
+    /// use the debruijn index `d` to find the right scope, and then
+    /// bound region name `br` to find the specific instantiation from
+    /// within that scope. See `replace_bound_region`.
+    ///
+    /// This field stores the instantiations for late-bound regions in
+    /// the `a` type.
+    a_scopes: Vec<BoundRegionScope<'tcx>>,
+
+    /// Same as `a_scopes`, but for the `b` type.
+    b_scopes: Vec<BoundRegionScope<'tcx>>,
+}
+
+pub trait TypeRelatingDelegate<'tcx> {
+    /// Push a constraint `sup: sub` -- this constraint must be
+    /// satisfied for the two types to be related. `sub` and `sup` may
+    /// be regions from the type or new variables created through the
+    /// delegate.
+    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
+
+    /// Creates a new universe index. Used when instantiating placeholders.
+    fn create_next_universe(&mut self) -> ty::UniverseIndex;
+
+    /// Creates a new region variable representing a higher-ranked
+    /// region that is instantiated existentially. This creates an
+    /// inference variable, typically.
+    ///
+    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+    /// we will invoke this method to instantiate `'a` with an
+    /// inference variable (though `'b` would be instantiated first,
+    /// as a placeholder).
+    fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
+
+    /// Creates a new region variable representing a
+    /// higher-ranked region that is instantiated universally.
+    /// This creates a new region placeholder, typically.
+    ///
+    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+    /// we will invoke this method to instantiate `'b` with a
+    /// placeholder region.
+    fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
+
+    /// Creates a new existential region in the given universe. This
+    /// is used when handling subtyping and type variables -- if we
+    /// have that `?X <: Foo<'a>`, for example, we would instantiate
+    /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
+    /// existential variable created by this function. We would then
+    /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
+    /// relation stating that `'?0: 'a`).
+    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
+}
+
+#[derive(Clone, Debug)]
+struct ScopesAndKind<'tcx> {
+    scopes: Vec<BoundRegionScope<'tcx>>,
+    kind: Kind<'tcx>,
+}
+
+#[derive(Clone, Debug, Default)]
+struct BoundRegionScope<'tcx> {
+    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+}
+
+#[derive(Copy, Clone)]
+struct UniversallyQuantified(bool);
+
+impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    pub fn new(
+        infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
+        delegate: D,
+        ambient_variance: ty::Variance,
+    ) -> Self {
+        Self {
+            infcx,
+            delegate,
+            ambient_variance,
+            a_scopes: vec![],
+            b_scopes: vec![],
+        }
+    }
+
+    fn ambient_covariance(&self) -> bool {
+        match self.ambient_variance {
+            ty::Variance::Covariant | ty::Variance::Invariant => true,
+            ty::Variance::Contravariant | ty::Variance::Bivariant => false,
+        }
+    }
+
+    fn ambient_contravariance(&self) -> bool {
+        match self.ambient_variance {
+            ty::Variance::Contravariant | ty::Variance::Invariant => true,
+            ty::Variance::Covariant | ty::Variance::Bivariant => false,
+        }
+    }
+
+    fn create_scope(
+        &mut self,
+        value: &ty::Binder<impl TypeFoldable<'tcx>>,
+        universally_quantified: UniversallyQuantified,
+    ) -> BoundRegionScope<'tcx> {
+        let mut scope = BoundRegionScope::default();
+
+        // Create a callback that creates (via the delegate) either an
+        // existential or placeholder region as needed.
+        let mut next_region = {
+            let delegate = &mut self.delegate;
+            let mut lazy_universe = None;
+            move |br: ty::BoundRegion| {
+                if universally_quantified.0 {
+                    // The first time this closure is called, create a
+                    // new universe for the placeholders we will make
+                    // from here out.
+                    let universe = lazy_universe.unwrap_or_else(|| {
+                        let universe = delegate.create_next_universe();
+                        lazy_universe = Some(universe);
+                        universe
+                    });
+
+                    let placeholder = ty::Placeholder { universe, name: br };
+                    delegate.next_placeholder_region(placeholder)
+                } else {
+                    delegate.next_existential_region_var()
+                }
+            }
+        };
+
+        value.skip_binder().visit_with(&mut ScopeInstantiator {
+            next_region: &mut next_region,
+            target_index: ty::INNERMOST,
+            bound_region_scope: &mut scope,
+        });
+
+        scope
+    }
+
+    /// When we encounter binders during the type traversal, we record
+    /// the value to substitute for each of the things contained in
+    /// that binder. (This will be either a universal placeholder or
+    /// an existential inference variable.) Given the debruijn index
+    /// `debruijn` (and name `br`) of some binder we have now
+    /// encountered, this routine finds the value that we instantiated
+    /// the region with; to do so, it indexes backwards into the list
+    /// of ambient scopes `scopes`.
+    fn lookup_bound_region(
+        debruijn: ty::DebruijnIndex,
+        br: &ty::BoundRegion,
+        first_free_index: ty::DebruijnIndex,
+        scopes: &[BoundRegionScope<'tcx>],
+    ) -> ty::Region<'tcx> {
+        // The debruijn index is a "reverse index" into the
+        // scopes listing. So when we have INNERMOST (0), we
+        // want the *last* scope pushed, and so forth.
+        let debruijn_index = debruijn.index() - first_free_index.index();
+        let scope = &scopes[scopes.len() - debruijn_index - 1];
+
+        // Find this bound region in that scope to map to a
+        // particular region.
+        scope.map[br]
+    }
+
+    /// If `r` is a bound region, find the scope in which it is bound
+    /// (from `scopes`) and return the value that we instantiated it
+    /// with. Otherwise just return `r`.
+    fn replace_bound_region(
+        &self,
+        r: ty::Region<'tcx>,
+        first_free_index: ty::DebruijnIndex,
+        scopes: &[BoundRegionScope<'tcx>],
+    ) -> ty::Region<'tcx> {
+        if let ty::ReLateBound(debruijn, br) = r {
+            Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
+        } else {
+            r
+        }
+    }
+
+    /// Push a new outlives requirement into our output set of
+    /// constraints.
+    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+        debug!("push_outlives({:?}: {:?})", sup, sub);
+
+        self.delegate.push_outlives(sup, sub);
+    }
+
+    /// When we encounter a canonical variable `var` in the output,
+    /// equate it with `kind`. If the variable has been previously
+    /// equated, then equate it again.
+    fn relate_var(&mut self, var_ty: Ty<'tcx>, value_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty);
+
+        let generalized_ty = self.generalize_value(value_ty);
+        self.infcx
+            .force_instantiate_unchecked(var_ty, generalized_ty);
+
+        // The generalized values we extract from `canonical_var_values` have
+        // been fully instantiated and hence the set of scopes we have
+        // doesn't matter -- just to be sure, put an empty vector
+        // in there.
+        let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
+
+        // Relate the generalized kind to the original one.
+        let result = self.relate(&generalized_ty, &value_ty);
+
+        // Restore the old scopes now.
+        self.a_scopes = old_a_scopes;
+
+        debug!("equate_var: complete, result = {:?}", result);
+        result
+    }
+
+    fn generalize_value<T: Relate<'tcx>>(&mut self, value: T) -> T {
+        TypeGeneralizer {
+            tcx: self.infcx.tcx,
+            delegate: &mut self.delegate,
+            first_free_index: ty::INNERMOST,
+            ambient_variance: self.ambient_variance,
+
+            // These always correspond to an `_` or `'_` written by
+            // user, and those are always in the root universe.
+            universe: ty::UniverseIndex::ROOT,
+        }.relate(&value, &value)
+            .unwrap()
+    }
+}
+
+impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+        self.infcx.tcx
+    }
+
+    fn tag(&self) -> &'static str {
+        "nll::subtype"
+    }
+
+    fn a_is_expected(&self) -> bool {
+        true
+    }
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        variance: ty::Variance,
+        a: &T,
+        b: &T,
+    ) -> RelateResult<'tcx, T> {
+        debug!(
+            "relate_with_variance(variance={:?}, a={:?}, b={:?})",
+            variance, a, b
+        );
+
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        debug!(
+            "relate_with_variance: ambient_variance = {:?}",
+            self.ambient_variance
+        );
+
+        let r = self.relate(a, b)?;
+
+        self.ambient_variance = old_ambient_variance;
+
+        debug!("relate_with_variance: r={:?}", r);
+
+        Ok(r)
+    }
+
+    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        let a = self.infcx.shallow_resolve(a);
+        match a.sty {
+            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
+                self.relate_var(a.into(), b.into())
+            }
+
+            _ => {
+                debug!(
+                    "tys(a={:?}, b={:?}, variance={:?})",
+                    a, b, self.ambient_variance
+                );
+
+                relate::super_relate_tys(self, a, b)
+            }
+        }
+    }
+
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!(
+            "regions(a={:?}, b={:?}, variance={:?})",
+            a, b, self.ambient_variance
+        );
+
+        let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
+        let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
+
+        debug!("regions: v_a = {:?}", v_a);
+        debug!("regions: v_b = {:?}", v_b);
+
+        if self.ambient_covariance() {
+            // Covariance: a <= b. Hence, `b: a`.
+            self.push_outlives(v_b, v_a);
+        }
+
+        if self.ambient_contravariance() {
+            // Contravariant: b <= a. Hence, `a: b`.
+            self.push_outlives(v_a, v_b);
+        }
+
+        Ok(a)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: &ty::Binder<T>,
+        b: &ty::Binder<T>,
+    ) -> RelateResult<'tcx, ty::Binder<T>>
+    where
+        T: Relate<'tcx>,
+    {
+        // We want that
+        //
+        // ```
+        // for<'a> fn(&'a u32) -> &'a u32 <:
+        //   fn(&'b u32) -> &'b u32
+        // ```
+        //
+        // but not
+        //
+        // ```
+        // fn(&'a u32) -> &'a u32 <:
+        //   for<'b> fn(&'b u32) -> &'b u32
+        // ```
+        //
+        // We therefore proceed as follows:
+        //
+        // - Instantiate binders on `b` universally, yielding a universe U1.
+        // - Instantiate binders on `a` existentially in U1.
+
+        debug!(
+            "binders({:?}: {:?}, ambient_variance={:?})",
+            a, b, self.ambient_variance
+        );
+
+        if self.ambient_covariance() {
+            // Covariance, so we want `for<..> A <: for<..> B` --
+            // therefore we compare any instantiation of A (i.e., A
+            // instantiated with existentials) against every
+            // instantiation of B (i.e., B instantiated with
+            // universals).
+
+            let b_scope = self.create_scope(b, UniversallyQuantified(true));
+            let a_scope = self.create_scope(a, UniversallyQuantified(false));
+
+            debug!("binders: a_scope = {:?} (existential)", a_scope);
+            debug!("binders: b_scope = {:?} (universal)", b_scope);
+
+            self.b_scopes.push(b_scope);
+            self.a_scopes.push(a_scope);
+
+            // Reset the ambient variance to covariant. This is needed
+            // to correctly handle cases like
+            //
+            //     for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
+            //
+            // Somewhat surprisingly, these two types are actually
+            // **equal**, even though the one on the right looks more
+            // polymorphic. The reason is due to subtyping. To see it,
+            // consider that each function can call the other:
+            //
+            // - The left function can call the right with `'b` and
+            //   `'c` both equal to `'a`
+            //
+            // - The right function can call the left with `'a` set to
+            //   `{P}`, where P is the point in the CFG where the call
+            //   itself occurs. Note that `'b` and `'c` must both
+            //   include P. At the point, the call works because of
+            //   subtyping (i.e., `&'b u32 <: &{P} u32`).
+            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
+
+            self.relate(a.skip_binder(), b.skip_binder())?;
+
+            self.ambient_variance = variance;
+
+            self.b_scopes.pop().unwrap();
+            self.a_scopes.pop().unwrap();
+        }
+
+        if self.ambient_contravariance() {
+            // Contravariance, so we want `for<..> A :> for<..> B`
+            // -- therefore we compare every instantiation of A (i.e.,
+            // A instantiated with universals) against any
+            // instantiation of B (i.e., B instantiated with
+            // existentials). Opposite of above.
+
+            let a_scope = self.create_scope(a, UniversallyQuantified(true));
+            let b_scope = self.create_scope(b, UniversallyQuantified(false));
+
+            debug!("binders: a_scope = {:?} (universal)", a_scope);
+            debug!("binders: b_scope = {:?} (existential)", b_scope);
+
+            self.a_scopes.push(a_scope);
+            self.b_scopes.push(b_scope);
+
+            // Reset ambient variance to contravariance. See the
+            // covariant case above for an explanation.
+            let variance =
+                ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
+
+            self.relate(a.skip_binder(), b.skip_binder())?;
+
+            self.ambient_variance = variance;
+
+            self.b_scopes.pop().unwrap();
+            self.a_scopes.pop().unwrap();
+        }
+
+        Ok(a.clone())
+    }
+}
+
+/// When we encounter a binder like `for<..> fn(..)`, we actually have
+/// to walk the `fn` value to find all the values bound by the `for`
+/// (these are not explicitly present in the ty representation right
+/// now). This visitor handles that: it descends the type, tracking
+/// binder depth, and finds late-bound regions targeting the
+/// `for<..`>.  For each of those, it creates an entry in
+/// `bound_region_scope`.
+struct ScopeInstantiator<'me, 'tcx: 'me> {
+    next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+    // The debruijn index of the scope we are instantiating.
+    target_index: ty::DebruijnIndex,
+    bound_region_scope: &'me mut BoundRegionScope<'tcx>,
+}
+
+impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
+        self.target_index.shift_in(1);
+        t.super_visit_with(self);
+        self.target_index.shift_out(1);
+
+        false
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+        let ScopeInstantiator {
+            bound_region_scope,
+            next_region,
+            ..
+        } = self;
+
+        match r {
+            ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
+                bound_region_scope
+                    .map
+                    .entry(*br)
+                    .or_insert_with(|| next_region(*br));
+            }
+
+            _ => {}
+        }
+
+        false
+    }
+}
+
+/// The "type generalize" is used when handling inference variables.
+///
+/// The basic strategy for handling a constraint like `?A <: B` is to
+/// apply a "generalization strategy" to the type `B` -- this replaces
+/// all the lifetimes in the type `B` with fresh inference
+/// variables. (You can read more about the strategy in this [blog
+/// post].)
+///
+/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
+/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
+/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
+/// establishes `'0: 'x` as a constraint.
+///
+/// As a side-effect of this generalization procedure, we also replace
+/// all the bound regions that we have traversed with concrete values,
+/// so that the resulting generalized type is independent from the
+/// scopes.
+///
+/// [blog post]: https://is.gd/0hKvIr
+struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
+where
+    D: TypeRelatingDelegate<'tcx> + 'me,
+{
+    tcx: TyCtxt<'me, 'gcx, 'tcx>,
+
+    delegate: &'me mut D,
+
+    /// After we generalize this type, we are going to relative it to
+    /// some other type. What will be the variance at this point?
+    ambient_variance: ty::Variance,
+
+    first_free_index: ty::DebruijnIndex,
+
+    universe: ty::UniverseIndex,
+}
+
+impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+        self.tcx
+    }
+
+    fn tag(&self) -> &'static str {
+        "nll::generalizer"
+    }
+
+    fn a_is_expected(&self) -> bool {
+        true
+    }
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        variance: ty::Variance,
+        a: &T,
+        b: &T,
+    ) -> RelateResult<'tcx, T> {
+        debug!(
+            "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
+            variance, a, b
+        );
+
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        debug!(
+            "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
+            self.ambient_variance
+        );
+
+        let r = self.relate(a, b)?;
+
+        self.ambient_variance = old_ambient_variance;
+
+        debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
+
+        Ok(r)
+    }
+
+    fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        debug!("TypeGeneralizer::tys(a={:?})", a,);
+
+        match a.sty {
+            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
+                bug!(
+                    "unexpected inference variable encountered in NLL generalization: {:?}",
+                    a
+                );
+            }
+
+            _ => relate::super_relate_tys(self, a, a),
+        }
+    }
+
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        _: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!("TypeGeneralizer::regions(a={:?})", a,);
+
+        if let ty::ReLateBound(debruijn, _) = a {
+            if *debruijn < self.first_free_index {
+                return Ok(a);
+            }
+        }
+
+        // For now, we just always create a fresh region variable to
+        // replace all the regions in the source type. In the main
+        // type checker, we special case the case where the ambient
+        // variance is `Invariant` and try to avoid creating a fresh
+        // region variable, but since this comes up so much less in
+        // NLL (only when users use `_` etc) it is much less
+        // important.
+        //
+        // As an aside, since these new variables are created in
+        // `self.universe` universe, this also serves to enforce the
+        // universe scoping rules.
+        //
+        // FIXME(#54105) -- if the ambient variance is bivariant,
+        // though, we may however need to check well-formedness or
+        // risk a problem like #41677 again.
+
+        let replacement_region_vid = self.delegate.generalize_existential(self.universe);
+
+        Ok(replacement_region_vid)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: &ty::Binder<T>,
+        _: &ty::Binder<T>,
+    ) -> RelateResult<'tcx, ty::Binder<T>>
+    where
+        T: Relate<'tcx>,
+    {
+        debug!("TypeGeneralizer::binders(a={:?})", a,);
+
+        self.first_free_index.shift_in(1);
+        let result = self.relate(a.skip_binder(), a.skip_binder())?;
+        self.first_free_index.shift_out(1);
+        Ok(ty::Binder::bind(result))
+    }
+}
+
+impl InferCtxt<'_, '_, 'tcx> {
+    /// A hacky sort of method used by the NLL type-relating code:
+    ///
+    /// - `var` must be some unbound type variable.
+    /// - `value` must be a suitable type to use as its value.
+    ///
+    /// `var` will then be equated with `value`. Note that this
+    /// sidesteps a number of important checks, such as the "occurs
+    /// check" that prevents cyclic types, so it is important not to
+    /// use this method during regular type-check.
+    fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) {
+        match (&var.sty, &value.sty) {
+            (&ty::Infer(ty::TyVar(vid)), _) => {
+                let mut type_variables = self.type_variables.borrow_mut();
+
+                // In NLL, we don't have type inference variables
+                // floating around, so we can do this rather imprecise
+                // variant of the occurs-check.
+                assert!(!value.has_infer_types());
+
+                type_variables.instantiate(vid, value);
+            }
+
+            (&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => {
+                let mut int_unification_table = self.int_unification_table.borrow_mut();
+                int_unification_table
+                    .unify_var_value(vid, Some(ty::IntVarValue::IntType(value)))
+                    .unwrap_or_else(|_| {
+                        bug!("failed to unify int var `{:?}` with `{:?}`", vid, value);
+                    });
+            }
+
+            (&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => {
+                let mut int_unification_table = self.int_unification_table.borrow_mut();
+                int_unification_table
+                    .unify_var_value(vid, Some(ty::IntVarValue::UintType(value)))
+                    .unwrap_or_else(|_| {
+                        bug!("failed to unify int var `{:?}` with `{:?}`", vid, value);
+                    });
+            }
+
+            (&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => {
+                let mut float_unification_table = self.float_unification_table.borrow_mut();
+                float_unification_table
+                    .unify_var_value(vid, Some(ty::FloatVarValue(value)))
+                    .unwrap_or_else(|_| {
+                        bug!("failed to unify float var `{:?}` with `{:?}`", vid, value)
+                    });
+            }
+
+            _ => {
+                bug!(
+                    "force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}",
+                    var,
+                    value,
+                );
+            }
+        }
+    }
+}
index 0633286e39838f3a85ee41442f17dae37a4a8fa0..852af2cdaa237a536e88bfd73a85247062a3f626 100644 (file)
@@ -67,10 +67,8 @@ pub struct LintStore {
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
 
-    /// Map of registered lint groups to what lints they expand to. The first
-    /// bool is true if the lint group was added by a plugin. The optional string
-    /// is used to store the new names of deprecated lint group names.
-    lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool, Option<&'static str>)>,
+    /// Map of registered lint groups to what lints they expand to.
+    lint_groups: FxHashMap<&'static str, LintGroup>,
 
     /// Extra info for future incompatibility lints, describing the
     /// issue or RFC that caused the incompatibility.
@@ -127,6 +125,18 @@ pub enum FindLintError {
     Removed,
 }
 
+struct LintAlias {
+    name: &'static str,
+    /// Whether deprecation warnings should be suppressed for this alias.
+    silent: bool,
+}
+
+struct LintGroup {
+    lint_ids: Vec<LintId>,
+    from_plugin: bool,
+    depr: Option<LintAlias>,
+}
+
 pub enum CheckLintNameResult<'a> {
     Ok(&'a [LintId]),
     /// Lint doesn't exist
@@ -160,9 +170,15 @@ pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
     }
 
     pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
-        self.lint_groups.iter().map(|(k, v)| (*k,
-                                              v.0.clone(),
-                                              v.1)).collect()
+        self.lint_groups.iter()
+            .filter(|(_, LintGroup { depr, .. })| {
+                // Don't display deprecated lint groups.
+                depr.is_none()
+            })
+            .map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
+                (*k, lint_ids.clone(), *from_plugin)
+            })
+            .collect()
     }
 
     pub fn register_early_pass(&mut self,
@@ -245,6 +261,18 @@ pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo>
         self.future_incompatible.get(&id)
     }
 
+    pub fn register_group_alias(
+        &mut self,
+        lint_name: &'static str,
+        alias: &'static str,
+    ) {
+        self.lint_groups.insert(alias, LintGroup {
+            lint_ids: vec![],
+            from_plugin: false,
+            depr: Some(LintAlias { name: lint_name, silent: true }),
+        });
+    }
+
     pub fn register_group(
         &mut self,
         sess: Option<&Session>,
@@ -255,11 +283,18 @@ pub fn register_group(
     ) {
         let new = self
             .lint_groups
-            .insert(name, (to, from_plugin, None))
+            .insert(name, LintGroup {
+                lint_ids: to,
+                from_plugin,
+                depr: None,
+            })
             .is_none();
         if let Some(deprecated) = deprecated_name {
-            self.lint_groups
-                .insert(deprecated, (vec![], from_plugin, Some(name)));
+            self.lint_groups.insert(deprecated, LintGroup {
+                lint_ids: vec![],
+                from_plugin,
+                depr: Some(LintAlias { name, silent: false }),
+            });
         }
 
         if !new {
@@ -288,7 +323,7 @@ pub fn register_removed(&mut self, name: &str, reason: &str) {
         self.by_name.insert(name.into(), Removed(reason.into()));
     }
 
-    pub fn find_lints(&self, lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
+    pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
         match self.by_name.get(lint_name) {
             Some(&Id(lint_id)) => Ok(vec![lint_id]),
             Some(&Renamed(_, lint_id)) => {
@@ -298,9 +333,17 @@ pub fn find_lints(&self, lint_name: &str) -> Result<Vec<LintId>, FindLintError>
                 Err(FindLintError::Removed)
             },
             None => {
-                match self.lint_groups.get(lint_name) {
-                    Some(v) => Ok(v.0.clone()),
-                    None => Err(FindLintError::Removed)
+                loop {
+                    return match self.lint_groups.get(lint_name) {
+                        Some(LintGroup {lint_ids, depr, .. }) => {
+                            if let Some(LintAlias { name, .. }) = depr {
+                                lint_name = name;
+                                continue;
+                            }
+                            Ok(lint_ids.clone())
+                        }
+                        None => Err(FindLintError::Removed)
+                    };
                 }
             }
         }
@@ -366,7 +409,9 @@ pub fn check_lint_name(
             match self.by_name.get(&complete_name) {
                 None => match self.lint_groups.get(&*complete_name) {
                     None => return CheckLintNameResult::Tool(Err((None, String::new()))),
-                    Some(ids) => return CheckLintNameResult::Tool(Ok(&ids.0)),
+                    Some(LintGroup { lint_ids, .. }) => {
+                        return CheckLintNameResult::Tool(Ok(&lint_ids));
+                    }
                 },
                 Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
                 // If the lint was registered as removed or renamed by the lint tool, we don't need
@@ -390,16 +435,20 @@ pub fn check_lint_name(
                 // If neither the lint, nor the lint group exists check if there is a `clippy::`
                 // variant of this lint
                 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
-                Some(ids) => {
+                Some(LintGroup { lint_ids, depr, .. }) => {
                     // Check if the lint group name is deprecated
-                    if let Some(new_name) = ids.2 {
-                        let lint_ids = self.lint_groups.get(new_name).unwrap();
-                        return CheckLintNameResult::Tool(Err((
-                            Some(&lint_ids.0),
-                            new_name.to_string(),
-                        )));
+                    if let Some(LintAlias { name, silent }) = depr {
+                        let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
+                        return if *silent {
+                            CheckLintNameResult::Ok(&lint_ids)
+                        } else {
+                            CheckLintNameResult::Tool(Err((
+                                Some(&lint_ids),
+                                name.to_string(),
+                            )))
+                        };
                     }
-                    CheckLintNameResult::Ok(&ids.0)
+                    CheckLintNameResult::Ok(&lint_ids)
                 }
             },
             Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
@@ -416,16 +465,20 @@ fn check_tool_name_for_backwards_compat(
             None => match self.lint_groups.get(&*complete_name) {
                 // Now we are sure, that this lint exists nowhere
                 None => CheckLintNameResult::NoLint,
-                Some(ids) => {
-                    // Reaching this would be weird, but lets cover this case anyway
-                    if let Some(new_name) = ids.2 {
-                        let lint_ids = self.lint_groups.get(new_name).unwrap();
-                        return CheckLintNameResult::Tool(Err((
-                            Some(&lint_ids.0),
-                            new_name.to_string(),
-                        )));
+                Some(LintGroup { lint_ids, depr, .. }) => {
+                    // Reaching this would be weird, but let's cover this case anyway
+                    if let Some(LintAlias { name, silent }) = depr {
+                        let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
+                        return if *silent {
+                            CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
+                        } else {
+                            CheckLintNameResult::Tool(Err((
+                                Some(&lint_ids),
+                                name.to_string(),
+                            )))
+                        };
                     }
-                    CheckLintNameResult::Tool(Err((Some(&ids.0), complete_name)))
+                    CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
                 }
             },
             Some(&Id(ref id)) => {
index 2587e19b1cb6255b5aff53965e0493167b505805..9a0623ca539387c930d870092fa32fe40d268e99 100644 (file)
@@ -37,7 +37,7 @@
 use syntax::symbol::InternedString;
 use syntax_pos::{Span, DUMMY_SP};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use ty::subst::{Subst, Substs};
+use ty::subst::{CanonicalUserSubsts, Subst, Substs};
 use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt};
 use util::ppaux;
 
@@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> {
     /// e.g. via `let x: T`, then we carry that type here. The MIR
     /// borrow checker needs this information since it can affect
     /// region inference.
-    pub user_ty: Option<(CanonicalTy<'tcx>, Span)>,
+    pub user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
 
     /// Name of the local, used in debuginfo and pretty-printing.
     ///
@@ -1737,7 +1737,7 @@ pub enum StatementKind<'tcx> {
     /// - `Contravariant` -- requires that `T_y :> T`
     /// - `Invariant` -- requires that `T_y == T`
     /// - `Bivariant` -- no effect
-    AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
+    AscribeUserType(Place<'tcx>, ty::Variance, UserTypeAnnotation<'tcx>),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
@@ -1967,7 +1967,10 @@ pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
         Place::Projection(Box::new(PlaceProjection { base: self, elem }))
     }
 
-    /// Find the innermost `Local` from this `Place`.
+    /// Find the innermost `Local` from this `Place`, *if* it is either a local itself or
+    /// a single deref of a local.
+    ///
+    /// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
     pub fn local(&self) -> Option<Local> {
         match self {
             Place::Local(local) |
@@ -1978,6 +1981,15 @@ pub fn local(&self) -> Option<Local> {
             _ => None,
         }
     }
+
+    /// Find the innermost `Local` from this `Place`.
+    pub fn base_local(&self) -> Option<Local> {
+        match self {
+            Place::Local(local) => Some(*local),
+            Place::Projection(box Projection { base, elem: _ }) => base.base_local(),
+            Place::Promoted(..) | Place::Static(..) => None,
+        }
+    }
 }
 
 impl<'tcx> Debug for Place<'tcx> {
@@ -2188,7 +2200,7 @@ pub enum AggregateKind<'tcx> {
         &'tcx AdtDef,
         usize,
         &'tcx Substs<'tcx>,
-        Option<CanonicalTy<'tcx>>,
+        Option<UserTypeAnnotation<'tcx>>,
         Option<usize>,
     ),
 
@@ -2392,7 +2404,7 @@ fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
 /// this does not necessarily mean that they are "==" in Rust -- in
 /// particular one must be wary of `NaN`!
 
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct Constant<'tcx> {
     pub span: Span,
     pub ty: Ty<'tcx>,
@@ -2402,11 +2414,29 @@ pub struct Constant<'tcx> {
     /// indicate that `Vec<_>` was explicitly specified.
     ///
     /// Needed for NLL to impose user-given type constraints.
-    pub user_ty: Option<CanonicalTy<'tcx>>,
+    pub user_ty: Option<UserTypeAnnotation<'tcx>>,
 
     pub literal: &'tcx ty::Const<'tcx>,
 }
 
+/// A user-given type annotation attached to a constant.  These arise
+/// from constants that are named via paths, like `Foo::<A>::new` and
+/// so forth.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum UserTypeAnnotation<'tcx> {
+    Ty(CanonicalTy<'tcx>),
+    FnDef(DefId, CanonicalUserSubsts<'tcx>),
+    AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>),
+}
+
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
+        (UserTypeAnnotation::Ty)(ty),
+        (UserTypeAnnotation::FnDef)(def, substs),
+        (UserTypeAnnotation::AdtDef)(def, substs),
+    }
+}
+
 newtype_index! {
     pub struct Promoted {
         DEBUG_FORMAT = "promoted[{}]"
index 920dc88d6a8fc5a01f26d3879faaa79d2ca808b8..76c76404d2fd251dd3368315fcdc985fb6bdcea0 100644 (file)
@@ -10,7 +10,7 @@
 
 use hir::def_id::DefId;
 use ty::subst::Substs;
-use ty::{CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty};
+use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty};
 use mir::*;
 use syntax_pos::Span;
 
@@ -147,9 +147,9 @@ fn visit_operand(&mut self,
             fn visit_ascribe_user_ty(&mut self,
                                      place: & $($mutability)* Place<'tcx>,
                                      variance: & $($mutability)* ty::Variance,
-                                     c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                     user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
                                      location: Location) {
-                self.super_ascribe_user_ty(place, variance, c_ty, location);
+                self.super_ascribe_user_ty(place, variance, user_ty, location);
             }
 
             fn visit_place(&mut self,
@@ -214,8 +214,11 @@ fn visit_ty(&mut self,
                 self.super_ty(ty);
             }
 
-            fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
-                self.super_canonical_ty(ty);
+            fn visit_user_type_annotation(
+                &mut self,
+                ty: & $($mutability)* UserTypeAnnotation<'tcx>,
+            ) {
+                self.super_user_type_annotation(ty);
             }
 
             fn visit_region(&mut self,
@@ -390,9 +393,9 @@ fn super_statement(&mut self,
                     StatementKind::AscribeUserType(
                         ref $($mutability)* place,
                         ref $($mutability)* variance,
-                        ref $($mutability)* c_ty,
+                        ref $($mutability)* user_ty,
                     ) => {
-                        self.visit_ascribe_user_ty(place, variance, c_ty, location);
+                        self.visit_ascribe_user_ty(place, variance, user_ty, location);
                     }
                     StatementKind::Nop => {}
                 }
@@ -637,10 +640,10 @@ fn super_operand(&mut self,
             fn super_ascribe_user_ty(&mut self,
                                      place: & $($mutability)* Place<'tcx>,
                                      _variance: & $($mutability)* ty::Variance,
-                                     c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                     user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
                                      location: Location) {
                 self.visit_place(place, PlaceContext::Validate, location);
-                self.visit_user_ty(c_ty);
+                self.visit_user_type_annotation(user_ty);
             }
 
             fn super_place(&mut self,
@@ -736,7 +739,7 @@ fn super_local_decl(&mut self,
                     source_info: *source_info,
                 });
                 if let Some((user_ty, _)) = user_ty {
-                    self.visit_user_ty(user_ty);
+                    self.visit_user_type_annotation(user_ty);
                 }
                 self.visit_source_info(source_info);
                 self.visit_source_scope(visibility_scope);
@@ -783,7 +786,10 @@ fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
                 self.visit_source_scope(scope);
             }
 
-            fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) {
+            fn super_user_type_annotation(
+                &mut self,
+                _ty: & $($mutability)* UserTypeAnnotation<'tcx>,
+            ) {
             }
 
             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
index e983ddc3108d7e62a862c4d8edded6c9afd77b7a..1ca60d54f7a3d0c935d15c444bb6ffd5f2367806 100644 (file)
@@ -35,7 +35,6 @@
 use syntax::feature_gate::{self, AttributeType};
 use syntax::json::JsonEmitter;
 use syntax::source_map;
-use syntax::symbol::Symbol;
 use syntax::parse::{self, ParseSess};
 use syntax_pos::{MultiSpan, Span};
 use util::profiling::SelfProfiler;
@@ -166,10 +165,6 @@ pub struct Session {
 
     /// Cap lint level specified by a driver specifically.
     pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
-
-    /// All the crate names specified with `--extern`, and the builtin ones.
-    /// Starting with the Rust 2018 edition, absolute paths resolve in this set.
-    pub extern_prelude: FxHashSet<Symbol>,
 }
 
 pub struct PerfStats {
@@ -1137,18 +1132,6 @@ pub fn build_session_(
         CguReuseTracker::new_disabled()
     };
 
-
-    let mut extern_prelude: FxHashSet<Symbol> =
-        sopts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
-
-    // HACK(eddyb) this ignores the `no_{core,std}` attributes.
-    // FIXME(eddyb) warn (somewhere) if core/std is used with `no_{core,std}`.
-    // if !attr::contains_name(&krate.attrs, "no_core") {
-    // if !attr::contains_name(&krate.attrs, "no_std") {
-    extern_prelude.insert(Symbol::intern("core"));
-    extern_prelude.insert(Symbol::intern("std"));
-    extern_prelude.insert(Symbol::intern("meta"));
-
     let sess = Session {
         target: target_cfg,
         host,
@@ -1224,7 +1207,6 @@ pub fn build_session_(
         has_global_allocator: Once::new(),
         has_panic_handler: Once::new(),
         driver_lint_caps: FxHashMap(),
-        extern_prelude,
     };
 
     validate_commandline_args_with_session_available(&sess);
index da2173fead3707d1e34a5e2b3cb0bf9dffbb1b59..fc34a71f39221c00f2bbbbe9c030002a0d275dc8 100644 (file)
@@ -349,9 +349,8 @@ fn impl_similar_to(&self,
     fn on_unimplemented_note(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        obligation: &PredicateObligation<'tcx>) ->
-        OnUnimplementedNote
-    {
+        obligation: &PredicateObligation<'tcx>,
+    ) -> OnUnimplementedNote {
         let def_id = self.impl_similar_to(trait_ref, obligation)
             .unwrap_or(trait_ref.def_id());
         let trait_ref = *trait_ref.skip_binder();
@@ -410,6 +409,38 @@ fn on_unimplemented_note(
             flags.push(("crate_local".to_owned(), None));
         }
 
+        // Allow targetting all integers using `{integral}`, even if the exact type was resolved
+        if self_ty.is_integral() {
+            flags.push(("_Self".to_owned(), Some("{integral}".to_owned())));
+        }
+
+        if let ty::Array(aty, len) = self_ty.sty {
+            flags.push(("_Self".to_owned(), Some("[]".to_owned())));
+            flags.push(("_Self".to_owned(), Some(format!("[{}]", aty))));
+            if let Some(def) = aty.ty_adt_def() {
+                // We also want to be able to select the array's type's original
+                // signature with no type arguments resolved
+                flags.push((
+                    "_Self".to_owned(),
+                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
+                ));
+                let tcx = self.tcx;
+                if let Some(len) = len.val.try_to_scalar().and_then(|scalar| {
+                    scalar.to_usize(tcx).ok()
+                }) {
+                    flags.push((
+                        "_Self".to_owned(),
+                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
+                    ));
+                } else {
+                    flags.push((
+                        "_Self".to_owned(),
+                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
+                    ));
+                }
+            }
+        }
+
         if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
             self.tcx, trait_ref.def_id, def_id
         ) {
index ab1df2d4c3bb9f3eaece7df32fef18c18ff1da4b..1bccd05af83237f82e1b1823d57bea542ca8d20e 100644 (file)
@@ -33,7 +33,7 @@
 use middle::stability;
 use mir::{self, Mir, interpret};
 use mir::interpret::Allocation;
-use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
+use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst};
 use ty::ReprOptions;
 use traits;
 use traits::{Clause, Clauses, GoalKind, Goal, Goals};
@@ -383,7 +383,7 @@ pub struct TypeckTables<'tcx> {
     /// If the user wrote `foo.collect::<Vec<_>>()`, then the
     /// canonical substitutions would include only `for<X> { Vec<X>
     /// }`.
-    user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,
+    user_substs: ItemLocalMap<CanonicalUserSubsts<'tcx>>,
 
     adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
@@ -573,14 +573,14 @@ pub fn node_substs_opt(&self, id: hir::HirId) -> Option<&'tcx Substs<'tcx>> {
         self.node_substs.get(&id.local_id).cloned()
     }
 
-    pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalSubsts<'tcx>> {
+    pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> {
         LocalTableInContextMut {
             local_id_root: self.local_id_root,
             data: &mut self.user_substs
         }
     }
 
-    pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalSubsts<'tcx>> {
+    pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalUserSubsts<'tcx>> {
         validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
         self.user_substs.get(&id.local_id).cloned()
     }
@@ -936,8 +936,8 @@ pub struct GlobalCtxt<'tcx> {
     freevars: FxHashMap<DefId, Lrc<Vec<hir::Freevar>>>,
 
     maybe_unused_trait_imports: FxHashSet<DefId>,
-
     maybe_unused_extern_crates: Vec<(DefId, Span)>,
+    pub extern_prelude: FxHashSet<ast::Name>,
 
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1223,6 +1223,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
                     .into_iter()
                     .map(|(id, sp)| (hir.local_def_id(id), sp))
                     .collect(),
+            extern_prelude: resolutions.extern_prelude,
             hir,
             def_path_hash_to_def_id,
             queries: query::Queries::new(
index c4a25971da3ad15145514e407ad45874c7d80130..2e635c6ecdecb7475de13c383f96a1eac5f26332 100644 (file)
@@ -289,7 +289,7 @@ pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId, pushed_prelude_cra
                 // printing the `CrateRoot` so we don't prepend a `crate::` to paths.
                 let mut is_prelude_crate = false;
                 if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
-                    if self.sess.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
+                    if self.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
                         is_prelude_crate = true;
                     }
                 }
index 4135d499c58532256fd045d3e97519d45fe52aac..45a70be5842fcab3818ae82f235ab89e35e91a61 100644 (file)
@@ -36,7 +36,7 @@
 use ty::util::{IntTypeExt, Discr};
 use ty::walk::TypeWalker;
 use util::captures::Captures;
-use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
 use arena::SyncDroplessArena;
 use session::DataTypeKind;
 
@@ -141,6 +141,7 @@ pub struct Resolutions {
     pub maybe_unused_trait_imports: NodeSet,
     pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
     pub export_map: ExportMap,
+    pub extern_prelude: FxHashSet<Name>,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
index c0a42fd5854822a0b49a1d3cb97536f32d136248..64cfba7df6e7d4df3379bcedafd58acf72aaef4c 100644 (file)
@@ -323,33 +323,6 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>;
-
-impl<'gcx> CanonicalSubsts<'gcx> {
-    /// True if this represents a substitution like
-    ///
-    /// ```text
-    /// [?0, ?1, ?2]
-    /// ```
-    ///
-    /// i.e., each thing is mapped to a canonical variable with the same index.
-    pub fn is_identity(&self) -> bool {
-        self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
-            match kind.unpack() {
-                UnpackedKind::Type(ty) => match ty.sty {
-                    ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
-                    _ => false,
-                },
-
-                UnpackedKind::Lifetime(r) => match r {
-                    ty::ReCanonical(cvar1) => cvar == *cvar1,
-                    _ => false,
-                },
-            }
-        })
-    }
-}
-
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
 
 ///////////////////////////////////////////////////////////////////////////
@@ -564,3 +537,98 @@ fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'
         self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
     }
 }
+
+pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
+
+impl CanonicalUserSubsts<'tcx> {
+    /// True if this represents a substitution like
+    ///
+    /// ```text
+    /// [?0, ?1, ?2]
+    /// ```
+    ///
+    /// i.e., each thing is mapped to a canonical variable with the same index.
+    pub fn is_identity(&self) -> bool {
+        if self.value.user_self_ty.is_some() {
+            return false;
+        }
+
+        self.value.substs.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
+            match kind.unpack() {
+                UnpackedKind::Type(ty) => match ty.sty {
+                    ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
+                    _ => false,
+                },
+
+                UnpackedKind::Lifetime(r) => match r {
+                    ty::ReCanonical(cvar1) => cvar == *cvar1,
+                    _ => false,
+                },
+            }
+        })
+    }
+}
+
+/// Stores the user-given substs to reach some fully qualified path
+/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct UserSubsts<'tcx> {
+    /// The substitutions for the item as given by the user.
+    pub substs: &'tcx Substs<'tcx>,
+
+    /// The self-type, in the case of a `<T>::Item` path (when applied
+    /// to an inherent impl). See `UserSelfTy` below.
+    pub user_self_ty: Option<UserSelfTy<'tcx>>,
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserSubsts<'tcx> {
+        substs,
+        user_self_ty,
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for UserSubsts<'a> {
+        type Lifted = UserSubsts<'tcx>;
+        substs,
+        user_self_ty,
+    }
+}
+
+/// Specifies the user-given self-type. In the case of a path that
+/// refers to a member in an inherent impl, this self-type is
+/// sometimes needed to constrain the type parameters on the impl. For
+/// example, in this code:
+///
+/// ```
+/// struct Foo<T> { }
+/// impl<A> Foo<A> { fn method() { } }
+/// ```
+///
+/// when you then have a path like `<Foo<&'static u32>>::method`,
+/// this struct would carry the def-id of the impl along with the
+/// self-type `Foo<u32>`. Then we can instantiate the parameters of
+/// the impl (with the substs from `UserSubsts`) and apply those to
+/// the self-type, giving `Foo<?A>`. Finally, we unify that with
+/// the self-type here, which contains `?A` to be `&'static u32`
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct UserSelfTy<'tcx> {
+    pub impl_def_id: DefId,
+    pub self_ty: Ty<'tcx>,
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserSelfTy<'tcx> {
+        impl_def_id,
+        self_ty,
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for UserSelfTy<'a> {
+        type Lifted = UserSelfTy<'tcx>;
+        impl_def_id,
+        self_ty,
+    }
+}
index 5a72fde6a2c8a1d917fb3d6d1efebf12a31084ae..10820007629ff09a892272cd286facaed32e638d 100644 (file)
@@ -13,6 +13,7 @@ ena = "0.9.3"
 log = "0.4"
 rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
 serialize = { path = "../libserialize" }
+graphviz = { path = "../libgraphviz" }
 cfg-if = "0.1.2"
 stable_deref_trait = "1.0.0"
 parking_lot_core = "0.2.8"
index c592a5eb1e043d77c231eb5b6adf575d3150fed2..5b01892dcb37ef7e7b41b2b187e0c0f35a33aecc 100644 (file)
@@ -49,6 +49,7 @@
 extern crate rustc_rayon_core as rayon_core;
 extern crate rustc_hash;
 extern crate serialize;
+extern crate graphviz;
 extern crate smallvec;
 
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs
new file mode 100644 (file)
index 0000000..dcd448e
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2018 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.
+
+use graphviz as dot;
+use obligation_forest::{ForestObligation, ObligationForest};
+use std::env::var_os;
+use std::fs::File;
+use std::path::Path;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+
+impl<O: ForestObligation> ObligationForest<O> {
+    /// Create a graphviz representation of the obligation forest.  Given a directory this will
+    /// create files with name of the format `<counter>_<description>.gv`.  The counter is
+    /// global and is maintained internally.
+    ///
+    /// Calling this will do nothing unless the environment variable
+    /// `DUMP_OBLIGATION_FOREST_GRAPHVIZ` is defined.
+    ///
+    /// A few post-processing that you might want to do make the forest easier to visualize:
+    ///
+    ///  * `sed 's,std::[a-z]*::,,g'` â€” Deletes the `std::<package>::` prefix of paths.
+    ///  * `sed 's,"Binder(TraitPredicate(<\(.*\)>)) (\([^)]*\))","\1 (\2)",'` â€” Transforms
+    ///    `Binder(TraitPredicate(<predicate>))` into just `<predicate>`.
+    #[allow(dead_code)]
+    pub fn dump_graphviz<P: AsRef<Path>>(&self, dir: P, description: &str) {
+        static COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+        if var_os("DUMP_OBLIGATION_FOREST_GRAPHVIZ").is_none() {
+            return;
+        }
+
+        let counter = COUNTER.fetch_add(1, Ordering::AcqRel);
+
+        let file_path = dir.as_ref().join(format!("{:010}_{}.gv", counter, description));
+
+        let mut gv_file = File::create(file_path).unwrap();
+
+        dot::render(&self, &mut gv_file).unwrap();
+    }
+}
+
+impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest<O> {
+    type Node = usize;
+    type Edge = (usize, usize);
+
+    fn graph_id(&self) -> dot::Id {
+        dot::Id::new("trait_obligation_forest").unwrap()
+    }
+
+    fn node_id(&self, index: &Self::Node) -> dot::Id {
+        dot::Id::new(format!("obligation_{}", index)).unwrap()
+    }
+
+    fn node_label(&self, index: &Self::Node) -> dot::LabelText {
+        let node = &self.nodes[*index];
+        let label = format!("{:?} ({:?})", node.obligation.as_predicate(), node.state.get());
+
+        dot::LabelText::LabelStr(label.into())
+    }
+
+    fn edge_label(&self, (_index_source, _index_target): &Self::Edge) -> dot::LabelText {
+        dot::LabelText::LabelStr("".into())
+    }
+}
+
+impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest<O> {
+    type Node = usize;
+    type Edge = (usize, usize);
+
+    fn nodes(&self) -> dot::Nodes<Self::Node> {
+        (0..self.nodes.len()).collect()
+    }
+
+    fn edges(&self) -> dot::Edges<Self::Edge> {
+        (0..self.nodes.len())
+            .flat_map(|i| {
+                let node = &self.nodes[i];
+
+                node.parent.iter().map(|p| p.get())
+                    .chain(node.dependents.iter().map(|p| p.get()))
+                    .map(move |p| (p, i))
+            })
+            .collect()
+    }
+
+    fn source(&self, (s, _): &Self::Edge) -> Self::Node {
+        *s
+    }
+
+    fn target(&self, (_, t): &Self::Edge) -> Self::Node {
+        *t
+    }
+}
index f159857e7446711e1d391327990c07618712e08d..92cc398db50113488f47a0355da92012b2f43378 100644 (file)
@@ -26,6 +26,8 @@
 mod node_index;
 use self::node_index::NodeIndex;
 
+mod graphviz;
+
 #[cfg(test)]
 mod test;
 
index 223df7cbb1874cb48fe2feaf0d3d19ac15aa80b1..4f48b00c93707a7aa05dfbc7a8fd8e8fa860403b 100644 (file)
@@ -790,6 +790,7 @@ pub fn phase_2_configure_and_expand<F>(
                 trait_map: resolver.trait_map,
                 maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
                 maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
+                extern_prelude: resolver.extern_prelude,
             },
 
             analysis: ty::CrateAnalysis {
index bdf09007fdd466a51a2f0a24aeac3f1c69e4fd86..7aae22d5739e7a28d72c58f0644220f08d9a41e4 100644 (file)
@@ -84,30 +84,30 @@ macro_rules! add_early_builtin {
         ($sess:ident, $($name:ident),*,) => (
             {$(
                 store.register_early_pass($sess, false, box $name);
-                )*}
-            )
+            )*}
+        )
     }
 
     macro_rules! add_pre_expansion_builtin {
         ($sess:ident, $($name:ident),*,) => (
             {$(
                 store.register_pre_expansion_pass($sess, box $name);
-                )*}
-            )
+            )*}
+        )
     }
 
     macro_rules! add_early_builtin_with_new {
         ($sess:ident, $($name:ident),*,) => (
             {$(
                 store.register_early_pass($sess, false, box $name::new());
-                )*}
-            )
+            )*}
+        )
     }
 
     macro_rules! add_lint_group {
         ($sess:ident, $name:expr, $($lint:ident),*) => (
             store.register_group($sess, false, $name, None, vec![$(LintId::of($lint)),*]);
-            )
+        )
     }
 
     add_pre_expansion_builtin!(sess,
@@ -162,12 +162,6 @@ macro_rules! add_lint_group {
 
     store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new());
 
-    add_lint_group!(sess,
-                    "bad_style",
-                    NON_CAMEL_CASE_TYPES,
-                    NON_SNAKE_CASE,
-                    NON_UPPER_CASE_GLOBALS);
-
     add_lint_group!(sess,
                     "nonstandard_style",
                     NON_CAMEL_CASE_TYPES,
@@ -357,6 +351,8 @@ macro_rules! add_lint_group {
     store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
     store.register_removed("negate_unsigned", "cast a signed value instead");
     store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
+    // Register lint group aliases
+    store.register_group_alias("nonstandard_style", "bad_style");
     // This was renamed to raw_pointer_derive, which was then removed,
     // so it is also considered removed
     store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
index 53a190efb58355b484c19f6dee7be91fc8cf8a28..546746aa72ebb9a929c9393439882d8c253c709a 100644 (file)
@@ -51,16 +51,16 @@ pub(super) fn report_use_of_moved_or_uninitialized(
         &mut self,
         context: Context,
         desired_action: InitializationRequiringAction,
-        (place, span): (&Place<'tcx>, Span),
+        (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
         mpi: MovePathIndex,
     ) {
         debug!(
-            "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} place={:?} \
-             span={:?} mpi={:?}",
-            context, desired_action, place, span, mpi
+            "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} \
+             moved_place={:?} used_place={:?} span={:?} mpi={:?}",
+            context, desired_action, moved_place, used_place, span, mpi
         );
 
-        let use_spans = self.move_spans(place, context.loc)
+        let use_spans = self.move_spans(moved_place, context.loc)
             .or_else(|| self.borrow_spans(span, context.loc));
         let span = use_spans.args_or_use();
 
@@ -75,7 +75,7 @@ pub(super) fn report_use_of_moved_or_uninitialized(
             .collect();
 
         if move_out_indices.is_empty() {
-            let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
+            let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
 
             if self.uninitialized_error_reported
                 .contains(&root_place.clone())
@@ -89,14 +89,15 @@ pub(super) fn report_use_of_moved_or_uninitialized(
 
             self.uninitialized_error_reported.insert(root_place.clone());
 
-            let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
+            let item_msg = match self.describe_place_with_options(used_place,
+                                                                  IncludingDowncast(true)) {
                 Some(name) => format!("`{}`", name),
                 None => "value".to_owned(),
             };
             let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
                 span,
                 desired_action.as_noun(),
-                &self.describe_place_with_options(place, IncludingDowncast(true))
+                &self.describe_place_with_options(moved_place, IncludingDowncast(true))
                     .unwrap_or("_".to_owned()),
                 Origin::Mir,
             );
@@ -111,7 +112,7 @@ pub(super) fn report_use_of_moved_or_uninitialized(
         } else {
             if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
                 if self.prefixes(&reported_place, PrefixSet::All)
-                    .any(|p| p == place)
+                    .any(|p| p == used_place)
                 {
                     debug!(
                         "report_use_of_moved_or_uninitialized place: error suppressed \
@@ -128,7 +129,7 @@ pub(super) fn report_use_of_moved_or_uninitialized(
                 span,
                 desired_action.as_noun(),
                 msg,
-                self.describe_place_with_options(&place, IncludingDowncast(true)),
+                self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
                 Origin::Mir,
             );
 
@@ -181,7 +182,7 @@ pub(super) fn report_use_of_moved_or_uninitialized(
                 );
             }
 
-            if let Some(ty) = self.retrieve_type_for_place(place) {
+            if let Some(ty) = self.retrieve_type_for_place(used_place) {
                 let needs_note = match ty.sty {
                     ty::Closure(id, _) => {
                         let tables = self.infcx.tcx.typeck_tables_of(id);
@@ -219,7 +220,7 @@ pub(super) fn report_use_of_moved_or_uninitialized(
             }
 
             if let Some((_, mut old_err)) = self.move_error_reported
-                .insert(move_out_indices, (place.clone(), err))
+                .insert(move_out_indices, (used_place.clone(), err))
             {
                 // Cancel the old error so it doesn't ICE.
                 old_err.cancel();
index fe80447e4a84f4b9647f959899995a302283154e..98663270882af031482153f10840b5e83cf28b17 100644 (file)
@@ -36,9 +36,8 @@
 
 use syntax_pos::Span;
 
-use dataflow::indexes::BorrowIndex;
-use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError, MovePathIndex};
-use dataflow::move_paths::indexes::MoveOutIndex;
+use dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex};
+use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError};
 use dataflow::Borrows;
 use dataflow::DataflowResultsConsumer;
 use dataflow::FlowAtLocation;
@@ -853,6 +852,7 @@ enum InitializationRequiringAction {
     MatchOn,
     Use,
     Assignment,
+    PartialAssignment,
 }
 
 struct RootPlace<'d, 'tcx: 'd> {
@@ -868,6 +868,7 @@ fn as_noun(self) -> &'static str {
             InitializationRequiringAction::MatchOn => "use", // no good noun
             InitializationRequiringAction::Use => "use",
             InitializationRequiringAction::Assignment => "assign",
+            InitializationRequiringAction::PartialAssignment => "assign to part",
         }
     }
 
@@ -878,6 +879,7 @@ fn as_verb_in_past_tense(self) -> &'static str {
             InitializationRequiringAction::MatchOn => "matched on",
             InitializationRequiringAction::Use => "used",
             InitializationRequiringAction::Assignment => "assigned",
+            InitializationRequiringAction::PartialAssignment => "partially assigned",
         }
     }
 }
@@ -1439,10 +1441,7 @@ fn check_if_reassignment_to_immutable_state(
         debug!("check_if_reassignment_to_immutable_state({:?})", local);
 
         // Check if any of the initializiations of `local` have happened yet:
-        let mpi = self.move_data.rev_lookup.find_local(local);
-        let init_indices = &self.move_data.init_path_map[mpi];
-        let first_init_index = init_indices.iter().find(|&ii| flow_state.ever_inits.contains(*ii));
-        if let Some(&init_index) = first_init_index {
+        if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
             // And, if so, report an error.
             let init = &self.move_data.inits[init_index];
             let span = init.span(&self.mir);
@@ -1498,12 +1497,12 @@ fn check_if_full_path_is_moved(
 
         debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
         match self.move_path_closest_to(place_span.0) {
-            Ok(mpi) => {
+            Ok((prefix, mpi)) => {
                 if maybe_uninits.contains(mpi) {
                     self.report_use_of_moved_or_uninitialized(
                         context,
                         desired_action,
-                        place_span,
+                        (prefix, place_span.0, place_span.1),
                         mpi,
                     );
                     return; // don't bother finding other problems.
@@ -1561,7 +1560,7 @@ fn check_if_path_or_subpath_is_moved(
                 self.report_use_of_moved_or_uninitialized(
                     context,
                     desired_action,
-                    place_span,
+                    (place_span.0, place_span.0, place_span.1),
                     child_mpi,
                 );
                 return; // don't bother finding other problems.
@@ -1579,14 +1578,14 @@ fn check_if_path_or_subpath_is_moved(
     /// An Err result includes a tag indicated why the search failed.
     /// Currently this can only occur if the place is built off of a
     /// static variable, as we do not track those in the MoveData.
-    fn move_path_closest_to(
+    fn move_path_closest_to<'a>(
         &mut self,
-        place: &Place<'tcx>,
-    ) -> Result<MovePathIndex, NoMovePathFound> {
+        place: &'a Place<'tcx>,
+    ) -> Result<(&'a Place<'tcx>, MovePathIndex), NoMovePathFound> where 'cx: 'a {
         let mut last_prefix = place;
         for prefix in self.prefixes(place, PrefixSet::All) {
             if let Some(mpi) = self.move_path_for_place(prefix) {
-                return Ok(mpi);
+                return Ok((prefix, mpi));
             }
             last_prefix = prefix;
         }
@@ -1667,6 +1666,26 @@ fn check_if_assigned_path_is_moved(
                                     // recur further)
                                     break;
                                 }
+
+
+                                // Once `let s; s.x = V; read(s.x);`,
+                                // is allowed, remove this match arm.
+                                ty::Adt(..) | ty::Tuple(..) => {
+                                    check_parent_of_field(self, context, base, span, flow_state);
+
+                                    if let Some(local) = place.base_local() {
+                                        // rust-lang/rust#21232,
+                                        // #54499, #54986: during
+                                        // period where we reject
+                                        // partial initialization, do
+                                        // not complain about
+                                        // unnecessary `mut` on an
+                                        // attempt to do a partial
+                                        // initialization.
+                                        self.used_mut.insert(local);
+                                    }
+                                }
+
                                 _ => {}
                             }
                         }
@@ -1677,8 +1696,73 @@ fn check_if_assigned_path_is_moved(
                 }
             }
         }
-    }
 
+        fn check_parent_of_field<'cx, 'gcx, 'tcx>(this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
+                                                  context: Context,
+                                                  base: &Place<'tcx>,
+                                                  span: Span,
+                                                  flow_state: &Flows<'cx, 'gcx, 'tcx>)
+        {
+            // rust-lang/rust#21232: Until Rust allows reads from the
+            // initialized parts of partially initialized structs, we
+            // will, starting with the 2018 edition, reject attempts
+            // to write to structs that are not fully initialized.
+            //
+            // In other words, *until* we allow this:
+            //
+            // 1. `let mut s; s.x = Val; read(s.x);`
+            //
+            // we will for now disallow this:
+            //
+            // 2. `let mut s; s.x = Val;`
+            //
+            // and also this:
+            //
+            // 3. `let mut s = ...; drop(s); s.x=Val;`
+            //
+            // This does not use check_if_path_or_subpath_is_moved,
+            // because we want to *allow* reinitializations of fields:
+            // e.g. want to allow
+            //
+            // `let mut s = ...; drop(s.x); s.x=Val;`
+            //
+            // This does not use check_if_full_path_is_moved on
+            // `base`, because that would report an error about the
+            // `base` as a whole, but in this scenario we *really*
+            // want to report an error about the actual thing that was
+            // moved, which may be some prefix of `base`.
+
+            // Shallow so that we'll stop at any dereference; we'll
+            // report errors about issues with such bases elsewhere.
+            let maybe_uninits = &flow_state.uninits;
+
+            // Find the shortest uninitialized prefix you can reach
+            // without going over a Deref.
+            let mut shortest_uninit_seen = None;
+            for prefix in this.prefixes(base, PrefixSet::Shallow) {
+                let mpi = match this.move_path_for_place(prefix) {
+                    Some(mpi) => mpi, None => continue,
+                };
+
+                if maybe_uninits.contains(mpi) {
+                    debug!("check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
+                           shortest_uninit_seen, Some((prefix, mpi)));
+                    shortest_uninit_seen = Some((prefix, mpi));
+                } else {
+                    debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
+                }
+            }
+
+            if let Some((prefix, mpi)) = shortest_uninit_seen {
+                this.report_use_of_moved_or_uninitialized(
+                    context,
+                    InitializationRequiringAction::PartialAssignment,
+                    (prefix, base, span),
+                    mpi,
+                );
+            }
+        }
+    }
 
     /// Check the permissions for the given place and read or write kind
     ///
@@ -1692,13 +1776,23 @@ fn check_access_permissions(
         location: Location,
     ) -> bool {
         debug!(
-            "check_access_permissions({:?}, {:?}, {:?})",
+            "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
             place, kind, is_local_mutation_allowed
         );
 
         let error_access;
         let the_place_err;
 
+        // rust-lang/rust#21232, #54986: during period where we reject
+        // partial initialization, do not complain about mutability
+        // errors except for actual mutation (as opposed to an attempt
+        // to do a partial initialization).
+        let previously_initialized = if let Some(local) = place.base_local() {
+            self.is_local_ever_initialized(local, flow_state).is_some()
+        } else {
+            true
+        };
+
         match kind {
             Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
             | Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. }))
@@ -1791,14 +1885,33 @@ fn check_access_permissions(
         }
 
         // at this point, we have set up the error reporting state.
-        self.report_mutability_error(
-            place,
-            span,
-            the_place_err,
-            error_access,
-            location,
-        );
-        return true;
+        if previously_initialized {
+            self.report_mutability_error(
+                place,
+                span,
+                the_place_err,
+                error_access,
+                location,
+            );
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    fn is_local_ever_initialized(&self,
+                                 local: Local,
+                                 flow_state: &Flows<'cx, 'gcx, 'tcx>)
+                                 -> Option<InitIndex>
+    {
+        let mpi = self.move_data.rev_lookup.find_local(local);
+        let ii = &self.move_data.init_path_map[mpi];
+        for &index in ii {
+            if flow_state.ever_inits.contains(index) {
+                return Some(index);
+            }
+        }
+        return None;
     }
 
     /// Adds the place into the used mutable variables set
@@ -1812,18 +1925,13 @@ fn add_used_mut<'d>(
                 place: Place::Local(local),
                 is_local_mutation_allowed,
             } => {
-                if is_local_mutation_allowed != LocalMutationIsAllowed::Yes {
-                    // If the local may be initialized, and it is now currently being
-                    // mutated, then it is justified to be annotated with the `mut`
-                    // keyword, since the mutation may be a possible reassignment.
-                    let mpi = self.move_data.rev_lookup.find_local(*local);
-                    let ii = &self.move_data.init_path_map[mpi];
-                    for &index in ii {
-                        if flow_state.ever_inits.contains(index) {
-                            self.used_mut.insert(*local);
-                            break;
-                        }
-                    }
+                // If the local may have been initialized, and it is now currently being
+                // mutated, then it is justified to be annotated with the `mut`
+                // keyword, since the mutation may be a possible reassignment.
+                if is_local_mutation_allowed != LocalMutationIsAllowed::Yes &&
+                    self.is_local_ever_initialized(*local, flow_state).is_some()
+                {
+                    self.used_mut.insert(*local);
                 }
             }
             RootPlace {
@@ -1849,7 +1957,7 @@ fn add_used_mut<'d>(
         }
     }
 
-    /// Whether this value be written or borrowed mutably.
+    /// Whether this value can be written or borrowed mutably.
     /// Returns the root place if the place passed in is a projection.
     fn is_mutable<'d>(
         &self,
@@ -1927,14 +2035,14 @@ fn is_mutable<'d>(
                             ty::RawPtr(tnm) => {
                                 match tnm.mutbl {
                                     // `*const` raw pointers are not mutable
-                                    hir::MutImmutable => return Err(place),
+                                    hir::MutImmutable => Err(place),
                                     // `*mut` raw pointers are always mutable, regardless of
                                     // context. The users have to check by themselves.
                                     hir::MutMutable => {
-                                        return Ok(RootPlace {
+                                        Ok(RootPlace {
                                             place,
                                             is_local_mutation_allowed,
-                                        });
+                                        })
                                     }
                                 }
                             }
index 7e8e1b32d4d98450dfb7b121926effbfa1d4ca0e..30b263a923a7fc3f06f041cbeaa7907fbb03ac4e 100644 (file)
 use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
 use rustc::mir::{Statement, Terminator};
+use rustc::mir::UserTypeAnnotation;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
+use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid};
 
 pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
     infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
@@ -179,7 +180,7 @@ fn visit_ascribe_user_ty(
         &mut self,
         _place: &Place<'tcx>,
         _variance: &ty::Variance,
-        _c_ty: &CanonicalTy<'tcx>,
+        _user_ty: &UserTypeAnnotation<'tcx>,
         _location: Location,
     ) {
     }
index 15a60badc93e2b50ec4ae8e84585c31ec5a46459..363afb87ed909f7c5654515778f6b4d4e5629409 100644 (file)
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
+use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
+use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind, UserTypeAnnotation};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
@@ -65,12 +65,12 @@ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
         debug!("visit_ty: ty={:?}", ty);
     }
 
-    fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
-        // `user_ty` annotations represent the types that the user
+    fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) {
+        // User type annotations represent the types that the user
         // wrote in the progarm. We don't want to erase the regions
         // from these types: rather, we want to add them as
         // constraints at type-check time.
-        debug!("visit_user_ty: skipping renumber");
+        debug!("visit_user_type_annotation: skipping renumber");
     }
 
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
index e11f452e16be1e349010fe360cdc1126a5fabafe..1e79bc272e4c0ba687dc58fe02a83375fcefc63a 100644 (file)
@@ -43,7 +43,7 @@
 use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{Subst, UnpackedKind};
-use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
+use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use std::rc::Rc;
 use std::{fmt, iter};
 use syntax_pos::{Span, DUMMY_SP};
@@ -966,7 +966,7 @@ fn relate_type_and_user_type(
         &mut self,
         a: Ty<'tcx>,
         v: ty::Variance,
-        b: CanonicalTy<'tcx>,
+        b: UserTypeAnnotation<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
@@ -1837,7 +1837,7 @@ fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Loc
     /// If this rvalue supports a user-given type annotation, then
     /// extract and return it. This represents the final type of the
     /// rvalue and will be unified with the inferred type.
-    fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
+    fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotation<'tcx>> {
         match rvalue {
             Rvalue::Use(_)
             | Rvalue::Repeat(..)
index 96cc1c0afecb41e4acbdd1bae9883cbb727a8ff2..72120eb18413b92395fea2de045f943a29240bcf 100644 (file)
 
 use borrow_check::nll::constraints::OutlivesConstraint;
 use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
-use rustc::infer::canonical::{Canonical, CanonicalVarInfos, CanonicalVarValues};
+use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
-use rustc::mir::ConstraintCategory;
+use rustc::mir::{ConstraintCategory, UserTypeAnnotation};
 use rustc::traits::query::Fallible;
-use rustc::ty::fold::{TypeFoldable, TypeVisitor};
-use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc::ty::subst::Kind;
-use rustc::ty::{self, CanonicalTy, CanonicalVar, Ty, TyCtxt};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc::ty::relate::TypeRelation;
+use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts};
+use rustc::ty::{self, Ty, TypeFoldable};
+use syntax_pos::DUMMY_SP;
 
 /// Adds sufficient constraints to ensure that `a <: b`.
 pub(super) fn sub_types<'tcx>(
@@ -32,10 +30,9 @@ pub(super) fn sub_types<'tcx>(
 ) -> Fallible<()> {
     debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
     TypeRelating::new(
-        infcx.tcx,
+        infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         ty::Variance::Covariant,
-        ty::List::empty(),
     ).relate(&a, &b)?;
     Ok(())
 }
@@ -51,10 +48,9 @@ pub(super) fn eq_types<'tcx>(
 ) -> Fallible<()> {
     debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
     TypeRelating::new(
-        infcx.tcx,
+        infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         ty::Variance::Invariant,
-        ty::List::empty(),
     ).relate(&a, &b)?;
     Ok(())
 }
@@ -66,19 +62,15 @@ pub(super) fn relate_type_and_user_type<'tcx>(
     infcx: &InferCtxt<'_, '_, 'tcx>,
     a: Ty<'tcx>,
     v: ty::Variance,
-    b: CanonicalTy<'tcx>,
+    user_ty: UserTypeAnnotation<'tcx>,
     locations: Locations,
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<Ty<'tcx>> {
     debug!(
-        "sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
-        a, b, locations
+        "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
+        a, v, user_ty, locations
     );
-    let Canonical {
-        variables: b_variables,
-        value: b_value,
-    } = b;
 
     // The `TypeRelating` code assumes that the "canonical variables"
     // appear in the "a" side, so flip `Contravariant` ambient
@@ -86,108 +78,75 @@ pub(super) fn relate_type_and_user_type<'tcx>(
     let v1 = ty::Contravariant.xform(v);
 
     let mut type_relating = TypeRelating::new(
-        infcx.tcx,
+        infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         v1,
-        b_variables,
     );
-    type_relating.relate(&b_value, &a)?;
 
-    Ok(b.substitute(
-        infcx.tcx,
-        &CanonicalVarValues {
-            var_values: type_relating
-                .canonical_var_values
-                .into_iter()
-                .map(|x| x.expect("unsubstituted canonical variable"))
-                .collect(),
-        },
-    ))
-}
-
-struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    tcx: TyCtxt<'me, 'gcx, 'tcx>,
-
-    /// Callback to use when we deduce an outlives relationship
-    delegate: D,
-
-    /// How are we relating `a` and `b`?
-    ///
-    /// - covariant means `a <: b`
-    /// - contravariant means `b <: a`
-    /// - invariant means `a == b
-    /// - bivariant means that it doesn't matter
-    ambient_variance: ty::Variance,
-
-    /// When we pass through a set of binders (e.g., when looking into
-    /// a `fn` type), we push a new bound region scope onto here.  This
-    /// will contain the instantiated region for each region in those
-    /// binders. When we then encounter a `ReLateBound(d, br)`, we can
-    /// use the debruijn index `d` to find the right scope, and then
-    /// bound region name `br` to find the specific instantiation from
-    /// within that scope. See `replace_bound_region`.
-    ///
-    /// This field stores the instantiations for late-bound regions in
-    /// the `a` type.
-    a_scopes: Vec<BoundRegionScope<'tcx>>,
-
-    /// Same as `a_scopes`, but for the `b` type.
-    b_scopes: Vec<BoundRegionScope<'tcx>>,
-
-    /// As we execute, the type on the LHS *may* come from a canonical
-    /// source. In that case, we will sometimes find a constraint like
-    /// `?0 = B`, where `B` is a type from the RHS. The first time we
-    /// find that, we simply record `B` (and the list of scopes that
-    /// tells us how to *interpret* `B`). The next time we encounter
-    /// `?0`, then, we can read this value out and use it.
-    ///
-    /// One problem: these variables may be in some other universe,
-    /// how can we enforce that? I guess I could add some kind of
-    /// "minimum universe constraint" that we can feed to the NLL checker.
-    /// --> also, we know this doesn't happen
-    canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
-}
-
-trait TypeRelatingDelegate<'tcx> {
-    /// Push a constraint `sup: sub` -- this constraint must be
-    /// satisfied for the two types to be related. `sub` and `sup` may
-    /// be regions from the type or new variables created through the
-    /// delegate.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
-
-    /// Creates a new universe index. Used when instantiating placeholders.
-    fn create_next_universe(&mut self) -> ty::UniverseIndex;
+    match user_ty {
+        UserTypeAnnotation::Ty(canonical_ty) => {
+            let (ty, _) =
+                infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
+            type_relating.relate(&ty, &a)?;
+            Ok(ty)
+        }
+        UserTypeAnnotation::FnDef(def_id, canonical_substs) => {
+            let (
+                UserSubsts {
+                    substs,
+                    user_self_ty,
+                },
+                _,
+            ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
+            let ty = infcx.tcx.mk_fn_def(def_id, substs);
+
+            type_relating.relate(&ty, &a)?;
+
+            if let Some(UserSelfTy {
+                impl_def_id,
+                self_ty,
+            }) = user_self_ty
+            {
+                let impl_self_ty = infcx.tcx.type_of(impl_def_id);
+                let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs);
+
+                // There may be type variables in `substs` and hence
+                // in `impl_self_ty`, but they should all have been
+                // resolved to some fixed value during the first call
+                // to `relate`, above. Therefore, if we use
+                // `resolve_type_vars_if_possible` we should get to
+                // something without type variables. This is important
+                // because the `b` type in `relate_with_variance`
+                // below is not permitted to have inference variables.
+                let impl_self_ty = infcx.resolve_type_vars_if_possible(&impl_self_ty);
+                assert!(!impl_self_ty.has_infer_types());
+
+                type_relating.relate_with_variance(
+                    ty::Variance::Invariant,
+                    &self_ty,
+                    &impl_self_ty,
+                )?;
+            }
 
-    /// Creates a new region variable representing a higher-ranked
-    /// region that is instantiated existentially. This creates an
-    /// inference variable, typically.
-    ///
-    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
-    /// we will invoke this method to instantiate `'a` with an
-    /// inference variable (though `'b` would be instantiated first,
-    /// as a placeholder).
-    fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
+            Ok(ty)
+        }
+        UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => {
+            let (
+                UserSubsts {
+                    substs,
+                    user_self_ty,
+                },
+                _,
+            ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
 
-    /// Creates a new region variable representing a
-    /// higher-ranked region that is instantiated universally.
-    /// This creates a new region placeholder, typically.
-    ///
-    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
-    /// we will invoke this method to instantiate `'b` with a
-    /// placeholder region.
-    fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
+            // We don't extract adt-defs with a self-type.
+            assert!(user_self_ty.is_none());
 
-    /// Creates a new existential region in the given universe. This
-    /// is used when handling subtyping and type variables -- if we
-    /// have that `?X <: Foo<'a>`, for example, we would instantiate
-    /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
-    /// existential variable created by this function. We would then
-    /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
-    /// relation stating that `'?0: 'a`).
-    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
+            let ty = infcx.tcx.mk_adt(adt_def, substs);
+            type_relating.relate(&ty, &a)?;
+            Ok(ty)
+        }
+    }
 }
 
 struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
@@ -256,585 +215,3 @@ fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
         }
     }
 }
-
-#[derive(Clone, Debug)]
-struct ScopesAndKind<'tcx> {
-    scopes: Vec<BoundRegionScope<'tcx>>,
-    kind: Kind<'tcx>,
-}
-
-#[derive(Clone, Debug, Default)]
-struct BoundRegionScope<'tcx> {
-    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
-}
-
-#[derive(Copy, Clone)]
-struct UniversallyQuantified(bool);
-
-impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    fn new(
-        tcx: TyCtxt<'me, 'gcx, 'tcx>,
-        delegate: D,
-        ambient_variance: ty::Variance,
-        canonical_var_infos: CanonicalVarInfos<'tcx>,
-    ) -> Self {
-        let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
-        Self {
-            tcx,
-            delegate,
-            ambient_variance,
-            canonical_var_values,
-            a_scopes: vec![],
-            b_scopes: vec![],
-        }
-    }
-
-    fn ambient_covariance(&self) -> bool {
-        match self.ambient_variance {
-            ty::Variance::Covariant | ty::Variance::Invariant => true,
-            ty::Variance::Contravariant | ty::Variance::Bivariant => false,
-        }
-    }
-
-    fn ambient_contravariance(&self) -> bool {
-        match self.ambient_variance {
-            ty::Variance::Contravariant | ty::Variance::Invariant => true,
-            ty::Variance::Covariant | ty::Variance::Bivariant => false,
-        }
-    }
-
-    fn create_scope(
-        &mut self,
-        value: &ty::Binder<impl TypeFoldable<'tcx>>,
-        universally_quantified: UniversallyQuantified,
-    ) -> BoundRegionScope<'tcx> {
-        let mut scope = BoundRegionScope::default();
-
-        // Create a callback that creates (via the delegate) either an
-        // existential or placeholder region as needed.
-        let mut next_region = {
-            let delegate = &mut self.delegate;
-            let mut lazy_universe = None;
-            move |br: ty::BoundRegion| {
-                if universally_quantified.0 {
-                    // The first time this closure is called, create a
-                    // new universe for the placeholders we will make
-                    // from here out.
-                    let universe = lazy_universe.unwrap_or_else(|| {
-                        let universe = delegate.create_next_universe();
-                        lazy_universe = Some(universe);
-                        universe
-                    });
-
-                    let placeholder = ty::Placeholder { universe, name: br };
-                    delegate.next_placeholder_region(placeholder)
-                } else {
-                    delegate.next_existential_region_var()
-                }
-            }
-        };
-
-        value.skip_binder().visit_with(&mut ScopeInstantiator {
-            next_region: &mut next_region,
-            target_index: ty::INNERMOST,
-            bound_region_scope: &mut scope,
-        });
-
-        scope
-    }
-
-    /// When we encounter binders during the type traversal, we record
-    /// the value to substitute for each of the things contained in
-    /// that binder. (This will be either a universal placeholder or
-    /// an existential inference variable.) Given the debruijn index
-    /// `debruijn` (and name `br`) of some binder we have now
-    /// encountered, this routine finds the value that we instantiated
-    /// the region with; to do so, it indexes backwards into the list
-    /// of ambient scopes `scopes`.
-    fn lookup_bound_region(
-        debruijn: ty::DebruijnIndex,
-        br: &ty::BoundRegion,
-        first_free_index: ty::DebruijnIndex,
-        scopes: &[BoundRegionScope<'tcx>],
-    ) -> ty::Region<'tcx> {
-        // The debruijn index is a "reverse index" into the
-        // scopes listing. So when we have INNERMOST (0), we
-        // want the *last* scope pushed, and so forth.
-        let debruijn_index = debruijn.index() - first_free_index.index();
-        let scope = &scopes[scopes.len() - debruijn_index - 1];
-
-        // Find this bound region in that scope to map to a
-        // particular region.
-        scope.map[br]
-    }
-
-    /// If `r` is a bound region, find the scope in which it is bound
-    /// (from `scopes`) and return the value that we instantiated it
-    /// with. Otherwise just return `r`.
-    fn replace_bound_region(
-        &self,
-        r: ty::Region<'tcx>,
-        first_free_index: ty::DebruijnIndex,
-        scopes: &[BoundRegionScope<'tcx>],
-    ) -> ty::Region<'tcx> {
-        if let ty::ReLateBound(debruijn, br) = r {
-            Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
-        } else {
-            r
-        }
-    }
-
-    /// Push a new outlives requirement into our output set of
-    /// constraints.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
-        debug!("push_outlives({:?}: {:?})", sup, sub);
-
-        self.delegate.push_outlives(sup, sub);
-    }
-
-    /// When we encounter a canonical variable `var` in the output,
-    /// equate it with `kind`. If the variable has been previously
-    /// equated, then equate it again.
-    fn relate_var(
-        &mut self,
-        var: CanonicalVar,
-        b_kind: Kind<'tcx>,
-    ) -> RelateResult<'tcx, Kind<'tcx>> {
-        debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
-
-        let generalized_kind = match self.canonical_var_values[var] {
-            Some(v) => v,
-            None => {
-                let generalized_kind = self.generalize_value(b_kind);
-                self.canonical_var_values[var] = Some(generalized_kind);
-                generalized_kind
-            }
-        };
-
-        // The generalized values we extract from `canonical_var_values` have
-        // been fully instantiated and hence the set of scopes we have
-        // doesn't matter -- just to be sure, put an empty vector
-        // in there.
-        let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
-
-        // Relate the generalized kind to the original one.
-        let result = self.relate(&generalized_kind, &b_kind);
-
-        // Restore the old scopes now.
-        self.a_scopes = old_a_scopes;
-
-        debug!("equate_var: complete, result = {:?}", result);
-        return result;
-    }
-
-    fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
-        TypeGeneralizer {
-            tcx: self.tcx,
-            delegate: &mut self.delegate,
-            first_free_index: ty::INNERMOST,
-            ambient_variance: self.ambient_variance,
-
-            // These always correspond to an `_` or `'_` written by
-            // user, and those are always in the root universe.
-            universe: ty::UniverseIndex::ROOT,
-        }.relate(&kind, &kind)
-            .unwrap()
-    }
-}
-
-impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
-        self.tcx
-    }
-
-    fn tag(&self) -> &'static str {
-        "nll::subtype"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        variance: ty::Variance,
-        a: &T,
-        b: &T,
-    ) -> RelateResult<'tcx, T> {
-        debug!(
-            "relate_with_variance(variance={:?}, a={:?}, b={:?})",
-            variance, a, b
-        );
-
-        let old_ambient_variance = self.ambient_variance;
-        self.ambient_variance = self.ambient_variance.xform(variance);
-
-        debug!(
-            "relate_with_variance: ambient_variance = {:?}",
-            self.ambient_variance
-        );
-
-        let r = self.relate(a, b)?;
-
-        self.ambient_variance = old_ambient_variance;
-
-        debug!("relate_with_variance: r={:?}", r);
-
-        Ok(r)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        // Watch out for the case that we are matching a `?T` against the
-        // right-hand side.
-        if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
-            self.relate_var(var, b.into())?;
-            Ok(a)
-        } else {
-            debug!(
-                "tys(a={:?}, b={:?}, variance={:?})",
-                a, b, self.ambient_variance
-            );
-
-            relate::super_relate_tys(self, a, b)
-        }
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        if let ty::ReCanonical(var) = a {
-            self.relate_var(*var, b.into())?;
-            return Ok(a);
-        }
-
-        debug!(
-            "regions(a={:?}, b={:?}, variance={:?})",
-            a, b, self.ambient_variance
-        );
-
-        let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
-        let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
-
-        debug!("regions: v_a = {:?}", v_a);
-        debug!("regions: v_b = {:?}", v_b);
-
-        if self.ambient_covariance() {
-            // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a);
-        }
-
-        if self.ambient_contravariance() {
-            // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b);
-        }
-
-        Ok(a)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
-    ) -> RelateResult<'tcx, ty::Binder<T>>
-    where
-        T: Relate<'tcx>,
-    {
-        // We want that
-        //
-        // ```
-        // for<'a> fn(&'a u32) -> &'a u32 <:
-        //   fn(&'b u32) -> &'b u32
-        // ```
-        //
-        // but not
-        //
-        // ```
-        // fn(&'a u32) -> &'a u32 <:
-        //   for<'b> fn(&'b u32) -> &'b u32
-        // ```
-        //
-        // We therefore proceed as follows:
-        //
-        // - Instantiate binders on `b` universally, yielding a universe U1.
-        // - Instantiate binders on `a` existentially in U1.
-
-        debug!(
-            "binders({:?}: {:?}, ambient_variance={:?})",
-            a, b, self.ambient_variance
-        );
-
-        if self.ambient_covariance() {
-            // Covariance, so we want `for<..> A <: for<..> B` --
-            // therefore we compare any instantiation of A (i.e., A
-            // instantiated with existentials) against every
-            // instantiation of B (i.e., B instantiated with
-            // universals).
-
-            let b_scope = self.create_scope(b, UniversallyQuantified(true));
-            let a_scope = self.create_scope(a, UniversallyQuantified(false));
-
-            debug!("binders: a_scope = {:?} (existential)", a_scope);
-            debug!("binders: b_scope = {:?} (universal)", b_scope);
-
-            self.b_scopes.push(b_scope);
-            self.a_scopes.push(a_scope);
-
-            // Reset the ambient variance to covariant. This is needed
-            // to correctly handle cases like
-            //
-            //     for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
-            //
-            // Somewhat surprisingly, these two types are actually
-            // **equal**, even though the one on the right looks more
-            // polymorphic. The reason is due to subtyping. To see it,
-            // consider that each function can call the other:
-            //
-            // - The left function can call the right with `'b` and
-            //   `'c` both equal to `'a`
-            //
-            // - The right function can call the left with `'a` set to
-            //   `{P}`, where P is the point in the CFG where the call
-            //   itself occurs. Note that `'b` and `'c` must both
-            //   include P. At the point, the call works because of
-            //   subtyping (i.e., `&'b u32 <: &{P} u32`).
-            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
-
-            self.relate(a.skip_binder(), b.skip_binder())?;
-
-            self.ambient_variance = variance;
-
-            self.b_scopes.pop().unwrap();
-            self.a_scopes.pop().unwrap();
-        }
-
-        if self.ambient_contravariance() {
-            // Contravariance, so we want `for<..> A :> for<..> B`
-            // -- therefore we compare every instantiation of A (i.e.,
-            // A instantiated with universals) against any
-            // instantiation of B (i.e., B instantiated with
-            // existentials). Opposite of above.
-
-            let a_scope = self.create_scope(a, UniversallyQuantified(true));
-            let b_scope = self.create_scope(b, UniversallyQuantified(false));
-
-            debug!("binders: a_scope = {:?} (universal)", a_scope);
-            debug!("binders: b_scope = {:?} (existential)", b_scope);
-
-            self.a_scopes.push(a_scope);
-            self.b_scopes.push(b_scope);
-
-            // Reset ambient variance to contravariance. See the
-            // covariant case above for an explanation.
-            let variance =
-                ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
-
-            self.relate(a.skip_binder(), b.skip_binder())?;
-
-            self.ambient_variance = variance;
-
-            self.b_scopes.pop().unwrap();
-            self.a_scopes.pop().unwrap();
-        }
-
-        Ok(a.clone())
-    }
-}
-
-/// When we encounter a binder like `for<..> fn(..)`, we actually have
-/// to walk the `fn` value to find all the values bound by the `for`
-/// (these are not explicitly present in the ty representation right
-/// now). This visitor handles that: it descends the type, tracking
-/// binder depth, and finds late-bound regions targeting the
-/// `for<..`>.  For each of those, it creates an entry in
-/// `bound_region_scope`.
-struct ScopeInstantiator<'me, 'tcx: 'me> {
-    next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
-    // The debruijn index of the scope we are instantiating.
-    target_index: ty::DebruijnIndex,
-    bound_region_scope: &'me mut BoundRegionScope<'tcx>,
-}
-
-impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
-        self.target_index.shift_in(1);
-        t.super_visit_with(self);
-        self.target_index.shift_out(1);
-
-        false
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-        let ScopeInstantiator {
-            bound_region_scope,
-            next_region,
-            ..
-        } = self;
-
-        match r {
-            ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
-                bound_region_scope
-                    .map
-                    .entry(*br)
-                    .or_insert_with(|| next_region(*br));
-            }
-
-            _ => {}
-        }
-
-        false
-    }
-}
-
-/// The "type generalize" is used when handling inference variables.
-///
-/// The basic strategy for handling a constraint like `?A <: B` is to
-/// apply a "generalization strategy" to the type `B` -- this replaces
-/// all the lifetimes in the type `B` with fresh inference
-/// variables. (You can read more about the strategy in this [blog
-/// post].)
-///
-/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
-/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
-/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
-/// establishes `'0: 'x` as a constraint.
-///
-/// As a side-effect of this generalization procedure, we also replace
-/// all the bound regions that we have traversed with concrete values,
-/// so that the resulting generalized type is independent from the
-/// scopes.
-///
-/// [blog post]: https://is.gd/0hKvIr
-struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
-where
-    D: TypeRelatingDelegate<'tcx> + 'me,
-{
-    tcx: TyCtxt<'me, 'gcx, 'tcx>,
-
-    delegate: &'me mut D,
-
-    /// After we generalize this type, we are going to relative it to
-    /// some other type. What will be the variance at this point?
-    ambient_variance: ty::Variance,
-
-    first_free_index: ty::DebruijnIndex,
-
-    universe: ty::UniverseIndex,
-}
-
-impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
-        self.tcx
-    }
-
-    fn tag(&self) -> &'static str {
-        "nll::generalizer"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        variance: ty::Variance,
-        a: &T,
-        b: &T,
-    ) -> RelateResult<'tcx, T> {
-        debug!(
-            "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
-            variance, a, b
-        );
-
-        let old_ambient_variance = self.ambient_variance;
-        self.ambient_variance = self.ambient_variance.xform(variance);
-
-        debug!(
-            "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
-            self.ambient_variance
-        );
-
-        let r = self.relate(a, b)?;
-
-        self.ambient_variance = old_ambient_variance;
-
-        debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
-
-        Ok(r)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("TypeGeneralizer::tys(a={:?})", a,);
-
-        match a.sty {
-            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
-                bug!(
-                    "unexpected inference variable encountered in NLL generalization: {:?}",
-                    a
-                );
-            }
-
-            _ => relate::super_relate_tys(self, a, a),
-        }
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        _: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("TypeGeneralizer::regions(a={:?})", a,);
-
-        if let ty::ReLateBound(debruijn, _) = a {
-            if *debruijn < self.first_free_index {
-                return Ok(a);
-            }
-        }
-
-        // For now, we just always create a fresh region variable to
-        // replace all the regions in the source type. In the main
-        // type checker, we special case the case where the ambient
-        // variance is `Invariant` and try to avoid creating a fresh
-        // region variable, but since this comes up so much less in
-        // NLL (only when users use `_` etc) it is much less
-        // important.
-        //
-        // As an aside, since these new variables are created in
-        // `self.universe` universe, this also serves to enforce the
-        // universe scoping rules.
-        //
-        // FIXME(#54105) -- if the ambient variance is bivariant,
-        // though, we may however need to check well-formedness or
-        // risk a problem like #41677 again.
-
-        let replacement_region_vid = self.delegate.generalize_existential(self.universe);
-
-        Ok(replacement_region_vid)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: &ty::Binder<T>,
-        _: &ty::Binder<T>,
-    ) -> RelateResult<'tcx, ty::Binder<T>>
-    where
-        T: Relate<'tcx>,
-    {
-        debug!("TypeGeneralizer::binders(a={:?})", a,);
-
-        self.first_free_index.shift_in(1);
-        let result = self.relate(a.skip_binder(), a.skip_binder())?;
-        self.first_free_index.shift_out(1);
-        Ok(ty::Binder::bind(result))
-    }
-}
index 394fa4e077c1b77af64e2b3c61cb31d7371dd4c8..99c0a52a8ee36c91c56380b6d4882452f6fc9098 100644 (file)
@@ -20,7 +20,7 @@
 use hair::*;
 use rustc::hir;
 use rustc::mir::*;
-use rustc::ty::{self, CanonicalTy, Ty};
+use rustc::ty::{self, Ty};
 use rustc_data_structures::bit_set::BitSet;
 use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::{Name, NodeId};
@@ -491,7 +491,7 @@ pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span, for_guard:
     pub fn visit_bindings(
         &mut self,
         pattern: &Pattern<'tcx>,
-        mut pattern_user_ty: Option<(CanonicalTy<'tcx>, Span)>,
+        mut pattern_user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
         f: &mut impl FnMut(
             &mut Self,
             Mutability,
@@ -500,7 +500,7 @@ pub fn visit_bindings(
             NodeId,
             Span,
             Ty<'tcx>,
-            Option<(CanonicalTy<'tcx>, Span)>,
+            Option<(UserTypeAnnotation<'tcx>, Span)>,
         ),
     ) {
         match *pattern.kind {
@@ -626,7 +626,7 @@ struct Binding<'tcx> {
 struct Ascription<'tcx> {
     span: Span,
     source: Place<'tcx>,
-    user_ty: CanonicalTy<'tcx>,
+    user_ty: UserTypeAnnotation<'tcx>,
 }
 
 #[derive(Clone, Debug)]
@@ -1470,7 +1470,7 @@ fn declare_binding(
         num_patterns: usize,
         var_id: NodeId,
         var_ty: Ty<'tcx>,
-        user_var_ty: Option<(CanonicalTy<'tcx>, Span)>,
+        user_var_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
         pat_span: Span,
index 022c606a0f819784fcf13b2567dbb44401c79a61..9865867a196ca3b34f5899cf6b6bc6e7eb0ba472 100644 (file)
@@ -86,12 +86,12 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         let mut pattern = cx.pattern_from_hir(&local.pat);
 
                         if let Some(ty) = &local.ty {
-                            if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
+                            if let Some(&user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
                                 pattern = Pattern {
                                     ty: pattern.ty,
                                     span: pattern.span,
                                     kind: Box::new(PatternKind::AscribeUserType {
-                                        user_ty: *user_ty,
+                                        user_ty: UserTypeAnnotation::Ty(user_ty),
                                         user_ty_span: ty.span,
                                         subpattern: pattern
                                     })
index c969a3ef3485ff1fabe2c221add74a8473b596ca..56a29f29d685f091eb72a962320c05fda3b1dbe6 100644 (file)
@@ -295,13 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     let substs = cx.tables().node_substs(fun.hir_id);
 
                     let user_ty = cx.tables().user_substs(fun.hir_id)
-                        .map(|user_substs| {
-                            user_substs.unchecked_map(|user_substs| {
-                                // Here, we just pair an `AdtDef` with the
-                                // `user_substs`, so no new types etc are introduced.
-                                cx.tcx().mk_adt(adt_def, user_substs)
-                            })
-                        });
+                        .map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs));
 
                     let field_refs = args.iter()
                         .enumerate()
@@ -725,9 +719,15 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
         hir::ExprKind::Type(ref source, ref ty) => {
             let user_provided_tys = cx.tables.user_provided_tys();
-            let user_ty = *user_provided_tys
-                .get(ty.hir_id)
-                .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source));
+            let user_ty = UserTypeAnnotation::Ty(
+                *user_provided_tys
+                    .get(ty.hir_id)
+                    .expect(&format!(
+                        "{:?} not found in user_provided_tys, source: {:?}",
+                        ty,
+                        source,
+                    ))
+            );
             if source.is_place_expr() {
                 ExprKind::PlaceTypeAscription {
                     source: source.to_ref(),
@@ -759,11 +759,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     }
 }
 
-fn user_annotated_ty_for_def(
+fn user_substs_applied_to_def(
     cx: &mut Cx<'a, 'gcx, 'tcx>,
     hir_id: hir::HirId,
     def: &Def,
-) -> Option<CanonicalTy<'tcx>> {
+) -> Option<UserTypeAnnotation<'tcx>> {
     match def {
         // A reference to something callable -- e.g., a fn, method, or
         // a tuple-struct or tuple-variant. This has the type of a
@@ -772,11 +772,7 @@ fn user_annotated_ty_for_def(
         Def::Method(_) |
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) =>
-            Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
-                // Here, we just pair a `DefId` with the
-                // `user_substs`, so no new types etc are introduced.
-                cx.tcx().mk_fn_def(def.def_id(), user_substs)
-            })),
+            Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)),
 
         Def::Const(_def_id) |
         Def::AssociatedConst(_def_id) =>
@@ -795,7 +791,7 @@ fn user_annotated_ty_for_def(
             cx.user_substs_applied_to_ty_of_hir_id(hir_id),
 
         _ =>
-            bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
+            bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id)
     }
 }
 
@@ -815,7 +811,7 @@ fn method_callee<'a, 'gcx, 'tcx>(
                 .unwrap_or_else(|| {
                     span_bug!(expr.span, "no type-dependent def for method callee")
                 });
-            let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, def);
+            let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def);
             (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
         }
     };
@@ -882,7 +878,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) |
         Def::SelfCtor(..) => {
-            let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def);
+            let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
             ExprKind::Literal {
                 literal: ty::Const::zero_sized(
                     cx.tcx,
index e4f88e4fcc3ba2e6238314ee14aa63d813707ca8..781b6c92aa13a859b00691c0bf1baa68606b8d97 100644 (file)
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
 use rustc::ty::subst::Substs;
-use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const};
+use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
 use rustc::hir;
 use syntax::ast;
 use syntax_pos::Span;
@@ -268,7 +268,7 @@ pub enum ExprKind<'tcx> {
 
         /// Optional user-given substs: for something like `let x =
         /// Bar::<T> { ... }`.
-        user_ty: Option<CanonicalTy<'tcx>>,
+        user_ty: Option<UserTypeAnnotation<'tcx>>,
 
         fields: Vec<FieldExprRef<'tcx>>,
         base: Option<FruInfo<'tcx>>
@@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> {
     PlaceTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
     },
     ValueTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
     },
     Closure {
         closure_id: DefId,
@@ -291,13 +291,7 @@ pub enum ExprKind<'tcx> {
     },
     Literal {
         literal: &'tcx Const<'tcx>,
-
-        /// Optional user-given type: for something like
-        /// `collect::<Vec<_>>`, this would be present and would
-        /// indicate that `Vec<_>` was explicitly specified.
-        ///
-        /// Needed for NLL to impose user-given type constraints.
-        user_ty: Option<CanonicalTy<'tcx>>,
+        user_ty: Option<UserTypeAnnotation<'tcx>>,
     },
     InlineAsm {
         asm: &'tcx hir::InlineAsm,
index 0238a23895e50f3fec7cfcc2c3eb89cfe1aca6bc..cb974366a3029b7560f86c72f0379f735e00db0c 100644 (file)
@@ -20,9 +20,9 @@
 
 use hair::util::UserAnnotatedTyHelpers;
 
-use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability, UserTypeAnnotation};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
 use rustc::hir::def::{Def, CtorKind};
@@ -69,7 +69,7 @@ pub enum PatternKind<'tcx> {
     Wild,
 
     AscribeUserType {
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
         subpattern: Pattern<'tcx>,
         user_ty_span: Span,
     },
@@ -980,7 +980,7 @@ fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
 CloneImpls!{ <'tcx>
     Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>
 }
 
 impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
index 48a2e67a3dcc3a5dbd2d5c4d718731fcf9e7c37d..71cbac6b7c88e7d4d97b1735112779658f8d7b44 100644 (file)
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 use rustc::hir;
-use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};
+use rustc::mir::UserTypeAnnotation;
+use rustc::ty::{self, AdtDef, TyCtxt};
 
 crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
     fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
@@ -20,32 +21,22 @@ fn user_substs_applied_to_adt(
         &self,
         hir_id: hir::HirId,
         adt_def: &'tcx AdtDef,
-    ) -> Option<CanonicalTy<'tcx>> {
+    ) -> Option<UserTypeAnnotation<'tcx>> {
         let user_substs = self.tables().user_substs(hir_id)?;
-        Some(user_substs.unchecked_map(|user_substs| {
-            // Here, we just pair an `AdtDef` with the
-            // `user_substs`, so no new types etc are introduced.
-            self.tcx().mk_adt(adt_def, user_substs)
-        }))
+        Some(UserTypeAnnotation::AdtDef(adt_def, user_substs))
     }
 
     /// Looks up the type associated with this hir-id and applies the
     /// user-given substitutions; the hir-id must map to a suitable
     /// type.
-    fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option<CanonicalTy<'tcx>> {
+    fn user_substs_applied_to_ty_of_hir_id(
+        &self,
+        hir_id: hir::HirId,
+    ) -> Option<UserTypeAnnotation<'tcx>> {
         let user_substs = self.tables().user_substs(hir_id)?;
         match &self.tables().node_id_to_type(hir_id).sty {
-            ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| {
-                // Ok to call `unchecked_map` because we just pair an
-                // `AdtDef` with the `user_substs`, so no new types
-                // etc are introduced.
-                self.tcx().mk_adt(adt_def, user_substs)
-            })),
-            ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
-                // Here, we just pair a `DefId` with the
-                // `user_substs`, so no new types etc are introduced.
-                self.tcx().mk_fn_def(*def_id, user_substs)
-            })),
+            ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)),
+            ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)),
             sty => bug!(
                 "sty: {:?} should not have user-substs {:?} recorded ",
                 sty,
index b9194fdfc15d73d9e0986c0f3955a47620af368e..74d1ae96e794f6c486a4485028ed5c49ca157322 100644 (file)
@@ -136,7 +136,7 @@ fn make_external_crate_suggestion(
         // Need to clone else we can't call `resolve_path` without a borrow error. We also store
         // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
         // each time.
-        let external_crate_names: BTreeSet<Symbol> = self.resolver.session.extern_prelude
+        let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude
             .clone().drain().collect();
 
         // Insert a new path segment that we can replace.
index a93cc7ad7518a7715893afef241826515a097859..86fe584dc3a40fe937c4199474e1958402d8602c 100644 (file)
@@ -1360,6 +1360,7 @@ pub struct Resolver<'a, 'b: 'a> {
     graph_root: Module<'a>,
 
     prelude: Option<Module<'a>>,
+    pub extern_prelude: FxHashSet<Name>,
 
     /// n.b. This is used only for better diagnostics, not name resolution itself.
     has_self: FxHashSet<DefId>,
@@ -1676,6 +1677,19 @@ pub fn new(session: &'a Session,
         DefCollector::new(&mut definitions, Mark::root())
             .collect_root(crate_name, session.local_crate_disambiguator());
 
+        let mut extern_prelude: FxHashSet<Name> =
+            session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
+
+        if !attr::contains_name(&krate.attrs, "no_core") {
+            extern_prelude.insert(Symbol::intern("core"));
+            if !attr::contains_name(&krate.attrs, "no_std") {
+                extern_prelude.insert(Symbol::intern("std"));
+                if session.rust_2018() {
+                    extern_prelude.insert(Symbol::intern("meta"));
+                }
+            }
+        }
+
         let mut invocations = FxHashMap();
         invocations.insert(Mark::root(),
                            arenas.alloc_invocation_data(InvocationData::root(graph_root)));
@@ -1694,6 +1708,7 @@ pub fn new(session: &'a Session,
             // AST.
             graph_root,
             prelude: None,
+            extern_prelude,
 
             has_self: FxHashSet(),
             field_names: FxHashMap(),
@@ -1966,7 +1981,7 @@ fn resolve_ident_in_lexical_scope(&mut self,
 
         if !module.no_implicit_prelude {
             // `record_used` means that we don't try to load crates during speculative resolution
-            if record_used && ns == TypeNS && self.session.extern_prelude.contains(&ident.name) {
+            if record_used && ns == TypeNS && self.extern_prelude.contains(&ident.name) {
                 let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
                 let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                 self.populate_module_if_necessary(&crate_root);
@@ -4018,7 +4033,7 @@ fn lookup_typo_candidate<FilterFn>(&mut self,
                     } else {
                         // Items from the prelude
                         if !module.no_implicit_prelude {
-                            names.extend(self.session.extern_prelude.iter().cloned());
+                            names.extend(self.extern_prelude.iter().cloned());
                             if let Some(prelude) = self.prelude {
                                 add_module_candidates(prelude, &mut names);
                             }
@@ -4464,7 +4479,8 @@ fn lookup_import_candidates<FilterFn>(&mut self,
         );
 
         if self.session.rust_2018() {
-            for &name in &self.session.extern_prelude {
+            let extern_prelude_names = self.extern_prelude.clone();
+            for &name in extern_prelude_names.iter() {
                 let ident = Ident::with_empty_ctxt(name);
                 match self.crate_loader.maybe_process_path_extern(name, ident.span) {
                     Some(crate_id) => {
index c31b558dedea03452bebb1a0010ec62f01465332..6c57e6c88abebd014fae159b31b32e645b6c8291 100644 (file)
@@ -692,7 +692,7 @@ struct Flags: u8 {
                     }
                 }
                 WhereToResolve::ExternPrelude => {
-                    if use_prelude && self.session.extern_prelude.contains(&ident.name) {
+                    if use_prelude && self.extern_prelude.contains(&ident.name) {
                         let crate_id =
                             self.crate_loader.process_path_extern(ident.name, ident.span);
                         let crate_root =
index 6e9877b1ab66d2591c385991b07e7013bc6dd414..48f312ce9f27d46763e307a3babc0d10bf4e5d5f 100644 (file)
@@ -199,7 +199,7 @@ pub fn resolve_ident_in_module_unadjusted(&mut self,
                     if !(
                         ns == TypeNS &&
                         !ident.is_path_segment_keyword() &&
-                        self.session.extern_prelude.contains(&ident.name)
+                        self.extern_prelude.contains(&ident.name)
                     ) {
                         // ... unless the crate name is not in the `extern_prelude`.
                         return binding;
@@ -218,7 +218,7 @@ pub fn resolve_ident_in_module_unadjusted(&mut self,
                 } else if
                     ns == TypeNS &&
                     !ident.is_path_segment_keyword() &&
-                    self.session.extern_prelude.contains(&ident.name)
+                    self.extern_prelude.contains(&ident.name)
                 {
                     let crate_id =
                         self.crate_loader.process_path_extern(ident.name, ident.span);
@@ -736,7 +736,7 @@ struct UniformPathsCanaryResults<'a> {
         let uniform_paths_feature = self.session.features_untracked().uniform_paths;
         for ((span, _, ns), results) in uniform_paths_canaries {
             let name = results.name;
-            let external_crate = if ns == TypeNS && self.session.extern_prelude.contains(&name) {
+            let external_crate = if ns == TypeNS && self.extern_prelude.contains(&name) {
                 let crate_id =
                     self.crate_loader.process_path_extern(name, span);
                 Some(Def::Mod(DefId { krate: crate_id, index: CRATE_DEF_INDEX }))
index d840c587464ee7d0f5857b4289fd5f89b06deedf..14ce1bb4ccdee9c00c0c08ca6774d0643c3656be 100644 (file)
@@ -95,7 +95,8 @@
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
-use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs};
+use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
+                       UserSelfTy, UserSubsts};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -2136,7 +2137,10 @@ pub fn write_method_call(&self,
                             method.substs[i]
                         }
                     });
-                    self.infcx.canonicalize_response(&just_method_substs)
+                    self.infcx.canonicalize_response(&UserSubsts {
+                        substs: just_method_substs,
+                        user_self_ty: None, // not relevant here
+                    })
                 });
 
                 debug!("write_method_call: user_substs = {:?}", user_substs);
@@ -2163,7 +2167,12 @@ pub fn write_substs(&self, node_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
     /// This should be invoked **before any unifications have
     /// occurred**, so that annotations like `Vec<_>` are preserved
     /// properly.
-    pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
+    pub fn write_user_substs_from_substs(
+        &self,
+        hir_id: hir::HirId,
+        substs: &'tcx Substs<'tcx>,
+        user_self_ty: Option<UserSelfTy<'tcx>>,
+    ) {
         debug!(
             "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
             hir_id,
@@ -2172,13 +2181,16 @@ pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Su
         );
 
         if !substs.is_noop() {
-            let user_substs = self.infcx.canonicalize_response(&substs);
+            let user_substs = self.infcx.canonicalize_response(&UserSubsts {
+                substs,
+                user_self_ty,
+            });
             debug!("instantiate_value_path: user_substs = {:?}", user_substs);
             self.write_user_substs(hir_id, user_substs);
         }
     }
 
-    pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalSubsts<'tcx>) {
+    pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) {
         debug!(
             "write_user_substs({:?}, {:?}) in fcx {}",
             hir_id,
@@ -3617,7 +3629,7 @@ pub fn check_struct_path(&self,
         if let Some((variant, did, substs)) = variant {
             debug!("check_struct_path: did={:?} substs={:?}", did, substs);
             let hir_id = self.tcx.hir.node_to_hir_id(node_id);
-            self.write_user_substs_from_substs(hir_id, substs);
+            self.write_user_substs_from_substs(hir_id, substs, None);
 
             // Check bounds on type arguments used in the path.
             let bounds = self.instantiate_bounds(path_span, did, substs);
@@ -5005,7 +5017,7 @@ pub fn instantiate_value_path(&self,
 
         let path_segs = self.def_ids_for_path_segments(segments, def);
 
-        let mut ufcs_associated = None;
+        let mut user_self_ty = None;
         match def {
             Def::Method(def_id) |
             Def::AssociatedConst(def_id) => {
@@ -5014,12 +5026,20 @@ pub fn instantiate_value_path(&self,
                     ty::TraitContainer(trait_did) => {
                         callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
                     }
-                    ty::ImplContainer(_) => {}
-                }
-                if segments.len() == 1 {
-                    // `<T>::assoc` will end up here, and so can `T::assoc`.
-                    let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                    ufcs_associated = Some((container, self_ty));
+                    ty::ImplContainer(impl_def_id) => {
+                        if segments.len() == 1 {
+                            // `<T>::assoc` will end up here, and so
+                            // can `T::assoc`. It this came from an
+                            // inherent impl, we need to record the
+                            // `T` for posterity (see `UserSelfTy` for
+                            // details).
+                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+                            user_self_ty = Some(UserSelfTy {
+                                impl_def_id,
+                                self_ty,
+                            });
+                        }
+                    }
                 }
             }
             _ => {}
@@ -5173,6 +5193,10 @@ pub fn instantiate_value_path(&self,
         assert!(!substs.has_escaping_regions());
         assert!(!ty.has_escaping_regions());
 
+        // Write the "user substs" down first thing for later.
+        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
+        self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
+
         // Add all the obligations that are required, substituting and
         // normalized appropriately.
         let bounds = self.instantiate_bounds(span, def_id, &substs);
@@ -5184,7 +5208,7 @@ pub fn instantiate_value_path(&self,
         // the referenced item.
         let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
 
-        if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
+        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
             // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
             // is inherent, there is no `Self` parameter, instead, the impl needs
             // type parameters, which we can infer by unifying the provided `Self`
@@ -5208,16 +5232,8 @@ pub fn instantiate_value_path(&self,
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
         self.write_substs(hir_id, substs);
 
-        debug!(
-            "instantiate_value_path: id={:?} substs={:?}",
-            node_id,
-            substs,
-        );
-        self.write_user_substs_from_substs(hir_id, substs);
-
         (ty_substituted, new_def)
     }
 
index 62ffffab07661304f48df4af1bdd9a0baa587413..f9aa0397257b8e63de1b1e5575723d8729598509 100644 (file)
@@ -164,7 +164,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
         // If the extern crate isn't in the extern prelude,
         // there is no way it can be written as an `use`.
         let orig_name = extern_crate.orig_name.unwrap_or(item.name);
-        if !tcx.sess.extern_prelude.contains(&orig_name) {
+        if !tcx.extern_prelude.contains(&orig_name) {
             continue;
         }
 
index b85604d860be4ca48b7e98f5faf1beb50a909d2e..4a698e499a7fbd18209becabf75f22488d895fc9 100644 (file)
@@ -474,6 +474,7 @@ pub fn run_core(search_paths: SearchPaths,
             trait_map: resolver.trait_map.clone(),
             maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
             maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
+            extern_prelude: resolver.extern_prelude.clone(),
         };
         let analysis = ty::CrateAnalysis {
             access_levels: Lrc::new(AccessLevels::default()),
index dbebc3ab393977a0e226e20dabeb03607e0d757a..d74e5c2ca6401763775b1303fd7ee0529fb48deb 100644 (file)
@@ -220,7 +220,6 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
         output_types: outputs,
         externs,
         cg: config::CodegenOptions {
-            prefer_dynamic: true,
             linker,
             ..cg
         },
index 1abe63afa80144228d02b7300117f6901dbe78b0..64e574fa8aee01819b8cb037ff7fcc45dae339d2 100644 (file)
@@ -56,7 +56,7 @@ fn main() {
 //        StorageLive(_4);
 //        _4 = std::option::Option<std::boxed::Box<u32>>::None;
 //        FakeRead(ForLet, _4);
-//        AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
+//        AscribeUserType(_4, o, Ty(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }));
 //        StorageLive(_5);
 //        StorageLive(_6);
 //        _6 = move _4;
index 8d53b739da2937f4ae1cc6ac3c6933d001e4e182..83445c6657e934c32a94b532148059187396165a 100644 (file)
@@ -9,6 +9,20 @@
 // except according to those terms.
 
 // run-pass
+
+// This test is bogus (i.e. should be compile-fail) during the period
+// where #54986 is implemented and #54987 is *not* implemented. For
+// now: just ignore it under nll
+//
+// ignore-compare-mode-nll
+
+// This test is checking that the write to `c.0` (which has been moved out of)
+// won't overwrite the state in `c2`.
+//
+// That's a fine thing to test when this code is accepted by the
+// compiler, and this code is being transcribed accordingly into
+// the ui test issue-21232-partial-init-and-use.rs
+
 fn main() {
     let mut c = (1, "".to_owned());
     match c {
index addeebe9def162206d002539ea7ed0b8e38431c0..dbad8556aeb2305b0f031ab05452189a7682c9f4 100644 (file)
@@ -9,6 +9,22 @@
 // except according to those terms.
 
 // run-pass
+
+// This test is bogus (i.e. should be compile-fail) during the period
+// where #54986 is implemented and #54987 is *not* implemented. For
+// now: just ignore it under nll
+//
+// ignore-compare-mode-nll
+
+// These are variants of issue-26996.rs. In all cases we are writing
+// into a record field that has been moved out of, and ensuring that
+// such a write won't overwrite the state of the thing it was moved
+// into.
+//
+// That's a fine thing to test when this code is accepted by the
+// compiler, and this code is being transcribed accordingly into
+// the ui test issue-21232-partial-init-and-use.rs
+
 fn main() {
     let mut c = (1, (1, "".to_owned()));
     match c {
index 6463adc48a8cb9449fcc3d808bcb70c36ec3ecbd..db3c9792f3560fc532fabb9ac96db07908ea62ce 100644 (file)
 #![feature(test)]
 #![allow(unused_mut)] // under NLL we get warning about `x` below: rust-lang/rust#54499
 
+// This test is bogus (i.e. should be compile-fail) during the period
+// where #54986 is implemented and #54987 is *not* implemented. For
+// now: just ignore it under nll
+//
+// ignore-compare-mode-nll
+
+// This test is checking that the space allocated for `x.1` does not
+// overlap with `y`. (The reason why such a thing happened at one
+// point was because `x.0: Void` and thus the whole type of `x` was
+// uninhabited, and so the compiler thought it was safe to use the
+// space of `x.1` to hold `y`.)
+//
+// That's a fine thing to test when this code is accepted by the
+// compiler, and this code is being transcribed accordingly into
+// the ui test issue-21232-partial-init-and-use.rs
+
 extern crate test;
 
 enum Void {}
index dbc65569afa876bab3c59bd270d7073c4ccd9483..cf417f8d412eeb93232039968efe2b9a74ef3c44 100644 (file)
@@ -12,7 +12,7 @@ error[E0425]: cannot find value `no` in this scope
 3 | no
   | ^^ not found in this scope
 
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 26)' panicked at 'couldn't compile the test', librustdoc/test.rs:333:13
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 26)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13
 note: Run with `RUST_BACKTRACE=1` for a backtrace.
 
 ---- $DIR/failed-doctest-output.rs - SomeStruct (line 20) stdout ----
@@ -21,7 +21,7 @@ thread '$DIR/failed-doctest-output.rs - SomeStruct (line 20)' panicked at 'test
 thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
 note: Run with `RUST_BACKTRACE=1` for a backtrace.
 
-', librustdoc/test.rs:368:17
+', librustdoc/test.rs:367:17
 
 
 failures:
index 5147075347283faa1b415158e0622cc2fc24b792..59af97d9f13db6101307ab788f5a59ffd574b780 100644 (file)
@@ -1,9 +1,15 @@
-error[E0381]: use of possibly uninitialized variable: `x`
-  --> $DIR/assign_mutable_fields.rs:29:10
+error[E0381]: assign to part of possibly uninitialized variable: `x`
+  --> $DIR/assign_mutable_fields.rs:19:5
    |
-LL |     drop(x); //~ ERROR
-   |          ^ use of possibly uninitialized `x`
+LL |     x.0 = 1;
+   |     ^^^^^^^ use of possibly uninitialized `x`
 
-error: aborting due to previous error
+error[E0381]: assign to part of possibly uninitialized variable: `x`
+  --> $DIR/assign_mutable_fields.rs:27:5
+   |
+LL |     x.0 = 1;
+   |     ^^^^^^^ use of possibly uninitialized `x`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
index 6ac5fef1416afd277ba6fa8d036fd4e2907ce6a3..81d9e958e28e20710504f549718853ee920515dd 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `*x.b`
+error[E0382]: use of moved value: `x.b`
   --> $DIR/borrowck-field-sensitivity.rs:18:10
    |
 LL |     drop(x.b);
@@ -6,7 +6,7 @@ LL |     drop(x.b);
 LL |     drop(*x.b); //~ ERROR use of moved value: `*x.b`
    |          ^^^^ value used here after move
 
-error[E0382]: use of moved value: `*x.b`
+error[E0382]: use of moved value: `x.b`
   --> $DIR/borrowck-field-sensitivity.rs:24:10
    |
 LL |     let y = A { a: 3, .. x };
@@ -104,7 +104,25 @@ LL |     let _z = A { a: 4, .. x };  //~ ERROR use of moved value: `x.b`
    |
    = note: move occurs because `x.b` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
 
-error: aborting due to 11 previous errors
+error[E0381]: assign to part of possibly uninitialized variable: `x`
+  --> $DIR/borrowck-field-sensitivity.rs:91:5
+   |
+LL |     x.a = 1;
+   |     ^^^^^^^ use of possibly uninitialized `x`
+
+error[E0381]: assign to part of possibly uninitialized variable: `x`
+  --> $DIR/borrowck-field-sensitivity.rs:97:5
+   |
+LL |     x.a = 1;
+   |     ^^^^^^^ use of possibly uninitialized `x`
+
+error[E0381]: assign to part of possibly uninitialized variable: `x`
+  --> $DIR/borrowck-field-sensitivity.rs:104:5
+   |
+LL |     x.b = box 1;
+   |     ^^^ use of possibly uninitialized `x`
+
+error: aborting due to 14 previous errors
 
-Some errors occurred: E0382, E0499, E0505.
-For more information about an error, try `rustc --explain E0382`.
+Some errors occurred: E0381, E0382, E0499, E0505.
+For more information about an error, try `rustc --explain E0381`.
index cac9d890dae0f6b8aab8e8282d794ade449bc302..e602597844457ccd1c8a199e6f2e168441a77cf3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0381]: use of possibly uninitialized variable: `origin.y`
+error[E0381]: use of possibly uninitialized variable: `origin`
   --> $DIR/borrowck-init-in-fru.rs:22:5
    |
 LL |     origin = point {x: 10,.. origin};
index cac9d890dae0f6b8aab8e8282d794ade449bc302..e602597844457ccd1c8a199e6f2e168441a77cf3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0381]: use of possibly uninitialized variable: `origin.y`
+error[E0381]: use of possibly uninitialized variable: `origin`
   --> $DIR/borrowck-init-in-fru.rs:22:5
    |
 LL |     origin = point {x: 10,.. origin};
index 9c7dbd7e77884da66beaa834b51c78a86f54eb15..97eb83d0f14efedb1c37a26edfa8a6f608ab338a 100644 (file)
@@ -1,10 +1,10 @@
-error[E0381]: use of possibly uninitialized variable: `a.x`
+error[E0381]: use of possibly uninitialized variable: `a`
   --> $DIR/borrowck-uninit-field-access.rs:34:13
    |
 LL |     let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x`
    |             ^^^ use of possibly uninitialized `a.x`
 
-error[E0382]: use of moved value: `line1.origin.x`
+error[E0382]: use of moved value: `line1.origin`
   --> $DIR/borrowck-uninit-field-access.rs:39:13
    |
 LL |     let _moved = line1.origin;
index 9c7dbd7e77884da66beaa834b51c78a86f54eb15..97eb83d0f14efedb1c37a26edfa8a6f608ab338a 100644 (file)
@@ -1,10 +1,10 @@
-error[E0381]: use of possibly uninitialized variable: `a.x`
+error[E0381]: use of possibly uninitialized variable: `a`
   --> $DIR/borrowck-uninit-field-access.rs:34:13
    |
 LL |     let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x`
    |             ^^^ use of possibly uninitialized `a.x`
 
-error[E0382]: use of moved value: `line1.origin.x`
+error[E0382]: use of moved value: `line1.origin`
   --> $DIR/borrowck-uninit-field-access.rs:39:13
    |
 LL |     let _moved = line1.origin;
index bd9836e3174fba1cb22d27d2b67841d4736a0b45..e9caf7d9e1e7e5f5c3203182215eb00df3619ffc 100644 (file)
@@ -1,33 +1,45 @@
-error[E0381]: borrow of possibly uninitialized variable: `**x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-uninit-ref-chain.rs:21:14
    |
 LL |     let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
    |              ^^^^ use of possibly uninitialized `**x`
 
-error[E0381]: borrow of possibly uninitialized variable: `**x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-uninit-ref-chain.rs:25:14
    |
 LL |     let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
    |              ^^^^ use of possibly uninitialized `**x`
 
-error[E0381]: borrow of possibly uninitialized variable: `**x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-uninit-ref-chain.rs:29:14
    |
 LL |     let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
    |              ^^^^ use of possibly uninitialized `**x`
 
-error[E0381]: borrow of possibly uninitialized variable: `a.y`
-  --> $DIR/borrowck-uninit-ref-chain.rs:46:14
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:34:5
    |
-LL |     let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381]
-   |              ^^^^ use of possibly uninitialized `a.y`
+LL |     a.x = 0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^ use of possibly uninitialized `a`
 
-error[E0381]: borrow of possibly uninitialized variable: `**a.y`
-  --> $DIR/borrowck-uninit-ref-chain.rs:51:14
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:39:5
    |
-LL |     let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381]
-   |              ^^^^^^ use of possibly uninitialized `**a.y`
+LL |     a.x = &&0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^^^ use of possibly uninitialized `a`
 
-error: aborting due to 5 previous errors
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:45:5
+   |
+LL |     a.x = 0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^ use of possibly uninitialized `a`
+
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:50:5
+   |
+LL |     a.x = &&0;       //[mir]~ assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^^^ use of possibly uninitialized `a`
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
index bd9836e3174fba1cb22d27d2b67841d4736a0b45..e9caf7d9e1e7e5f5c3203182215eb00df3619ffc 100644 (file)
@@ -1,33 +1,45 @@
-error[E0381]: borrow of possibly uninitialized variable: `**x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-uninit-ref-chain.rs:21:14
    |
 LL |     let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
    |              ^^^^ use of possibly uninitialized `**x`
 
-error[E0381]: borrow of possibly uninitialized variable: `**x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-uninit-ref-chain.rs:25:14
    |
 LL |     let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
    |              ^^^^ use of possibly uninitialized `**x`
 
-error[E0381]: borrow of possibly uninitialized variable: `**x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-uninit-ref-chain.rs:29:14
    |
 LL |     let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
    |              ^^^^ use of possibly uninitialized `**x`
 
-error[E0381]: borrow of possibly uninitialized variable: `a.y`
-  --> $DIR/borrowck-uninit-ref-chain.rs:46:14
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:34:5
    |
-LL |     let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381]
-   |              ^^^^ use of possibly uninitialized `a.y`
+LL |     a.x = 0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^ use of possibly uninitialized `a`
 
-error[E0381]: borrow of possibly uninitialized variable: `**a.y`
-  --> $DIR/borrowck-uninit-ref-chain.rs:51:14
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:39:5
    |
-LL |     let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381]
-   |              ^^^^^^ use of possibly uninitialized `**a.y`
+LL |     a.x = &&0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^^^ use of possibly uninitialized `a`
 
-error: aborting due to 5 previous errors
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:45:5
+   |
+LL |     a.x = 0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^ use of possibly uninitialized `a`
+
+error[E0381]: assign to part of possibly uninitialized variable: `a`
+  --> $DIR/borrowck-uninit-ref-chain.rs:50:5
+   |
+LL |     a.x = &&0;       //[mir]~ assign to part of possibly uninitialized variable: `a` [E0381]
+   |     ^^^^^^^^^ use of possibly uninitialized `a`
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
index c52b1f0bf64c00e9be15bad37ec5a40c558a6a39..dc9d8405102eea4fba7cdff22b460d301381917d 100644 (file)
@@ -31,23 +31,23 @@ fn main() {
 
 
     let mut a: S<i32, i32>;
-    a.x = 0;
+    a.x = 0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
     let _b = &a.x; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` [E0381]
-                   // (deliberately *not* an error under MIR-borrowck)
+
 
     let mut a: S<&&i32, &&i32>;
-    a.x = &&0;
+    a.x = &&0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
     let _b = &**a.x; //[ast]~ ERROR use of possibly uninitialized variable: `**a.x` [E0381]
-                     // (deliberately *not* an error under MIR-borrowck)
+
 
 
     let mut a: S<i32, i32>;
-    a.x = 0;
+    a.x = 0;       //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381]
     let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381]
-                   //[mir]~^ ERROR [E0381]
+
 
     let mut a: S<&&i32, &&i32>;
-    a.x = &&0;
+    a.x = &&0;       //[mir]~ assign to part of possibly uninitialized variable: `a` [E0381]
     let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381]
-                     //[mir]~^ ERROR [E0381]
+
 }
index 2a877050e4c873009465e40c2aba26aee61ee641..423a44514db81525a229aac04a32ca4f7e08bf8d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `u.a`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move-assign.rs:27:21
    |
 LL |             let a = u.a;
@@ -8,7 +8,7 @@ LL |             let a = u.a; //~ ERROR use of moved value: `u.a`
    |
    = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.a`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move-assign.rs:33:21
    |
 LL |             let a = u.a;
@@ -19,7 +19,7 @@ LL |             let a = u.a; // OK
    |
    = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.a`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move-assign.rs:39:21
    |
 LL |             let a = u.a;
index 6fd6a1c82a1a0e82e88567420366f93873bb1f77..8597117dbcc8a0099d72a9268ec49b5599d375a3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `u.n1`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:36:21
    |
 LL |             let a = u.n1;
@@ -18,7 +18,7 @@ LL |             let a = u; //~ ERROR use of partially moved value: `u`
    |
    = note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.n2`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:46:21
    |
 LL |             let a = u.n1;
@@ -28,7 +28,7 @@ LL |             let a = u.n2; //~ ERROR use of moved value: `u.n2`
    |
    = note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.n`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:73:21
    |
 LL |             let a = u.n;
@@ -38,7 +38,7 @@ LL |             let a = u.n; //~ ERROR use of moved value: `u.n`
    |
    = note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.c`
+error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:78:21
    |
 LL |             let a = u.n;
index 49bc6d3263660e562c52b0db904d20c4ff9c0e77..94a7a4866e6b90f3aa304e1c6130266939a3a1e0 100644 (file)
@@ -1,9 +1,15 @@
-error[E0381]: use of possibly uninitialized variable: `u.a`
-  --> $DIR/borrowck-union-uninitialized.rs:26:18
+error[E0381]: assign to part of possibly uninitialized variable: `s`
+  --> $DIR/borrowck-union-uninitialized.rs:23:9
    |
-LL |         let ua = u.a; //~ ERROR use of possibly uninitialized variable: `u.a`
-   |                  ^^^ use of possibly uninitialized `u.a`
+LL |         s.a = 0;
+   |         ^^^^^^^ use of possibly uninitialized `s`
 
-error: aborting due to previous error
+error[E0381]: assign to part of possibly uninitialized variable: `u`
+  --> $DIR/borrowck-union-uninitialized.rs:24:9
+   |
+LL |         u.a = 0;
+   |         ^^^^^^^ use of possibly uninitialized `u`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
index d69693eb035320206604ee9ae86732ff31d4e179..502978f25be9435643614686eb486524055a9736 100644 (file)
@@ -1,10 +1,10 @@
-error[E0381]: use of possibly uninitialized variable: `*w`
+error[E0381]: use of possibly uninitialized variable: `w`
   --> $DIR/borrowck-use-in-index-lvalue.rs:16:5
    |
 LL |     w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
    |     ^^^^ use of possibly uninitialized `*w`
 
-error[E0381]: use of possibly uninitialized variable: `*w`
+error[E0381]: use of possibly uninitialized variable: `w`
   --> $DIR/borrowck-use-in-index-lvalue.rs:20:5
    |
 LL |     w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
index d69693eb035320206604ee9ae86732ff31d4e179..502978f25be9435643614686eb486524055a9736 100644 (file)
@@ -1,10 +1,10 @@
-error[E0381]: use of possibly uninitialized variable: `*w`
+error[E0381]: use of possibly uninitialized variable: `w`
   --> $DIR/borrowck-use-in-index-lvalue.rs:16:5
    |
 LL |     w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
    |     ^^^^ use of possibly uninitialized `*w`
 
-error[E0381]: use of possibly uninitialized variable: `*w`
+error[E0381]: use of possibly uninitialized variable: `w`
   --> $DIR/borrowck-use-in-index-lvalue.rs:20:5
    |
 LL |     w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
index b96379db650bb9421fec0c95259383052faf59b7..22e95ca3ad0e2ee922383395c2fa6b058361126f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0381]: borrow of possibly uninitialized variable: `*x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:22:13
    |
 LL |     let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x`
index b96379db650bb9421fec0c95259383052faf59b7..22e95ca3ad0e2ee922383395c2fa6b058361126f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0381]: borrow of possibly uninitialized variable: `*x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:22:13
    |
 LL |     let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x`
index 6eddbd934d54ebce9688f2649cf1b369656be801..11897f50910e17df1c4d6965aa57dca33c1b8519 100644 (file)
@@ -1,4 +1,4 @@
-error[E0381]: borrow of possibly uninitialized variable: `*x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-use-uninitialized-in-cast.rs:20:13
    |
 LL |     let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381]
index 6eddbd934d54ebce9688f2649cf1b369656be801..11897f50910e17df1c4d6965aa57dca33c1b8519 100644 (file)
@@ -1,4 +1,4 @@
-error[E0381]: borrow of possibly uninitialized variable: `*x`
+error[E0381]: borrow of possibly uninitialized variable: `x`
   --> $DIR/borrowck-use-uninitialized-in-cast.rs:20:13
    |
 LL |     let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381]
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.ast.stderr
new file mode 100644 (file)
index 0000000..d72cc20
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0381]: use of possibly uninitialized variable: `t.0`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:25:31
+   |
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                               ^^^ use of possibly uninitialized `t.0`
+
+error[E0381]: use of possibly uninitialized variable: `t.1`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:25:36
+   |
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                                    ^^^ use of possibly uninitialized `t.1`
+
+error[E0381]: use of possibly uninitialized variable: `u.0`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:35:31
+   |
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                               ^^^ use of possibly uninitialized `u.0`
+
+error[E0381]: use of possibly uninitialized variable: `u.1`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:35:36
+   |
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                                    ^^^ use of possibly uninitialized `u.1`
+
+error[E0381]: use of possibly uninitialized variable: `v.x`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:45:31
+   |
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                               ^^^ use of possibly uninitialized `v.x`
+
+error[E0381]: use of possibly uninitialized variable: `v.y`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:45:36
+   |
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                                    ^^^ use of possibly uninitialized `v.y`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.nll.stderr
new file mode 100644 (file)
index 0000000..ebc6c7f
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0381]: assign to part of possibly uninitialized variable: `t`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:22:9
+   |
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ use of possibly uninitialized `t`
+
+error[E0381]: assign to part of possibly uninitialized variable: `u`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:32:9
+   |
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ use of possibly uninitialized `u`
+
+error[E0381]: assign to part of possibly uninitialized variable: `v`
+  --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:42:9
+   |
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ use of possibly uninitialized `v`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs
new file mode 100644 (file)
index 0000000..4358e8e
--- /dev/null
@@ -0,0 +1,49 @@
+// revisions: ast nll
+
+// Since we are testing nll migration explicitly as a separate
+// revision, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[ast]compile-flags: -Z borrowck=ast
+//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let mut t: Tuple;
+        t.0 = S(1);
+        //[nll]~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
+        t.1 = 2;
+        println!("{:?} {:?}", t.0, t.1);
+        //[ast]~^ ERROR use of possibly uninitialized variable: `t.0` [E0381]
+        //[ast]~| ERROR use of possibly uninitialized variable: `t.1` [E0381]
+    }
+
+    {
+        let mut u: Tpair;
+        u.0 = S(1);
+        //[nll]~^ ERROR assign to part of possibly uninitialized variable: `u` [E0381]
+        u.1 = 2;
+        println!("{:?} {:?}", u.0, u.1);
+        //[ast]~^ ERROR use of possibly uninitialized variable: `u.0` [E0381]
+        //[ast]~| ERROR use of possibly uninitialized variable: `u.1` [E0381]
+    }
+
+    {
+        let mut v: Spair;
+        v.x = S(1);
+        //[nll]~^ ERROR assign to part of possibly uninitialized variable: `v` [E0381]
+        v.y = 2;
+        println!("{:?} {:?}", v.x, v.y);
+        //[ast]~^ ERROR use of possibly uninitialized variable: `v.x` [E0381]
+        //[ast]~| ERROR use of possibly uninitialized variable: `v.y` [E0381]
+    }
+}
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.ast.stderr
new file mode 100644 (file)
index 0000000..e3b5341
--- /dev/null
@@ -0,0 +1,69 @@
+error[E0382]: use of moved value: `t.0`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:25:31
+   |
+LL |         drop(t);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                               ^^^ value used here after move
+   |
+   = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `t.1`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:25:36
+   |
+LL |         drop(t);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                                    ^^^ value used here after move
+   |
+   = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `u.0`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:33:31
+   |
+LL |         drop(u);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                               ^^^ value used here after move
+   |
+   = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `u.1`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:33:36
+   |
+LL |         drop(u);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                                    ^^^ value used here after move
+   |
+   = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `v.x`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:41:31
+   |
+LL |         drop(v);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                               ^^^ value used here after move
+   |
+   = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `v.y`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:41:36
+   |
+LL |         drop(v);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                                    ^^^ value used here after move
+   |
+   = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr
new file mode 100644 (file)
index 0000000..001ed59
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0382]: assign to part of moved value: `t`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:23:9
+   |
+LL |         drop(t);
+   |              - value moved here
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `u`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9
+   |
+LL |         drop(u);
+   |              - value moved here
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `v`
+  --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:39:9
+   |
+LL |         drop(v);
+   |              - value moved here
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs
new file mode 100644 (file)
index 0000000..b6339c4
--- /dev/null
@@ -0,0 +1,43 @@
+// revisions: ast nll
+
+// Since we are testing nll migration explicitly as a separate
+// revision, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[ast]compile-flags: -Z borrowck=ast
+//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let mut t: Tuple = (S(0), 0);
+        drop(t);
+        t.0 = S(1);
+        t.1 = 2;
+        println!("{:?} {:?}", t.0, t.1);
+    }
+
+    {
+        let mut u: Tpair = Tpair(S(0), 0);
+        drop(u);
+        u.0 = S(1);
+        u.1 = 2;
+        println!("{:?} {:?}", u.0, u.1);
+    }
+
+    {
+        let mut v: Spair = Spair { x: S(0), y: 0 };
+        drop(v);
+        v.x = S(1);
+        v.y = 2;
+        println!("{:?} {:?}", v.x, v.y);
+    }
+}
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.ast.stderr
new file mode 100644 (file)
index 0000000..565272a
--- /dev/null
@@ -0,0 +1,124 @@
+error[E0594]: cannot assign to field `t.0` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9
+   |
+LL |         let t: Tuple = (S(0), 0);
+   |             - help: make this binding mutable: `mut t`
+LL |         drop(t);
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `t.1` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
+   |
+LL |         let t: Tuple = (S(0), 0);
+   |             - help: make this binding mutable: `mut t`
+...
+LL |         t.1 = 2;
+   |         ^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `u.0` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
+   |
+LL |         let u: Tpair = Tpair(S(0), 0);
+   |             - help: make this binding mutable: `mut u`
+LL |         drop(u);
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `u.1` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:42:9
+   |
+LL |         let u: Tpair = Tpair(S(0), 0);
+   |             - help: make this binding mutable: `mut u`
+...
+LL |         u.1 = 2;
+   |         ^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `v.x` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9
+   |
+LL |         let v: Spair = Spair { x: S(0), y: 0 };
+   |             - help: make this binding mutable: `mut v`
+LL |         drop(v);
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `v.y` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:57:9
+   |
+LL |         let v: Spair = Spair { x: S(0), y: 0 };
+   |             - help: make this binding mutable: `mut v`
+...
+LL |         v.y = 2;
+   |         ^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0382]: use of moved value: `t.0`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:30:31
+   |
+LL |         drop(t);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                               ^^^ value used here after move
+   |
+   = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `t.1`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:30:36
+   |
+LL |         drop(t);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                                    ^^^ value used here after move
+   |
+   = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `u.0`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:45:31
+   |
+LL |         drop(u);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                               ^^^ value used here after move
+   |
+   = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `u.1`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:45:36
+   |
+LL |         drop(u);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                                    ^^^ value used here after move
+   |
+   = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `v.x`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:60:31
+   |
+LL |         drop(v);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                               ^^^ value used here after move
+   |
+   = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `v.y`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:60:36
+   |
+LL |         drop(v);
+   |              - value moved here
+...
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                                    ^^^ value used here after move
+   |
+   = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+
+error: aborting due to 12 previous errors
+
+Some errors occurred: E0382, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr
new file mode 100644 (file)
index 0000000..d35d005
--- /dev/null
@@ -0,0 +1,88 @@
+error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9
+   |
+LL |         let t: Tuple = (S(0), 0);
+   |             - help: consider changing this to be mutable: `mut t`
+LL |         drop(t);
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ cannot assign
+
+error[E0382]: assign to part of moved value: `t`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9
+   |
+LL |         drop(t);
+   |              - value moved here
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
+
+error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
+   |
+LL |         let t: Tuple = (S(0), 0);
+   |             - help: consider changing this to be mutable: `mut t`
+...
+LL |         t.1 = 2;
+   |         ^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
+   |
+LL |         let u: Tpair = Tpair(S(0), 0);
+   |             - help: consider changing this to be mutable: `mut u`
+LL |         drop(u);
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ cannot assign
+
+error[E0382]: assign to part of moved value: `u`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
+   |
+LL |         drop(u);
+   |              - value moved here
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
+
+error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:42:9
+   |
+LL |         let u: Tpair = Tpair(S(0), 0);
+   |             - help: consider changing this to be mutable: `mut u`
+...
+LL |         u.1 = 2;
+   |         ^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9
+   |
+LL |         let v: Spair = Spair { x: S(0), y: 0 };
+   |             - help: consider changing this to be mutable: `mut v`
+LL |         drop(v);
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ cannot assign
+
+error[E0382]: assign to part of moved value: `v`
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9
+   |
+LL |         drop(v);
+   |              - value moved here
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
+
+error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
+  --> $DIR/issue-54499-field-mutation-of-moved-out.rs:57:9
+   |
+LL |         let v: Spair = Spair { x: S(0), y: 0 };
+   |             - help: consider changing this to be mutable: `mut v`
+...
+LL |         v.y = 2;
+   |         ^^^^^^^ cannot assign
+
+error: aborting due to 9 previous errors
+
+Some errors occurred: E0382, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs
new file mode 100644 (file)
index 0000000..b19dcd6
--- /dev/null
@@ -0,0 +1,64 @@
+// revisions: ast nll
+
+// Since we are testing nll migration explicitly as a separate
+// revision, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[ast]compile-flags: -Z borrowck=ast
+//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let t: Tuple = (S(0), 0);
+        drop(t);
+        t.0 = S(1);
+        //[ast]~^ ERROR cannot assign to field `t.0` of immutable binding [E0594]
+        //[nll]~^^ ERROR assign to part of moved value: `t` [E0382]
+        //[nll]~| ERROR cannot assign to `t.0`, as `t` is not declared as mutable [E0594]
+        t.1 = 2;
+        //[ast]~^ ERROR cannot assign to field `t.1` of immutable binding [E0594]
+        //[nll]~^^ ERROR cannot assign to `t.1`, as `t` is not declared as mutable [E0594]
+        println!("{:?} {:?}", t.0, t.1);
+        //[ast]~^ ERROR use of moved value: `t.0` [E0382]
+        //[ast]~| ERROR use of moved value: `t.1` [E0382]
+    }
+
+    {
+        let u: Tpair = Tpair(S(0), 0);
+        drop(u);
+        u.0 = S(1);
+        //[ast]~^ ERROR cannot assign to field `u.0` of immutable binding [E0594]
+        //[nll]~^^ ERROR assign to part of moved value: `u` [E0382]
+        //[nll]~| ERROR cannot assign to `u.0`, as `u` is not declared as mutable [E0594]
+        u.1 = 2;
+        //[ast]~^ ERROR cannot assign to field `u.1` of immutable binding [E0594]
+        //[nll]~^^ ERROR cannot assign to `u.1`, as `u` is not declared as mutable [E0594]
+        println!("{:?} {:?}", u.0, u.1);
+        //[ast]~^ ERROR use of moved value: `u.0` [E0382]
+        //[ast]~| ERROR use of moved value: `u.1` [E0382]
+    }
+
+    {
+        let v: Spair = Spair { x: S(0), y: 0 };
+        drop(v);
+        v.x = S(1);
+        //[ast]~^ ERROR cannot assign to field `v.x` of immutable binding [E0594]
+        //[nll]~^^ ERROR assign to part of moved value: `v` [E0382]
+        //[nll]~| ERROR cannot assign to `v.x`, as `v` is not declared as mutable [E0594]
+        v.y = 2;
+        //[ast]~^ ERROR cannot assign to field `v.y` of immutable binding [E0594]
+        //[nll]~^^ ERROR cannot assign to `v.y`, as `v` is not declared as mutable [E0594]
+        println!("{:?} {:?}", v.x, v.y);
+        //[ast]~^ ERROR use of moved value: `v.x` [E0382]
+        //[ast]~| ERROR use of moved value: `v.y` [E0382]
+    }
+}
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.ast.stderr
new file mode 100644 (file)
index 0000000..ea6b63b
--- /dev/null
@@ -0,0 +1,91 @@
+error[E0594]: cannot assign to field `t.0` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:22:9
+   |
+LL |         let t: Tuple;
+   |             - help: make this binding mutable: `mut t`
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `t.1` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:25:9
+   |
+LL |         let t: Tuple;
+   |             - help: make this binding mutable: `mut t`
+...
+LL |         t.1 = 2;
+   |         ^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `u.0` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:34:9
+   |
+LL |         let u: Tpair;
+   |             - help: make this binding mutable: `mut u`
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `u.1` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:37:9
+   |
+LL |         let u: Tpair;
+   |             - help: make this binding mutable: `mut u`
+...
+LL |         u.1 = 2;
+   |         ^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `v.x` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:46:9
+   |
+LL |         let v: Spair;
+   |             - help: make this binding mutable: `mut v`
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0594]: cannot assign to field `v.y` of immutable binding
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:49:9
+   |
+LL |         let v: Spair;
+   |             - help: make this binding mutable: `mut v`
+...
+LL |         v.y = 2;
+   |         ^^^^^^^ cannot mutably borrow field of immutable binding
+
+error[E0381]: use of possibly uninitialized variable: `t.0`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:27:31
+   |
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                               ^^^ use of possibly uninitialized `t.0`
+
+error[E0381]: use of possibly uninitialized variable: `t.1`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:27:36
+   |
+LL |         println!("{:?} {:?}", t.0, t.1);
+   |                                    ^^^ use of possibly uninitialized `t.1`
+
+error[E0381]: use of possibly uninitialized variable: `u.0`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:39:31
+   |
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                               ^^^ use of possibly uninitialized `u.0`
+
+error[E0381]: use of possibly uninitialized variable: `u.1`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:39:36
+   |
+LL |         println!("{:?} {:?}", u.0, u.1);
+   |                                    ^^^ use of possibly uninitialized `u.1`
+
+error[E0381]: use of possibly uninitialized variable: `v.x`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:51:31
+   |
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                               ^^^ use of possibly uninitialized `v.x`
+
+error[E0381]: use of possibly uninitialized variable: `v.y`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:51:36
+   |
+LL |         println!("{:?} {:?}", v.x, v.y);
+   |                                    ^^^ use of possibly uninitialized `v.y`
+
+error: aborting due to 12 previous errors
+
+Some errors occurred: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.nll.stderr
new file mode 100644 (file)
index 0000000..3dc2b5b
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0381]: assign to part of possibly uninitialized variable: `t`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:22:9
+   |
+LL |         t.0 = S(1);
+   |         ^^^^^^^^^^ use of possibly uninitialized `t`
+
+error[E0381]: assign to part of possibly uninitialized variable: `u`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:34:9
+   |
+LL |         u.0 = S(1);
+   |         ^^^^^^^^^^ use of possibly uninitialized `u`
+
+error[E0381]: assign to part of possibly uninitialized variable: `v`
+  --> $DIR/issue-54499-field-mutation-of-never-init.rs:46:9
+   |
+LL |         v.x = S(1);
+   |         ^^^^^^^^^^ use of possibly uninitialized `v`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs
new file mode 100644 (file)
index 0000000..03eb962
--- /dev/null
@@ -0,0 +1,55 @@
+// revisions: ast nll
+
+// Since we are testing nll migration explicitly as a separate
+// revision, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[ast]compile-flags: -Z borrowck=ast
+//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+#![warn(unused)]
+#[derive(Debug)]
+struct S(i32);
+
+type Tuple = (S, i32);
+struct Tpair(S, i32);
+struct Spair { x: S, y: i32 }
+
+fn main() {
+    {
+        let t: Tuple;
+        t.0 = S(1);
+        //[ast]~^ ERROR cannot assign to field `t.0` of immutable binding [E0594]
+        //[nll]~^^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
+        t.1 = 2;
+        //[ast]~^ ERROR cannot assign to field `t.1` of immutable binding [E0594]
+        println!("{:?} {:?}", t.0, t.1);
+        //[ast]~^ ERROR use of possibly uninitialized variable: `t.0` [E0381]
+        //[ast]~| ERROR use of possibly uninitialized variable: `t.1` [E0381]
+    }
+
+    {
+        let u: Tpair;
+        u.0 = S(1);
+        //[ast]~^ ERROR cannot assign to field `u.0` of immutable binding [E0594]
+        //[nll]~^^ ERROR assign to part of possibly uninitialized variable: `u` [E0381]
+        u.1 = 2;
+        //[ast]~^ ERROR cannot assign to field `u.1` of immutable binding [E0594]
+        println!("{:?} {:?}", u.0, u.1);
+        //[ast]~^ ERROR use of possibly uninitialized variable: `u.0` [E0381]
+        //[ast]~| ERROR use of possibly uninitialized variable: `u.1` [E0381]
+    }
+
+    {
+        let v: Spair;
+        v.x = S(1);
+        //[ast]~^ ERROR cannot assign to field `v.x` of immutable binding [E0594]
+        //[nll]~^^ ERROR assign to part of possibly uninitialized variable: `v` [E0381]
+        v.y = 2;
+        //[ast]~^ ERROR cannot assign to field `v.y` of immutable binding [E0594]
+        println!("{:?} {:?}", v.x, v.y);
+        //[ast]~^ ERROR use of possibly uninitialized variable: `v.x` [E0381]
+        //[ast]~| ERROR use of possibly uninitialized variable: `v.y` [E0381]
+    }
+}
index 97f3bf5b81f66d79dc5b76e01bd4124e9ba5839b..1f0938dd3d27ba168b1fb2421aa0fcd8fe965c22 100644 (file)
@@ -1,44 +1,15 @@
-error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+error[E0381]: assign to part of possibly uninitialized variable: `x`
   --> $DIR/reassignment_immutable_fields.rs:17:5
    |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     x.0 = 1; //~ ERROR
-   |     ^^^^^^^ cannot assign
+   |     ^^^^^^^ use of possibly uninitialized `x`
 
-error[E0594]: cannot assign to `x.1`, as `x` is not declared as mutable
-  --> $DIR/reassignment_immutable_fields.rs:18:5
-   |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x.0 = 1; //~ ERROR
-LL |     x.1 = 22; //~ ERROR
-   |     ^^^^^^^^ cannot assign
-
-error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+error[E0381]: assign to part of possibly uninitialized variable: `x`
   --> $DIR/reassignment_immutable_fields.rs:25:5
    |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x.0 = 1; //~ ERROR
-   |     ^^^^^^^ cannot assign
-
-error[E0594]: cannot assign to `x.1`, as `x` is not declared as mutable
-  --> $DIR/reassignment_immutable_fields.rs:26:5
-   |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     x.0 = 1; //~ ERROR
-LL |     x.1 = 22; //~ ERROR
-   |     ^^^^^^^^ cannot assign
-
-error[E0381]: use of possibly uninitialized variable: `x`
-  --> $DIR/reassignment_immutable_fields.rs:27:10
-   |
-LL |     drop(x); //~ ERROR
-   |          ^ use of possibly uninitialized `x`
+   |     ^^^^^^^ use of possibly uninitialized `x`
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors occurred: E0381, E0594.
-For more information about an error, try `rustc --explain E0381`.
+For more information about this error, try `rustc --explain E0381`.
index c433d6e25c9de134e1919de840ac5f19400dee7f..7da9dbfc088cb5a0f15ef80b27272f918117cc78 100644 (file)
@@ -1,20 +1,9 @@
-error[E0594]: cannot assign to `x.a`, as `x` is not declared as mutable
+error[E0381]: assign to part of possibly uninitialized variable: `x`
   --> $DIR/reassignment_immutable_fields_overlapping.rs:22:5
    |
-LL |     let x: Foo;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     x.a = 1;  //~ ERROR
-   |     ^^^^^^^ cannot assign
+   |     ^^^^^^^ use of possibly uninitialized `x`
 
-error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
-  --> $DIR/reassignment_immutable_fields_overlapping.rs:23:5
-   |
-LL |     let x: Foo;
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x.a = 1;  //~ ERROR
-LL |     x.b = 22; //~ ERROR
-   |     ^^^^^^^^ cannot assign
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0594`.
+For more information about this error, try `rustc --explain E0381`.
index 2160ae20c425a512e42779043fb21d6c51ee1dba..96677be724131274f26565b030aa8085b25eea1e 100644 (file)
@@ -7,32 +7,13 @@ LL |     x = (22, 44);
 LL |     x.0 = 1; //~ ERROR
    |     ^^^^^^^ cannot assign
 
-error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
+error[E0381]: assign to part of possibly uninitialized variable: `x`
   --> $DIR/reassignment_immutable_fields_twice.rs:22:5
    |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x.0 = 1; //~ ERROR
-   |     ^^^^^^^ cannot assign
-
-error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
-  --> $DIR/reassignment_immutable_fields_twice.rs:23:5
-   |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     x.0 = 1; //~ ERROR
-LL |     x.0 = 22; //~ ERROR
-   |     ^^^^^^^^ cannot assign
-
-error[E0594]: cannot assign to `x.1`, as `x` is not declared as mutable
-  --> $DIR/reassignment_immutable_fields_twice.rs:24:5
-   |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
-...
-LL |     x.1 = 44; //~ ERROR
-   |     ^^^^^^^^ cannot assign
+   |     ^^^^^^^ use of possibly uninitialized `x`
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0594`.
+Some errors occurred: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
index 30895bce357bb8f47698af2be6715f22e9326455..8554b346beb28490f668518e833905187dcc2826 100644 (file)
@@ -11,7 +11,7 @@
 // #39872, #39553
 
 fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
-    //~^ ERROR the trait bound `(): std::iter::Iterator` is not satisfied [E0277]
+    //~^ ERROR `()` is not an iterator
 }
 
 fn main() {}
index 6fcd384566cf8ba5747e3c11b69739d738afb661..cfa4618566ef1cea057b3b1df1972be7749ed427 100644 (file)
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
+error[E0277]: `()` is not an iterator
   --> $DIR/conservative_impl_trait.rs:13:33
    |
 LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `()`
    = note: the return type of a function must have a statically known size
index f20c1ebb37aa9e9db60dbd40dea61e0b3e7a91e3..14764b4e9f0f8afae82c8e263b4f34f67d09ec0b 100644 (file)
@@ -75,15 +75,16 @@ LL | | }
    = help: see issue #48214
    = help: add #![feature(trivial_bounds)] to the crate attributes to enable
 
-error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+error[E0277]: `i32` is not an iterator
   --> $DIR/feature-gate-trivial_bounds.rs:50:1
    |
 LL | / fn use_for() where i32: Iterator { //~ ERROR
 LL | |     for _ in 2i32 {}
 LL | | }
-   | |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+   | |_^ `i32` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `i32`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = help: see issue #48214
    = help: add #![feature(trivial_bounds)] to the crate attributes to enable
 
index 011886e8073467e67126ede597a0006dcf6dbfee..83ec6c2db9b806c90f809659b5f92b52fb90754f 100644 (file)
@@ -12,7 +12,7 @@
 
 fn main() {
     for c in "asdf" {
-    //~^ ERROR the trait bound `&str: std::iter::Iterator` is not satisfied
+    //~^ ERROR `&str` is not an iterator
     //~| NOTE `&str` is not an iterator
     //~| HELP the trait `std::iter::Iterator` is not implemented for `&str`
     //~| NOTE required by `std::iter::IntoIterator::into_iter`
index b249df3b4ef6a1fd622628a8f86c1e4f55332351..d3db935166eb4e5f99fff2d4d37586ce628e5cd2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied
+error[E0277]: `&str` is not an iterator
   --> $DIR/for-c-in-str.rs:14:14
    |
 LL |     for c in "asdf" {
index 96ad184fd355840c602ab11ce998a3ca7cca3a43..b54d445ae37f0f645ddda32ab8a87ebdb64ce33c 100644 (file)
@@ -24,7 +24,8 @@ pub fn main() {
         x: 1,
         y: 2,
     };
-    for x in bogus { //~ ERROR `MyStruct: std::iter::Iterator` is not satisfied
+    for x in bogus {
+    //~^ ERROR `MyStruct` is not an iterator
         drop(x);
     }
 }
index 0476ec06c705a21eba6af5aa01c8a40e1530db93..1aaf12c5da029277d87b3e3a9a811f95b3cda62d 100644 (file)
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `MyStruct: std::iter::Iterator` is not satisfied
+error[E0277]: `MyStruct` is not an iterator
   --> $DIR/for-loop-bogosity.rs:27:14
    |
-LL |     for x in bogus { //~ ERROR `MyStruct: std::iter::Iterator` is not satisfied
-   |              ^^^^^ `MyStruct` is not an iterator; maybe try calling `.iter()` or a similar method
+LL |     for x in bogus {
+   |              ^^^^^ `MyStruct` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `MyStruct`
    = note: required by `std::iter::IntoIterator::into_iter`
index c7b0b57000f5e18b97d22f24b00e6bf4538be8c9..cdc5a047c07245729558156b08203842514901ac 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `foo.0`
+error[E0382]: use of moved value: `foo`
   --> $DIR/issue-17385.rs:29:11
    |
 LL |     drop(foo);
diff --git a/src/test/ui/issues/issue-22872.rs b/src/test/ui/issues/issue-22872.rs
new file mode 100644 (file)
index 0000000..7a83b09
--- /dev/null
@@ -0,0 +1,23 @@
+trait Wrap<'b> {
+    fn foo(&'b mut self);
+}
+
+struct Wrapper<P>(P);
+
+impl<'b, P> Wrap<'b> for Wrapper<P>
+where P: Process<'b>,
+      <P as Process<'b>>::Item: Iterator {
+    fn foo(&mut self) {}
+}
+
+
+pub trait Process<'a> {
+    type Item;
+    fn bar(&'a self);
+}
+
+fn push_process<P>(process: P) where P: Process<'static> {
+    let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr
new file mode 100644 (file)
index 0000000..231080a
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `for<'b> P: Process<'b>` is not satisfied
+  --> $DIR/issue-22872.rs:20:36
+   |
+LL |     let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> Process<'b>` is not implemented for `P`
+   |
+   = help: consider adding a `where for<'b> P: Process<'b>` bound
+   = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
+   = note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
+
+error[E0277]: `<P as Process<'b>>::Item` is not an iterator
+  --> $DIR/issue-22872.rs:20:36
+   |
+LL |     let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'b>>::Item` is not an iterator
+   |
+   = help: the trait `for<'b> std::iter::Iterator` is not implemented for `<P as Process<'b>>::Item`
+   = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
+   = note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 909c369354bc377ea2d0b8e0c6861786a1b9abc9..769e5474e000aec2e49aeafc6e16a1d5da3418b9 100644 (file)
@@ -26,7 +26,7 @@ fn main() {
         _ if { (|| { let bar = b; *bar = false; })();
                      false } => { },
         &mut true => { println!("You might think we should get here"); },
-        //~^ ERROR use of moved value: `*b` [E0382]
+        //~^ ERROR use of moved value: `b` [E0382]
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
 }
index 0b783e37615ee93646a45f78e9fa7b26c52248bc..5f3b07bd1e8b89131db9e17c86dd776dd90f97bc 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `*b`
+error[E0382]: use of moved value: `b`
   --> $DIR/issue-27282-move-match-input-into-guard.rs:28:14
    |
 LL |         _ if { (|| { let bar = b; *bar = false; })();
index 5dded2b1e16973e9cf259805273a349894313de7..11990c34fbae44ac1a4501b2bf47421228204501 100644 (file)
 
 fn main() {
     let _ = Iterator::next(&mut ());
-    //~^ ERROR `(): std::iter::Iterator` is not satisfied
+    //~^ ERROR `()` is not an iterator
 
     for _ in false {}
-    //~^ ERROR `bool: std::iter::Iterator` is not satisfied
+    //~^ ERROR `bool` is not an iterator
 
     let _ = Iterator::next(&mut ());
-    //~^ ERROR `(): std::iter::Iterator` is not satisfied
+    //~^ ERROR `()` is not an iterator
 
     other()
 }
@@ -25,11 +25,11 @@ pub fn other() {
     // check errors are still reported globally
 
     let _ = Iterator::next(&mut ());
-    //~^ ERROR `(): std::iter::Iterator` is not satisfied
+    //~^ ERROR `()` is not an iterator
 
     let _ = Iterator::next(&mut ());
-    //~^ ERROR `(): std::iter::Iterator` is not satisfied
+    //~^ ERROR `()` is not an iterator
 
     for _ in false {}
-    //~^ ERROR `bool: std::iter::Iterator` is not satisfied
+    //~^ ERROR `bool` is not an iterator
 }
index 3a6e1aea288348d77ebef8442f433915c3e8b79a..c7537065b32b6adae4abe98d52062a0a4d667930 100644 (file)
@@ -1,53 +1,53 @@
-error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
+error[E0277]: `()` is not an iterator
   --> $DIR/issue-28098.rs:12:13
    |
 LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `()`
    = note: required by `std::iter::Iterator::next`
 
-error[E0277]: the trait bound `bool: std::iter::Iterator` is not satisfied
+error[E0277]: `bool` is not an iterator
   --> $DIR/issue-28098.rs:15:14
    |
 LL |     for _ in false {}
-   |              ^^^^^ `bool` is not an iterator; maybe try calling `.iter()` or a similar method
+   |              ^^^^^ `bool` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `bool`
    = note: required by `std::iter::IntoIterator::into_iter`
 
-error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
+error[E0277]: `()` is not an iterator
   --> $DIR/issue-28098.rs:18:13
    |
 LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `()`
    = note: required by `std::iter::Iterator::next`
 
-error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
+error[E0277]: `()` is not an iterator
   --> $DIR/issue-28098.rs:27:13
    |
 LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `()`
    = note: required by `std::iter::Iterator::next`
 
-error[E0277]: the trait bound `(): std::iter::Iterator` is not satisfied
+error[E0277]: `()` is not an iterator
   --> $DIR/issue-28098.rs:30:13
    |
 LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator; maybe try calling `.iter()` or a similar method
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `()`
    = note: required by `std::iter::Iterator::next`
 
-error[E0277]: the trait bound `bool: std::iter::Iterator` is not satisfied
+error[E0277]: `bool` is not an iterator
   --> $DIR/issue-28098.rs:33:14
    |
 LL |     for _ in false {}
-   |              ^^^^^ `bool` is not an iterator; maybe try calling `.iter()` or a similar method
+   |              ^^^^^ `bool` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `bool`
    = note: required by `std::iter::IntoIterator::into_iter`
index 3427cf6bf9ca2d810fbfde47c0fe60c3cdf9eb1e..565ba8dd4de45259d7ffc4de5ca7c6ae743de0ad 100644 (file)
@@ -12,6 +12,6 @@
 //~^ ERROR the trait `Copy` may not be implemented for this type
 struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
 //~^ ERROR cannot find type `NotDefined` in this scope
-//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied
+//~| ERROR `i32` is not an iterator
 
 fn main() {}
index f5281fec4d1eac5ec7bf4c0a86c40e0b145bab5c..cbff927ac74d4370b45dd2b31f80fa2fd680eda8 100644 (file)
@@ -4,13 +4,14 @@ error[E0412]: cannot find type `NotDefined` in this scope
 LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |            ^^^^^^^^^^ not found in this scope
 
-error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+error[E0277]: `i32` is not an iterator
   --> $DIR/issue-50480.rs:13:24
    |
 LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `i32`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
 
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/issue-50480.rs:11:17
diff --git a/src/test/ui/iterators/array-of-ranges.rs b/src/test/ui/iterators/array-of-ranges.rs
new file mode 100644 (file)
index 0000000..a7d6e80
--- /dev/null
@@ -0,0 +1,14 @@
+fn main() {
+    for _ in [0..1] {}
+    for _ in [0..=1] {}
+    for _ in [0..] {}
+    for _ in [..1] {}
+    for _ in [..=1] {}
+    let start = 0;
+    let end = 0;
+    for _ in [start..end] {}
+    let array_of_range = [start..end];
+    for _ in array_of_range {}
+    for _ in [0..1, 2..3] {}
+    for _ in [0..=1] {}
+}
diff --git a/src/test/ui/iterators/array-of-ranges.stderr b/src/test/ui/iterators/array-of-ranges.stderr
new file mode 100644 (file)
index 0000000..fbe7e0e
--- /dev/null
@@ -0,0 +1,93 @@
+error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:2:14
+   |
+LL |     for _ in [0..1] {}
+   |              ^^^^^^ if you meant to iterate between two values, remove the square brackets
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
+   = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::RangeInclusive<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:3:14
+   |
+LL |     for _ in [0..=1] {}
+   |              ^^^^^^^ if you meant to iterate between two values, remove the square brackets
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeInclusive<{integer}>; 1]`
+   = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::RangeFrom<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:4:14
+   |
+LL |     for _ in [0..] {}
+   |              ^^^^^ if you meant to iterate from a value onwards, remove the square brackets
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeFrom<{integer}>; 1]`
+   = note: `[start..]` is an array of one `RangeFrom`; you might have meant to have a `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an unbounded iterator will run forever unless you `break` or `return` from within the loop
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::RangeTo<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:5:14
+   |
+LL |     for _ in [..1] {}
+   |              ^^^^^ if you meant to iterate until a value, remove the square brackets and add a starting value
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeTo<{integer}>; 1]`
+   = note: `[..end]` is an array of one `RangeTo`; you might have meant to have a bounded `Range` without the brackets: `0..end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::RangeToInclusive<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:6:14
+   |
+LL |     for _ in [..=1] {}
+   |              ^^^^^^ if you meant to iterate until a value (including it), remove the square brackets and add a starting value
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeToInclusive<{integer}>; 1]`
+   = note: `[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a bounded `RangeInclusive` without the brackets: `0..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:9:14
+   |
+LL |     for _ in [start..end] {}
+   |              ^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
+   = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:11:14
+   |
+LL |     for _ in array_of_range {}
+   |              ^^^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
+   = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator
+  --> $DIR/array-of-ranges.rs:12:14
+   |
+LL |     for _ in [0..1, 2..3] {}
+   |              ^^^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]`
+   = note: arrays are not an iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[std::ops::RangeInclusive<{integer}>; 1]` is not an iterator
+  --> $DIR/array-of-ranges.rs:13:14
+   |
+LL |     for _ in [0..=1] {}
+   |              ^^^^^^^ if you meant to iterate between two values, remove the square brackets
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeInclusive<{integer}>; 1]`
+   = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/iterators/array.rs b/src/test/ui/iterators/array.rs
new file mode 100644 (file)
index 0000000..f54bb81
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    for _ in [1, 2] {}
+    let x = [1, 2];
+    for _ in x {}
+    for _ in [1.0, 2.0] {}
+}
diff --git a/src/test/ui/iterators/array.stderr b/src/test/ui/iterators/array.stderr
new file mode 100644 (file)
index 0000000..fd74cd7
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0277]: `[{integer}; 2]` is not an iterator
+  --> $DIR/array.rs:2:14
+   |
+LL |     for _ in [1, 2] {}
+   |              ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 2]`
+   = note: arrays are not an iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[{integer}; 2]` is not an iterator
+  --> $DIR/array.rs:4:14
+   |
+LL |     for _ in x {}
+   |              ^ borrow the array with `&` or call `.iter()` on it to iterate over it
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 2]`
+   = note: arrays are not an iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `[{float}; 2]` is not an iterator
+  --> $DIR/array.rs:5:14
+   |
+LL |     for _ in [1.0, 2.0] {}
+   |              ^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `[{float}; 2]`
+   = note: arrays are not an iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/iterators/bound.rs b/src/test/ui/iterators/bound.rs
new file mode 100644 (file)
index 0000000..78285b8
--- /dev/null
@@ -0,0 +1,3 @@
+struct S<I: Iterator>(I);
+struct T(S<u8>);
+fn main() {}
diff --git a/src/test/ui/iterators/bound.stderr b/src/test/ui/iterators/bound.stderr
new file mode 100644 (file)
index 0000000..1405738
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: `u8` is not an iterator
+  --> $DIR/bound.rs:2:10
+   |
+LL | struct T(S<u8>);
+   |          ^^^^^ `u8` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `u8`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+note: required by `S`
+  --> $DIR/bound.rs:1:1
+   |
+LL | struct S<I: Iterator>(I);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/iterators/integral.rs b/src/test/ui/iterators/integral.rs
new file mode 100644 (file)
index 0000000..7537c79
--- /dev/null
@@ -0,0 +1,26 @@
+fn main() {
+    for _ in 42 {}
+    //~^ ERROR `{integer}` is not an iterator
+    for _ in 42 as u8 {}
+    //~^ ERROR `u8` is not an iterator
+    for _ in 42 as i8 {}
+    //~^ ERROR `i8` is not an iterator
+    for _ in 42 as u16 {}
+    //~^ ERROR `u16` is not an iterator
+    for _ in 42 as i16 {}
+    //~^ ERROR `i16` is not an iterator
+    for _ in 42 as u32 {}
+    //~^ ERROR `u32` is not an iterator
+    for _ in 42 as i32 {}
+    //~^ ERROR `i32` is not an iterator
+    for _ in 42 as u64 {}
+    //~^ ERROR `u64` is not an iterator
+    for _ in 42 as i64 {}
+    //~^ ERROR `i64` is not an iterator
+    for _ in 42 as usize {}
+    //~^ ERROR `usize` is not an iterator
+    for _ in 42 as isize {}
+    //~^ ERROR `isize` is not an iterator
+    for _ in 42.0 {}
+    //~^ ERROR `{float}` is not an iterator
+}
diff --git a/src/test/ui/iterators/integral.stderr b/src/test/ui/iterators/integral.stderr
new file mode 100644 (file)
index 0000000..71e1e81
--- /dev/null
@@ -0,0 +1,122 @@
+error[E0277]: `{integer}` is not an iterator
+  --> $DIR/integral.rs:2:14
+   |
+LL |     for _ in 42 {}
+   |              ^^ `{integer}` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `{integer}`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `u8` is not an iterator
+  --> $DIR/integral.rs:4:14
+   |
+LL |     for _ in 42 as u8 {}
+   |              ^^^^^^^^ `u8` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `u8`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `i8` is not an iterator
+  --> $DIR/integral.rs:6:14
+   |
+LL |     for _ in 42 as i8 {}
+   |              ^^^^^^^^ `i8` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i8`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `u16` is not an iterator
+  --> $DIR/integral.rs:8:14
+   |
+LL |     for _ in 42 as u16 {}
+   |              ^^^^^^^^^ `u16` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `u16`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `i16` is not an iterator
+  --> $DIR/integral.rs:10:14
+   |
+LL |     for _ in 42 as i16 {}
+   |              ^^^^^^^^^ `i16` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i16`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `u32` is not an iterator
+  --> $DIR/integral.rs:12:14
+   |
+LL |     for _ in 42 as u32 {}
+   |              ^^^^^^^^^ `u32` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `u32`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `i32` is not an iterator
+  --> $DIR/integral.rs:14:14
+   |
+LL |     for _ in 42 as i32 {}
+   |              ^^^^^^^^^ `i32` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i32`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `u64` is not an iterator
+  --> $DIR/integral.rs:16:14
+   |
+LL |     for _ in 42 as u64 {}
+   |              ^^^^^^^^^ `u64` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `u64`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `i64` is not an iterator
+  --> $DIR/integral.rs:18:14
+   |
+LL |     for _ in 42 as i64 {}
+   |              ^^^^^^^^^ `i64` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i64`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `usize` is not an iterator
+  --> $DIR/integral.rs:20:14
+   |
+LL |     for _ in 42 as usize {}
+   |              ^^^^^^^^^^^ `usize` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `usize`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `isize` is not an iterator
+  --> $DIR/integral.rs:22:14
+   |
+LL |     for _ in 42 as isize {}
+   |              ^^^^^^^^^^^ `isize` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `isize`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `{float}` is not an iterator
+  --> $DIR/integral.rs:24:14
+   |
+LL |     for _ in 42.0 {}
+   |              ^^^^ `{float}` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `{float}`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/iterators/ranges.rs b/src/test/ui/iterators/ranges.rs
new file mode 100644 (file)
index 0000000..925d2d6
--- /dev/null
@@ -0,0 +1,9 @@
+fn main() {
+    for _ in ..10 {}
+    //~^ ERROR E0277
+    for _ in ..=10 {}
+    //~^ ERROR E0277
+    for _ in 0..10 {}
+    for _ in 0..=10 {}
+    for _ in 0.. {}
+}
diff --git a/src/test/ui/iterators/ranges.stderr b/src/test/ui/iterators/ranges.stderr
new file mode 100644 (file)
index 0000000..e5e2d87
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0277]: `std::ops::RangeTo<{integer}>` is not an iterator
+  --> $DIR/ranges.rs:2:14
+   |
+LL |     for _ in ..10 {}
+   |              ^^^^ if you meant to iterate until a value, add a starting value
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `std::ops::RangeTo<{integer}>`
+   = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `std::ops::RangeToInclusive<{integer}>` is not an iterator
+  --> $DIR/ranges.rs:4:14
+   |
+LL |     for _ in ..=10 {}
+   |              ^^^^^ if you meant to iterate until a value (including it), add a starting value
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `std::ops::RangeToInclusive<{integer}>`
+   = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/iterators/string.rs b/src/test/ui/iterators/string.rs
new file mode 100644 (file)
index 0000000..4373dca
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    for _ in "".to_owned() {}
+    //~^ ERROR `std::string::String` is not an iterator
+    for _ in "" {}
+    //~^ ERROR `&str` is not an iterator
+}
diff --git a/src/test/ui/iterators/string.stderr b/src/test/ui/iterators/string.stderr
new file mode 100644 (file)
index 0000000..927de95
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0277]: `std::string::String` is not an iterator
+  --> $DIR/string.rs:2:14
+   |
+LL |     for _ in "".to_owned() {}
+   |              ^^^^^^^^^^^^^ `std::string::String` is not an iterator; try calling `.chars()` or `.bytes()`
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `std::string::String`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `&str` is not an iterator
+  --> $DIR/string.rs:4:14
+   |
+LL |     for _ in "" {}
+   |              ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `&str`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 62d9a8b115a19511943fa6cfdb5da979657d5628..463a64f4beca897e26de52df3b1404aed15069f3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: borrow of moved value: `*x`
+error[E0382]: borrow of moved value: `x`
   --> $DIR/liveness-use-after-move.rs:16:20
    |
 LL |     let y = x;
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
new file mode 100644 (file)
index 0000000..abafd33
--- /dev/null
@@ -0,0 +1,66 @@
+// This test enumerates various cases of interest where a ADT or tuple is
+// partially initialized and then used in some way that is wrong *even*
+// after rust-lang/rust#54987 is implemented.
+//
+// See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987.
+//
+// See issue-21232-partial-init-and-use.rs for cases of tests that are
+// meant to compile and run successfully once rust-lang/rust#54987 is
+// implemented.
+
+#![feature(nll)]
+
+struct D {
+    x: u32,
+    s: S,
+}
+
+struct S {
+    y: u32,
+    z: u32,
+}
+
+
+impl Drop for D {
+    fn drop(&mut self) { }
+}
+
+fn cannot_partially_init_adt_with_drop() {
+    let d: D;
+    d.x = 10;
+    //~^ ERROR assign of possibly uninitialized variable: `d` [E0381]
+}
+
+fn cannot_partially_init_mutable_adt_with_drop() {
+    let mut d: D;
+    d.x = 10;
+    //~^ ERROR assign of possibly uninitialized variable: `d` [E0381]
+}
+
+fn cannot_partially_reinit_adt_with_drop() {
+    let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
+    drop(d);
+    d.x = 10;
+    //~^ ERROR assign of moved value: `d` [E0382]
+}
+
+fn cannot_partially_init_inner_adt_via_outer_with_drop() {
+    let d: D;
+    d.s.y = 20;
+    //~^ ERROR assign to part of possibly uninitialized variable: `d` [E0381]
+}
+
+fn cannot_partially_init_inner_adt_via_mutable_outer_with_drop() {
+    let mut d: D;
+    d.s.y = 20;
+    //~^ ERROR assign to part of possibly uninitialized variable: `d` [E0381]
+}
+
+fn cannot_partially_reinit_inner_adt_via_outer_with_drop() {
+    let mut d = D { x: 0, s: S{ y: 0, z: 0} };
+    drop(d);
+    d.s.y = 20;
+    //~^ ERROR assign to part of moved value: `d` [E0382]
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
new file mode 100644 (file)
index 0000000..e29c447
--- /dev/null
@@ -0,0 +1,48 @@
+error[E0381]: assign of possibly uninitialized variable: `d`
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:30:5
+   |
+LL |     d.x = 10;
+   |     ^^^^^^^^ use of possibly uninitialized `d`
+
+error[E0381]: assign of possibly uninitialized variable: `d`
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:36:5
+   |
+LL |     d.x = 10;
+   |     ^^^^^^^^ use of possibly uninitialized `d`
+
+error[E0382]: assign of moved value: `d`
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:43:5
+   |
+LL |     drop(d);
+   |          - value moved here
+LL |     d.x = 10;
+   |     ^^^^^^^^ value assigned here after move
+   |
+   = note: move occurs because `d` has type `D`, which does not implement the `Copy` trait
+
+error[E0381]: assign to part of possibly uninitialized variable: `d`
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:49:5
+   |
+LL |     d.s.y = 20;
+   |     ^^^^^^^^^^ use of possibly uninitialized `d.s`
+
+error[E0381]: assign to part of possibly uninitialized variable: `d`
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:55:5
+   |
+LL |     d.s.y = 20;
+   |     ^^^^^^^^^^ use of possibly uninitialized `d.s`
+
+error[E0382]: assign to part of moved value: `d`
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:62:5
+   |
+LL |     drop(d);
+   |          - value moved here
+LL |     d.s.y = 20;
+   |     ^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `d` has type `D`, which does not implement the `Copy` trait
+
+error: aborting due to 6 previous errors
+
+Some errors occurred: E0381, E0382.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-use.rs
new file mode 100644 (file)
index 0000000..e3ae4c0
--- /dev/null
@@ -0,0 +1,311 @@
+// This test enumerates various cases of interest for partial
+// [re]initialization of ADTs and tuples.
+//
+// See rust-lang/rust#21232, rust-lang/rust#54986, and rust-lang/rust#54987.
+//
+// All of tests in this file are expected to change from being
+// rejected, at least under NLL (by rust-lang/rust#54986) to being
+// **accepted** when rust-lang/rust#54987 is implemented.
+// (That's why there are assertions in the code.)
+//
+// See issue-21232-partial-init-and-erroneous-use.rs for cases of
+// tests that are meant to continue failing to compile once
+// rust-lang/rust#54987 is implemented.
+
+#![feature(nll)]
+
+struct S<Y> {
+    x: u32,
+
+    // Note that even though `y` may implement `Drop`, under #54987 we
+    // will still allow partial initialization of `S` itself.
+    y: Y,
+}
+
+enum Void { }
+
+type B = Box<u32>;
+
+impl S<B> { fn new() -> Self { S { x: 0, y: Box::new(0) } } }
+
+fn borrow_s(s: &S<B>) { assert_eq!(s.x, 10); assert_eq!(*s.y, 20); }
+fn move_s(s: S<B>) {  assert_eq!(s.x, 10); assert_eq!(*s.y, 20); }
+fn borrow_field(x: &u32) { assert_eq!(*x, 10); }
+
+type T = (u32, B);
+type Tvoid = (u32, Void);
+
+fn borrow_t(t: &T) { assert_eq!(t.0, 10); assert_eq!(*t.1, 20); }
+fn move_t(t: T) {  assert_eq!(t.0, 10); assert_eq!(*t.1, 20); }
+
+struct Q<F> {
+    v: u32,
+    r: R<F>,
+}
+
+struct R<F> {
+    w: u32,
+    f: F,
+}
+
+impl<F> Q<F> { fn new(f: F) -> Self { Q { v: 0, r: R::new(f) } } }
+impl<F> R<F> { fn new(f: F) -> Self { R { w: 0, f } } }
+
+// Axes to cover:
+// * local/field: Is the structure in a local or a field
+// * fully/partial/void: Are we fully initializing it before using any part?
+//                       Is whole type empty due to a void component?
+// * init/reinit: First initialization, or did we previously inititalize and then move out?
+// * struct/tuple: Is this a struct or a (X, Y).
+//
+// As a shorthand for the cases above, adding a numeric summary to
+// each test's fn name to denote each point on each axis.
+//
+// E.g. 1000 = field fully init struct; 0211 = local void reinit tuple
+
+// It got pretty monotonous writing the same code over and over, and I
+// feared I would forget details. So I abstracted some desiderata into
+// macros. But I left the initialization code inline, because that's
+// where the errors for #54986 will be emited.
+
+macro_rules! use_fully {
+    (struct $s:expr) => { {
+        borrow_field(& $s.x );
+        borrow_s(& $s );
+        move_s( $s );
+    } };
+
+    (tuple $t:expr) => { {
+        borrow_field(& $t.0 );
+        borrow_t(& $t );
+        move_t( $t );
+    } }
+}
+
+macro_rules! use_part {
+    (struct $s:expr) => { {
+        borrow_field(& $s.x );
+        match $s { S { ref x, y: _ } => { borrow_field(x); } }
+    } };
+
+    (tuple $t:expr) => { {
+        borrow_field(& $t.0 );
+        match $t { (ref x, _) => { borrow_field(x); } }
+    } }
+}
+
+fn test_0000_local_fully_init_and_use_struct() {
+    let s: S<B>;
+    s.x = 10; s.y = Box::new(20);
+    //~^ ERROR assign to part of possibly uninitialized variable: `s` [E0381]
+    use_fully!(struct s);
+}
+
+fn test_0001_local_fully_init_and_use_tuple() {
+    let t: T;
+    t.0 = 10; t.1 = Box::new(20);
+    //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
+    use_fully!(tuple t);
+}
+
+fn test_0010_local_fully_reinit_and_use_struct() {
+    let mut s: S<B> = S::new(); drop(s);
+    s.x = 10; s.y = Box::new(20);
+    //~^ ERROR assign to part of moved value: `s` [E0382]
+    use_fully!(struct s);
+}
+
+fn test_0011_local_fully_reinit_and_use_tuple() {
+    let mut t: T = (0, Box::new(0)); drop(t);
+    t.0 = 10; t.1 = Box::new(20);
+    //~^ ERROR assign to part of moved value: `t` [E0382]
+    use_fully!(tuple t);
+}
+
+fn test_0100_local_partial_init_and_use_struct() {
+    let s: S<B>;
+    s.x = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `s` [E0381]
+    use_part!(struct s);
+}
+
+fn test_0101_local_partial_init_and_use_tuple() {
+    let t: T;
+    t.0 = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
+    use_part!(tuple t);
+}
+
+fn test_0110_local_partial_reinit_and_use_struct() {
+    let mut s: S<B> = S::new(); drop(s);
+    s.x = 10;
+    //~^ ERROR assign to part of moved value: `s` [E0382]
+    use_part!(struct s);
+}
+
+fn test_0111_local_partial_reinit_and_use_tuple() {
+    let mut t: T = (0, Box::new(0)); drop(t);
+    t.0 = 10;
+    //~^ ERROR assign to part of moved value: `t` [E0382]
+    use_part!(tuple t);
+}
+
+fn test_0200_local_void_init_and_use_struct() {
+    let s: S<Void>;
+    s.x = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `s` [E0381]
+    use_part!(struct s);
+}
+
+fn test_0201_local_void_init_and_use_tuple() {
+    let t: Tvoid;
+    t.0 = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381]
+    use_part!(tuple t);
+}
+
+// NOTE: uniform structure of tests here makes n21n (aka combining
+// Void with Reinit) an (even more) senseless case, as we cannot
+// safely create initial instance containing Void to move out of and
+// then reinitialize. While I was tempted to sidestep this via some
+// unsafe code (eek), lets just instead not encode such tests.
+
+// fn test_0210_local_void_reinit_and_use_struct() { unimplemented!() }
+// fn test_0211_local_void_reinit_and_use_tuple() { unimplemented!() }
+
+fn test_1000_field_fully_init_and_use_struct() {
+    let q: Q<S<B>>;
+    q.r.f.x = 10; q.r.f.y = Box::new(20);
+    //~^ ERROR assign to part of possibly uninitialized variable: `q` [E0381]
+    use_fully!(struct q.r.f);
+}
+
+fn test_1001_field_fully_init_and_use_tuple() {
+    let q: Q<T>;
+    q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+    //~^ ERROR assign to part of possibly uninitialized variable: `q` [E0381]
+    use_fully!(tuple q.r.f);
+}
+
+fn test_1010_field_fully_reinit_and_use_struct() {
+    let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+    q.r.f.x = 10; q.r.f.y = Box::new(20);
+    //~^ ERROR assign to part of moved value: `q.r` [E0382]
+    use_fully!(struct q.r.f);
+}
+
+fn test_1011_field_fully_reinit_and_use_tuple() {
+    let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+    q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+    //~^ ERROR assign to part of moved value: `q.r` [E0382]
+    use_fully!(tuple q.r.f);
+}
+
+fn test_1100_field_partial_init_and_use_struct() {
+    let q: Q<S<B>>;
+    q.r.f.x = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `q` [E0381]
+    use_part!(struct q.r.f);
+}
+
+fn test_1101_field_partial_init_and_use_tuple() {
+    let q: Q<T>;
+    q.r.f.0 = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `q` [E0381]
+    use_part!(tuple q.r.f);
+}
+
+fn test_1110_field_partial_reinit_and_use_struct() {
+    let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+    q.r.f.x = 10;
+    //~^ ERROR assign to part of moved value: `q.r` [E0382]
+    use_part!(struct q.r.f);
+}
+
+fn test_1111_field_partial_reinit_and_use_tuple() {
+    let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+    q.r.f.0 = 10;
+    //~^ ERROR assign to part of moved value: `q.r` [E0382]
+    use_part!(tuple q.r.f);
+}
+
+fn test_1200_field_void_init_and_use_struct() {
+    let mut q: Q<S<Void>>;
+    q.r.f.x = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `q` [E0381]
+    use_part!(struct q.r.f);
+}
+
+fn test_1201_field_void_init_and_use_tuple() {
+    let mut q: Q<Tvoid>;
+    q.r.f.0 = 10;
+    //~^ ERROR assign to part of possibly uninitialized variable: `q` [E0381]
+    use_part!(tuple q.r.f);
+}
+
+// See NOTE abve.
+
+// fn test_1210_field_void_reinit_and_use_struct() { unimplemented!() }
+// fn test_1211_field_void_reinit_and_use_tuple() { unimplemented!() }
+
+// The below are some additional cases of interest that have been
+// transcribed from other bugs based on old erroneous codegen when we
+// encountered partial writes.
+
+fn issue_26996() {
+    let mut c = (1, "".to_owned());
+    match c {
+        c2 => {
+            c.0 = 2; //~ ERROR assign to part of moved value
+            assert_eq!(c2.0, 1);
+        }
+    }
+}
+
+fn issue_27021() {
+    let mut c = (1, (1, "".to_owned()));
+    match c {
+        c2 => {
+            (c.1).0 = 2; //~ ERROR assign to part of moved value
+            assert_eq!((c2.1).0, 1);
+        }
+    }
+
+    let mut c = (1, (1, (1, "".to_owned())));
+    match c.1 {
+        c2 => {
+            ((c.1).1).0 = 3; //~ ERROR assign to part of moved value
+            assert_eq!((c2.1).0, 1);
+        }
+    }
+}
+
+fn main() {
+    test_0000_local_fully_init_and_use_struct();
+    test_0001_local_fully_init_and_use_tuple();
+    test_0010_local_fully_reinit_and_use_struct();
+    test_0011_local_fully_reinit_and_use_tuple();
+    test_0100_local_partial_init_and_use_struct();
+    test_0101_local_partial_init_and_use_tuple();
+    test_0110_local_partial_reinit_and_use_struct();
+    test_0111_local_partial_reinit_and_use_tuple();
+    test_0200_local_void_init_and_use_struct();
+    test_0201_local_void_init_and_use_tuple();
+    // test_0210_local_void_reinit_and_use_struct();
+    // test_0211_local_void_reinit_and_use_tuple();
+    test_1000_field_fully_init_and_use_struct();
+    test_1001_field_fully_init_and_use_tuple();
+    test_1010_field_fully_reinit_and_use_struct();
+    test_1011_field_fully_reinit_and_use_tuple();
+    test_1100_field_partial_init_and_use_struct();
+    test_1101_field_partial_init_and_use_tuple();
+    test_1110_field_partial_reinit_and_use_struct();
+    test_1111_field_partial_reinit_and_use_tuple();
+    test_1200_field_void_init_and_use_struct();
+    test_1201_field_void_init_and_use_tuple();
+    // test_1210_field_void_reinit_and_use_struct();
+    // test_1211_field_void_reinit_and_use_tuple();
+
+    issue_26996();
+    issue_27021();
+}
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
new file mode 100644 (file)
index 0000000..aec7f67
--- /dev/null
@@ -0,0 +1,186 @@
+error[E0381]: assign to part of possibly uninitialized variable: `s`
+  --> $DIR/issue-21232-partial-init-and-use.rs:99:5
+   |
+LL |     s.x = 10; s.y = Box::new(20);
+   |     ^^^^^^^^ use of possibly uninitialized `s`
+
+error[E0381]: assign to part of possibly uninitialized variable: `t`
+  --> $DIR/issue-21232-partial-init-and-use.rs:106:5
+   |
+LL |     t.0 = 10; t.1 = Box::new(20);
+   |     ^^^^^^^^ use of possibly uninitialized `t`
+
+error[E0382]: assign to part of moved value: `s`
+  --> $DIR/issue-21232-partial-init-and-use.rs:113:5
+   |
+LL |     let mut s: S<B> = S::new(); drop(s);
+   |                                      - value moved here
+LL |     s.x = 10; s.y = Box::new(20);
+   |     ^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `t`
+  --> $DIR/issue-21232-partial-init-and-use.rs:120:5
+   |
+LL |     let mut t: T = (0, Box::new(0)); drop(t);
+   |                                           - value moved here
+LL |     t.0 = 10; t.1 = Box::new(20);
+   |     ^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
+
+error[E0381]: assign to part of possibly uninitialized variable: `s`
+  --> $DIR/issue-21232-partial-init-and-use.rs:127:5
+   |
+LL |     s.x = 10;
+   |     ^^^^^^^^ use of possibly uninitialized `s`
+
+error[E0381]: assign to part of possibly uninitialized variable: `t`
+  --> $DIR/issue-21232-partial-init-and-use.rs:134:5
+   |
+LL |     t.0 = 10;
+   |     ^^^^^^^^ use of possibly uninitialized `t`
+
+error[E0382]: assign to part of moved value: `s`
+  --> $DIR/issue-21232-partial-init-and-use.rs:141:5
+   |
+LL |     let mut s: S<B> = S::new(); drop(s);
+   |                                      - value moved here
+LL |     s.x = 10;
+   |     ^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `t`
+  --> $DIR/issue-21232-partial-init-and-use.rs:148:5
+   |
+LL |     let mut t: T = (0, Box::new(0)); drop(t);
+   |                                           - value moved here
+LL |     t.0 = 10;
+   |     ^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
+
+error[E0381]: assign to part of possibly uninitialized variable: `s`
+  --> $DIR/issue-21232-partial-init-and-use.rs:155:5
+   |
+LL |     s.x = 10;
+   |     ^^^^^^^^ use of possibly uninitialized `s`
+
+error[E0381]: assign to part of possibly uninitialized variable: `t`
+  --> $DIR/issue-21232-partial-init-and-use.rs:162:5
+   |
+LL |     t.0 = 10;
+   |     ^^^^^^^^ use of possibly uninitialized `t`
+
+error[E0381]: assign to part of possibly uninitialized variable: `q`
+  --> $DIR/issue-21232-partial-init-and-use.rs:178:5
+   |
+LL |     q.r.f.x = 10; q.r.f.y = Box::new(20);
+   |     ^^^^^^^^^^^^ use of possibly uninitialized `q.r.f`
+
+error[E0381]: assign to part of possibly uninitialized variable: `q`
+  --> $DIR/issue-21232-partial-init-and-use.rs:185:5
+   |
+LL |     q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+   |     ^^^^^^^^^^^^ use of possibly uninitialized `q.r.f`
+
+error[E0382]: assign to part of moved value: `q.r`
+  --> $DIR/issue-21232-partial-init-and-use.rs:192:5
+   |
+LL |     let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+   |                                                 --- value moved here
+LL |     q.r.f.x = 10; q.r.f.y = Box::new(20);
+   |     ^^^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `q.r` has type `R<S<std::boxed::Box<u32>>>`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `q.r`
+  --> $DIR/issue-21232-partial-init-and-use.rs:199:5
+   |
+LL |     let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+   |                                                      --- value moved here
+LL |     q.r.f.0 = 10; q.r.f.1 = Box::new(20);
+   |     ^^^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `q.r` has type `R<(u32, std::boxed::Box<u32>)>`, which does not implement the `Copy` trait
+
+error[E0381]: assign to part of possibly uninitialized variable: `q`
+  --> $DIR/issue-21232-partial-init-and-use.rs:206:5
+   |
+LL |     q.r.f.x = 10;
+   |     ^^^^^^^^^^^^ use of possibly uninitialized `q.r.f`
+
+error[E0381]: assign to part of possibly uninitialized variable: `q`
+  --> $DIR/issue-21232-partial-init-and-use.rs:213:5
+   |
+LL |     q.r.f.0 = 10;
+   |     ^^^^^^^^^^^^ use of possibly uninitialized `q.r.f`
+
+error[E0382]: assign to part of moved value: `q.r`
+  --> $DIR/issue-21232-partial-init-and-use.rs:220:5
+   |
+LL |     let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
+   |                                                 --- value moved here
+LL |     q.r.f.x = 10;
+   |     ^^^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `q.r` has type `R<S<std::boxed::Box<u32>>>`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `q.r`
+  --> $DIR/issue-21232-partial-init-and-use.rs:227:5
+   |
+LL |     let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
+   |                                                      --- value moved here
+LL |     q.r.f.0 = 10;
+   |     ^^^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `q.r` has type `R<(u32, std::boxed::Box<u32>)>`, which does not implement the `Copy` trait
+
+error[E0381]: assign to part of possibly uninitialized variable: `q`
+  --> $DIR/issue-21232-partial-init-and-use.rs:234:5
+   |
+LL |     q.r.f.x = 10;
+   |     ^^^^^^^^^^^^ use of possibly uninitialized `q.r.f`
+
+error[E0381]: assign to part of possibly uninitialized variable: `q`
+  --> $DIR/issue-21232-partial-init-and-use.rs:241:5
+   |
+LL |     q.r.f.0 = 10;
+   |     ^^^^^^^^^^^^ use of possibly uninitialized `q.r.f`
+
+error[E0382]: assign to part of moved value: `c`
+  --> $DIR/issue-21232-partial-init-and-use.rs:259:13
+   |
+LL |         c2 => {
+   |         -- value moved here
+LL |             c.0 = 2; //~ ERROR assign to part of moved value
+   |             ^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `c`
+  --> $DIR/issue-21232-partial-init-and-use.rs:269:13
+   |
+LL |         c2 => {
+   |         -- value moved here
+LL |             (c.1).0 = 2; //~ ERROR assign to part of moved value
+   |             ^^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait
+
+error[E0382]: assign to part of moved value: `c.1`
+  --> $DIR/issue-21232-partial-init-and-use.rs:277:13
+   |
+LL |         c2 => {
+   |         -- value moved here
+LL |             ((c.1).1).0 = 3; //~ ERROR assign to part of moved value
+   |             ^^^^^^^^^^^^^^^ value partially assigned here after move
+   |
+   = note: move occurs because `c.1` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait
+
+error: aborting due to 23 previous errors
+
+Some errors occurred: E0381, E0382.
+For more information about an error, try `rustc --explain E0381`.
index 4543d2ba638c46681019e96efba1fa714c152eec..43debec69b5f25ceaf11cc1d170289479fb6e14f 100644 (file)
@@ -15,5 +15,5 @@ fn main() {
     let range = 0..1;
     let r = range;
     let x = range.start;
-    //~^ ERROR use of moved value: `range.start` [E0382]
+    //~^ ERROR use of moved value: `range` [E0382]
 }
index 102de43e5d710077234b67317d70dc504c29de91..49c419998a4809d766bf8e8902114e02debc8e48 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `range.start`
+error[E0382]: use of moved value: `range`
   --> $DIR/issue-51512.rs:17:13
    |
 LL |     let r = range;
index 2b0e5039d8d4ed4bdb1c71d7376939676c4f0318..901ace59d33a04c75320af5150fe6a485e31f67c 100644 (file)
@@ -1,4 +1,4 @@
-error: user substs: Canonical { variables: [], value: [u32] }
+error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
   --> $DIR/dump-adt-brace-struct.rs:28:5
    |
 LL |     SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
index 6531f87dd9878377e86357220548120e643ac5ed..a26be359fc4aa4c28ed9b608c31d6604a727483d 100644 (file)
@@ -1,22 +1,22 @@
-error: user substs: Canonical { variables: [], value: [u32] }
+error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:36:13
    |
 LL |     let x = foo::<u32>; //~ ERROR [u32]
    |             ^^^^^^^^^^
 
-error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, u32, ?1] }
+error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, u32, ?1], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:42:13
    |
 LL |     let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { variables: [], value: [u8, u16, u32] }
+error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:46:13
    |
 LL |     let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, ?1, u32] }
+error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, ?1, u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:54:5
    |
 LL |     y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs
new file mode 100644 (file)
index 0000000..b7292c0
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(nll)]
+
+// Check that substitutions given on the self type (here, `A`) carry
+// through to NLL.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = A::<'a>::new(&v, 22);
+    //~^ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr
new file mode 100644 (file)
index 0000000..aa133ce
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-1.rs:16:26
+   |
+LL |     let x = A::<'a>::new(&v, 22);
+   |                          ^^ borrowed value does not live long enough
+LL |     //~^ ERROR
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-1.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
new file mode 100644 (file)
index 0000000..a77d6af
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(nll)]
+
+// Check that substitutions given on the self type (here, `A`) can be
+// used in combination with annotations given for method arguments.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = A::<'a>::new::<&'a u32>(&v, &v);
+    //~^ ERROR
+    //~| ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
new file mode 100644 (file)
index 0000000..f1f4787
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-2.rs:16:37
+   |
+LL |     let x = A::<'a>::new::<&'a u32>(&v, &v);
+   |                                     ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-2.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-2.rs:16:41
+   |
+LL |     let x = A::<'a>::new::<&'a u32>(&v, &v);
+   |                                         ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-2.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs
new file mode 100644 (file)
index 0000000..24d83c4
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(nll)]
+
+// Check that inherent methods invoked with `<T>::new` style
+// carry their annotations through to NLL.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = <A<'a>>::new(&v, 22);
+    //~^ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr
new file mode 100644 (file)
index 0000000..f3766a8
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-3.rs:16:26
+   |
+LL |     let x = <A<'a>>::new(&v, 22);
+   |                          ^^ borrowed value does not live long enough
+LL |     //~^ ERROR
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-3.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
new file mode 100644 (file)
index 0000000..3f88c3d
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(nll)]
+
+// Check that inherent methods invoked with `<T>::new` style
+// carry their annotations through to NLL in connection with
+// method type parameters.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = <A<'a>>::new::<&'a u32>(&v, &v);
+    //~^ ERROR
+    //~| ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
new file mode 100644 (file)
index 0000000..c9bce50
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-4.rs:17:37
+   |
+LL |     let x = <A<'a>>::new::<&'a u32>(&v, &v);
+   |                                     ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8...
+  --> $DIR/method-ufcs-inherent-4.rs:15:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-4.rs:17:41
+   |
+LL |     let x = <A<'a>>::new::<&'a u32>(&v, &v);
+   |                                         ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8...
+  --> $DIR/method-ufcs-inherent-4.rs:15:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
index 37bf19e61f8d84d765ee585df142245eb2e5dc8c..268a16e5d2a0f0163e01cf80efb8407443c0df21 100644 (file)
@@ -2,7 +2,7 @@ error[E0432]: unresolved import `alloc`
   --> $DIR/issue-54006.rs:16:5
    |
 LL | use alloc::vec;
-   |     ^^^^^ Did you mean `std::alloc`?
+   |     ^^^^^ Did you mean `core::alloc`?
 
 error: cannot determine resolution for the macro `vec`
   --> $DIR/issue-54006.rs:20:18
index 0f19c48337b1e351554c184ebbe7f0a6ba3c0494..d7c80a677a5e13d334ca4a98d7e457e04dcc63b7 100644 (file)
@@ -12,7 +12,7 @@ fn main() {
     let v = vec![0, 1, 2, 3];
 
     for (i, n) in &v.iter().enumerate() {
-        //~^ ERROR the trait bound
+        //~^ ERROR `&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
         println!("{}", i);
     }
 }
index c47b4d283d7cda5195b9edc6087ca8931276e4cc..1fc661efd91f4b7f9bdffa01771e6b4d9a1d6f8f 100644 (file)
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>: std::iter::Iterator` is not satisfied
+error[E0277]: `&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
   --> $DIR/suggest-remove-refs-1.rs:14:19
    |
 LL |     for (i, n) in &v.iter().enumerate() {
    |                   -^^^^^^^^^^^^^^^^^^^^
    |                   |
-   |                   `&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator; maybe try calling `.iter()` or a similar method
+   |                   `&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |                   help: consider removing 1 leading `&`-references
    |
    = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>`
index c427f697ae1efe297f6b0aa8fba5f7f9a74d4887..37af97323d5980b8c7d2c00a2179aa4be94df74a 100644 (file)
@@ -12,7 +12,7 @@ fn main() {
     let v = vec![0, 1, 2, 3];
 
     for (i, n) in & & & & &v.iter().enumerate() {
-        //~^ ERROR the trait bound
+        //~^ ERROR `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
         println!("{}", i);
     }
 }
index fdd654ea3923f9019a2ecc204be1e0f610ab0d64..96c6c92d59baa94a356c17fac1267baa33e50691 100644 (file)
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>: std::iter::Iterator` is not satisfied
+error[E0277]: `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
   --> $DIR/suggest-remove-refs-2.rs:14:19
    |
 LL |     for (i, n) in & & & & &v.iter().enumerate() {
    |                   ---------^^^^^^^^^^^^^^^^^^^^
    |                   |
-   |                   `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator; maybe try calling `.iter()` or a similar method
+   |                   `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |                   help: consider removing 5 leading `&`-references
    |
    = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>`
index f54ae30caebca921c40229dec68cca855fa352e4..c9dff35f92c0b860f1f24fa76bb041a70251998b 100644 (file)
@@ -15,7 +15,7 @@ fn main() {
         & &v
         .iter()
         .enumerate() {
-        //~^^^^ ERROR the trait bound
+        //~^^^^ ERROR `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an
         println!("{}", i);
     }
 }
index b0920a0fa523ee2b1850db901d036b29689c8955..4311c432b41d35a82f74a6caaaa6da91150087ad 100644 (file)
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>: std::iter::Iterator` is not satisfied
+error[E0277]: `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
   --> $DIR/suggest-remove-refs-3.rs:14:19
    |
 LL |        for (i, n) in & & &
@@ -9,7 +9,7 @@ LL | ||         & &v
    | ||___________- help: consider removing 5 leading `&`-references
 LL | |          .iter()
 LL | |          .enumerate() {
-   | |_____________________^ `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator; maybe try calling `.iter()` or a similar method
+   | |_____________________^ `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required by `std::iter::IntoIterator::into_iter`
index 1ca2a56e757fbf9039c73622fca2a89079d9d378..a4f5e41b5291c7e57db7eae26469bdf0712eddab 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `u.y`
+error[E0382]: use of moved value: `u`
   --> $DIR/union-borrow-move-parent-sibling.rs:29:13
    |
 LL |     let a = u.x.0;
@@ -8,7 +8,7 @@ LL |     let a = u.y; //~ ERROR use of moved value: `u.y`
    |
    = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.y`
+error[E0382]: use of moved value: `u`
   --> $DIR/union-borrow-move-parent-sibling.rs:41:13
    |
 LL |     let a = (u.x.0).0;
@@ -18,7 +18,7 @@ LL |     let a = u.y; //~ ERROR use of moved value: `u.y`
    |
    = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
 
-error[E0382]: use of moved value: `u.x`
+error[E0382]: use of moved value: `u`
   --> $DIR/union-borrow-move-parent-sibling.rs:53:13
    |
 LL |     let a = *u.y;
diff --git a/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr b/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr
new file mode 100644 (file)
index 0000000..f133249
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0382]: use of moved value: `self`
+  --> $DIR/use-after-move-self-based-on-type.rs:22:16
+   |
+LL |         self.bar();
+   |         ---- value moved here
+LL |         return self.x;  //~ ERROR use of moved value: `self.x`
+   |                ^^^^^^ value used here after move
+   |
+   = note: move occurs because `self` has type `S`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index 3b19e96d12cce5cac2771b5a742d3762cfff6ebf..241dc32bb05e3b18c140938e2d33fbdfe23031d0 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: use of moved value: `*self.x`
+error[E0382]: use of moved value: `self`
   --> $DIR/use-after-move-self.rs:20:16
    |
 LL |         self.bar();
index 668473882ab6e468cfe64e02068430031dc0cc38..e2c4a19debe4b5da84062e374267716f3b56f668 100644 (file)
@@ -1,4 +1,4 @@
-error[E0382]: borrow of moved value: `start.test`
+error[E0382]: borrow of moved value: `start`
   --> $DIR/walk-struct-literal-with.rs:26:20
    |
 LL |     let end = Mine{other_val:1, ..start.make_string_bar()};