diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 2c407a24493ff..8f2a658afa631 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -191,7 +191,7 @@ rustc_queries! { /// Returns the inferred outlives predicates (e.g., for `struct /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - query inferred_outlives_of(_: DefId) -> &'tcx [ty::Predicate<'tcx>] {} + query inferred_outlives_of(_: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {} /// Maps from the `DefId` of a trait to the list of /// super-predicates. This is a subset of the full list of diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 14f0c3284fcb7..74e02192be572 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1136,7 +1136,7 @@ pub struct CratePredicatesMap<'tcx> { /// For each struct with outlive bounds, maps to a vector of the /// predicate of its outlive bounds. If an item has no outlives /// bounds, it will have no entry. - pub predicates: FxHashMap]>, + pub predicates: FxHashMap, Span)]>, } impl<'tcx> AsRef> for Predicate<'tcx> { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 08f6f43ab0cff..9fde1d1662bbc 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1518,10 +1518,10 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( - inferred_outlives: &'tcx [ty::Predicate<'tcx>], + inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], index: u32, ) -> Vec> { - inferred_outlives.iter().filter_map(|pred| { + inferred_outlives.iter().filter_map(|(pred, _)| { match pred { ty::Predicate::RegionOutlives(outlives) => { let outlives = outlives.skip_binder(); @@ -1538,10 +1538,10 @@ impl ExplicitOutlivesRequirements { } fn lifetimes_outliving_type<'tcx>( - inferred_outlives: &'tcx [ty::Predicate<'tcx>], + inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], index: u32, ) -> Vec> { - inferred_outlives.iter().filter_map(|pred| { + inferred_outlives.iter().filter_map(|(pred, _)| { match pred { ty::Predicate::TypeOutlives(outlives) => { let outlives = outlives.skip_binder(); @@ -1560,7 +1560,7 @@ impl ExplicitOutlivesRequirements { &self, param: &'tcx hir::GenericParam, tcx: TyCtxt<'tcx>, - inferred_outlives: &'tcx [ty::Predicate<'tcx>], + inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], ty_generics: &'tcx ty::Generics, ) -> Vec> { let index = ty_generics.param_def_id_to_index[ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1749fd1075e05..720c69bc37070 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1970,19 +1970,18 @@ fn predicates_defined_on( ); let inferred_outlives = tcx.inferred_outlives_of(def_id); if !inferred_outlives.is_empty() { - let span = tcx.def_span(def_id); debug!( "predicates_defined_on: inferred_outlives_of({:?}) = {:?}", def_id, inferred_outlives, ); - result.predicates = tcx.arena.alloc_from_iter( - result.predicates.iter().copied().chain( - // FIXME(eddyb) use better spans - maybe add `Span`s - // to `inferred_outlives_of` predicates as well? - inferred_outlives.iter().map(|&p| (p, span)), - ), - ); + if result.predicates.is_empty() { + result.predicates = inferred_outlives; + } else { + result.predicates = tcx.arena.alloc_from_iter( + result.predicates.iter().chain(inferred_outlives).copied(), + ); + } } debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index cdb83eb328ac2..b2699fffc2c17 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -5,6 +5,7 @@ use rustc::ty::query::Providers; use rustc::ty::subst::GenericArgKind; use rustc::ty::{self, CratePredicatesMap, TyCtxt}; use syntax::symbol::sym; +use syntax_pos::Span; mod explicit; mod implicit_infer; @@ -23,7 +24,7 @@ pub fn provide(providers: &mut Providers<'_>) { fn inferred_outlives_of( tcx: TyCtxt<'_>, item_def_id: DefId, -) -> &[ty::Predicate<'_>] { +) -> &[(ty::Predicate<'_>, Span)] { let id = tcx .hir() .as_local_hir_id(item_def_id) @@ -43,7 +44,7 @@ fn inferred_outlives_of( if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates .iter() - .map(|out_pred| match out_pred { + .map(|(out_pred, _)| match out_pred { ty::Predicate::RegionOutlives(p) => p.to_string(), ty::Predicate::TypeOutlives(p) => p.to_string(), err => bug!("unexpected predicate {:?}", err), @@ -96,19 +97,35 @@ fn inferred_outlives_crate( let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let predicates = tcx.arena.alloc_from_iter(set + let def_span = tcx.def_span(def_id); + let generics = tcx.generics_of(def_id); + let predicates = &*tcx.arena.alloc_from_iter(set .iter() .filter_map( |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { GenericArgKind::Type(ty1) => { - Some(ty::Predicate::TypeOutlives(ty::Binder::bind( + // FIXME(eddyb) compute `Span`s in `implicit_infer`. + let span = match &ty1.kind { + ty::Param(p) => { + tcx.def_span(generics.type_param(p, tcx).def_id) + } + _ => def_span, + }; + Some((ty::Predicate::TypeOutlives(ty::Binder::bind( ty::OutlivesPredicate(ty1, region2) - ))) + )), span)) } GenericArgKind::Lifetime(region1) => { - Some(ty::Predicate::RegionOutlives( + // FIXME(eddyb) compute `Span`s in `implicit_infer`. + let span = match region1 { + ty::RegionKind::ReEarlyBound(p) => { + tcx.def_span(generics.region_param(p, tcx).def_id) + } + _ => def_span, + }; + Some((ty::Predicate::RegionOutlives( ty::Binder::bind(ty::OutlivesPredicate(region1, region2)) - )) + ), span)) } GenericArgKind::Const(_) => { // Generic consts don't impose any constraints. @@ -116,7 +133,7 @@ fn inferred_outlives_crate( } }, )); - (def_id, &*predicates) + (def_id, predicates) }).collect(); tcx.arena.alloc(ty::CratePredicatesMap {