Skip to content

Commit 9b1bd94

Browse files
committed
Add existential type definitons
1 parent c131bdc commit 9b1bd94

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+582
-287
lines changed

src/librustc/hir/def.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub enum Def {
3535
Enum(DefId),
3636
Variant(DefId),
3737
Trait(DefId),
38+
Existential(DefId),
3839
TyAlias(DefId),
3940
TyForeign(DefId),
4041
TraitAlias(DefId),
@@ -162,6 +163,7 @@ impl Def {
162163
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
163164
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
164165
Def::AssociatedConst(id) | Def::Macro(id, ..) |
166+
Def::Existential(id) |
165167
Def::GlobalAsm(id) | Def::TyForeign(id) => {
166168
id
167169
}
@@ -188,6 +190,7 @@ impl Def {
188190
Def::VariantCtor(.., CtorKind::Const) => "unit variant",
189191
Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
190192
Def::Enum(..) => "enum",
193+
Def::Existential(..) => "existential type",
191194
Def::TyAlias(..) => "type alias",
192195
Def::TraitAlias(..) => "trait alias",
193196
Def::AssociatedTy(..) => "associated type",

src/librustc/hir/intravisit.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
502502
visitor.visit_ty(typ);
503503
visitor.visit_generics(type_parameters)
504504
}
505+
ItemExistential(ExistTy {ref generics, ref bounds, impl_trait_fn}) => {
506+
visitor.visit_id(item.id);
507+
walk_generics(visitor, generics);
508+
walk_list!(visitor, visit_ty_param_bound, bounds);
509+
if let Some(impl_trait_fn) = impl_trait_fn {
510+
visitor.visit_def_mention(Def::Fn(impl_trait_fn))
511+
}
512+
}
505513
ItemEnum(ref enum_definition, ref type_parameters) => {
506514
visitor.visit_generics(type_parameters);
507515
// visit_enum_def() takes care of visiting the Item's NodeId
@@ -596,10 +604,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
596604
}
597605
visitor.visit_lifetime(lifetime);
598606
}
599-
TyImplTraitExistential(ref existty, ref lifetimes) => {
600-
let ExistTy { ref generics, ref bounds } = *existty;
601-
walk_generics(visitor, generics);
602-
walk_list!(visitor, visit_ty_param_bound, bounds);
607+
TyImplTraitExistential(item_id, def_id, ref lifetimes) => {
608+
visitor.visit_def_mention(Def::Existential(def_id));
609+
visitor.visit_nested_item(item_id);
603610
walk_list!(visitor, visit_lifetime, lifetimes);
604611
}
605612
TyTypeof(ref expression) => {

src/librustc/hir/lowering.rs

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ enum ImplTraitContext {
179179
/// Treat `impl Trait` as shorthand for a new universal existential parameter.
180180
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
181181
/// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
182-
Existential,
182+
///
183+
/// We store a DefId here so we can look up necessary information later
184+
Existential(DefId),
183185

184186
/// `impl Trait` is not accepted in this position.
185187
Disallowed,
@@ -235,6 +237,7 @@ enum ParamMode {
235237
Optional,
236238
}
237239

240+
#[derive(Debug)]
238241
struct LoweredNodeId {
239242
node_id: NodeId,
240243
hir_id: hir::HirId,
@@ -485,16 +488,16 @@ impl<'a> LoweringContext<'a> {
485488
}
486489
}
487490

488-
fn with_hir_id_owner<F>(&mut self, owner: NodeId, f: F)
491+
fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
489492
where
490-
F: FnOnce(&mut Self),
493+
F: FnOnce(&mut Self) -> T,
491494
{
492495
let counter = self.item_local_id_counters
493496
.insert(owner, HIR_ID_COUNTER_LOCKED)
494497
.unwrap();
495498
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
496499
self.current_hir_id_owner.push((def_index, counter));
497-
f(self);
500+
let ret = f(self);
498501
let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
499502

500503
debug_assert!(def_index == new_def_index);
@@ -504,6 +507,7 @@ impl<'a> LoweringContext<'a> {
504507
.insert(owner, new_counter)
505508
.unwrap();
506509
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
510+
ret
507511
}
508512

509513
/// This method allocates a new HirId for the given NodeId and stores it in
@@ -527,7 +531,10 @@ impl<'a> LoweringContext<'a> {
527531

528532
fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> LoweredNodeId {
529533
self.lower_node_id_generic(ast_node_id, |this| {
530-
let local_id_counter = this.item_local_id_counters.get_mut(&owner).unwrap();
534+
let local_id_counter = this
535+
.item_local_id_counters
536+
.get_mut(&owner)
537+
.expect("called lower_node_id_with_owner before allocate_hir_id_counter");
531538
let local_id = *local_id_counter;
532539

533540
// We want to be sure not to modify the counter in the map while it
@@ -536,7 +543,12 @@ impl<'a> LoweringContext<'a> {
536543
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
537544

538545
*local_id_counter += 1;
539-
let def_index = this.resolver.definitions().opt_def_index(owner).unwrap();
546+
let def_index = this
547+
.resolver
548+
.definitions()
549+
.opt_def_index(owner)
550+
.expect("You forgot to call `create_def_with_parent` or are lowering node ids \
551+
that do not belong to the current owner");
540552

541553
hir::HirId {
542554
owner: def_index,
@@ -1108,26 +1120,93 @@ impl<'a> LoweringContext<'a> {
11081120
TyKind::ImplTrait(ref bounds) => {
11091121
let span = t.span;
11101122
match itctx {
1111-
ImplTraitContext::Existential => {
1112-
let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap();
1113-
let hir_bounds = self.lower_bounds(bounds, itctx);
1114-
let (lifetimes, lifetime_defs) =
1115-
self.lifetimes_from_impl_trait_bounds(def_index, &hir_bounds);
1123+
ImplTraitContext::Existential(fn_def_id) => {
1124+
1125+
// We need to manually repeat the code of `next_id` because the lowering
1126+
// needs to happen while the owner_id is pointing to the item itself,
1127+
// because items are their own owners
1128+
let exist_ty_node_id = self.sess.next_node_id();
1129+
1130+
// Make sure we know that some funky desugaring has been going on here.
1131+
// This is a first: there is code in other places like for loop
1132+
// desugaring that explicitly states that we don't want to track that.
1133+
// Not tracking it makes lints in rustc and clippy very fragile as
1134+
// frequently opened issues show.
1135+
let exist_ty_span = self.allow_internal_unstable(
1136+
CompilerDesugaringKind::ExistentialReturnType,
1137+
t.span,
1138+
);
11161139

1117-
hir::TyImplTraitExistential(
1118-
hir::ExistTy {
1140+
// Pull a new definition from the ether
1141+
let exist_ty_def_index = self
1142+
.resolver
1143+
.definitions()
1144+
.create_def_with_parent(
1145+
fn_def_id.index,
1146+
exist_ty_node_id,
1147+
DefPathData::ExistentialImplTrait,
1148+
DefIndexAddressSpace::High,
1149+
Mark::root(),
1150+
exist_ty_span,
1151+
);
1152+
1153+
// the `t` is just for printing debug messages
1154+
self.allocate_hir_id_counter(exist_ty_node_id, t);
1155+
1156+
let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
1157+
lctx.lower_bounds(bounds, itctx)
1158+
});
1159+
1160+
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
1161+
exist_ty_node_id,
1162+
exist_ty_def_index,
1163+
&hir_bounds,
1164+
);
1165+
1166+
self.with_hir_id_owner(exist_ty_node_id, |lctx| {
1167+
let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
11191168
generics: hir::Generics {
11201169
params: lifetime_defs,
11211170
where_clause: hir::WhereClause {
1122-
id: self.next_id().node_id,
1171+
id: lctx.next_id().node_id,
11231172
predicates: Vec::new().into(),
11241173
},
11251174
span,
11261175
},
11271176
bounds: hir_bounds,
1128-
},
1129-
lifetimes,
1130-
)
1177+
impl_trait_fn: Some(fn_def_id),
1178+
});
1179+
let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
1180+
// Generate an `existential type Foo: Trait;` declaration
1181+
trace!("creating existential type with id {:#?}", exist_ty_id);
1182+
// Set the name to `impl Bound1 + Bound2`
1183+
let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
1184+
1185+
trace!("exist ty def index: {:#?}", exist_ty_def_index);
1186+
let exist_ty_item = hir::Item {
1187+
id: exist_ty_id.node_id,
1188+
hir_id: exist_ty_id.hir_id,
1189+
name: exist_ty_name,
1190+
attrs: Default::default(),
1191+
node: exist_ty_item_kind,
1192+
vis: hir::Visibility::Inherited,
1193+
span: exist_ty_span,
1194+
};
1195+
1196+
// Insert the item into the global list. This usually happens
1197+
// automatically for all AST items. But this existential type item
1198+
// does not actually exist in the AST.
1199+
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
1200+
1201+
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
1202+
hir::TyImplTraitExistential(
1203+
hir::ItemId {
1204+
id: exist_ty_id.node_id
1205+
},
1206+
DefId::local(exist_ty_def_index),
1207+
lifetimes,
1208+
)
1209+
})
11311210
}
11321211
ImplTraitContext::Universal(def_id) => {
11331212
let def_node_id = self.next_id().node_id;
@@ -1136,7 +1215,7 @@ impl<'a> LoweringContext<'a> {
11361215
let def_index = self.resolver.definitions().create_def_with_parent(
11371216
def_id.index,
11381217
def_node_id,
1139-
DefPathData::ImplTrait,
1218+
DefPathData::UniversalImplTrait,
11401219
DefIndexAddressSpace::High,
11411220
Mark::root(),
11421221
span,
@@ -1191,6 +1270,7 @@ impl<'a> LoweringContext<'a> {
11911270

11921271
fn lifetimes_from_impl_trait_bounds(
11931272
&mut self,
1273+
exist_ty_id: NodeId,
11941274
parent_index: DefIndex,
11951275
bounds: &hir::TyParamBounds,
11961276
) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
@@ -1200,6 +1280,7 @@ impl<'a> LoweringContext<'a> {
12001280
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
12011281
context: &'r mut LoweringContext<'a>,
12021282
parent: DefIndex,
1283+
exist_ty_id: NodeId,
12031284
collect_elided_lifetimes: bool,
12041285
currently_bound_lifetimes: Vec<hir::LifetimeName>,
12051286
already_defined_lifetimes: HashSet<hir::LifetimeName>,
@@ -1294,7 +1375,11 @@ impl<'a> LoweringContext<'a> {
12941375
name,
12951376
});
12961377

1297-
let def_node_id = self.context.next_id().node_id;
1378+
// We need to manually create the ids here, because the
1379+
// definitions will go into the explicit `existential type`
1380+
// declaration and thus need to have their owner set to that item
1381+
let def_node_id = self.context.sess.next_node_id();
1382+
let _ = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
12981383
self.context.resolver.definitions().create_def_with_parent(
12991384
self.parent,
13001385
def_node_id,
@@ -1306,7 +1391,7 @@ impl<'a> LoweringContext<'a> {
13061391
let def_lifetime = hir::Lifetime {
13071392
id: def_node_id,
13081393
span: lifetime.span,
1309-
name: name,
1394+
name,
13101395
};
13111396
self.output_lifetime_params
13121397
.push(hir::GenericParam::Lifetime(hir::LifetimeDef {
@@ -1322,6 +1407,7 @@ impl<'a> LoweringContext<'a> {
13221407
let mut lifetime_collector = ImplTraitLifetimeCollector {
13231408
context: self,
13241409
parent: parent_index,
1410+
exist_ty_id,
13251411
collect_elided_lifetimes: true,
13261412
currently_bound_lifetimes: Vec::new(),
13271413
already_defined_lifetimes: HashSet::new(),
@@ -1759,8 +1845,8 @@ impl<'a> LoweringContext<'a> {
17591845
.collect(),
17601846
output: match decl.output {
17611847
FunctionRetTy::Ty(ref ty) => match fn_def_id {
1762-
Some(_) if impl_trait_return_allow => {
1763-
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential))
1848+
Some(def_id) if impl_trait_return_allow => {
1849+
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
17641850
}
17651851
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
17661852
},

src/librustc/hir/map/def_collector.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
8888
debug!("visit_item: {:?}", i);
8989

9090
// Pick the def data. This need not be unique, but the more
91-
// information we encapsulate into
91+
// information we encapsulate into, the better
9292
let def_data = match i.node {
9393
ItemKind::Impl(..) => DefPathData::Impl,
9494
ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_interned_str()),
@@ -256,9 +256,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
256256
fn visit_ty(&mut self, ty: &'a Ty) {
257257
match ty.node {
258258
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id),
259-
TyKind::ImplTrait(..) => {
260-
self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE, ty.span);
261-
}
262259
_ => {}
263260
}
264261
visit::walk_ty(self, ty);

src/librustc/hir/map/definitions.rs

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -210,30 +210,9 @@ impl DefKey {
210210
} = self.disambiguated_data;
211211

212212
::std::mem::discriminant(data).hash(&mut hasher);
213-
match *data {
214-
DefPathData::TypeNs(name) |
215-
DefPathData::Trait(name) |
216-
DefPathData::AssocTypeInTrait(name) |
217-
DefPathData::AssocTypeInImpl(name) |
218-
DefPathData::ValueNs(name) |
219-
DefPathData::Module(name) |
220-
DefPathData::MacroDef(name) |
221-
DefPathData::TypeParam(name) |
222-
DefPathData::LifetimeDef(name) |
223-
DefPathData::EnumVariant(name) |
224-
DefPathData::Field(name) |
225-
DefPathData::GlobalMetaData(name) => {
226-
name.hash(&mut hasher);
227-
}
228-
229-
DefPathData::Impl |
230-
DefPathData::CrateRoot |
231-
DefPathData::Misc |
232-
DefPathData::ClosureExpr |
233-
DefPathData::StructCtor |
234-
DefPathData::AnonConst |
235-
DefPathData::ImplTrait => {}
236-
};
213+
if let Some(name) = data.get_opt_name() {
214+
name.hash(&mut hasher);
215+
}
237216

238217
disambiguator.hash(&mut hasher);
239218

@@ -390,8 +369,10 @@ pub enum DefPathData {
390369
StructCtor,
391370
/// A constant expression (see {ast,hir}::AnonConst).
392371
AnonConst,
393-
/// An `impl Trait` type node.
394-
ImplTrait,
372+
/// An `impl Trait` type node in argument position.
373+
UniversalImplTrait,
374+
/// An `impl Trait` type node in return position.
375+
ExistentialImplTrait,
395376

396377
/// GlobalMetaData identifies a piece of crate metadata that is global to
397378
/// a whole crate (as opposed to just one item). GlobalMetaData components
@@ -655,7 +636,8 @@ impl DefPathData {
655636
ClosureExpr |
656637
StructCtor |
657638
AnonConst |
658-
ImplTrait => None
639+
ExistentialImplTrait |
640+
UniversalImplTrait => None
659641
}
660642
}
661643

@@ -685,7 +667,8 @@ impl DefPathData {
685667
ClosureExpr => "{{closure}}",
686668
StructCtor => "{{constructor}}",
687669
AnonConst => "{{constant}}",
688-
ImplTrait => "{{impl-Trait}}",
670+
ExistentialImplTrait => "{{exist-impl-Trait}}",
671+
UniversalImplTrait => "{{univ-impl-Trait}}",
689672
};
690673

691674
Symbol::intern(s).as_interned_str()

0 commit comments

Comments
 (0)