diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index b660187945cdb..a82a8ca6bdff0 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -597,11 +597,7 @@ impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation< 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) => { + mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index c29a75c34cf9d..b9edc9f51eaa8 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -19,7 +19,7 @@ use infer::canonical::substitute::substitute_value; use infer::canonical::{ - Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, + Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues, QueryRegionConstraint, QueryResponse, }; use infer::region_constraints::{Constraint, RegionConstraintData}; @@ -262,13 +262,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { where R: Debug + TypeFoldable<'tcx>, { - // In an NLL query, there should be no type variables in the - // query, only region variables. - debug_assert!(query_response.variables.iter().all(|v| match v.kind { - CanonicalVarKind::Ty(_) => false, - CanonicalVarKind::Region => true, - })); - let result_subst = self.query_response_substitution_guess(cause, original_values, query_response); diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 525ae03dfaf93..df30ad360062c 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -149,7 +149,7 @@ pub struct Verify<'tcx> { pub bound: VerifyBound<'tcx>, } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), Projection(ty::ProjectionTy<'tcx>), diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9a0623ca53938..34fc81a495e24 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2425,15 +2425,16 @@ pub struct Constant<'tcx> { #[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>), + + /// The canonical type is the result of `type_of(def_id)` with the + /// given substitutions applied. + TypeOf(DefId, CanonicalUserSubsts<'tcx>), } EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { (UserTypeAnnotation::Ty)(ty), - (UserTypeAnnotation::FnDef)(def, substs), - (UserTypeAnnotation::AdtDef)(def, substs), + (UserTypeAnnotation::TypeOf)(def, substs), } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 0fabcfe456449..2c84a9e014e93 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -25,7 +25,7 @@ use rustc::mir::{ use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::{Diagnostic, DiagnosticBuilder}; @@ -67,10 +67,8 @@ pub struct RegionInferenceContext<'tcx> { constraint_sccs: Rc>, /// Map closure bounds to a `Span` that should be used for error reporting. - closure_bounds_mapping: FxHashMap< - Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, - >, + closure_bounds_mapping: + FxHashMap>, /// Contains the minimum universe of any variable within the same /// SCC. We will ensure that no SCC contains values that are not @@ -580,6 +578,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) { let tcx = infcx.tcx; + // Sometimes we register equivalent type-tests that would + // result in basically the exact same error being reported to + // the user. Avoid that. + let mut deduplicate_errors = FxHashSet::default(); + for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); @@ -605,11 +608,31 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - // Oh the humanity. Obviously we will do better than this error eventually. + // Type-test failed. Report the error. + + // Try to convert the lower-bound region into something named we can print for the user. let lower_bound_region = self.to_error_region(type_test.lower_bound); + + // Skip duplicate-ish errors. + let type_test_span = type_test.locations.span(mir); + let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind); + if !deduplicate_errors.insert(( + erased_generic_kind, + lower_bound_region, + type_test.locations, + )) { + continue; + } else { + debug!( + "check_type_test: reporting error for erased_generic_kind={:?}, \ + lower_bound_region={:?}, \ + type_test.locations={:?}", + erased_generic_kind, lower_bound_region, type_test.locations, + ); + } + if let Some(lower_bound_region) = lower_bound_region { let region_scope_tree = &tcx.region_scope_tree(mir_def_id); - let type_test_span = type_test.locations.span(mir); infcx .construct_generic_bound_failure( region_scope_tree, @@ -629,7 +652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to report it; we could probably handle it by // iterating over the universal regions and reporting // an error that multiple bounds are required. - let type_test_span = type_test.locations.span(mir); tcx.sess .struct_span_err( type_test_span, diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 4ab0f952bdee9..994f20a011d65 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { } fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { + debug!("add_type_test(type_test={:?})", type_test); self.type_tests.push(type_test); } } 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 c5758cde9494d..7737fcc765d80 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, Substs, UnpackedKind}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; @@ -753,10 +753,8 @@ crate struct MirTypeckRegionConstraints<'tcx> { crate outlives_constraints: ConstraintSet, - crate closure_bounds_mapping: FxHashMap< - Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, - >, + crate closure_bounds_mapping: + FxHashMap>, crate type_tests: Vec>, } @@ -866,7 +864,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, locations: Locations, category: ConstraintCategory, - op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>, + op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>, ) -> Fallible { let (r, opt_data) = op.fully_perform(self.infcx)?; @@ -903,23 +901,37 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn sub_types( + /// Convenient wrapper around `relate_tys::relate_types` -- see + /// that fn for docs. + fn relate_types( &mut self, - sub: Ty<'tcx>, - sup: Ty<'tcx>, + a: Ty<'tcx>, + v: ty::Variance, + b: Ty<'tcx>, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - relate_tys::sub_types( + relate_tys::relate_types( self.infcx, - sub, - sup, + a, + v, + b, locations, category, self.borrowck_context.as_mut().map(|x| &mut **x), ) } + fn sub_types( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + self.relate_types(sub, ty::Variance::Covariant, sup, locations, category) + } + /// Try to relate `sub <: sup`; if this fails, instantiate opaque /// variables in `sub` with their inferred definitions and try /// again. This is used for opaque types in places (e.g., `let x: @@ -952,41 +964,133 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - relate_tys::eq_types( - self.infcx, - a, - b, - locations, - category, - self.borrowck_context.as_mut().map(|x| &mut **x), - ) + self.relate_types(a, ty::Variance::Invariant, b, locations, category) } fn relate_type_and_user_type( &mut self, a: Ty<'tcx>, v: ty::Variance, - b: UserTypeAnnotation<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - let ty = relate_tys::relate_type_and_user_type( - self.infcx, - a, - v, - b, - locations, - category, - self.borrowck_context.as_mut().map(|x| &mut **x), - )?; - self.prove_predicate( - ty::Predicate::WellFormed(ty), - locations, - category, + let tcx = self.tcx(); + + debug!( + "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", + a, v, user_ty, locations ); + + // The `TypeRelating` code assumes that "unresolved inference + // variables" appear in the "a" side, so flip `Contravariant` + // ambient variance to get the right relationship. + let v1 = ty::Contravariant.xform(v); + + match user_ty { + UserTypeAnnotation::Ty(canonical_ty) => { + let (ty, _) = self.infcx + .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); + + self.relate_types(ty, v1, a, locations, category)?; + + self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + } + UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { + let ( + UserSubsts { + substs, + user_self_ty, + }, + _, + ) = self.infcx + .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + + let ty = self.tcx().type_of(def_id); + let ty = ty.subst(tcx, substs); + let ty = self.normalize(ty, locations); + + self.relate_types(ty, v1, a, locations, category)?; + + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty + { + let impl_self_ty = tcx.type_of(impl_def_id); + let impl_self_ty = impl_self_ty.subst(tcx, &substs); + let impl_self_ty = self.normalize(impl_self_ty, locations); + + // 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 = self.infcx.resolve_type_vars_if_possible(&impl_self_ty); + assert!(!impl_self_ty.has_infer_types()); + + self.eq_types(self_ty, impl_self_ty, locations, category)?; + } + + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates); + self.normalize_and_prove_instantiated_predicates( + instantiated_predicates, + locations, + ); + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + } + } + Ok(()) } + /// Replace all free regions in `value` with their NLL `RegionVid` + /// equivalents; if not in NLL, does nothing. This is never + /// particularly necessary -- we'll do it lazilly as we process + /// the value anyway -- but in some specific cases it is useful to + /// normalize so we can suppress duplicate error messages. + fn fold_to_region_vid( + &self, + value: T + ) -> T + where T: TypeFoldable<'tcx> + { + if let Some(borrowck_context) = &self.borrowck_context { + self.tcx().fold_regions(&value, &mut false, |r, _debruijn| { + if r.has_free_regions() { + self.tcx().mk_region(ty::RegionKind::ReVar( + borrowck_context.universal_regions.to_region_vid(r), + )) + } else { + r + } + }) + } else { + value + } + } + fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, @@ -1115,9 +1219,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Err(terr) = - self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) - { - span_mirbug!( + self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) + { + span_mirbug!( self, stmt, "bad assignment ({:?} = {:?}): {:?}", @@ -1125,7 +1229,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { rv_ty, terr ); - } + } if let Some(user_ty) = self.rvalue_user_ty(rv) { if let Err(terr) = self.relate_type_and_user_type( @@ -1245,9 +1349,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let locations = term_location.to_locations(); if let Err(terr) = - self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) - { - span_mirbug!( + self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) + { + span_mirbug!( self, term, "bad DropAndReplace ({:?} = {:?}): {:?}", @@ -1255,7 +1359,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { rv_ty, terr ); - } + } } TerminatorKind::SwitchInt { ref discr, @@ -1399,9 +1503,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let locations = term_location.to_locations(); if let Err(terr) = - self.sub_types_or_anon(sig.output(), dest_ty, locations, category) - { - span_mirbug!( + self.sub_types_or_anon(sig.output(), dest_ty, locations, category) + { + span_mirbug!( self, term, "call dest mismatch ({:?} <- {:?}): {:?}", @@ -1409,7 +1513,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { sig.output(), terr ); - } + } // When `#![feature(unsized_locals)]` is not enabled, // this check is done at `check_local`. @@ -2050,7 +2154,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { aggregate_kind, location ); - let instantiated_predicates = match aggregate_kind { + let instantiated_predicates = match aggregate_kind { AggregateKind::Adt(def, _, substs, _, _) => { tcx.predicates_of(def.did).instantiate(tcx, substs) } @@ -2096,15 +2200,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: &'tcx Substs<'tcx>, location: Location, ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(closure_region_requirements) = - tcx.mir_borrowck(def_id).closure_requirements - { - let closure_constraints = closure_region_requirements.apply_requirements( - tcx, - location, - def_id, - substs, - ); + if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements { + let closure_constraints = + closure_region_requirements.apply_requirements(tcx, location, def_id, substs); if let Some(ref mut borrowck_context) = self.borrowck_context { let bounds_mapping = closure_constraints @@ -2113,10 +2211,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .filter_map(|(idx, constraint)| { let ty::OutlivesPredicate(k1, r2) = constraint.no_late_bound_regions().unwrap_or_else(|| { - bug!( - "query_constraint {:?} contained bound regions", - constraint, - ); + bug!("query_constraint {:?} contained bound regions", constraint,); }); match k1.unpack() { @@ -2124,8 +2219,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // constraint is r1: r2 let r1_vid = borrowck_context.universal_regions.to_region_vid(r1); let r2_vid = borrowck_context.universal_regions.to_region_vid(r2); - let outlives_requirements = &closure_region_requirements - .outlives_requirements[idx]; + let outlives_requirements = + &closure_region_requirements.outlives_requirements[idx]; Some(( (r1_vid, r2_vid), ( @@ -2139,10 +2234,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }) .collect(); - let existing = borrowck_context.constraints + let existing = borrowck_context + .constraints .closure_bounds_mapping .insert(location, bounds_mapping); - assert!(existing.is_none(), "Multiple closures at the same location."); + assert!( + existing.is_none(), + "Multiple closures at the same location." + ); } self.push_region_constraints( diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 72120eb18413b..13ebf46bdb149 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -12,35 +12,23 @@ use borrow_check::nll::constraints::OutlivesConstraint; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; -use rustc::mir::{ConstraintCategory, UserTypeAnnotation}; +use rustc::mir::ConstraintCategory; use rustc::traits::query::Fallible; 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>( - infcx: &InferCtxt<'_, '_, 'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, -) -> Fallible<()> { - debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations); - TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - ty::Variance::Covariant, - ).relate(&a, &b)?; - Ok(()) -} - -/// Adds sufficient constraints to ensure that `a == b`. -pub(super) fn eq_types<'tcx>( +use rustc::ty::{self, Ty}; + +/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: +/// +/// - "Covariant" `a <: b` +/// - "Invariant" `a == b` +/// - "Contravariant" `a :> b` +/// +/// NB. The type `a` is permitted to have unresolved inference +/// variables, but not the type `b`. +pub(super) fn relate_types<'tcx>( infcx: &InferCtxt<'_, '_, 'tcx>, a: Ty<'tcx>, + v: ty::Variance, b: Ty<'tcx>, locations: Locations, category: ConstraintCategory, @@ -50,105 +38,11 @@ pub(super) fn eq_types<'tcx>( TypeRelating::new( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - ty::Variance::Invariant, + v, ).relate(&a, &b)?; Ok(()) } -/// Adds sufficient constraints to ensure that `a <: b`, where `b` is -/// a user-given type (which means it may have canonical variables -/// encoding things like `_`). -pub(super) fn relate_type_and_user_type<'tcx>( - infcx: &InferCtxt<'_, '_, 'tcx>, - a: Ty<'tcx>, - v: ty::Variance, - user_ty: UserTypeAnnotation<'tcx>, - locations: Locations, - category: ConstraintCategory, - borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, -) -> Fallible> { - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", - a, v, user_ty, locations - ); - - // The `TypeRelating` code assumes that the "canonical variables" - // appear in the "a" side, so flip `Contravariant` ambient - // variance to get the right relationship. - let v1 = ty::Contravariant.xform(v); - - let mut type_relating = TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), - v1, - ); - - 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, - )?; - } - - 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); - - // We don't extract adt-defs with a self-type. - assert!(user_self_ty.is_none()); - - 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> { infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>, diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 29c3fb6933967..820822b7f5bbd 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -139,17 +139,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::PlaceTypeAscription { source, user_ty } => { let place = unpack!(block = this.as_place(block, source)); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - place.clone(), - Variance::Invariant, - user_ty, - ), - }, - ); + if let Some(user_ty) = user_ty { + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::AscribeUserType( + place.clone(), + Variance::Invariant, + user_ty, + ), + }, + ); + } block.and(place) } ExprKind::ValueTypeAscription { source, user_ty } => { @@ -157,17 +159,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let temp = unpack!( block = this.as_temp(block, source.temp_lifetime, source, mutability) ); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::AscribeUserType( - Place::Local(temp.clone()), - Variance::Invariant, - user_ty, - ), - }, - ); + if let Some(user_ty) = user_ty { + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::AscribeUserType( + Place::Local(temp.clone()), + Variance::Invariant, + user_ty, + ), + }, + ); + } block.and(Place::Local(temp)) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 56a29f29d685f..1df5f78975139 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -295,7 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let substs = cx.tables().node_substs(fun.hir_id); let user_ty = cx.tables().user_substs(fun.hir_id) - .map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs)); + .map(|user_substs| UserTypeAnnotation::TypeOf(adt_def.did, user_substs)); let field_refs = args.iter() .enumerate() @@ -637,12 +637,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, name: Field::new(cx.tcx.field_index(expr.id, cx.tables)), } } - hir::ExprKind::Cast(ref source, _) => { + hir::ExprKind::Cast(ref source, ref cast_ty) => { + // Check for a user-given type annotation on this `cast` + let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id) + .map(|&t| UserTypeAnnotation::Ty(t)); + + debug!( + "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}", + expr, + cast_ty.hir_id, + user_ty, + ); + // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - if let Some(&TyCastKind::CoercionCast) = cx.tables() - .cast_kinds() - .get(source.hir_id) { + let cast = if let Some(&TyCastKind::CoercionCast) = + cx.tables() + .cast_kinds() + .get(source.hir_id) + { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { @@ -679,24 +692,30 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { None }; - let source = if let Some((did, offset, ty)) = var { + + let source = if let Some((did, offset, var_ty)) = var { let mk_const = |literal| Expr { temp_lifetime, - ty, + ty: var_ty, span: expr.span, kind: ExprKind::Literal { literal, user_ty: None }, }.to_ref(); let offset = mk_const(ty::Const::from_bits( cx.tcx, offset as u128, - cx.param_env.and(ty), + cx.param_env.and(var_ty), )); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = Substs::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty)); + let lhs = mk_const(ty::Const::unevaluated( + cx.tcx(), + did, + substs, + var_ty, + )); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -704,7 +723,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; Expr { temp_lifetime, - ty, + ty: var_ty, span: expr.span, kind: bin, }.to_ref() @@ -714,20 +733,33 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { source.to_ref() }; + ExprKind::Cast { source } + }; + + if let Some(user_ty) = user_ty { + // NOTE: Creating a new Expr and wrapping a Cast inside of it may be + // inefficient, revisit this when performance becomes an issue. + let cast_expr = Expr { + temp_lifetime, + ty: expr_ty, + span: expr.span, + kind: cast, + }; + + ExprKind::ValueTypeAscription { + source: cast_expr.to_ref(), + user_ty: Some(user_ty), + } + } else { + cast } } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_tys = cx.tables.user_provided_tys(); - let user_ty = UserTypeAnnotation::Ty( - *user_provided_tys - .get(ty.hir_id) - .expect(&format!( - "{:?} not found in user_provided_tys, source: {:?}", - ty, - source, - )) - ); + let user_ty = user_provided_tys + .get(ty.hir_id) + .map(|&c_ty| UserTypeAnnotation::Ty(c_ty)); if source.is_place_expr() { ExprKind::PlaceTypeAscription { source: source.to_ref(), @@ -771,12 +803,10 @@ fn user_substs_applied_to_def( Def::Fn(_) | Def::Method(_) | Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) => - Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)), - - Def::Const(_def_id) | - Def::AssociatedConst(_def_id) => - bug!("unimplemented"), + Def::VariantCtor(_, CtorKind::Fn) | + Def::Const(_) | + Def::AssociatedConst(_) => + Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)), // A unit struct/variant which is used as a value (e.g., // `None`). This has the type of the enum/struct that defines @@ -889,14 +919,17 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, Def::Const(def_id) | - Def::AssociatedConst(def_id) => ExprKind::Literal { - literal: ty::Const::unevaluated( - cx.tcx, - def_id, - substs, - cx.tables().node_id_to_type(expr.hir_id), - ), - user_ty: None, // FIXME(#47184) -- user given type annot on constants + Def::AssociatedConst(def_id) => { + let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); + ExprKind::Literal { + literal: ty::Const::unevaluated( + cx.tcx, + def_id, + substs, + cx.tables().node_id_to_type(expr.hir_id), + ), + user_ty, + } }, Def::StructCtor(def_id, CtorKind::Const) | diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 781b6c92aa13a..788db5c0b7e52 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> { PlaceTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: UserTypeAnnotation<'tcx>, + user_ty: Option>, }, ValueTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: UserTypeAnnotation<'tcx>, + user_ty: Option>, }, Closure { closure_id: DefId, diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 71cbac6b7c88e..f81a0fa5dfadb 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -23,7 +23,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { adt_def: &'tcx AdtDef, ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; - Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)) + Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)) } /// Looks up the type associated with this hir-id and applies the @@ -35,8 +35,8 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; match &self.tables().node_id_to_type(hir_id).sty { - ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)), - ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)), + ty::Adt(adt_def, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)), + ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)), sty => bug!( "sty: {:?} should not have user-substs {:?} recorded ", sty, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 14ce1bb4ccdee..ffa21e1fc22a5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2357,6 +2357,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t } + pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { + let ty = self.to_ty(ast_ty); + + // If the type given by the user has free regions, save it for + // later, since NLL would like to enforce those. Also pass in + // types that involve projections, since those can resolve to + // `'static` bounds (modulo #54940, which hopefully will be + // fixed by the time you see this comment, dear reader, + // although I have my doubts). Other sorts of things are + // already sufficiently enforced with erased regions. =) + if ty.has_free_regions() || ty.has_projections() { + let c_ty = self.infcx.canonicalize_response(&ty); + self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty); + } + + ty + } + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.tables.borrow().node_types().get(id) { Some(&t) => t, @@ -4153,7 +4171,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprKind::Cast(ref e, ref t) => { // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. - let t_cast = self.to_ty(t); + let t_cast = self.to_ty_saving_user_provided_ty(t); let t_cast = self.resolve_type_vars_if_possible(&t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); let t_cast = self.resolve_type_vars_if_possible(&t_cast); @@ -4176,10 +4194,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::ExprKind::Type(ref e, ref t) => { - let ty = self.to_ty(&t); + let ty = self.to_ty_saving_user_provided_ty(&t); self.check_expr_eq_type(&e, ty); - let c_ty = self.infcx.canonicalize_response(&ty); - self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty); ty } hir::ExprKind::Array(ref args) => { diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs index b3f56f27f6352..8142ed0155aae 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.rs +++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs @@ -17,6 +17,6 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; fn main() { println!("{}", FOO); - //~^ ERROR erroneous constant used - //~| E0080 + //~^ ERROR + //~| ERROR } diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs new file mode 100644 index 0000000000000..aa2cf85dfd999 --- /dev/null +++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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. + +#![allow(warnings)] +#![feature(nll)] + +fn main() { + let x = 22_u32; + let y: &u32 = (&x) as &'static u32; +} diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr new file mode 100644 index 0000000000000..a35035b07ba54 --- /dev/null +++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr @@ -0,0 +1,13 @@ +error[E0597]: `x` does not live long enough + --> $DIR/cast_static_lifetime.rs:16:19 + | +LL | let y: &u32 = (&x) as &'static u32; + | ^^^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs new file mode 100644 index 0000000000000..058ebaee9e512 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs @@ -0,0 +1,15 @@ +#![feature(nll)] + +struct Foo<'a> { x: &'a u32 } + +impl<'a> Foo<'a> { + const C: &'a u32 = &22; +} + +fn foo<'a>(_: &'a u32) -> &'static u32 { + >::C //~ ERROR +} + +fn main() { +} + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr new file mode 100644 index 0000000000000..94fbe01772412 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-inherent-1.rs:10:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | >::C //~ ERROR + | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs new file mode 100644 index 0000000000000..4292fc710e98b --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs @@ -0,0 +1,24 @@ +#![feature(nll)] + +trait Mirror { + type Me; +} + +impl Mirror for T { + type Me = T; +} + +trait Foo<'a> { + const C: <&'a u32 as Mirror>::Me; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a>(_: &'a u32) -> &'static u32 { + <() as Foo<'a>>::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr new file mode 100644 index 0000000000000..7aeb276eeb929 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-normalize.rs:20:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | <() as Foo<'a>>::C //~ ERROR + | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs new file mode 100644 index 0000000000000..daa0d7bc24140 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a>(_: &'a u32) -> &'static u32 { + <() as Foo<'a>>::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr new file mode 100644 index 0000000000000..fee9abc1ed83a --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-trait-item-1.rs:12:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | <() as Foo<'a>>::C //~ ERROR + | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs new file mode 100644 index 0000000000000..cd66e7a49cb83 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a, T: Foo<'a>>() -> &'static u32 { + >::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr new file mode 100644 index 0000000000000..047aad9831923 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-trait-item-2.rs:12:5 + | +LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { + | -- lifetime `'a` defined here +LL | >::C //~ ERROR + | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs new file mode 100644 index 0000000000000..f83ae2438e6d5 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a, T: Foo<'a>>() -> &'static u32 { + T::C //~ ERROR +} + +fn main() { +} diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr new file mode 100644 index 0000000000000..b373cebacb063 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr @@ -0,0 +1,10 @@ +error: unsatisfied lifetime constraints + --> $DIR/constant-in-expr-trait-item-3.rs:12:5 + | +LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { + | -- lifetime `'a` defined here +LL | T::C //~ ERROR + | ^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/normalization.rs b/src/test/ui/nll/user-annotations/normalization.rs new file mode 100644 index 0000000000000..51d9adccd7372 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization.rs @@ -0,0 +1,13 @@ +// Test that we enforce a `&'static` requirement that is only visible +// after normalization. + +#![feature(nll)] +#![ignore(unused)] + +trait Foo { type Out; } +impl Foo for () { type Out = &'static u32; } + +fn main() { + let a = 22; + let b: <() as Foo>::Out = &a; //~ ERROR +} diff --git a/src/test/ui/nll/user-annotations/normalization.stderr b/src/test/ui/nll/user-annotations/normalization.stderr new file mode 100644 index 0000000000000..489f9feb044c8 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization.stderr @@ -0,0 +1,13 @@ +error[E0597]: `a` does not live long enough + --> $DIR/normalization.rs:12:31 + | +LL | let b: <() as Foo>::Out = &a; //~ 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: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/normalize-self-ty.rs b/src/test/ui/nll/user-annotations/normalize-self-ty.rs new file mode 100644 index 0000000000000..d97cc88dd9af4 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalize-self-ty.rs @@ -0,0 +1,25 @@ +// Regression test for #55183: check a case where the self type from +// the inherent impl requires normalization to be equal to the +// user-provided type. +// +// run-pass + +#![feature(nll)] + +trait Mirror { + type Me; +} + +impl Mirror for T { + type Me = T; +} + +struct Foo(A, B); + +impl Foo::Me> { + fn m(b: A) { } +} + +fn main() { + >::m(&22); +}