Skip to content

Commit 3307274

Browse files
committedJun 29, 2023
Auto merge of rust-lang#112682 - spastorino:new-rpitit-21, r=compiler-errors
Add bidirectional where clauses on RPITIT synthesized GATs Given the following: ```rust struct MyStruct<'a, T>(&'a T); trait MyTrait<'a, T> { fn my_fn<'b, 'c, 'd, V>(item: &'c String) -> impl Sized + 'a + 'b + 'c where V: 'b, V: 'd; } impl<'a, T> MyTrait<'a, T> for MyStruct<'a, T> { fn my_fn<'b, 'c, 'd, V>(_: &'c String) -> impl Sized + 'a + 'b + 'c where V: 'b, V: 'd, { unimplemented!(); } } ``` We need the desugaring to be: ```rust trait MyTrait<'a, T> { type MyFn<'bf, 'df, Vf, 'a2, 'b2, 'c2>: Sized + 'a2 + 'b2 + 'c2 where Vf: 'b2, 'a2: 'a, 'a: 'a2, 'b2: 'bf, 'bf: 'b2; fn my_fn<'b, 'c, 'd, V>(item: &'c String) -> MyStruct<'a>::MyFn<'b, 'd, V, 'a, 'b, 'c> where V: 'b, V: 'd { type opaque<'a3, 'b3, 'c3>; }; } impl<'a, T> MyIter<'a, T> for MyStruct<'a, T> { type MyFn<'bf, 'df, Vf, 'a2, 'b2, 'c2> = impl Sized + 'a2 + 'b2 + 'c2 where Vf: b2, 'a2: 'a, 'a: 'a2, 'b2: 'bf, 'bf: 'b2; fn my_fn<'b, 'c, 'd, V>(_: &'c String) -> MyStruct<'a>::MyFn<'a, 'b, 'c, V> where V: 'b, V: 'd { type opaque<'a3, 'b3, 'c3>; unimplemented!(); } } ``` This PR adds the where clauses for the `MyFn` generated GATs. This is a draft with a very ugly solution so we can make comments over concrete code. r? `@compiler-errors`
2 parents b23a5ad + 6f4a51e commit 3307274

File tree

13 files changed

+207
-104
lines changed

13 files changed

+207
-104
lines changed
 

‎compiler/rustc_ast_lowering/src/lib.rs

+83-50
Original file line numberDiff line numberDiff line change
@@ -1539,9 +1539,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15391539
);
15401540
debug!(?opaque_ty_def_id);
15411541

1542-
// Contains the new lifetime definitions created for the TAIT (if any).
1543-
let mut collected_lifetimes = Vec::new();
1544-
15451542
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
15461543
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
15471544
// exactly which ones those are.
@@ -1558,20 +1555,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15581555
};
15591556
debug!(?lifetimes_to_remap);
15601557

1561-
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
1562-
let mut new_remapping = FxHashMap::default();
1558+
let mut new_remapping = FxHashMap::default();
15631559

1564-
// If this opaque type is only capturing a subset of the lifetimes (those that appear
1565-
// in bounds), then create the new lifetime parameters required and create a mapping
1566-
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
1567-
collected_lifetimes = lctx.create_lifetime_defs(
1568-
opaque_ty_def_id,
1569-
&lifetimes_to_remap,
1570-
&mut new_remapping,
1571-
);
1572-
debug!(?collected_lifetimes);
1573-
debug!(?new_remapping);
1560+
// Contains the new lifetime definitions created for the TAIT (if any).
1561+
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
1562+
// bounds), then create the new lifetime parameters required and create a mapping from the
1563+
// old `'a` (on the function) to the new `'a` (on the opaque type).
1564+
let collected_lifetimes =
1565+
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
1566+
debug!(?collected_lifetimes);
1567+
debug!(?new_remapping);
1568+
1569+
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
1570+
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
1571+
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
1572+
.iter()
1573+
.map(|(node_id, lifetime)| {
1574+
let id = self.next_node_id();
1575+
let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
1576+
let def_id = self.local_def_id(*node_id);
1577+
(lifetime, def_id)
1578+
})
1579+
.collect();
1580+
debug!(?collected_lifetime_mapping);
15741581

1582+
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
15751583
// Install the remapping from old to new (if any):
15761584
lctx.with_remapping(new_remapping, |lctx| {
15771585
// This creates HIR lifetime definitions as `hir::GenericParam`, in the given
@@ -1610,6 +1618,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16101618
let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
16111619
debug!(?hir_bounds);
16121620

1621+
let lifetime_mapping = if in_trait {
1622+
self.arena.alloc_from_iter(
1623+
collected_lifetime_mapping
1624+
.iter()
1625+
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
1626+
)
1627+
} else {
1628+
&mut []
1629+
};
1630+
16131631
let opaque_ty_item = hir::OpaqueTy {
16141632
generics: self.arena.alloc(hir::Generics {
16151633
params: lifetime_defs,
@@ -1620,6 +1638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16201638
}),
16211639
bounds: hir_bounds,
16221640
origin,
1641+
lifetime_mapping,
16231642
in_trait,
16241643
};
16251644
debug!(?opaque_ty_item);
@@ -1628,20 +1647,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16281647
})
16291648
});
16301649

1631-
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
1632-
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
1633-
let lifetimes =
1634-
self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
1635-
let id = self.next_node_id();
1636-
let l = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
1637-
hir::GenericArg::Lifetime(l)
1638-
}));
1639-
debug!(?lifetimes);
1640-
16411650
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
16421651
hir::TyKind::OpaqueDef(
16431652
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
1644-
lifetimes,
1653+
self.arena.alloc_from_iter(
1654+
collected_lifetime_mapping
1655+
.iter()
1656+
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
1657+
),
16451658
in_trait,
16461659
)
16471660
}
@@ -1655,7 +1668,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16551668
span: Span,
16561669
opaque_ty_span: Span,
16571670
) -> hir::OwnerNode<'hir> {
1658-
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
1671+
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
16591672
// Generate an `type Foo = impl Trait;` declaration.
16601673
trace!("registering opaque type with id {:#?}", opaque_ty_id);
16611674
let opaque_ty_item = hir::Item {
@@ -1983,7 +1996,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19831996
let lifetime = Lifetime { id: outer_node_id, ident };
19841997
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
19851998
}
1986-
19871999
debug!(?collected_lifetimes);
19882000

19892001
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
@@ -1993,22 +2005,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19932005
let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
19942006
debug!(?lifetimes_to_remap);
19952007

1996-
self.with_hir_id_owner(opaque_ty_node_id, |this| {
1997-
// If this opaque type is only capturing a subset of the lifetimes (those that appear
1998-
// in bounds), then create the new lifetime parameters required and create a mapping
1999-
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
2000-
collected_lifetimes.extend(
2001-
this.create_lifetime_defs(
2002-
opaque_ty_def_id,
2003-
&lifetimes_to_remap,
2004-
&mut new_remapping,
2005-
)
2008+
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
2009+
// bounds), then create the new lifetime parameters required and create a mapping from the
2010+
// old `'a` (on the function) to the new `'a` (on the opaque type).
2011+
collected_lifetimes.extend(
2012+
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
20062013
.into_iter()
20072014
.map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
2008-
);
2009-
debug!(?collected_lifetimes);
2010-
debug!(?new_remapping);
2015+
);
2016+
debug!(?collected_lifetimes);
2017+
debug!(?new_remapping);
2018+
2019+
// This creates pairs of HIR lifetimes and def_ids. In the given example `type
2020+
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
2021+
// new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
2022+
// `TestReturn`.
2023+
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
2024+
.iter()
2025+
.map(|(node_id, lifetime, res)| {
2026+
let id = self.next_node_id();
2027+
let res = res.unwrap_or(
2028+
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
2029+
);
2030+
let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
2031+
let def_id = self.local_def_id(*node_id);
2032+
(lifetime, def_id)
2033+
})
2034+
.collect();
2035+
debug!(?collected_lifetime_mapping);
20112036

2037+
self.with_hir_id_owner(opaque_ty_node_id, |this| {
20122038
// Install the remapping from old to new (if any):
20132039
this.with_remapping(new_remapping, |this| {
20142040
// We have to be careful to get elision right here. The
@@ -2063,6 +2089,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20632089
));
20642090
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
20652091

2092+
let lifetime_mapping = if in_trait {
2093+
self.arena.alloc_from_iter(
2094+
collected_lifetime_mapping
2095+
.iter()
2096+
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
2097+
)
2098+
} else {
2099+
&mut []
2100+
};
2101+
20662102
let opaque_ty_item = hir::OpaqueTy {
20672103
generics: this.arena.alloc(hir::Generics {
20682104
params: generic_params,
@@ -2073,6 +2109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20732109
}),
20742110
bounds: arena_vec![this; future_bound],
20752111
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
2112+
lifetime_mapping,
20762113
in_trait,
20772114
};
20782115

@@ -2096,15 +2133,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20962133
//
20972134
// For the "output" lifetime parameters, we just want to
20982135
// generate `'_`.
2099-
let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
2100-
|(_, lifetime, res)| {
2101-
let id = self.next_node_id();
2102-
let res = res.unwrap_or(
2103-
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
2104-
);
2105-
hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, lifetime.ident, res))
2106-
},
2107-
));
2136+
let generic_args = self.arena.alloc_from_iter(
2137+
collected_lifetime_mapping
2138+
.iter()
2139+
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
2140+
);
21082141

21092142
// Create the `Foo<...>` reference itself. Note that the `type
21102143
// Foo = impl Trait` is, internally, created as a child of the

‎compiler/rustc_hir/src/hir.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,10 @@ pub struct OpaqueTy<'hir> {
26642664
pub generics: &'hir Generics<'hir>,
26652665
pub bounds: GenericBounds<'hir>,
26662666
pub origin: OpaqueTyOrigin,
2667+
// Opaques have duplicated lifetimes, this mapping connects the original lifetime with the copy
2668+
// so we can later generate bidirectional outlives predicates to enforce that these lifetimes
2669+
// stay in sync.
2670+
pub lifetime_mapping: &'hir [(Lifetime, LocalDefId)],
26672671
pub in_trait: bool,
26682672
}
26692673

@@ -3315,7 +3319,7 @@ pub enum ItemKind<'hir> {
33153319
/// A type alias, e.g., `type Foo = Bar<u8>`.
33163320
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
33173321
/// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
3318-
OpaqueTy(OpaqueTy<'hir>),
3322+
OpaqueTy(&'hir OpaqueTy<'hir>),
33193323
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
33203324
Enum(EnumDef<'hir>, &'hir Generics<'hir>),
33213325
/// A struct definition, e.g., `struct Foo<A> {x: A}`.

‎compiler/rustc_hir/src/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
502502
visitor.visit_ty(ty);
503503
visitor.visit_generics(generics)
504504
}
505-
ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => {
505+
ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
506506
visitor.visit_id(item.hir_id());
507507
walk_generics(visitor, generics);
508508
walk_list!(visitor, visit_param_bound, bounds);

‎compiler/rustc_hir_analysis/src/astconv/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2809,7 +2809,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
28092809
let opaque_ty = tcx.hir().item(item_id);
28102810

28112811
match opaque_ty.kind {
2812-
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
2812+
hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => {
28132813
let local_def_id = item_id.owner_id.def_id;
28142814
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
28152815
// generate the def_id of an associated type for the trait and return as

‎compiler/rustc_hir_analysis/src/check/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
299299
}
300300
}
301301

302-
if let ItemKind::OpaqueTy(hir::OpaqueTy {
302+
if let ItemKind::OpaqueTy(&hir::OpaqueTy {
303303
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
304304
in_trait,
305305
..

‎compiler/rustc_hir_analysis/src/collect/generics_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
144144
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
145145
}
146146
Node::Item(item) => match item.kind {
147-
ItemKind::OpaqueTy(hir::OpaqueTy {
147+
ItemKind::OpaqueTy(&hir::OpaqueTy {
148148
origin:
149149
hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
150150
in_trait,

0 commit comments

Comments
 (0)
Please sign in to comment.