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)",
/// [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 {
}
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);
+ }
+ }
+ }
+}
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 });
+
/// 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>,
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);
pub mod lattice;
mod lexical_region_resolve;
mod lub;
+pub mod nll_relate;
pub mod opaque_types;
pub mod outlives;
pub mod region_constraints;
--- /dev/null
+// 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,
+ );
+ }
+ }
+ }
+}
/// 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.
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
}
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,
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>,
) {
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 {
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)) => {
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)
+ };
}
}
}
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
// 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)),
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)) => {
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;
/// 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.
///
/// - `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,
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) |
_ => 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> {
&'tcx AdtDef,
usize,
&'tcx Substs<'tcx>,
- Option<CanonicalTy<'tcx>>,
+ Option<UserTypeAnnotation<'tcx>>,
Option<usize>,
),
/// 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>,
/// 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[{}]"
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;
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,
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,
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 => {}
}
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,
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);
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>) {
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;
/// 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 {
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,
has_global_allocator: Once::new(),
has_panic_handler: Once::new(),
driver_lint_caps: FxHashMap(),
- extern_prelude,
};
validate_commandline_args_with_session_available(&sess);
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();
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
) {
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};
/// 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>>>,
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()
}
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>>>,
.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(
// 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;
}
}
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;
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)]
}
}
-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> {}
///////////////////////////////////////////////////////////////////////////
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,
+ }
+}
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"
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.
--- /dev/null
+// 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
+ }
+}
mod node_index;
use self::node_index::NodeIndex;
+mod graphviz;
+
#[cfg(test)]
mod test;
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 {
($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,
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,
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");
&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();
.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())
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,
);
} 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 \
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,
);
);
}
- 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);
}
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();
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;
MatchOn,
Use,
Assignment,
+ PartialAssignment,
}
struct RootPlace<'d, 'tcx: 'd> {
InitializationRequiringAction::MatchOn => "use", // no good noun
InitializationRequiringAction::Use => "use",
InitializationRequiringAction::Assignment => "assign",
+ InitializationRequiringAction::PartialAssignment => "assign to part",
}
}
InitializationRequiringAction::MatchOn => "matched on",
InitializationRequiringAction::Use => "used",
InitializationRequiringAction::Assignment => "assigned",
+ InitializationRequiringAction::PartialAssignment => "partially assigned",
}
}
}
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);
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.
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.
/// 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;
}
// 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);
+ }
+ }
+
_ => {}
}
}
}
}
}
- }
+ 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
///
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 { .. }))
}
// 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
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 {
}
}
- /// 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,
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,
- });
+ })
}
}
}
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>,
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
- _c_ty: &CanonicalTy<'tcx>,
+ _user_ty: &UserTypeAnnotation<'tcx>,
_location: Location,
) {
}
// 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};
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) {
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};
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
- b: CanonicalTy<'tcx>,
+ b: UserTypeAnnotation<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
/// 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(..)
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>(
) -> 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(())
}
) -> 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(())
}
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
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> {
}
}
}
-
-#[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))
- }
-}
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};
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,
NodeId,
Span,
Ty<'tcx>,
- Option<(CanonicalTy<'tcx>, Span)>,
+ Option<(UserTypeAnnotation<'tcx>, Span)>,
),
) {
match *pattern.kind {
struct Ascription<'tcx> {
span: Span,
source: Place<'tcx>,
- user_ty: CanonicalTy<'tcx>,
+ user_ty: UserTypeAnnotation<'tcx>,
}
#[derive(Clone, Debug)]
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,
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
})
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()
}
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(),
}
}
-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
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) =>
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)
}
}
.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)
}
};
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,
//! 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;
/// 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>>
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,
},
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,
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};
Wild,
AscribeUserType {
- user_ty: CanonicalTy<'tcx>,
+ user_ty: UserTypeAnnotation<'tcx>,
subpattern: Pattern<'tcx>,
user_ty_span: Span,
},
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> {
// 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>;
&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,
// 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.
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>,
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)));
// AST.
graph_root,
prelude: None,
+ extern_prelude,
has_self: FxHashSet(),
field_names: FxHashMap(),
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);
} 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);
}
);
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) => {
}
}
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 =
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;
} 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);
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 }))
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};
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);
/// 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,
);
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,
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);
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) => {
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,
+ });
+ }
+ }
}
}
_ => {}
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);
// 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`
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)
}
// 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;
}
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()),
output_types: outputs,
externs,
cg: config::CodegenOptions {
- prefer_dynamic: true,
linker,
..cg
},
// 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;
// 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 {
// 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 {
#![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 {}
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 ----
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:
-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`.
-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);
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 };
|
= 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`.
-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};
-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};
-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;
-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;
-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`.
-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`.
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]
+
}
-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;
|
= 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;
|
= 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;
-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;
|
= 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;
|
= 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;
|
= 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;
-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`.
-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]
-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]
-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`
-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`
-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]
-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]
--- /dev/null
+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`.
--- /dev/null
+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`.
--- /dev/null
+// 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]
+ }
+}
--- /dev/null
+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`.
--- /dev/null
+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`.
--- /dev/null
+// 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);
+ }
+}
--- /dev/null
+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`.
--- /dev/null
+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`.
--- /dev/null
+// 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]
+ }
+}
--- /dev/null
+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`.
--- /dev/null
+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`.
--- /dev/null
+// 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]
+ }
+}
-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`.
-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`.
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`.
// #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() {}
-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
= 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
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`
-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" {
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);
}
}
-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`
-error[E0382]: use of moved value: `foo.0`
+error[E0382]: use of moved value: `foo`
--> $DIR/issue-17385.rs:29:11
|
LL | drop(foo);
--- /dev/null
+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() {}
--- /dev/null
+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`.
_ 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."),
}
}
-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; })();
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()
}
// 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
}
-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`
//~^ 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() {}
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
--- /dev/null
+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] {}
+}
--- /dev/null
+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`.
--- /dev/null
+fn main() {
+ for _ in [1, 2] {}
+ let x = [1, 2];
+ for _ in x {}
+ for _ in [1.0, 2.0] {}
+}
--- /dev/null
+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`.
--- /dev/null
+struct S<I: Iterator>(I);
+struct T(S<u8>);
+fn main() {}
--- /dev/null
+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`.
--- /dev/null
+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
+}
--- /dev/null
+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`.
--- /dev/null
+fn main() {
+ for _ in ..10 {}
+ //~^ ERROR E0277
+ for _ in ..=10 {}
+ //~^ ERROR E0277
+ for _ in 0..10 {}
+ for _ in 0..=10 {}
+ for _ in 0.. {}
+}
--- /dev/null
+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`.
--- /dev/null
+fn main() {
+ for _ in "".to_owned() {}
+ //~^ ERROR `std::string::String` is not an iterator
+ for _ in "" {}
+ //~^ ERROR `&str` is not an iterator
+}
--- /dev/null
+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`.
-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;
--- /dev/null
+// 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() { }
--- /dev/null
+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`.
--- /dev/null
+// 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();
+}
--- /dev/null
+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`.
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]
}
-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;
-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]
-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]
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--> $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
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);
}
}
-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}>>`
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);
}
}
-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}>>`
& &v
.iter()
.enumerate() {
- //~^^^^ ERROR the trait bound
+ //~^^^^ ERROR `&&&&&std::iter::Enumerate<std::slice::Iter<'_, {integer}>>` is not an
println!("{}", i);
}
}
-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 & & &
| ||___________- 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`
-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;
|
= 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;
|
= 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;
--- /dev/null
+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`.
-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();
-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()};