Skip to content

Commit 4925b57

Browse files
committed
Add bidirectional where clauses on RPITIT synthesized GATs
1 parent d70deac commit 4925b57

File tree

6 files changed

+92
-36
lines changed

6 files changed

+92
-36
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+28-22
Original file line numberDiff line numberDiff line change
@@ -1568,14 +1568,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15681568

15691569
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
15701570
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
1571-
let lifetimes: Vec<_> = collected_lifetimes
1571+
let lifetime_mapping: Vec<_> = collected_lifetimes
15721572
.iter()
1573-
.map(|(_, lifetime)| {
1573+
.map(|(node_id, lifetime)| {
15741574
let id = self.next_node_id();
1575-
self.new_named_lifetime(lifetime.id, id, lifetime.ident)
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)
15761578
})
15771579
.collect();
1578-
debug!(?lifetimes);
1580+
debug!(?lifetime_mapping);
15791581

15801582
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
15811583
// Install the remapping from old to new (if any):
@@ -1626,6 +1628,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16261628
}),
16271629
bounds: hir_bounds,
16281630
origin,
1631+
lifetime_mapping: self.arena.alloc_from_iter(
1632+
lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)),
1633+
),
16291634
in_trait,
16301635
};
16311636
debug!(?opaque_ty_item);
@@ -1634,17 +1639,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16341639
})
16351640
});
16361641

1637-
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
1638-
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
1639-
let lifetimes = self.arena.alloc_from_iter(
1640-
lifetimes.into_iter().map(|lifetime| hir::GenericArg::Lifetime(lifetime)),
1641-
);
1642-
debug!(?lifetimes);
1643-
16441642
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
16451643
hir::TyKind::OpaqueDef(
16461644
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
1647-
lifetimes,
1645+
self.arena.alloc_from_iter(
1646+
lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
1647+
),
16481648
in_trait,
16491649
)
16501650
}
@@ -1986,7 +1986,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19861986
let lifetime = Lifetime { id: outer_node_id, ident };
19871987
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
19881988
}
1989-
19901989
debug!(?collected_lifetimes);
19911990

19921991
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
@@ -2007,19 +2006,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20072006
debug!(?collected_lifetimes);
20082007
debug!(?new_remapping);
20092008

2010-
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
2011-
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
2012-
let lifetimes: Vec<_> = collected_lifetimes
2009+
// This creates pairs of HIR lifetimes and def_ids. In the given example `type
2010+
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
2011+
// new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
2012+
// `TestReturn`.
2013+
let lifetime_mapping: Vec<_> = collected_lifetimes
20132014
.iter()
2014-
.map(|(_, lifetime, res)| {
2015+
.map(|(node_id, lifetime, res)| {
20152016
let id = self.next_node_id();
20162017
let res = res.unwrap_or(
20172018
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
20182019
);
2019-
self.new_named_lifetime_with_res(id, lifetime.ident, res)
2020+
let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
2021+
let def_id = self.local_def_id(*node_id);
2022+
(lifetime, def_id)
20202023
})
20212024
.collect();
2022-
debug!(?lifetimes);
2025+
debug!(?lifetime_mapping);
20232026

20242027
self.with_hir_id_owner(opaque_ty_node_id, |this| {
20252028
// Install the remapping from old to new (if any):
@@ -2086,6 +2089,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20862089
}),
20872090
bounds: arena_vec![this; future_bound],
20882091
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
2092+
lifetime_mapping: self.arena.alloc_from_iter(
2093+
lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)),
2094+
),
20892095
in_trait,
20902096
};
20912097

@@ -2109,9 +2115,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21092115
//
21102116
// For the "output" lifetime parameters, we just want to
21112117
// generate `'_`.
2112-
let generic_args = self
2113-
.arena
2114-
.alloc_from_iter(lifetimes.iter().map(|lifetime| hir::GenericArg::Lifetime(*lifetime)));
2118+
let generic_args = self.arena.alloc_from_iter(
2119+
lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
2120+
);
21152121

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

compiler/rustc_hir/src/hir.rs

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

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+56-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
1010
use rustc_hir::intravisit::{self, Visitor};
1111
use rustc_middle::ty::subst::InternalSubsts;
1212
use rustc_middle::ty::{self, Ty, TyCtxt};
13-
use rustc_middle::ty::{GenericPredicates, Generics, ToPredicate};
13+
use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
1414
use rustc_span::symbol::{sym, Ident};
1515
use rustc_span::{Span, Symbol, DUMMY_SP};
1616

@@ -62,6 +62,54 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
6262
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
6363
use rustc_hir::*;
6464

65+
match tcx.opt_rpitit_info(def_id.to_def_id()) {
66+
Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
67+
let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
68+
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
69+
let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else {
70+
bug!("unexpected {opaque_ty_node:?}")
71+
};
72+
73+
let mut predicates = Vec::new();
74+
compute_bidirectional_outlives_predicates(
75+
tcx,
76+
def_id,
77+
lifetime_mapping.iter().map(|(lifetime, def_id)| {
78+
(*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
79+
}),
80+
tcx.generics_of(def_id.to_def_id()),
81+
&mut predicates,
82+
);
83+
84+
return ty::GenericPredicates {
85+
parent: Some(tcx.parent(def_id.to_def_id())),
86+
predicates: tcx.arena.alloc_from_iter(predicates),
87+
};
88+
}
89+
90+
Some(ImplTraitInTraitData::Impl { fn_def_id }) => {
91+
let assoc_item = tcx.associated_item(def_id);
92+
let trait_assoc_predicates = tcx.predicates_of(assoc_item.trait_item_def_id.unwrap());
93+
94+
let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
95+
let impl_def_id = tcx.parent(fn_def_id);
96+
let impl_trait_ref_substs =
97+
tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder().substs;
98+
99+
let impl_assoc_substs =
100+
impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs);
101+
102+
let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs);
103+
104+
return ty::GenericPredicates {
105+
parent: Some(impl_def_id),
106+
predicates: tcx.arena.alloc_from_iter(impl_predicates),
107+
};
108+
}
109+
110+
None => {}
111+
}
112+
65113
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
66114
let node = tcx.hir().get(hir_id);
67115

@@ -298,7 +346,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
298346
.filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. }))
299347
.map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span)));
300348

301-
bidirectional_lifetime_predicates(tcx, def_id, lifetime_mapping, generics, &mut predicates);
349+
compute_bidirectional_outlives_predicates(
350+
tcx,
351+
def_id,
352+
lifetime_mapping,
353+
generics,
354+
&mut predicates,
355+
);
302356
debug!(?predicates);
303357
}
304358

compiler/rustc_ty_utils/src/assoc.rs

-12
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,6 @@ fn associated_type_for_impl_trait_in_trait(
340340
}
341341
});
342342

343-
// There are no predicates for the synthesized associated type.
344-
trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
345-
parent: Some(trait_def_id.to_def_id()),
346-
predicates: &[],
347-
});
348-
349343
// There are no inferred outlives for the synthesized associated type.
350344
trait_assoc_ty.inferred_outlives_of(&[]);
351345

@@ -424,12 +418,6 @@ fn associated_type_for_impl_trait_in_impl(
424418
}
425419
});
426420

427-
// There are no predicates for the synthesized associated type.
428-
impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
429-
parent: Some(impl_local_def_id.to_def_id()),
430-
predicates: &[],
431-
});
432-
433421
// There are no inferred outlives for the synthesized associated type.
434422
impl_assoc_ty.inferred_outlives_of(&[]);
435423

tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// check-pass
22
// edition: 2021
3+
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
4+
// revisions: current next
35

46
#![feature(async_fn_in_trait)]
57
#![allow(incomplete_features)]

tests/ui/async-await/in-trait/async-lifetimes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// check-pass
22
// edition: 2021
3+
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
4+
// revisions: current next
35

46
#![feature(async_fn_in_trait)]
57
#![allow(incomplete_features)]

0 commit comments

Comments
 (0)