From 93cac9c3da06e1fbbdee10df7525234ffc7c76cd Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 18 Oct 2019 04:24:22 +0300 Subject: [PATCH 1/2] rustc: add `Span`s to `inferred_outlives_of` predicates. --- src/librustc/query/mod.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc_lint/builtin.rs | 10 ++++----- src/librustc_typeck/collect.rs | 15 ++++++------- src/librustc_typeck/outlives/mod.rs | 33 ++++++++++++++++++++++------- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index fdca6d0e17a1d..7cae74b59c7f9 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 feede00fea1c3..e58ba9d6a2b3a 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 ad674911e6f33..7c19449f96b86 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1497,10 +1497,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(); @@ -1517,10 +1517,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(); @@ -1539,7 +1539,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 d4c64512f984b..78347ded72635 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 { From 1ca8da40366a417aef90415d8f745764cab5783b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 19 Oct 2019 03:45:16 +0300 Subject: [PATCH 2/2] rustc_typeck: compute better spans for inferred_outlives. --- src/librustc_metadata/encoder.rs | 8 ++++++++ src/librustc_typeck/outlives/explicit.rs | 13 ++++++++++--- src/librustc_typeck/outlives/implicit_infer.rs | 13 +++++++++---- src/librustc_typeck/outlives/mod.rs | 18 +----------------- src/librustc_typeck/outlives/utils.rs | 16 +++++++++++----- 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0dc9f91ae00e1..08554c83ed5bf 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -197,6 +197,13 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { return TAG_INVALID_SPAN.encode(self) } + // HACK(eddyb) there's no way to indicate which crate a Span is coming + // from right now, so decoding would fail to find the SourceFile if + // it's not local to the crate the Span is found in. + if self.source_file_cache.is_imported() { + return TAG_INVALID_SPAN.encode(self) + } + TAG_VALID_SPAN.encode(self)?; span.lo.encode(self)?; @@ -379,6 +386,7 @@ impl<'tcx> EncodeContext<'tcx> { .filter(|source_file| { // No need to re-export imported source_files, as any downstream // crate will import them from their original source. + // FIXME(eddyb) the `Span` encoding should take that into account. !source_file.is_imported() }) .map(|source_file| { diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 83194144216ee..21e529f33cfd0 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -30,11 +30,17 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { let mut required_predicates = RequiredPredicates::default(); // process predicates and convert to `RequiredPredicates` entry, see below - for (pred, _) in predicates.predicates { - match pred { + for &(predicate, span) in predicates.predicates { + match predicate { ty::Predicate::TypeOutlives(predicate) => { let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); - insert_outlives_predicate(tcx, (*ty).into(), reg, &mut required_predicates) + insert_outlives_predicate( + tcx, + (*ty).into(), + reg, + span, + &mut required_predicates, + ) } ty::Predicate::RegionOutlives(predicate) => { @@ -43,6 +49,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { tcx, (*reg1).into(), reg2, + span, &mut required_predicates, ) } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index 433d04ffa64ff..74048b8d20c82 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -4,6 +4,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::subst::{GenericArg, Subst, GenericArgKind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; +use syntax_pos::Span; use super::explicit::ExplicitPredicatesMap; use super::utils::*; @@ -79,9 +80,11 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { // (struct/enum/union) there will be outlive // requirements for adt_def. let field_ty = self.tcx.type_of(field_def.did); + let field_span = self.tcx.def_span(field_def.did); insert_required_predicates_to_be_wf( self.tcx, field_ty, + field_span, self.global_inferred_outlives, &mut item_required_predicates, &mut self.explicit_map, @@ -118,6 +121,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, field_ty: Ty<'tcx>, + field_span: Span, global_inferred_outlives: &FxHashMap>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, @@ -130,7 +134,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( // We also want to calculate potential predicates for the T ty::Ref(region, rty, _) => { debug!("Ref"); - insert_outlives_predicate(tcx, rty.into(), region, required_predicates); + insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates); } // For each Adt (struct/enum/union) type `Foo<'a, T>`, we @@ -158,7 +162,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( // 'a` holds for `Foo`. debug!("Adt"); if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) { - for unsubstituted_predicate in unsubstituted_predicates { + for (unsubstituted_predicate, &span) in unsubstituted_predicates { // `unsubstituted_predicate` is `U: 'b` in the // example above. So apply the substitution to // get `T: 'a` (or `predicate`): @@ -167,6 +171,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( tcx, predicate.0, predicate.1, + span, required_predicates, ); } @@ -272,7 +277,7 @@ pub fn check_explicit_predicates<'tcx>( ); let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); - for outlives_predicate in explicit_predicates.iter() { + for (outlives_predicate, &span) in explicit_predicates { debug!("outlives_predicate = {:?}", &outlives_predicate); // Careful: If we are inferring the effects of a `dyn Trait<..>` @@ -320,6 +325,6 @@ pub fn check_explicit_predicates<'tcx>( let predicate = outlives_predicate.subst(tcx, substs); debug!("predicate = {:?}", &predicate); - insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates); + insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, span, required_predicates); } } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index b2699fffc2c17..6b861656d7e2d 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -97,32 +97,16 @@ fn inferred_outlives_crate( let predicates = global_inferred_outlives .iter() .map(|(&def_id, 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() { + |(ty::OutlivesPredicate(kind1, region2), &span)| match kind1.unpack() { GenericArgKind::Type(ty1) => { - // 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) => { - // 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)) diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index d34605dc482a3..361116e96d0bf 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -2,12 +2,13 @@ use rustc::ty::outlives::Component; use rustc::ty::subst::{GenericArg, GenericArgKind}; use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt}; use smallvec::smallvec; -use std::collections::BTreeSet; +use std::collections::BTreeMap; +use syntax_pos::Span; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. pub type RequiredPredicates<'tcx> = - BTreeSet, ty::Region<'tcx>>>; + BTreeMap, ty::Region<'tcx>>, Span>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` @@ -15,6 +16,7 @@ pub fn insert_outlives_predicate<'tcx>( tcx: TyCtxt<'tcx>, kind: GenericArg<'tcx>, outlived_region: Region<'tcx>, + span: Span, required_predicates: &mut RequiredPredicates<'tcx>, ) { // If the `'a` region is bound within the field type itself, we @@ -53,6 +55,7 @@ pub fn insert_outlives_predicate<'tcx>( tcx, r.into(), outlived_region, + span, required_predicates, ); } @@ -73,7 +76,8 @@ pub fn insert_outlives_predicate<'tcx>( // where clause that `U: 'a`. let ty: Ty<'tcx> = param_ty.to_ty(tcx); required_predicates - .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); + .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) + .or_insert(span); } Component::Projection(proj_ty) => { @@ -88,7 +92,8 @@ pub fn insert_outlives_predicate<'tcx>( // Here we want to add an explicit `where ::Item: 'a`. let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs); required_predicates - .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); + .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) + .or_insert(span); } Component::EscapingProjection(_) => { @@ -117,7 +122,8 @@ pub fn insert_outlives_predicate<'tcx>( if !is_free_region(tcx, r) { return; } - required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); + required_predicates.entry(ty::OutlivesPredicate(kind, outlived_region)) + .or_insert(span); } GenericArgKind::Const(_) => {