diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index bbe47ecee790..a7ecfc269f35 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -8,77 +8,66 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir; -use rustc::hir::def_id::{CrateNum, DefId}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::ty::{self, TyCtxt}; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, OutlivesPredicate, TyCtxt}; use util::nodemap::FxHashMap; use super::utils::*; -pub fn explicit_predicates<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - crate_num: CrateNum, -) -> FxHashMap> { - let mut predicates = FxHashMap::default(); - - // iterate over the entire crate - tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor { - tcx: tcx, - explicit_predicates: &mut predicates, - crate_num: crate_num, - }); - - predicates +#[derive(Debug)] +pub struct ExplicitPredicatesMap<'tcx> { + map: FxHashMap>, } -pub struct ExplicitVisitor<'cx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx>, - explicit_predicates: &'cx mut FxHashMap>, - crate_num: CrateNum, -} - -impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item) { - let def_id = DefId { - krate: self.crate_num, - index: item.hir_id.owner, - }; - - let mut required_predicates = RequiredPredicates::default(); - let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id).predicates; - - for pred in local_explicit_predicate.into_iter() { - match pred { - ty::Predicate::TypeOutlives(predicate) => { - let ty::OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); - insert_outlives_predicate(self.tcx, (*ty).into(), reg, &mut required_predicates) - } - - ty::Predicate::RegionOutlives(predicate) => { - let ty::OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder(); - insert_outlives_predicate( - self.tcx, - (*reg1).into(), - reg2, - &mut required_predicates, - ) - } - - ty::Predicate::Trait(..) - | ty::Predicate::Projection(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => (), - } +impl<'tcx> ExplicitPredicatesMap<'tcx> { + pub fn new() -> ExplicitPredicatesMap<'tcx> { + ExplicitPredicatesMap { + map: FxHashMap::default(), } - - self.explicit_predicates.insert(def_id, required_predicates); } - fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {} + pub fn explicit_predicates_of( + &mut self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + def_id: DefId, + ) -> &RequiredPredicates<'tcx> { + self.map.entry(def_id).or_insert_with(|| { + let predicates = if def_id.is_local() { + tcx.explicit_predicates_of(def_id).predicates + } else { + tcx.predicates_of(def_id).predicates + }; + let mut required_predicates = RequiredPredicates::default(); - fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {} + // process predicates and convert to `RequiredPredicates` entry, see below + for pred in predicates.into_iter() { + match pred { + ty::Predicate::TypeOutlives(predicate) => { + let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); + insert_outlives_predicate(tcx, (*ty).into(), reg, &mut required_predicates) + } + + ty::Predicate::RegionOutlives(predicate) => { + let OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder(); + insert_outlives_predicate( + tcx, + (*reg1).into(), + reg2, + &mut required_predicates, + ) + } + + ty::Predicate::Trait(..) + | ty::Predicate::Projection(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::ConstEvaluatable(..) => (), + } + } + + required_predicates + }) + } } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index c966db98c8e1..a015122d62e7 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -15,6 +15,7 @@ use rustc::ty::subst::{Kind, Subst, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; +use super::explicit::ExplicitPredicatesMap; use super::utils::*; /// Infer predicates for the items in the crate. @@ -24,7 +25,7 @@ use super::utils::*; /// now be filled with inferred predicates. pub fn infer_predicates<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, - explicit_map: &FxHashMap>, + explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) -> FxHashMap> { debug!("infer_predicates"); @@ -55,7 +56,7 @@ pub struct InferVisitor<'cx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'tcx, 'tcx>, global_inferred_outlives: &'cx mut FxHashMap>, predicates_added: &'cx mut bool, - explicit_map: &'cx FxHashMap>, + explicit_map: &'cx mut ExplicitPredicatesMap<'tcx>, } impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { @@ -93,7 +94,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { field_ty, self.global_inferred_outlives, &mut item_required_predicates, - self.explicit_map, + &mut self.explicit_map, ); } } @@ -129,7 +130,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( field_ty: Ty<'tcx>, global_inferred_outlives: &FxHashMap>, required_predicates: &mut RequiredPredicates<'tcx>, - explicit_map: &FxHashMap>, + explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { for ty in field_ty.walk() { match ty.sty { @@ -257,53 +258,54 @@ pub fn check_explicit_predicates<'tcx>( def_id: &DefId, substs: &[Kind<'tcx>], required_predicates: &mut RequiredPredicates<'tcx>, - explicit_map: &FxHashMap>, + explicit_map: &mut ExplicitPredicatesMap<'tcx>, ignore_self_ty: bool, ) { debug!("def_id = {:?}", &def_id); debug!("substs = {:?}", &substs); debug!("explicit_map = {:?}", explicit_map); debug!("required_predicates = {:?}", required_predicates); - if let Some(explicit_predicates) = explicit_map.get(def_id) { - for outlives_predicate in explicit_predicates.iter() { - debug!("outlives_predicate = {:?}", &outlives_predicate); + let explicit_predicates = explicit_map.explicit_predicates_of(tcx, *def_id); - // Careful: If we are inferring the effects of a `dyn Trait<..>` - // type, then when we look up the predicates for `Trait`, - // we may find some that reference `Self`. e.g., perhaps the - // definition of `Trait` was: - // - // ``` - // trait Trait<'a, T> where Self: 'a { .. } - // ``` - // - // we want to ignore such predicates here, because - // there is no type parameter for them to affect. Consider - // a struct containing `dyn Trait`: - // - // ``` - // struct MyStruct<'x, X> { field: Box> } - // ``` - // - // The `where Self: 'a` predicate refers to the *existential, hidden type* - // that is represented by the `dyn Trait`, not to the `X` type parameter - // (or any other generic parameter) declared on `MyStruct`. - // - // Note that we do this check for self **before** applying `substs`. In the - // case that `substs` come from a `dyn Trait` type, our caller will have - // included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were - // to apply the substs, and not filter this predicate, we might then falsely - // conclude that e.g. `X: 'x` was a reasonable inferred requirement. - if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.is_self() && ignore_self_ty { - debug!("skipping self ty = {:?}", &ty); - continue; - } + for outlives_predicate in explicit_predicates.iter() { + debug!("outlives_predicate = {:?}", &outlives_predicate); + + // Careful: If we are inferring the effects of a `dyn Trait<..>` + // type, then when we look up the predicates for `Trait`, + // we may find some that reference `Self`. e.g., perhaps the + // definition of `Trait` was: + // + // ``` + // trait Trait<'a, T> where Self: 'a { .. } + // ``` + // + // we want to ignore such predicates here, because + // there is no type parameter for them to affect. Consider + // a struct containing `dyn Trait`: + // + // ``` + // struct MyStruct<'x, X> { field: Box> } + // ``` + // + // The `where Self: 'a` predicate refers to the *existential, hidden type* + // that is represented by the `dyn Trait`, not to the `X` type parameter + // (or any other generic parameter) declared on `MyStruct`. + // + // Note that we do this check for self **before** applying `substs`. In the + // case that `substs` come from a `dyn Trait` type, our caller will have + // included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were + // to apply the substs, and not filter this predicate, we might then falsely + // conclude that e.g. `X: 'x` was a reasonable inferred requirement. + if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() { + if ty.is_self() && ignore_self_ty { + debug!("skipping self ty = {:?}", &ty); + continue; } - - let predicate = outlives_predicate.subst(tcx, substs); - debug!("predicate = {:?}", &predicate); - insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates); } + + let predicate = outlives_predicate.subst(tcx, substs); + debug!("predicate = {:?}", &predicate); + insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates); } + // } } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index c6c7e8f931f8..9c483924992d 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -84,6 +84,8 @@ fn inferred_outlives_crate<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, crate_num: CrateNum, ) -> Lrc> { + assert_eq!(crate_num, LOCAL_CRATE); + // Compute a map from each struct/enum/union S to the **explicit** // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote. // Typically there won't be many of these, except in older code where @@ -92,8 +94,9 @@ fn inferred_outlives_crate<'tcx>( // for the type. // Compute the inferred predicates - let exp = explicit::explicit_predicates(tcx, crate_num); - let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp); + let mut exp_map = explicit::ExplicitPredicatesMap::new(); + + let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &mut exp_map); // Convert the inferred predicates into the "collected" form the // global data structure expects. diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs b/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs index b05a6e5fee2d..016739978834 100644 --- a/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs +++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs @@ -11,9 +11,9 @@ #![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// #[rustc_outlives] -struct Foo<'a, T> { - bar: std::slice::IterMut<'a, T> //~ ERROR 16:5: 16:36: the parameter type `T` may not live long enough [E0309] +#[rustc_outlives] +struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives + bar: std::slice::IterMut<'a, T> } fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr index 82690bea64d1..a90643ae8916 100644 --- a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr @@ -1,17 +1,12 @@ -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/cross-crate.rs:16:5 +error: rustc_outlives + --> $DIR/cross-crate.rs:15:1 | -LL | struct Foo<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | bar: std::slice::IterMut<'a, T> //~ ERROR 16:5: 16:36: the parameter type `T` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives +LL | | bar: std::slice::IterMut<'a, T> +LL | | } + | |_^ | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/cross-crate.rs:16:5 - | -LL | bar: std::slice::IterMut<'a, T> //~ ERROR 16:5: 16:36: the parameter type `T` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: T : 'a error: aborting due to previous error -For more information about this error, try `rustc --explain E0309`.