diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 65146f2de8441..b10f4785f1637 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -68,7 +68,7 @@ pub enum Def { Const(DefId), Static(DefId, bool /* is_mutbl */), StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor - VariantCtor(DefId, CtorKind), + VariantCtor(DefId, CtorKind), // DefId refers to the enum variant Method(DefId), AssociatedConst(DefId), diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 38ea536b4ee72..1c9387d02d5a3 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -479,10 +479,11 @@ for mir::AggregateKind<'gcx> { mir::AggregateKind::Array(t) => { t.hash_stable(hcx, hasher); } - mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => { + mir::AggregateKind::Adt(adt_def, idx, substs, user_substs, active_field) => { adt_def.hash_stable(hcx, hasher); idx.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); + user_substs.hash_stable(hcx, hasher); active_field.hash_stable(hcx, hasher); } mir::AggregateKind::Closure(def_id, ref substs) => { @@ -528,7 +529,7 @@ impl_stable_hash_for!(enum mir::NullOp { SizeOf }); -impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); +impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, user_ty, literal }); impl_stable_hash_for!(struct mir::Location { block, statement_index }); diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 2e57ef7b17d44..85aa4f62f214c 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -188,6 +188,36 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> { } } +impl<'gcx, V> Canonical<'gcx, V> { + /// Allows you to map the `value` of a canonical while keeping the + /// same set of bound variables. + /// + /// **WARNING:** This function is very easy to mis-use, hence the + /// name! In particular, the new value `W` must use all **the + /// same type/region variables** in **precisely the same order** + /// as the original! (The ordering is defined by the + /// `TypeFoldable` implementation of the type in question.) + /// + /// An example of a **correct** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical<'_, T> = ...; + /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); + /// ``` + /// + /// An example of an **incorrect** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical<'tcx, T> = ...; + /// let ty: Ty<'tcx> = ...; + /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); + /// ``` + pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> { + let Canonical { variables, value } = self; + Canonical { variables, value: map_op(value) } + } +} + pub type QueryRegionConstraint<'tcx> = ty::Binder, Region<'tcx>>>; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 14981a700a32e..7f292f6167f3a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1888,12 +1888,15 @@ pub enum Operand<'tcx> { /// This implies that the type of the place must be `Copy`; this is true /// by construction during build, but also checked by the MIR type checker. Copy(Place<'tcx>), + /// Move: The value (including old borrows of it) will not be used again. /// /// Safe for values of all types (modulo future developments towards `?Move`). /// Correct usage patterns are enforced by the borrow checker for safe code. /// `Copy` may be converted to `Move` to enable "last-use" optimizations. Move(Place<'tcx>), + + /// Synthesizes a constant value. Constant(Box>), } @@ -1909,6 +1912,9 @@ impl<'tcx> Debug for Operand<'tcx> { } impl<'tcx> Operand<'tcx> { + /// Convenience helper to make a constant that refers to the fn + /// with given def-id and substs. Since this is used to synthesize + /// MIR, assumes `user_ty` is None. pub fn function_handle<'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, @@ -1919,6 +1925,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, ty, + user_ty: None, literal: ty::Const::zero_sized(tcx, ty), }) } @@ -2002,7 +2009,7 @@ pub enum AggregateKind<'tcx> { /// active field number and is present only for union expressions /// -- e.g. for a union expression `SomeUnion { c: .. }`, the /// active field index would identity the field `c` - Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option), + Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option>, Option), Closure(DefId, ClosureSubsts<'tcx>), Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), @@ -2128,7 +2135,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { _ => fmt_tuple(fmt, places), }, - AggregateKind::Adt(adt_def, variant, substs, _) => { + AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { let variant_def = &adt_def.variants[variant]; ppaux::parameterized(fmt, substs, variant_def.did, &[])?; @@ -2207,6 +2214,14 @@ impl<'tcx> Debug for Rvalue<'tcx> { pub struct Constant<'tcx> { pub span: Span, pub ty: Ty<'tcx>, + + /// Optional user-given type: for something like + /// `collect::>`, this would be present and would + /// indicate that `Vec<_>` was explicitly specified. + /// + /// Needed for NLL to impose user-given type constraints. + pub user_ty: Option>, + pub literal: &'tcx ty::Const<'tcx>, } @@ -2798,8 +2813,14 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { let kind = box match **kind { AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), AggregateKind::Tuple => AggregateKind::Tuple, - AggregateKind::Adt(def, v, substs, n) => { - AggregateKind::Adt(def, v, substs.fold_with(folder), n) + AggregateKind::Adt(def, v, substs, user_ty, n) => { + AggregateKind::Adt( + def, + v, + substs.fold_with(folder), + user_ty.fold_with(folder), + n, + ) } AggregateKind::Closure(id, substs) => { AggregateKind::Closure(id, substs.fold_with(folder)) @@ -2831,7 +2852,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { (match **kind { AggregateKind::Array(ty) => ty.visit_with(visitor), AggregateKind::Tuple => false, - AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), + AggregateKind::Adt(_, _, substs, user_ty, _) => + substs.visit_with(visitor) || user_ty.visit_with(visitor), AggregateKind::Closure(_, substs) => substs.visit_with(visitor), AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), }) || fields.visit_with(visitor) @@ -2902,6 +2924,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { Constant { span: self.span.clone(), ty: self.ty.fold_with(folder), + user_ty: self.user_ty.fold_with(folder), literal: self.literal.fold_with(folder), } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index ec395478ec6b5..c928be4f9df78 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -216,7 +216,7 @@ impl<'tcx> Rvalue<'tcx> { AggregateKind::Tuple => { tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))) } - AggregateKind::Adt(def, _, substs, _) => { + AggregateKind::Adt(def, _, substs, _, _) => { tcx.type_of(def.did).subst(tcx, substs) } AggregateKind::Closure(did, substs) => { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index cab6ed0c122cd..c7723fdf19137 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -213,6 +213,10 @@ macro_rules! make_mir_visitor { self.super_ty(ty); } + fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) { + self.super_canonical_ty(ty); + } + fn visit_region(&mut self, region: & $($mutability)* ty::Region<'tcx>, _: Location) { @@ -585,6 +589,7 @@ macro_rules! make_mir_visitor { AggregateKind::Adt(_adt_def, _variant_index, ref $($mutability)* substs, + _user_substs, _active_field_index) => { self.visit_substs(substs, location); } @@ -625,9 +630,10 @@ macro_rules! make_mir_visitor { } fn super_user_assert_ty(&mut self, - _c_ty: & $($mutability)* CanonicalTy<'tcx>, + c_ty: & $($mutability)* CanonicalTy<'tcx>, local: & $($mutability)* Local, location: Location) { + self.visit_canonical_ty(c_ty); self.visit_local(local, PlaceContext::Validate, location); } @@ -740,11 +746,13 @@ macro_rules! make_mir_visitor { let Constant { ref $($mutability)* span, ref $($mutability)* ty, + ref $($mutability)* user_ty, ref $($mutability)* literal, } = *constant; self.visit_span(span); self.visit_ty(ty, TyContext::Location(location)); + drop(user_ty); // no visit method for this self.visit_const(literal, location); } @@ -764,6 +772,9 @@ macro_rules! make_mir_visitor { self.visit_source_scope(scope); } + fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) { + } + fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0545a88f36bdc..424139e752736 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; use mir::interpret::Allocation; -use ty::subst::{Kind, Substs, Subst}; +use ty::subst::{CanonicalSubsts, Kind, Substs, Subst}; use ty::ReprOptions; use traits; use traits::{Clause, Clauses, Goal, Goals}; @@ -371,6 +371,18 @@ pub struct TypeckTables<'tcx> { /// other items. node_substs: ItemLocalMap<&'tcx Substs<'tcx>>, + /// Stores the substitutions that the user explicitly gave (if any) + /// attached to `id`. These will not include any inferred + /// values. The canonical form is used to capture things like `_` + /// or other unspecified values. + /// + /// Example: + /// + /// If the user wrote `foo.collect::>()`, then the + /// canonical substitutions would include only `for { Vec + /// }`. + user_substs: ItemLocalMap>, + adjustments: ItemLocalMap>>, /// Stores the actual binding mode for all instances of hir::BindingAnnotation. @@ -444,6 +456,7 @@ impl<'tcx> TypeckTables<'tcx> { user_provided_tys: ItemLocalMap(), node_types: ItemLocalMap(), node_substs: ItemLocalMap(), + user_substs: ItemLocalMap(), adjustments: ItemLocalMap(), pat_binding_modes: ItemLocalMap(), pat_adjustments: ItemLocalMap(), @@ -561,6 +574,18 @@ impl<'tcx> TypeckTables<'tcx> { self.node_substs.get(&id.local_id).cloned() } + pub fn user_substs_mut(&mut self) -> LocalTableInContextMut> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.user_substs + } + } + + pub fn user_substs(&self, id: hir::HirId) -> Option> { + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); + self.user_substs.get(&id.local_id).cloned() + } + // Returns the type of a pattern as a monotype. Like @expr_ty, this function // doesn't provide type parameter substitutions. pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { @@ -740,6 +765,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { ref user_provided_tys, ref node_types, ref node_substs, + ref user_substs, ref adjustments, ref pat_binding_modes, ref pat_adjustments, @@ -762,6 +788,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { user_provided_tys.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); + user_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); pat_binding_modes.hash_stable(hcx, hasher); pat_adjustments.hash_stable(hcx, hasher); diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0e85c68b8b1de..6dadc5070368b 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -11,13 +11,15 @@ // Type substitutions. use hir::def_id::DefId; -use ty::{self, Lift, List, Ty, TyCtxt}; +use infer::canonical::Canonical; +use ty::{self, CanonicalVar, Lift, List, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::array_vec::ArrayVec; +use rustc_data_structures::indexed_vec::Idx; use core::intrinsics; use std::cmp::Ordering; @@ -339,6 +341,33 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } +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> {} /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index 25f32360815e7..e301e5ae70be8 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -148,7 +148,7 @@ impl FunctionCx<'a, 'll, 'tcx> { mir::Rvalue::Aggregate(ref kind, ref operands) => { let (dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { + mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { dest.codegen_set_discr(&bx, variant_index); if adt_def.is_enum() { (dest.project_downcast(&bx, variant_index), active_field_index) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 2fb5861dff444..5c14e552cfd37 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -15,7 +15,7 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; -use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues}; +use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements}; use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap; @@ -256,6 +256,22 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.super_constant(constant, location); self.sanitize_constant(constant, location); self.sanitize_type(constant, constant.ty); + + if let Some(user_ty) = constant.user_ty { + if let Err(terr) = + self.cx + .eq_canonical_type_and_type(user_ty, constant.ty, location.boring()) + { + span_mirbug!( + self, + constant, + "bad constant user type {:?} vs {:?}: {:?}", + user_ty, + constant.ty, + terr, + ); + } + } } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { @@ -343,8 +359,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty); - if let Err(terr) = self - .cx + if let Err(terr) = self.cx .eq_types(constant.literal.ty, constant.ty, location.boring()) { span_mirbug!( @@ -902,6 +917,24 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { terr ); } + + if let Some(user_ty) = self.rvalue_user_ty(rv) { + if let Err(terr) = self.eq_canonical_type_and_type( + user_ty, + rv_ty, + location.boring(), + ) { + span_mirbug!( + self, + stmt, + "bad user type on rvalue ({:?} = {:?}): {:?}", + user_ty, + rv_ty, + terr + ); + } + } + self.check_rvalue(mir, rv, location); if !self.tcx().features().unsized_locals { let trait_ref = ty::TraitRef { @@ -1376,7 +1409,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let tcx = self.tcx(); match *ak { - AggregateKind::Adt(def, variant_index, substs, active_field_index) => { + AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => { let variant = &def.variants[variant_index]; let adj_field_index = active_field_index.unwrap_or(field_index); if let Some(field) = variant.fields.get(adj_field_index) { @@ -1542,6 +1575,36 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } + /// 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> { + match rvalue { + Rvalue::Use(_) | + Rvalue::Repeat(..) | + Rvalue::Ref(..) | + Rvalue::Len(..) | + Rvalue::Cast(..) | + Rvalue::BinaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::NullaryOp(..) | + Rvalue::UnaryOp(..) | + Rvalue::Discriminant(..) => + None, + + Rvalue::Aggregate(aggregate, _) => match **aggregate { + AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, + AggregateKind::Array(_) => None, + AggregateKind::Tuple => None, + AggregateKind::Closure(_, _) => None, + AggregateKind::Generator(_, _, _) => None, + } + } + } + fn check_aggregate_rvalue( &mut self, mir: &Mir<'tcx>, @@ -1735,7 +1798,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); let instantiated_predicates = match aggregate_kind { - AggregateKind::Adt(def, _, substs, _) => { + AggregateKind::Adt(def, _, substs, _, _) => { tcx.predicates_of(def.did).instantiate(tcx, substs) } diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index a57f1b9549485..1106f750d6d24 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -31,8 +31,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), - ExprKind::Literal { literal } => - Constant { span: span, ty: ty, literal: literal }, + ExprKind::Literal { literal, user_ty } => + Constant { span, ty, user_ty, literal }, _ => span_bug!( span, diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 68009e962a302..b90a58f2a7ec0 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -239,6 +239,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { operands.push(Operand::Constant(box Constant { span: expr_span, ty: this.hir.tcx().types.u32, + user_ty: None, literal: ty::Const::from_bits( this.hir.tcx(), 0, @@ -254,7 +255,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Adt { - adt_def, variant_index, substs, fields, base + adt_def, variant_index, substs, user_ty, fields, base } => { // see (*) above let is_union = adt_def.is_union(); let active_field_index = if is_union { Some(fields[0].name.index()) } else { None }; @@ -284,8 +285,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect() }; - let adt = - box AggregateKind::Adt(adt_def, variant_index, substs, active_field_index); + let adt = box AggregateKind::Adt( + adt_def, + variant_index, + substs, + user_ty, + active_field_index, + ); block.and(Rvalue::Aggregate(adt, fields)) } ExprKind::Assign { .. } | diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 2b05e2c023a5c..3cd1270d7ef11 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -128,6 +128,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Constant { span: expr_span, ty: this.hir.bool_ty(), + user_ty: None, literal: this.hir.true_literal(), }); @@ -136,6 +137,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Constant { span: expr_span, ty: this.hir.bool_ty(), + user_ty: None, literal: this.hir.false_literal(), }); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 15a983635f7ae..4a0b4b0c88580 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -344,7 +344,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { func: Operand::Constant(box Constant { span: test.span, ty: mty, - literal: method + + // FIXME(#47184): This constant comes from user + // input (a constant in a pattern). Are + // there forms where users can add type + // annotations here? For example, an + // associated constant? Need to + // experiment. + user_ty: None, + + literal: method, }), args: vec![val, expect], destination: Some((eq_result.clone(), eq_block)), diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index ae8070698c299..9405f43c056b7 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -32,6 +32,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { place } + /// Convenience function for creating a literal operand, one + /// without any user type annotation. pub fn literal_operand(&mut self, span: Span, ty: Ty<'tcx>, @@ -40,6 +42,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let constant = box Constant { span, ty, + user_ty: None, literal, }; Operand::Constant(constant) @@ -69,6 +72,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Constant { span: source_info.span, ty: self.hir.usize_ty(), + user_ty: None, literal: self.hir.usize_literal(value), }); temp diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 04a3b5c115f22..7153a388467a2 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -256,6 +256,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; if let Some((adt_def, index)) = adt_data { 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) + }) + }); + let field_refs = args.iter() .enumerate() .map(|(idx, e)| { @@ -270,6 +280,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, substs, variant_index: index, fields: field_refs, + user_ty, base: None, } } else { @@ -317,6 +328,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprKind::Lit(ref lit) => ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), + user_ty: None, }, hir::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -406,6 +418,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if let hir::ExprKind::Lit(ref lit) = arg.node { ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + user_ty: None, } } else { ExprKind::Unary { @@ -425,6 +438,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, adt_def: adt, variant_index: 0, substs, + user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt), fields: field_refs(cx, fields), base: base.as_ref().map(|base| { FruInfo { @@ -450,6 +464,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, adt_def: adt, variant_index: index, substs, + user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt), fields: field_refs(cx, fields), base: None, } @@ -631,7 +646,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime, ty, span: expr.span, - kind: ExprKind::Literal { literal }, + kind: ExprKind::Literal { literal, user_ty: None }, }.to_ref(); let offset = mk_const(ty::Const::from_bits( cx.tcx, @@ -684,18 +699,77 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } -fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &hir::Expr, - custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>) - -> Expr<'tcx> { +fn user_annotated_ty_for_def( + cx: &mut Cx<'a, 'gcx, 'tcx>, + hir_id: hir::HirId, + def: &Def, +) -> Option> { + 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 + // `Fn` but with the user-given substitutions. + Def::Fn(_) | + 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) + })), + + Def::Const(_def_id) | + Def::AssociatedConst(_def_id) => + bug!("unimplemented"), + + // A unit struct/variant which is used as a value (e.g., + // `None`). This has the type of the enum/struct that defines + // this variant -- but with the substitutions given by the + // user. + Def::StructCtor(_def_id, CtorKind::Const) | + Def::VariantCtor(_def_id, CtorKind::Const) => + match &cx.tables().node_id_to_type(hir_id).sty { + ty::Adt(adt_def, _) => user_annotated_ty_for_adt(cx, hir_id, adt_def), + sty => bug!("unexpected sty: {:?}", sty), + }, + + _ => + bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id) + } +} + +fn user_annotated_ty_for_adt( + cx: &mut Cx<'a, 'gcx, 'tcx>, + hir_id: hir::HirId, + adt_def: &'tcx AdtDef, +) -> Option> { + let user_substs = cx.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. + cx.tcx().mk_adt(adt_def, user_substs) + })) +} + +fn method_callee<'a, 'gcx, 'tcx>( + cx: &mut Cx<'a, 'gcx, 'tcx>, + expr: &hir::Expr, + overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>, +) -> Expr<'tcx> { let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let (def_id, substs) = custom_callee.unwrap_or_else(|| { - if let Some(def) = cx.tables().type_dependent_defs().get(expr.hir_id) { - (def.def_id(), cx.tables().node_substs(expr.hir_id)) - } else { - span_bug!(expr.span, "no type-dependent def for method callee") + let (def_id, substs, user_ty) = match overloaded_callee { + Some((def_id, substs)) => (def_id, substs, None), + None => { + let type_dependent_defs = cx.tables().type_dependent_defs(); + let def = type_dependent_defs + .get(expr.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); + (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty) } - }); + }; let ty = cx.tcx().mk_fn_def(def_id, substs); Expr { temp_lifetime, @@ -703,6 +777,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx(), ty), + user_ty, }, } } @@ -753,11 +828,15 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::Fn(_) | Def::Method(_) | Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal { - literal: ty::Const::zero_sized( - cx.tcx, - cx.tables().node_id_to_type(expr.hir_id), - ), + Def::VariantCtor(_, CtorKind::Fn) => { + let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def); + ExprKind::Literal { + literal: ty::Const::zero_sized( + cx.tcx, + cx.tables().node_id_to_type(expr.hir_id), + ), + user_ty, + } }, Def::Const(def_id) | @@ -768,6 +847,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, substs, cx.tables().node_id_to_type(expr.hir_id), ), + user_ty: None, // FIXME(#47184) -- user given type annot on constants }, Def::StructCtor(def_id, CtorKind::Const) | @@ -780,6 +860,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, adt_def, variant_index: adt_def.variant_index_with_id(def_id), substs, + user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt_def), fields: vec![], base: None, } @@ -958,12 +1039,13 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } -fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr, - place_ty: Ty<'tcx>, - custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, - args: Vec>) - -> ExprKind<'tcx> { +fn overloaded_place<'a, 'gcx, 'tcx>( + cx: &mut Cx<'a, 'gcx, 'tcx>, + expr: &'tcx hir::Expr, + place_ty: Ty<'tcx>, + overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>, + args: Vec>, +) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types // line up (this is because `*x` and `x[y]` represent places): @@ -988,7 +1070,7 @@ fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let fun = method_callee(cx, expr, custom_callee); + let fun = method_callee(cx, expr, overloaded_callee); let ref_expr = Expr { temp_lifetime, ty: ref_ty, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index c39aa9ca7806d..d6037adb53bb7 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -18,7 +18,7 @@ use rustc::mir::{BinOp, BorrowKind, Field, UnOp}; use rustc::hir::def_id::DefId; use rustc::middle::region; use rustc::ty::subst::Substs; -use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const}; +use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const}; use rustc::hir; use syntax::ast; use syntax_pos::Span; @@ -261,6 +261,11 @@ pub enum ExprKind<'tcx> { adt_def: &'tcx AdtDef, variant_index: usize, substs: &'tcx Substs<'tcx>, + + /// Optional user-given substs: for something like `let x = + /// Bar:: { ... }`. + user_ty: Option>, + fields: Vec>, base: Option> }, @@ -272,6 +277,13 @@ pub enum ExprKind<'tcx> { }, Literal { literal: &'tcx Const<'tcx>, + + /// Optional user-given type: for something like + /// `collect::>`, this would be present and would + /// indicate that `Vec<_>` was explicitly specified. + /// + /// Needed for NLL to impose user-given type constraints. + user_ty: Option>, }, InlineAsm { asm: &'tcx hir::InlineAsm, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index f39a5ee3e4ef2..db556db241773 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -208,7 +208,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { Aggregate(ref kind, ref operands) => { let (dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { + mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { self.write_discriminant_value(variant_index, dest)?; if adt_def.is_enum() { (self.place_downcast(dest, variant_index)?, active_field_index) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 765a47e729e68..7e7e7cfade623 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -440,6 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let func = Operand::Constant(box Constant { span: self.span, ty: func_ty, + user_ty: None, literal: ty::Const::zero_sized(self.tcx, func_ty), }); @@ -498,6 +499,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { box Constant { span: self.span, ty: self.tcx.types.usize, + user_ty: None, literal: ty::Const::from_usize(self.tcx, value), } } @@ -725,6 +727,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (Operand::Constant(box Constant { span, ty, + user_ty: None, literal: ty::Const::zero_sized(tcx, ty), }), vec![rcvr]) @@ -847,7 +850,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, kind: StatementKind::Assign( Place::Local(RETURN_PLACE), Rvalue::Aggregate( - box AggregateKind::Adt(adt_def, variant_no, substs, None), + box AggregateKind::Adt(adt_def, variant_no, substs, None, None), (1..sig.inputs().len()+1).map(|i| { Operand::Move(Place::Local(Local::new(i))) }).collect() diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 8b2b9ef7e814d..cff098c7b73d5 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -48,7 +48,7 @@ impl MirPass for Deaggregator { let mut set_discriminant = None; let active_field_index = match *kind { - AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { + AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { if adt_def.is_enum() { set_discriminant = Some(Statement { kind: StatementKind::SetDiscriminant { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index bbf896e624f20..225de03a32965 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -543,6 +543,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { Rvalue::Use(Operand::Constant(Box::new(Constant { span, ty: self.tcx.types.bool, + user_ty: None, literal: ty::Const::from_bool(self.tcx, val), }))) } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index dc657f228c9fc..db588884d8e61 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -157,7 +157,7 @@ struct TransformVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { // Make a GeneratorState rvalue fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> { - let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None); + let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); Rvalue::Aggregate(box adt, vec![val]) } @@ -177,6 +177,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { let val = Operand::Constant(box Constant { span: source_info.span, ty: self.tcx.types.u32, + user_ty: None, literal: ty::Const::from_bits( self.tcx, state_disc.into(), @@ -710,6 +711,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cond: Operand::Constant(box Constant { span: mir.span, ty: tcx.types.bool, + user_ty: None, literal: ty::Const::from_bool(tcx, false), }), expected: true, diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 4cf4a8f23a443..12780ef8be945 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -103,7 +103,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { if let TyKind::Array(_, len) = place_ty.sty { let span = self.mir.source_info(location).span; let ty = self.tcx.types.usize; - let constant = Constant { span, ty, literal: len }; + let constant = Constant { span, ty, literal: len, user_ty: None }; self.optimizations.arrays_lengths.insert(location, constant); } } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 45e405cb55e32..1c0c98d621c83 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -969,6 +969,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> Operand::Constant(box Constant { span: self.source_info.span, ty: self.tcx().types.usize, + user_ty: None, literal: ty::Const::from_usize(self.tcx(), val.into()), }) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 886f83b8f2f3b..e0643d8f97810 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -397,10 +397,13 @@ impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - let Constant { span, ty, literal } = constant; + let Constant { span, ty, user_ty, literal } = constant; self.push("mir::Constant"); self.push(&format!("+ span: {:?}", span)); self.push(&format!("+ ty: {:?}", ty)); + if let Some(user_ty) = user_ty { + self.push(&format!("+ user_ty: {:?}", user_ty)); + } self.push(&format!("+ literal: {:?}", literal)); } @@ -429,6 +432,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { self.push(&format!("+ movability: {:?}", movability)); } + AggregateKind::Adt(_, _, _, Some(user_ty), _) => { + self.push("adt"); + self.push(&format!("+ user_ty: {:?}", user_ty)); + } + _ => {} }, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a528c8e9b4f96..37f4f22cb02c5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1367,7 +1367,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { -> Ty<'tcx> { let tcx = self.tcx(); - debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})", + debug!("def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})", path.def, opt_self_ty, path.segments); let span = path.span; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index db4dda0da5b4e..54acdd8c55296 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ use rustc::infer::anon_types::AnonTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{GlobalId}; -use rustc::ty::subst::{UnpackedKind, Subst, Substs}; +use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs}; 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}; @@ -122,6 +122,7 @@ use std::ops::{self, Deref}; use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; +use syntax::source_map::DUMMY_SP; use syntax::source_map::original_sp; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; @@ -2058,11 +2059,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { + debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); self.tables .borrow_mut() .type_dependent_defs_mut() .insert(hir_id, Def::Method(method.def_id)); + self.write_substs(hir_id, method.substs); + + // When the method is confirmed, the `method.substs` includes + // parameters from not just the method, but also the impl of + // the method -- in particular, the `Self` type will be fully + // resolved. However, those are not something that the "user + // specified" -- i.e., those types come from the inferred type + // of the receiver, not something the user wrote. So when we + // create the user-substs, we want to replace those earlier + // types with just the types that the user actually wrote -- + // that is, those that appear on the *method itself*. + // + // As an example, if the user wrote something like + // `foo.bar::(...)` -- the `Self` type here will be the + // type of `foo` (possibly adjusted), but we don't want to + // include that. We want just the `[_, u32]` part. + if !method.substs.is_noop() { + let method_generics = self.tcx.generics_of(method.def_id); + if !method_generics.params.is_empty() { + let user_substs = self.infcx.probe(|_| { + let just_method_substs = Substs::for_item(self.tcx, method.def_id, |param, _| { + let i = param.index as usize; + if i < method_generics.parent_count { + self.infcx.var_for_def(DUMMY_SP, param) + } else { + method.substs[i] + } + }); + self.infcx.canonicalize_response(&just_method_substs) + }); + + debug!("write_method_call: user_substs = {:?}", user_substs); + self.write_user_substs(hir_id, user_substs); + } + } } pub fn write_substs(&self, node_id: hir::HirId, substs: &'tcx Substs<'tcx>) { @@ -2076,6 +2113,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// Given the substs that we just converted from the HIR, try to + /// canonicalize them and store them as user-given substitutions + /// (i.e., substitutions that must be respected by the NLL check). + /// + /// 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>) { + if !substs.is_noop() { + let user_substs = self.infcx.canonicalize_response(&substs); + 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>) { + debug!( + "write_user_substs({:?}, {:?}) in fcx {}", + hir_id, + substs, + self.tag(), + ); + + if !substs.is_identity() { + self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs); + } else { + debug!("write_user_substs: skipping identity substs"); + } + } + pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec>) { debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); @@ -3544,6 +3611,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; 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); + // Check bounds on type arguments used in the path. let bounds = self.instantiate_bounds(path_span, did, substs); let cause = traits::ObligationCause::new(path_span, self.body_id, @@ -5083,7 +5154,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); - self.write_substs(self.tcx.hir.node_to_hir_id(node_id), substs); + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + self.write_substs(hir_id, substs); + + self.write_user_substs_from_substs(hir_id, substs); + ty_substituted } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 319de51713b93..0d8401c1c86ef 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -35,7 +35,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let item_id = self.tcx.hir.body_owner(body.id()); let item_def_id = self.tcx.hir.local_def_id(item_id); - let mut wbcx = WritebackCx::new(self, body); + // This attribute causes us to dump some writeback information + // in the form of errors, which is used for unit tests. + let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, "rustc_dump_user_substs"); + + let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); for arg in &body.arguments { wbcx.visit_node_id(arg.pat.span, arg.hir_id); } @@ -84,12 +88,15 @@ struct WritebackCx<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> { tables: ty::TypeckTables<'gcx>, body: &'gcx hir::Body, + + rustc_dump_user_substs: bool, } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn new( fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body, + rustc_dump_user_substs: bool, ) -> WritebackCx<'cx, 'gcx, 'tcx> { let owner = fcx.tcx.hir.definitions().node_to_hir_id(body.id().node_id); @@ -97,6 +104,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fcx, tables: ty::TypeckTables::empty(Some(DefId::local(owner.owner))), body, + rustc_dump_user_substs, } } @@ -558,6 +566,22 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { assert!(!substs.needs_infer() && !substs.has_skol()); self.tables.node_substs_mut().insert(hir_id, substs); } + + // Copy over any user-substs + if let Some(user_substs) = self.fcx.tables.borrow().user_substs(hir_id) { + let user_substs = self.tcx().lift_to_global(&user_substs).unwrap(); + self.tables.user_substs_mut().insert(hir_id, user_substs); + + // Unit-testing mechanism: + if self.rustc_dump_user_substs { + let node_id = self.tcx().hir.hir_to_node_id(hir_id); + let span = self.tcx().hir.span(node_id); + self.tcx().sess.span_err( + span, + &format!("user substs: {:?}", user_substs), + ); + } + } } fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 4ed96d269061b..e2a22167b7e45 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -865,6 +865,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_dump_user_substs", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "the `#[rustc_if_this_changed]` attribute \ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr index 1999df909ed2b..bb4e922fdc0d2 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr @@ -18,17 +18,33 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |__________________________________________________- in this macro invocation -error: compilation successful - --> $DIR/hr-subtype.rs:110:1 +error: unsatisfied lifetime constraints + --> $DIR/hr-subtype.rs:43:13 | -LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful -LL | | } - | |_^ +LL | fn subtype<'x,'y:'x,'z:'y>() { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | gimme::<$t2>(None::<$t1>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` +... +LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), +LL | | fn(Inv<'y>)) } + | |__________________________________________________- in this macro invocation + +error: unsatisfied lifetime constraints + --> $DIR/hr-subtype.rs:49:13 + | +LL | fn supertype<'x,'y:'x,'z:'y>() { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` +... +LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), +LL | | fn(Inv<'y>)) } + | |__________________________________________________- in this macro invocation -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr index f76b26b5191d3..c33e6fbfde72c 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr @@ -8,17 +8,19 @@ LL | / check! { free_x_vs_free_y: (fn(&'x u32), LL | | fn(&'y u32)) } | |__________________________________________- in this macro invocation -error: compilation successful - --> $DIR/hr-subtype.rs:110:1 +error: unsatisfied lifetime constraints + --> $DIR/hr-subtype.rs:49:13 | -LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful -LL | | } - | |_^ +LL | fn supertype<'x,'y:'x,'z:'y>() { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` +... +LL | / check! { free_x_vs_free_y: (fn(&'x u32), +LL | | fn(&'y u32)) } + | |__________________________________________- in this macro invocation error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.rs b/src/test/ui/nll/user-annotations/adt-brace-enums.rs new file mode 100644 index 0000000000000..4465be414bc2c --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-brace-enums.rs @@ -0,0 +1,62 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +enum SomeEnum { + SomeVariant { t: T } +} + +fn no_annot() { + let c = 66; + SomeEnum::SomeVariant { t: &c }; +} + +fn annot_underscore() { + let c = 66; + SomeEnum::SomeVariant::<_> { t: &c }; +} + +fn annot_reference_any_lifetime() { + let c = 66; + SomeEnum::SomeVariant::<&u32> { t: &c }; +} + +fn annot_reference_static_lifetime() { + let c = 66; + SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + SomeEnum::SomeVariant::<&'a u32> { t: c }; +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + SomeEnum::SomeVariant::<&'a u32> { t: c }; + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr new file mode 100644 index 0000000000000..842bb622bc323 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/adt-brace-enums.rs:37:48 + | +LL | SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/adt-brace-enums.rs:42:43 + | +LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 40:35... + --> $DIR/adt-brace-enums.rs:40:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/adt-brace-enums.rs:52:47 + | +LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 49:46... + --> $DIR/adt-brace-enums.rs:49:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.rs b/src/test/ui/nll/user-annotations/adt-brace-structs.rs new file mode 100644 index 0000000000000..c479e05056447 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-brace-structs.rs @@ -0,0 +1,60 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +struct SomeStruct { t: T } + +fn no_annot() { + let c = 66; + SomeStruct { t: &c }; +} + +fn annot_underscore() { + let c = 66; + SomeStruct::<_> { t: &c }; +} + +fn annot_reference_any_lifetime() { + let c = 66; + SomeStruct::<&u32> { t: &c }; +} + +fn annot_reference_static_lifetime() { + let c = 66; + SomeStruct::<&'static u32> { t: &c }; //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + SomeStruct::<&'a u32> { t: &c }; //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + SomeStruct::<&'a u32> { t: c }; +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + SomeStruct::<&'a u32> { t: &c }; //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + SomeStruct::<&'a u32> { t: c }; + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr new file mode 100644 index 0000000000000..7ba76212dc520 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/adt-brace-structs.rs:35:37 + | +LL | SomeStruct::<&'static u32> { t: &c }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/adt-brace-structs.rs:40:32 + | +LL | SomeStruct::<&'a u32> { t: &c }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35... + --> $DIR/adt-brace-structs.rs:38:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/adt-brace-structs.rs:50:36 + | +LL | SomeStruct::<&'a u32> { t: &c }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46... + --> $DIR/adt-brace-structs.rs:47:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.rs b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs new file mode 100644 index 0000000000000..df62b67a4598f --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs @@ -0,0 +1,80 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] +#![allow(warnings)] + +use std::cell::Cell; + +enum SomeEnum { + SomeVariant(T), + SomeOtherVariant, +} + +fn combine(_: T, _: T) { } + +fn no_annot() { + let c = 66; + combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant); +} + +fn annot_underscore() { + let c = 66; + combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::>); +} + +fn annot_reference_any_lifetime() { + let c = 66; + combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::>); +} + +fn annot_reference_static_lifetime() { + let c = 66; + combine( + SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR + SomeEnum::SomeOtherVariant::>, + ); +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + combine( + SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR + SomeEnum::SomeOtherVariant::>, + ); +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + combine(SomeEnum::SomeVariant(Cell::new(c)), SomeEnum::SomeOtherVariant::>); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + combine( + SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR + SomeEnum::SomeOtherVariant::>, + ); + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + combine( + SomeEnum::SomeVariant(Cell::new(c)), + SomeEnum::SomeOtherVariant::>, + ); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr new file mode 100644 index 0000000000000..fa251f3df17b9 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr @@ -0,0 +1,44 @@ +error[E0597]: `c` does not live long enough + --> $DIR/adt-nullary-enums.rs:44:41 + | +LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/adt-nullary-enums.rs:52:41 + | +LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 49:35... + --> $DIR/adt-nullary-enums.rs:49:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/adt-nullary-enums.rs:65:45 + | +LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 61:46... + --> $DIR/adt-nullary-enums.rs:61:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.rs b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs new file mode 100644 index 0000000000000..ae75a54f64990 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs @@ -0,0 +1,64 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] +#![allow(warnings)] + +enum SomeEnum { + SomeVariant(T), + SomeOtherVariant, +} + +fn no_annot() { + let c = 66; + SomeEnum::SomeVariant(&c); +} + +fn annot_underscore() { + let c = 66; + SomeEnum::SomeVariant::<_>(&c); +} + +fn annot_reference_any_lifetime() { + let c = 66; + SomeEnum::SomeVariant::<&u32>(&c); +} + +fn annot_reference_static_lifetime() { + let c = 66; + SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + SomeEnum::SomeVariant::<&'a u32>(c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + SomeEnum::SomeVariant::<&'a u32>(c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr new file mode 100644 index 0000000000000..18d1cc7e08793 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-enums.rs:39:43 + | +LL | SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-enums.rs:44:38 + | +LL | SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 42:35... + --> $DIR/adt-tuple-enums.rs:42:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-enums.rs:54:42 + | +LL | SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:46... + --> $DIR/adt-tuple-enums.rs:51:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.rs b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs new file mode 100644 index 0000000000000..401a71c1fe5aa --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs @@ -0,0 +1,60 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +struct SomeStruct(T); + +fn no_annot() { + let c = 66; + SomeStruct(&c); +} + +fn annot_underscore() { + let c = 66; + SomeStruct::<_>(&c); +} + +fn annot_reference_any_lifetime() { + let c = 66; + SomeStruct::<&u32>(&c); +} + +fn annot_reference_static_lifetime() { + let c = 66; + SomeStruct::<&'static u32>(&c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + SomeStruct::<&'a u32>(&c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + SomeStruct::<&'a u32>(c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + SomeStruct::<&'a u32>(&c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + SomeStruct::<&'a u32>(c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr new file mode 100644 index 0000000000000..397016e52d0f7 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct.rs:35:32 + | +LL | SomeStruct::<&'static u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct.rs:40:27 + | +LL | SomeStruct::<&'a u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35... + --> $DIR/adt-tuple-struct.rs:38:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct.rs:50:31 + | +LL | SomeStruct::<&'a u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46... + --> $DIR/adt-tuple-struct.rs:47:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs new file mode 100644 index 0000000000000..970fbf98af4ac --- /dev/null +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +// compile-flags:-Zverbose + +#![allow(warnings)] +#![feature(nll)] +#![feature(rustc_attrs)] + +struct SomeStruct { t: T } + +#[rustc_dump_user_substs] +fn main() { + SomeStruct { t: 22 }; // Nothing given, no annotation. + + SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation. + + SomeStruct:: { t: 22 }; //~ ERROR [u32] +} diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr new file mode 100644 index 0000000000000..2b0e5039d8d4e --- /dev/null +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -0,0 +1,8 @@ +error: user substs: Canonical { variables: [], value: [u32] } + --> $DIR/dump-adt-brace-struct.rs:28:5 + | +LL | SomeStruct:: { t: 22 }; //~ ERROR [u32] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.rs b/src/test/ui/nll/user-annotations/dump-fn-method.rs new file mode 100644 index 0000000000000..7f726d13a33ed --- /dev/null +++ b/src/test/ui/nll/user-annotations/dump-fn-method.rs @@ -0,0 +1,59 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +// compile-flags:-Zverbose + +#![feature(nll)] +#![feature(rustc_attrs)] + +// Note: we reference the names T and U in the comments below. +trait Bazoom { + fn method(&self, arg: T, arg2: U) { } +} + +impl Bazoom for T { +} + +fn foo<'a, T>(_: T) { } + +#[rustc_dump_user_substs] +fn main() { + // Here: nothing is given, so we don't have any annotation. + let x = foo; + x(22); + + // Here: `u32` is given. + let x = foo::; //~ ERROR [u32] + x(22); + + // Here: we only want the `T` to be given, the rest should be variables. + // + // (`T` refers to the declaration of `Bazoom`) + let x = <_ as Bazoom>::method::<_>; //~ ERROR [?0, u32, ?1] + x(&22, 44, 66); + + // Here: all are given + let x = >::method::; //~ ERROR [u8, u16, u32] + x(&22, 44, 66); + + // Here: we want in particular that *only* the method `U` + // annotation is given, the rest are variables. + // + // (`U` refers to the declaration of `Bazoom`) + let y = 22_u32; + y.method::(44, 66); //~ ERROR [?0, ?1, u32] + + // Here: nothing is given, so we don't have any annotation. + let y = 22_u32; + y.method(44, 66); +} diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr new file mode 100644 index 0000000000000..6531f87dd9878 --- /dev/null +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -0,0 +1,26 @@ +error: user substs: Canonical { variables: [], value: [u32] } + --> $DIR/dump-fn-method.rs:36:13 + | +LL | let x = foo::; //~ ERROR [u32] + | ^^^^^^^^^^ + +error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, u32, ?1] } + --> $DIR/dump-fn-method.rs:42:13 + | +LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [?0, u32, ?1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: user substs: Canonical { variables: [], value: [u8, u16, u32] } + --> $DIR/dump-fn-method.rs:46:13 + | +LL | let x = >::method::; //~ ERROR [u8, u16, u32] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, ?1, u32] } + --> $DIR/dump-fn-method.rs:54:5 + | +LL | y.method::(44, 66); //~ ERROR [?0, ?1, u32] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/nll/user-annotations/fns.rs b/src/test/ui/nll/user-annotations/fns.rs new file mode 100644 index 0000000000000..4f26d5422b0a4 --- /dev/null +++ b/src/test/ui/nll/user-annotations/fns.rs @@ -0,0 +1,60 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +fn some_fn(arg: T) { } + +fn no_annot() { + let c = 66; + some_fn(&c); // OK +} + +fn annot_underscore() { + let c = 66; + some_fn::<_>(&c); // OK +} + +fn annot_reference_any_lifetime() { + let c = 66; + some_fn::<&u32>(&c); // OK +} + +fn annot_reference_static_lifetime() { + let c = 66; + some_fn::<&'static u32>(&c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + some_fn::<&'a u32>(&c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + some_fn::<&'a u32>(c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + some_fn::<&'a u32>(&c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + some_fn::<&'a u32>(c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/fns.stderr b/src/test/ui/nll/user-annotations/fns.stderr new file mode 100644 index 0000000000000..b6ef336567ca0 --- /dev/null +++ b/src/test/ui/nll/user-annotations/fns.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/fns.rs:35:29 + | +LL | some_fn::<&'static u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/fns.rs:40:24 + | +LL | some_fn::<&'a u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35... + --> $DIR/fns.rs:38:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/fns.rs:50:28 + | +LL | some_fn::<&'a u32>(&c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46... + --> $DIR/fns.rs:47:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-call.rs b/src/test/ui/nll/user-annotations/method-call.rs new file mode 100644 index 0000000000000..9a03679bef0a1 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-call.rs @@ -0,0 +1,81 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +trait Bazoom { + fn method(&self, arg: T, arg2: U) { } +} + +impl Bazoom for T { +} + +fn no_annot() { + let a = 22; + let b = 44; + let c = 66; + a.method(b, &c); // OK +} + +fn annot_underscore() { + let a = 22; + let b = 44; + let c = 66; + a.method::<_>(b, &c); // OK +} + +fn annot_reference_any_lifetime() { + let a = 22; + let b = 44; + let c = 66; + a.method::<&u32>(b, &c); // OK +} + +fn annot_reference_static_lifetime() { + let a = 22; + let b = 44; + let c = 66; + a.method::<&'static u32>(b, &c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let a = 22; + let b = 44; + let c = 66; + a.method::<&'a u32>(b, &c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + let a = 22; + let b = 44; + a.method::<&'a u32>(b, c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let a = 22; + let b = 44; + let _closure = || { + let c = 66; + a.method::<&'a u32>(b, &c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let a = 22; + let b = 44; + let _closure = || { + a.method::<&'a u32>(b, c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/method-call.stderr b/src/test/ui/nll/user-annotations/method-call.stderr new file mode 100644 index 0000000000000..f1c7ff1e0fb19 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-call.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/method-call.rs:48:34 + | +LL | a.method::<&'static u32>(b, &c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/method-call.rs:55:29 + | +LL | a.method::<&'a u32>(b, &c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:35... + --> $DIR/method-call.rs:51:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/method-call.rs:69:33 + | +LL | a.method::<&'a u32>(b, &c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:46... + --> $DIR/method-call.rs:64:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-1.rs new file mode 100644 index 0000000000000..5ac2ba5fa480a --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-1.rs @@ -0,0 +1,75 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +trait Bazoom: Sized { + fn method(self, arg: T, arg2: U) { } +} + +impl Bazoom for T { +} + +fn annot_underscore() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method::<_>(&a, b, c); // OK +} + +fn annot_reference_any_lifetime() { + let a = 22; + let b = 44; + let c = 66; + <&u32 as Bazoom<_>>::method(&a, b, c); // OK +} + +fn annot_reference_static_lifetime() { + let a = 22; + let b = 44; + let c = 66; + let x = <&'static u32 as Bazoom<_>>::method; + x(&a, b, c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let a = 22; + let b = 44; + let c = 66; + <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(a: &'a u32) { + let b = 44; + let c = 66; + <&'a u32 as Bazoom<_>>::method(&a, b, c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let a = 22; + let b = 44; + let _closure = || { + let c = 66; + <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(a: &'a u32) { + let b = 44; + let c = 66; + let _closure = || { + <&'a u32 as Bazoom<_>>::method(&a, b, c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr new file mode 100644 index 0000000000000..f439748ef97b9 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr @@ -0,0 +1,45 @@ +error[E0597]: `a` does not live long enough + --> $DIR/method-ufcs-1.rs:42:7 + | +LL | x(&a, b, c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `a` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `a` does not live long enough + --> $DIR/method-ufcs-1.rs:49:36 + | +LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `a` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 45:35... + --> $DIR/method-ufcs-1.rs:45:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `a` does not live long enough + --> $DIR/method-ufcs-1.rs:63:41 + | +LL | let _closure = || { + | -- value captured here +LL | let c = 66; +LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR + | ^ borrowed value does not live long enough +LL | }; +LL | } + | - `a` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 58:46... + --> $DIR/method-ufcs-1.rs:58:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-2.rs new file mode 100644 index 0000000000000..082cc561ae78f --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-2.rs @@ -0,0 +1,75 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +trait Bazoom: Sized { + fn method(self, arg: T, arg2: U) { } +} + +impl Bazoom for T { +} + +fn annot_underscore() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method(a, &b, c); // OK +} + +fn annot_reference_any_lifetime() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<&u32>>::method(a, &b, c); // OK +} + +fn annot_reference_static_lifetime() { + let a = 22; + let b = 44; + let c = 66; + let x = <&'static u32 as Bazoom<_>>::method; + x(&a, b, c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(b: &'a u32) { + let a = 44; + let c = 66; + <_ as Bazoom<&'a u32>>::method(a, &b, c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let a = 22; + let b = 44; + let _closure = || { + let c = 66; + <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(b: &'a u32) { + let a = 44; + let c = 66; + let _closure = || { + <_ as Bazoom<&'a u32>>::method(a, &b, c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr new file mode 100644 index 0000000000000..dc0f559659001 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr @@ -0,0 +1,45 @@ +error[E0597]: `a` does not live long enough + --> $DIR/method-ufcs-2.rs:42:7 + | +LL | x(&a, b, c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `a` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `b` does not live long enough + --> $DIR/method-ufcs-2.rs:49:39 + | +LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `b` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 45:35... + --> $DIR/method-ufcs-2.rs:45:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `b` does not live long enough + --> $DIR/method-ufcs-2.rs:63:44 + | +LL | let _closure = || { + | -- value captured here +LL | let c = 66; +LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR + | ^ borrowed value does not live long enough +LL | }; +LL | } + | - `b` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 58:46... + --> $DIR/method-ufcs-2.rs:58:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-3.rs new file mode 100644 index 0000000000000..f4fdb3ee57236 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-3.rs @@ -0,0 +1,81 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unit test for the "user substitutions" that are annotated on each +// node. + +#![feature(nll)] + +trait Bazoom { + fn method(&self, arg: T, arg2: U) { } +} + +impl Bazoom for T { +} + +fn no_annot() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method(&a, b, &c); // OK +} + +fn annot_underscore() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method::<_>(&a, b, &c); // OK +} + +fn annot_reference_any_lifetime() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method::<&u32>(&a, b, &c); // OK +} + +fn annot_reference_static_lifetime() { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let a = 22; + let b = 44; + let c = 66; + <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + let a = 22; + let b = 44; + <_ as Bazoom<_>>::method::<&'a u32>(&a, b, c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let a = 22; + let b = 44; + let _closure = || { + let c = 66; + <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let a = 22; + let b = 44; + let _closure = || { + <_ as Bazoom<_>>::method::<&'a u32>(&a, b, c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr new file mode 100644 index 0000000000000..7ddea3eb2c62f --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr @@ -0,0 +1,41 @@ +error[E0597]: `c` does not live long enough + --> $DIR/method-ufcs-3.rs:48:53 + | +LL | <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `c` does not live long enough + --> $DIR/method-ufcs-3.rs:55:48 + | +LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:35... + --> $DIR/method-ufcs-3.rs:51:35 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | ^^ + +error[E0597]: `c` does not live long enough + --> $DIR/method-ufcs-3.rs:69:52 + | +LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR + | ^^ borrowed value does not live long enough +LL | }; + | - `c` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:46... + --> $DIR/method-ufcs-3.rs:64:46 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`.