1
Fork 0

Auto merge of #65541 - eddyb:spanned-inferred-outlives, r=nikomatsakis

rustc: add `Span`s to `inferred_outlives_of` predicates.

This would simplify #59789, and I suspect it has some potential in diagnostics (although we don't seem to use the predicate `Span`s much atm).
This commit is contained in:
bors 2019-10-27 12:58:10 +00:00
commit 0f677c65e8
9 changed files with 62 additions and 36 deletions

View file

@ -191,7 +191,7 @@ rustc_queries! {
/// Returns the inferred outlives predicates (e.g., for `struct /// Returns the inferred outlives predicates (e.g., for `struct
/// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). /// 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 /// Maps from the `DefId` of a trait to the list of
/// super-predicates. This is a subset of the full list of /// super-predicates. This is a subset of the full list of

View file

@ -1143,7 +1143,7 @@ pub struct CratePredicatesMap<'tcx> {
/// For each struct with outlive bounds, maps to a vector of the /// For each struct with outlive bounds, maps to a vector of the
/// predicate of its outlive bounds. If an item has no outlives /// predicate of its outlive bounds. If an item has no outlives
/// bounds, it will have no entry. /// bounds, it will have no entry.
pub predicates: FxHashMap<DefId, &'tcx [ty::Predicate<'tcx>]>, pub predicates: FxHashMap<DefId, &'tcx [(ty::Predicate<'tcx>, Span)]>,
} }
impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> { impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> {

View file

@ -1497,10 +1497,10 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
impl ExplicitOutlivesRequirements { impl ExplicitOutlivesRequirements {
fn lifetimes_outliving_lifetime<'tcx>( fn lifetimes_outliving_lifetime<'tcx>(
inferred_outlives: &'tcx [ty::Predicate<'tcx>], inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
index: u32, index: u32,
) -> Vec<ty::Region<'tcx>> { ) -> Vec<ty::Region<'tcx>> {
inferred_outlives.iter().filter_map(|pred| { inferred_outlives.iter().filter_map(|(pred, _)| {
match pred { match pred {
ty::Predicate::RegionOutlives(outlives) => { ty::Predicate::RegionOutlives(outlives) => {
let outlives = outlives.skip_binder(); let outlives = outlives.skip_binder();
@ -1517,10 +1517,10 @@ impl ExplicitOutlivesRequirements {
} }
fn lifetimes_outliving_type<'tcx>( fn lifetimes_outliving_type<'tcx>(
inferred_outlives: &'tcx [ty::Predicate<'tcx>], inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
index: u32, index: u32,
) -> Vec<ty::Region<'tcx>> { ) -> Vec<ty::Region<'tcx>> {
inferred_outlives.iter().filter_map(|pred| { inferred_outlives.iter().filter_map(|(pred, _)| {
match pred { match pred {
ty::Predicate::TypeOutlives(outlives) => { ty::Predicate::TypeOutlives(outlives) => {
let outlives = outlives.skip_binder(); let outlives = outlives.skip_binder();
@ -1539,7 +1539,7 @@ impl ExplicitOutlivesRequirements {
&self, &self,
param: &'tcx hir::GenericParam, param: &'tcx hir::GenericParam,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
inferred_outlives: &'tcx [ty::Predicate<'tcx>], inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
ty_generics: &'tcx ty::Generics, ty_generics: &'tcx ty::Generics,
) -> Vec<ty::Region<'tcx>> { ) -> Vec<ty::Region<'tcx>> {
let index = ty_generics.param_def_id_to_index[ let index = ty_generics.param_def_id_to_index[

View file

@ -197,6 +197,13 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
return TAG_INVALID_SPAN.encode(self) 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)?; TAG_VALID_SPAN.encode(self)?;
span.lo.encode(self)?; span.lo.encode(self)?;
@ -379,6 +386,7 @@ impl<'tcx> EncodeContext<'tcx> {
.filter(|source_file| { .filter(|source_file| {
// No need to re-export imported source_files, as any downstream // No need to re-export imported source_files, as any downstream
// crate will import them from their original source. // crate will import them from their original source.
// FIXME(eddyb) the `Span` encoding should take that into account.
!source_file.is_imported() !source_file.is_imported()
}) })
.map(|source_file| { .map(|source_file| {

View file

@ -1983,19 +1983,18 @@ fn predicates_defined_on(
); );
let inferred_outlives = tcx.inferred_outlives_of(def_id); let inferred_outlives = tcx.inferred_outlives_of(def_id);
if !inferred_outlives.is_empty() { if !inferred_outlives.is_empty() {
let span = tcx.def_span(def_id);
debug!( debug!(
"predicates_defined_on: inferred_outlives_of({:?}) = {:?}", "predicates_defined_on: inferred_outlives_of({:?}) = {:?}",
def_id, def_id,
inferred_outlives, inferred_outlives,
); );
result.predicates = tcx.arena.alloc_from_iter( if result.predicates.is_empty() {
result.predicates.iter().copied().chain( result.predicates = inferred_outlives;
// FIXME(eddyb) use better spans - maybe add `Span`s } else {
// to `inferred_outlives_of` predicates as well? result.predicates = tcx.arena.alloc_from_iter(
inferred_outlives.iter().map(|&p| (p, span)), result.predicates.iter().chain(inferred_outlives).copied(),
), );
); }
} }
debug!("predicates_defined_on({:?}) = {:?}", def_id, result); debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
result result

View file

@ -30,11 +30,17 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
let mut required_predicates = RequiredPredicates::default(); let mut required_predicates = RequiredPredicates::default();
// process predicates and convert to `RequiredPredicates` entry, see below // process predicates and convert to `RequiredPredicates` entry, see below
for (pred, _) in predicates.predicates { for &(predicate, span) in predicates.predicates {
match pred { match predicate {
ty::Predicate::TypeOutlives(predicate) => { ty::Predicate::TypeOutlives(predicate) => {
let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); 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) => { ty::Predicate::RegionOutlives(predicate) => {
@ -43,6 +49,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
tcx, tcx,
(*reg1).into(), (*reg1).into(),
reg2, reg2,
span,
&mut required_predicates, &mut required_predicates,
) )
} }

View file

@ -4,6 +4,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::subst::{GenericArg, Subst, GenericArgKind}; use rustc::ty::subst::{GenericArg, Subst, GenericArgKind};
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap; use rustc::util::nodemap::FxHashMap;
use syntax_pos::Span;
use super::explicit::ExplicitPredicatesMap; use super::explicit::ExplicitPredicatesMap;
use super::utils::*; use super::utils::*;
@ -79,9 +80,11 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
// (struct/enum/union) there will be outlive // (struct/enum/union) there will be outlive
// requirements for adt_def. // requirements for adt_def.
let field_ty = self.tcx.type_of(field_def.did); 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( insert_required_predicates_to_be_wf(
self.tcx, self.tcx,
field_ty, field_ty,
field_span,
self.global_inferred_outlives, self.global_inferred_outlives,
&mut item_required_predicates, &mut item_required_predicates,
&mut self.explicit_map, &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>( fn insert_required_predicates_to_be_wf<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
field_ty: Ty<'tcx>, field_ty: Ty<'tcx>,
field_span: Span,
global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>, global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
required_predicates: &mut RequiredPredicates<'tcx>, required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'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 // We also want to calculate potential predicates for the T
ty::Ref(region, rty, _) => { ty::Ref(region, rty, _) => {
debug!("Ref"); 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 // 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`. // 'a` holds for `Foo`.
debug!("Adt"); debug!("Adt");
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) { 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 // `unsubstituted_predicate` is `U: 'b` in the
// example above. So apply the substitution to // example above. So apply the substitution to
// get `T: 'a` (or `predicate`): // get `T: 'a` (or `predicate`):
@ -167,6 +171,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
tcx, tcx,
predicate.0, predicate.0,
predicate.1, predicate.1,
span,
required_predicates, required_predicates,
); );
} }
@ -272,7 +277,7 @@ pub fn check_explicit_predicates<'tcx>(
); );
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); 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); debug!("outlives_predicate = {:?}", &outlives_predicate);
// Careful: If we are inferring the effects of a `dyn Trait<..>` // 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); let predicate = outlives_predicate.subst(tcx, substs);
debug!("predicate = {:?}", &predicate); 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);
} }
} }

View file

@ -5,6 +5,7 @@ use rustc::ty::query::Providers;
use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::GenericArgKind;
use rustc::ty::{self, CratePredicatesMap, TyCtxt}; use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use syntax::symbol::sym; use syntax::symbol::sym;
use syntax_pos::Span;
mod explicit; mod explicit;
mod implicit_infer; mod implicit_infer;
@ -23,7 +24,7 @@ pub fn provide(providers: &mut Providers<'_>) {
fn inferred_outlives_of( fn inferred_outlives_of(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
item_def_id: DefId, item_def_id: DefId,
) -> &[ty::Predicate<'_>] { ) -> &[(ty::Predicate<'_>, Span)] {
let id = tcx let id = tcx
.hir() .hir()
.as_local_hir_id(item_def_id) .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) { if tcx.has_attr(item_def_id, sym::rustc_outlives) {
let mut pred: Vec<String> = predicates let mut pred: Vec<String> = predicates
.iter() .iter()
.map(|out_pred| match out_pred { .map(|(out_pred, _)| match out_pred {
ty::Predicate::RegionOutlives(p) => p.to_string(), ty::Predicate::RegionOutlives(p) => p.to_string(),
ty::Predicate::TypeOutlives(p) => p.to_string(), ty::Predicate::TypeOutlives(p) => p.to_string(),
err => bug!("unexpected predicate {:?}", err), err => bug!("unexpected predicate {:?}", err),
@ -96,19 +97,19 @@ fn inferred_outlives_crate(
let predicates = global_inferred_outlives let predicates = global_inferred_outlives
.iter() .iter()
.map(|(&def_id, set)| { .map(|(&def_id, set)| {
let predicates = tcx.arena.alloc_from_iter(set let predicates = &*tcx.arena.alloc_from_iter(set
.iter() .iter()
.filter_map( .filter_map(
|ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { |(ty::OutlivesPredicate(kind1, region2), &span)| match kind1.unpack() {
GenericArgKind::Type(ty1) => { GenericArgKind::Type(ty1) => {
Some(ty::Predicate::TypeOutlives(ty::Binder::bind( Some((ty::Predicate::TypeOutlives(ty::Binder::bind(
ty::OutlivesPredicate(ty1, region2) ty::OutlivesPredicate(ty1, region2)
))) )), span))
} }
GenericArgKind::Lifetime(region1) => { GenericArgKind::Lifetime(region1) => {
Some(ty::Predicate::RegionOutlives( Some((ty::Predicate::RegionOutlives(
ty::Binder::bind(ty::OutlivesPredicate(region1, region2)) ty::Binder::bind(ty::OutlivesPredicate(region1, region2))
)) ), span))
} }
GenericArgKind::Const(_) => { GenericArgKind::Const(_) => {
// Generic consts don't impose any constraints. // Generic consts don't impose any constraints.
@ -116,7 +117,7 @@ fn inferred_outlives_crate(
} }
}, },
)); ));
(def_id, &*predicates) (def_id, predicates)
}).collect(); }).collect();
tcx.arena.alloc(ty::CratePredicatesMap { tcx.arena.alloc(ty::CratePredicatesMap {

View file

@ -2,12 +2,13 @@ use rustc::ty::outlives::Component;
use rustc::ty::subst::{GenericArg, GenericArgKind}; use rustc::ty::subst::{GenericArg, GenericArgKind};
use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt}; use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt};
use smallvec::smallvec; 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 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
/// must be added to the struct header. /// must be added to the struct header.
pub type RequiredPredicates<'tcx> = pub type RequiredPredicates<'tcx> =
BTreeSet<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>>; BTreeMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>;
/// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// Given a requirement `T: 'a` or `'b: 'a`, deduce the
/// outlives_component and add it to `required_predicates` /// outlives_component and add it to `required_predicates`
@ -15,6 +16,7 @@ pub fn insert_outlives_predicate<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
kind: GenericArg<'tcx>, kind: GenericArg<'tcx>,
outlived_region: Region<'tcx>, outlived_region: Region<'tcx>,
span: Span,
required_predicates: &mut RequiredPredicates<'tcx>, required_predicates: &mut RequiredPredicates<'tcx>,
) { ) {
// If the `'a` region is bound within the field type itself, we // If the `'a` region is bound within the field type itself, we
@ -53,6 +55,7 @@ pub fn insert_outlives_predicate<'tcx>(
tcx, tcx,
r.into(), r.into(),
outlived_region, outlived_region,
span,
required_predicates, required_predicates,
); );
} }
@ -73,7 +76,8 @@ pub fn insert_outlives_predicate<'tcx>(
// where clause that `U: 'a`. // where clause that `U: 'a`.
let ty: Ty<'tcx> = param_ty.to_ty(tcx); let ty: Ty<'tcx> = param_ty.to_ty(tcx);
required_predicates required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region)); .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
.or_insert(span);
} }
Component::Projection(proj_ty) => { Component::Projection(proj_ty) => {
@ -88,7 +92,8 @@ pub fn insert_outlives_predicate<'tcx>(
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`. // Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs); let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
required_predicates required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region)); .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
.or_insert(span);
} }
Component::EscapingProjection(_) => { Component::EscapingProjection(_) => {
@ -117,7 +122,8 @@ pub fn insert_outlives_predicate<'tcx>(
if !is_free_region(tcx, r) { if !is_free_region(tcx, r) {
return; return;
} }
required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); required_predicates.entry(ty::OutlivesPredicate(kind, outlived_region))
.or_insert(span);
} }
GenericArgKind::Const(_) => { GenericArgKind::Const(_) => {