Skip to content

Commit 862703e

Browse files
committed
Auto merge of #51414 - oli-obk:impl_trait_type_def, r=pnkfelix
Add existential type definitions Note: this does not allow creating named existential types, it just desugars `impl Trait` to a less (but still very) hacky version of actual `existential type` items. r? @nikomatsakis
2 parents c45ae9e + adec1f9 commit 862703e

Some content is hidden

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

49 files changed

+646
-288
lines changed

src/librustc/hir/def.rs

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub enum Def {
3737
Enum(DefId),
3838
Variant(DefId),
3939
Trait(DefId),
40+
Existential(DefId),
4041
TyAlias(DefId),
4142
TyForeign(DefId),
4243
TraitAlias(DefId),
@@ -234,6 +235,7 @@ impl Def {
234235
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
235236
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
236237
Def::AssociatedConst(id) | Def::Macro(id, ..) |
238+
Def::Existential(id) |
237239
Def::GlobalAsm(id) | Def::TyForeign(id) => {
238240
id
239241
}
@@ -260,6 +262,7 @@ impl Def {
260262
Def::VariantCtor(.., CtorKind::Const) => "unit variant",
261263
Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
262264
Def::Enum(..) => "enum",
265+
Def::Existential(..) => "existential type",
263266
Def::TyAlias(..) => "type alias",
264267
Def::TraitAlias(..) => "trait alias",
265268
Def::AssociatedTy(..) => "associated type",

src/librustc/hir/intravisit.rs

+11-4
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

+108-22
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ enum ImplTraitContext {
182182
/// Treat `impl Trait` as shorthand for a new universal existential parameter.
183183
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
184184
/// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
185-
Existential,
185+
///
186+
/// We store a DefId here so we can look up necessary information later
187+
Existential(DefId),
186188

187189
/// `impl Trait` is not accepted in this position.
188190
Disallowed,
@@ -238,6 +240,7 @@ enum ParamMode {
238240
Optional,
239241
}
240242

243+
#[derive(Debug)]
241244
struct LoweredNodeId {
242245
node_id: NodeId,
243246
hir_id: hir::HirId,
@@ -488,16 +491,16 @@ impl<'a> LoweringContext<'a> {
488491
}
489492
}
490493

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

503506
debug_assert!(def_index == new_def_index);
@@ -507,6 +510,7 @@ impl<'a> LoweringContext<'a> {
507510
.insert(owner, new_counter)
508511
.unwrap();
509512
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
513+
ret
510514
}
511515

512516
/// This method allocates a new HirId for the given NodeId and stores it in
@@ -530,7 +534,10 @@ impl<'a> LoweringContext<'a> {
530534

531535
fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> LoweredNodeId {
532536
self.lower_node_id_generic(ast_node_id, |this| {
533-
let local_id_counter = this.item_local_id_counters.get_mut(&owner).unwrap();
537+
let local_id_counter = this
538+
.item_local_id_counters
539+
.get_mut(&owner)
540+
.expect("called lower_node_id_with_owner before allocate_hir_id_counter");
534541
let local_id = *local_id_counter;
535542

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

541548
*local_id_counter += 1;
542-
let def_index = this.resolver.definitions().opt_def_index(owner).unwrap();
549+
let def_index = this
550+
.resolver
551+
.definitions()
552+
.opt_def_index(owner)
553+
.expect("You forgot to call `create_def_with_parent` or are lowering node ids \
554+
that do not belong to the current owner");
543555

544556
hir::HirId {
545557
owner: def_index,
@@ -1120,26 +1132,93 @@ impl<'a> LoweringContext<'a> {
11201132
TyKind::ImplTrait(ref bounds) => {
11211133
let span = t.span;
11221134
match itctx {
1123-
ImplTraitContext::Existential => {
1124-
let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap();
1125-
let hir_bounds = self.lower_bounds(bounds, itctx);
1126-
let (lifetimes, lifetime_defs) =
1127-
self.lifetimes_from_impl_trait_bounds(def_index, &hir_bounds);
1135+
ImplTraitContext::Existential(fn_def_id) => {
1136+
1137+
// We need to manually repeat the code of `next_id` because the lowering
1138+
// needs to happen while the owner_id is pointing to the item itself,
1139+
// because items are their own owners
1140+
let exist_ty_node_id = self.sess.next_node_id();
1141+
1142+
// Make sure we know that some funky desugaring has been going on here.
1143+
// This is a first: there is code in other places like for loop
1144+
// desugaring that explicitly states that we don't want to track that.
1145+
// Not tracking it makes lints in rustc and clippy very fragile as
1146+
// frequently opened issues show.
1147+
let exist_ty_span = self.allow_internal_unstable(
1148+
CompilerDesugaringKind::ExistentialReturnType,
1149+
t.span,
1150+
);
11281151

1129-
hir::TyImplTraitExistential(
1130-
hir::ExistTy {
1152+
// Pull a new definition from the ether
1153+
let exist_ty_def_index = self
1154+
.resolver
1155+
.definitions()
1156+
.create_def_with_parent(
1157+
fn_def_id.index,
1158+
exist_ty_node_id,
1159+
DefPathData::ExistentialImplTrait,
1160+
DefIndexAddressSpace::High,
1161+
Mark::root(),
1162+
exist_ty_span,
1163+
);
1164+
1165+
// the `t` is just for printing debug messages
1166+
self.allocate_hir_id_counter(exist_ty_node_id, t);
1167+
1168+
let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
1169+
lctx.lower_bounds(bounds, itctx)
1170+
});
1171+
1172+
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
1173+
exist_ty_node_id,
1174+
exist_ty_def_index,
1175+
&hir_bounds,
1176+
);
1177+
1178+
self.with_hir_id_owner(exist_ty_node_id, |lctx| {
1179+
let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
11311180
generics: hir::Generics {
11321181
params: lifetime_defs,
11331182
where_clause: hir::WhereClause {
1134-
id: self.next_id().node_id,
1183+
id: lctx.next_id().node_id,
11351184
predicates: Vec::new().into(),
11361185
},
11371186
span,
11381187
},
11391188
bounds: hir_bounds,
1140-
},
1141-
lifetimes,
1142-
)
1189+
impl_trait_fn: Some(fn_def_id),
1190+
});
1191+
let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
1192+
// Generate an `existential type Foo: Trait;` declaration
1193+
trace!("creating existential type with id {:#?}", exist_ty_id);
1194+
// Set the name to `impl Bound1 + Bound2`
1195+
let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
1196+
1197+
trace!("exist ty def index: {:#?}", exist_ty_def_index);
1198+
let exist_ty_item = hir::Item {
1199+
id: exist_ty_id.node_id,
1200+
hir_id: exist_ty_id.hir_id,
1201+
name: exist_ty_name,
1202+
attrs: Default::default(),
1203+
node: exist_ty_item_kind,
1204+
vis: hir::Visibility::Inherited,
1205+
span: exist_ty_span,
1206+
};
1207+
1208+
// Insert the item into the global list. This usually happens
1209+
// automatically for all AST items. But this existential type item
1210+
// does not actually exist in the AST.
1211+
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
1212+
1213+
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
1214+
hir::TyImplTraitExistential(
1215+
hir::ItemId {
1216+
id: exist_ty_id.node_id
1217+
},
1218+
DefId::local(exist_ty_def_index),
1219+
lifetimes,
1220+
)
1221+
})
11431222
}
11441223
ImplTraitContext::Universal(def_id) => {
11451224
let def_node_id = self.next_id().node_id;
@@ -1148,7 +1227,7 @@ impl<'a> LoweringContext<'a> {
11481227
let def_index = self.resolver.definitions().create_def_with_parent(
11491228
def_id.index,
11501229
def_node_id,
1151-
DefPathData::ImplTrait,
1230+
DefPathData::UniversalImplTrait,
11521231
DefIndexAddressSpace::High,
11531232
Mark::root(),
11541233
span,
@@ -1203,6 +1282,7 @@ impl<'a> LoweringContext<'a> {
12031282

12041283
fn lifetimes_from_impl_trait_bounds(
12051284
&mut self,
1285+
exist_ty_id: NodeId,
12061286
parent_index: DefIndex,
12071287
bounds: &hir::TyParamBounds,
12081288
) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
@@ -1212,6 +1292,7 @@ impl<'a> LoweringContext<'a> {
12121292
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
12131293
context: &'r mut LoweringContext<'a>,
12141294
parent: DefIndex,
1295+
exist_ty_id: NodeId,
12151296
collect_elided_lifetimes: bool,
12161297
currently_bound_lifetimes: Vec<hir::LifetimeName>,
12171298
already_defined_lifetimes: HashSet<hir::LifetimeName>,
@@ -1306,7 +1387,11 @@ impl<'a> LoweringContext<'a> {
13061387
name,
13071388
});
13081389

1309-
let def_node_id = self.context.next_id().node_id;
1390+
// We need to manually create the ids here, because the
1391+
// definitions will go into the explicit `existential type`
1392+
// declaration and thus need to have their owner set to that item
1393+
let def_node_id = self.context.sess.next_node_id();
1394+
let _ = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
13101395
self.context.resolver.definitions().create_def_with_parent(
13111396
self.parent,
13121397
def_node_id,
@@ -1318,7 +1403,7 @@ impl<'a> LoweringContext<'a> {
13181403
let def_lifetime = hir::Lifetime {
13191404
id: def_node_id,
13201405
span: lifetime.span,
1321-
name: name,
1406+
name,
13221407
};
13231408
self.output_lifetime_params
13241409
.push(hir::GenericParam::Lifetime(hir::LifetimeDef {
@@ -1334,6 +1419,7 @@ impl<'a> LoweringContext<'a> {
13341419
let mut lifetime_collector = ImplTraitLifetimeCollector {
13351420
context: self,
13361421
parent: parent_index,
1422+
exist_ty_id,
13371423
collect_elided_lifetimes: true,
13381424
currently_bound_lifetimes: Vec::new(),
13391425
already_defined_lifetimes: HashSet::new(),
@@ -1772,8 +1858,8 @@ impl<'a> LoweringContext<'a> {
17721858
.collect(),
17731859
output: match decl.output {
17741860
FunctionRetTy::Ty(ref ty) => match fn_def_id {
1775-
Some(_) if impl_trait_return_allow => {
1776-
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential))
1861+
Some(def_id) if impl_trait_return_allow => {
1862+
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
17771863
}
17781864
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
17791865
},

src/librustc/hir/map/def_collector.rs

+1-4
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

+11-28
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)