Skip to content

Commit 97fbf49

Browse files
committed
Filter lifetimes from impl trait parent generics
1 parent 215e0b1 commit 97fbf49

File tree

4 files changed

+147
-16
lines changed

4 files changed

+147
-16
lines changed

src/librustc/ich/impls_ty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Ge
345345
// Reverse map to each `TypeParameterDef`'s `index` field, from
346346
// `def_id.index` (`def_id.krate` is the same as the item's).
347347
type_param_to_index: _, // Don't hash this
348+
region_param_to_index: _, // Don't hash this either
348349
has_self,
349350
has_late_bound_regions,
350351
} = *self;

src/librustc/ty/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,10 @@ pub struct Generics {
716716
pub regions: Vec<RegionParameterDef>,
717717
pub types: Vec<TypeParameterDef>,
718718

719+
/// Reverse map to each `RegionParameterDef`'s `index` field.
720+
/// Currently only appears for an `impl Trait` type's `ty::Generics`
721+
pub region_param_to_index: Option<BTreeMap<DefIndex, u32>>,
722+
719723
/// Reverse map to each `TypeParameterDef`'s `index` field, from
720724
/// `def_id.index` (`def_id.krate` is the same as the item's).
721725
pub type_param_to_index: BTreeMap<DefIndex, u32>,

src/librustc_typeck/astconv.rs

+49-2
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,54 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
10781078
}
10791079
}
10801080

1081+
fn impl_trait_to_ty(&self, impl_trait_node: ast::NodeId) -> Ty<'tcx> {
1082+
let tcx = self.tcx();
1083+
let def_id = tcx.hir.local_def_id(impl_trait_node);
1084+
let generics = tcx.generics_of(def_id);
1085+
let type_param_to_index = &generics.type_param_to_index;
1086+
let region_param_to_index = if let Some(ref x) = generics.region_param_to_index {
1087+
x
1088+
} else {
1089+
bug!("missing region_param_to_index for `impl Trait` generics")
1090+
};
1091+
let param_count = type_param_to_index.len() + region_param_to_index.len();
1092+
1093+
// Filter the parent substs into just the ones that are relevant to us
1094+
let parent = tcx.hir.local_def_id(tcx.hir.get_parent(impl_trait_node));
1095+
let parent_substs = Substs::identity_for_item(tcx, parent);
1096+
let mut opt_substs: Vec<Option<Kind>> =
1097+
::std::iter::repeat(None).take(param_count).collect();
1098+
1099+
let mut parent_id = Some(parent);
1100+
while let Some(cur_gen_id) = parent_id {
1101+
let cur_generics = tcx.generics_of(cur_gen_id);
1102+
1103+
for region in &cur_generics.regions {
1104+
if let Some(&new_index) = region_param_to_index.get(&region.def_id.index) {
1105+
opt_substs[new_index as usize] = Some(parent_substs[region.index as usize]);
1106+
}
1107+
}
1108+
for type_ in &cur_generics.types {
1109+
if let Some(&new_index) = type_param_to_index.get(&type_.def_id.index) {
1110+
opt_substs[new_index as usize] = Some(parent_substs[type_.index as usize]);
1111+
}
1112+
}
1113+
1114+
parent_id = cur_generics.parent;
1115+
}
1116+
1117+
let mut substs = Vec::with_capacity(param_count);
1118+
for opt_subst in opt_substs {
1119+
if let Some(subst) = opt_subst {
1120+
substs.push(subst);
1121+
} else {
1122+
bug!("missing `impl Trait` subst");
1123+
}
1124+
}
1125+
1126+
tcx.mk_anon(def_id, tcx.intern_substs(&substs))
1127+
}
1128+
10811129
/// Parses the programmer's textual representation of a type into our
10821130
/// internal notion of a type.
10831131
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
@@ -1154,8 +1202,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
11541202

11551203
// Create the anonymized type.
11561204
if allow {
1157-
let def_id = tcx.hir.local_def_id(ast_ty.id);
1158-
tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
1205+
self.impl_trait_to_ty(ast_ty.id)
11591206
} else {
11601207
span_err!(tcx.sess, ast_ty.span, E0562,
11611208
"`impl Trait` not allowed outside of function \

src/librustc_typeck/collect.rs

+93-14
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use rustc::ty::{ToPredicate, ReprOptions};
6565
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
6666
use rustc::ty::maps::Providers;
6767
use rustc::ty::util::IntTypeExt;
68-
use util::nodemap::FxHashMap;
68+
use util::nodemap::{DefIdSet, FxHashMap};
6969

7070
use rustc_const_math::ConstInt;
7171

@@ -76,7 +76,7 @@ use syntax::codemap::Spanned;
7676
use syntax::symbol::{Symbol, keywords};
7777
use syntax_pos::{Span, DUMMY_SP};
7878

79-
use rustc::hir::{self, map as hir_map};
79+
use rustc::hir::{self, map as hir_map, Lifetime};
8080
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
8181
use rustc::hir::def::{Def, CtorKind};
8282
use rustc::hir::def_id::DefId;
@@ -863,6 +863,35 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
863863
}
864864
}
865865

866+
struct ImplTraitRegionBoundsCollector<'a, 'tcx: 'a, 'b> {
867+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
868+
region_bounds: &'b mut DefIdSet,
869+
}
870+
871+
impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for ImplTraitRegionBoundsCollector<'a, 'tcx, 'b> {
872+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
873+
NestedVisitorMap::None
874+
}
875+
876+
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
877+
if !lifetime.is_static() { // no need to look up the lifetime if we already know it's static
878+
match self.tcx.named_region_map.defs.get(&lifetime.id) {
879+
Some(&rl::Region::EarlyBound(_, id)) => {
880+
self.region_bounds.insert(self.tcx.hir.local_def_id(id));
881+
}
882+
Some(&rl::Region::LateBound(_, _)) |
883+
Some(&rl::Region::LateBoundAnon(_, _)) => {
884+
span_bug!(lifetime.span,
885+
"Late-bound lifetimes not yet handed properly in `impl Trait`");
886+
}
887+
Some(&rl::Region::Static) |
888+
Some(&rl::Region::Free(_, _)) |
889+
None => {}
890+
}
891+
}
892+
}
893+
}
894+
866895
fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
867896
def_id: DefId)
868897
-> &'tcx ty::Generics {
@@ -884,18 +913,6 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
884913
NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
885914
Some(tcx.closure_base_def_id(def_id))
886915
}
887-
NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
888-
let mut parent_id = node_id;
889-
loop {
890-
match tcx.hir.get(parent_id) {
891-
NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
892-
_ => {
893-
parent_id = tcx.hir.get_parent_node(parent_id);
894-
}
895-
}
896-
}
897-
Some(tcx.hir.local_def_id(parent_id))
898-
}
899916
_ => None
900917
};
901918

@@ -962,6 +979,67 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
962979
}
963980
}
964981

982+
NodeTy(&hir::Ty{ node: hir::TyImplTrait(ref impl_trait_bounds), .. }) => {
983+
// Traverse impl_trait_bounds to identify all of the region bounds that appear
984+
// so that we can copy them from the environment
985+
let mut region_bounds = DefIdSet();
986+
{
987+
let mut bounds_collector = ImplTraitRegionBoundsCollector {
988+
tcx: tcx,
989+
region_bounds: &mut region_bounds,
990+
};
991+
for bound in impl_trait_bounds {
992+
bounds_collector.visit_ty_param_bound(bound);
993+
}
994+
}
995+
996+
let mut regions = vec![];
997+
let mut types = vec![];
998+
let mut region_param_to_index = BTreeMap::new();
999+
let mut type_param_to_index = BTreeMap::new();
1000+
let mut has_self = false;
1001+
1002+
// Copy generics from parents, filtering out unused region parameters
1003+
let mut parent_id = Some(tcx.hir.local_def_id(tcx.hir.get_parent(node_id)));
1004+
while let Some(cur_gen_id) = parent_id {
1005+
let cur_generics = tcx.generics_of(cur_gen_id);
1006+
1007+
has_self |= cur_generics.has_self;
1008+
1009+
for region in &cur_generics.regions {
1010+
if region_bounds.contains(&region.def_id) {
1011+
regions.push(*region);
1012+
}
1013+
}
1014+
1015+
types.extend_from_slice(&cur_generics.types);
1016+
1017+
parent_id = cur_generics.parent;
1018+
}
1019+
1020+
// Fixup indices
1021+
for (i, ref mut region) in regions.iter_mut().enumerate() {
1022+
region.index = i as u32;
1023+
region_param_to_index.insert(region.def_id.index, region.index);
1024+
}
1025+
for (i, ref mut type_) in types.iter_mut().enumerate() {
1026+
type_.index = (regions.len() + i) as u32;
1027+
type_param_to_index.insert(type_.def_id.index, type_.index);
1028+
}
1029+
1030+
return tcx.alloc_generics(ty::Generics {
1031+
parent: None,
1032+
parent_regions: 0,
1033+
parent_types: 0,
1034+
regions: regions,
1035+
types: types,
1036+
region_param_to_index: Some(region_param_to_index),
1037+
type_param_to_index: type_param_to_index,
1038+
has_self: has_self,
1039+
has_late_bound_regions: None,
1040+
});
1041+
}
1042+
9651043
_ => &no_generics
9661044
};
9671045

@@ -1048,6 +1126,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10481126
regions: regions,
10491127
types: types,
10501128
type_param_to_index: type_param_to_index,
1129+
region_param_to_index: None,
10511130
has_self: has_self || parent_has_self,
10521131
has_late_bound_regions: has_late_bound_regions(tcx, node),
10531132
})

0 commit comments

Comments
 (0)