Skip to content

Commit 5fc261e

Browse files
committed
Inherit generics for impl-trait.
1 parent b956509 commit 5fc261e

File tree

6 files changed

+144
-72
lines changed

6 files changed

+144
-72
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2767,35 +2767,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27672767
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
27682768
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
27692769
// Our own parameters are the resolved lifetimes.
2770-
if let GenericParamDefKind::Lifetime = param.kind {
2771-
if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
2772-
self.ast_region_to_region(lifetime, None).into()
2773-
} else {
2774-
bug!()
2775-
}
2776-
} else {
2777-
bug!()
2778-
}
2770+
let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
2771+
let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
2772+
self.ast_region_to_region(lifetime, None).into()
27792773
} else {
2780-
match param.kind {
2781-
// For RPIT (return position impl trait), only lifetimes
2782-
// mentioned in the impl Trait predicate are captured by
2783-
// the opaque type, so the lifetime parameters from the
2784-
// parent item need to be replaced with `'static`.
2785-
//
2786-
// For `impl Trait` in the types of statics, constants,
2787-
// locals and type aliases. These capture all parent
2788-
// lifetimes, so they can use their identity subst.
2789-
GenericParamDefKind::Lifetime
2790-
if matches!(
2791-
origin,
2792-
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
2793-
) =>
2794-
{
2795-
tcx.lifetimes.re_static.into()
2796-
}
2797-
_ => tcx.mk_param_from_def(param),
2798-
}
2774+
tcx.mk_param_from_def(param)
27992775
}
28002776
});
28012777
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
@@ -2972,6 +2948,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29722948
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
29732949
}
29742950

2951+
#[instrument(level = "trace", skip(self, generate_err))]
29752952
fn validate_late_bound_regions(
29762953
&self,
29772954
constrained_regions: FxHashSet<ty::BoundRegionKind>,

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
240240
}
241241
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
242242
}
243+
243244
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
244245
/// in "inheriting lifetimes".
245246
#[instrument(level = "debug", skip(tcx, span))]
@@ -251,15 +252,19 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
251252
let item = tcx.hir().expect_item(def_id);
252253
debug!(?item, ?span);
253254

255+
#[derive(Debug)]
254256
struct FoundParentLifetime;
255-
struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
257+
struct FindParentLifetimeVisitor<'tcx> {
258+
tcx: TyCtxt<'tcx>,
259+
parent_count: u32,
260+
}
256261
impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
257262
type BreakTy = FoundParentLifetime;
258263

264+
#[instrument(level = "trace", skip(self), ret)]
259265
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
260-
debug!("FindParentLifetimeVisitor: r={:?}", r);
261266
if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
262-
if index < self.0.parent_count as u32 {
267+
if index < self.parent_count {
263268
return ControlFlow::Break(FoundParentLifetime);
264269
} else {
265270
return ControlFlow::CONTINUE;
@@ -269,6 +274,63 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
269274
r.super_visit_with(self)
270275
}
271276

277+
#[instrument(level = "trace", skip(self), ret)]
278+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
279+
// We're only interested in types involving regions
280+
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
281+
return ControlFlow::CONTINUE;
282+
}
283+
284+
match ty.kind() {
285+
ty::Closure(_, ref substs) => {
286+
// Skip lifetime parameters of the enclosing item(s)
287+
288+
substs.as_closure().tupled_upvars_ty().visit_with(self)?;
289+
substs.as_closure().sig_as_fn_ptr_ty().visit_with(self)?;
290+
}
291+
292+
ty::Generator(_, ref substs, _) => {
293+
// Skip lifetime parameters of the enclosing item(s)
294+
// Also skip the witness type, because that has no free regions.
295+
296+
substs.as_generator().tupled_upvars_ty().visit_with(self)?;
297+
substs.as_generator().return_ty().visit_with(self)?;
298+
substs.as_generator().yield_ty().visit_with(self)?;
299+
substs.as_generator().resume_ty().visit_with(self)?;
300+
}
301+
302+
ty::Opaque(def_id, ref substs) => {
303+
// Skip lifetime paramters that are not captures.
304+
let variances = self.tcx.variances_of(*def_id);
305+
306+
for (v, s) in std::iter::zip(variances, substs.iter()) {
307+
if *v != ty::Variance::Bivariant {
308+
s.visit_with(self)?;
309+
}
310+
}
311+
}
312+
313+
ty::Projection(proj)
314+
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
315+
{
316+
// Skip lifetime paramters that are not captures.
317+
let variances = self.tcx.variances_of(proj.item_def_id);
318+
319+
for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
320+
if *v != ty::Variance::Bivariant {
321+
s.visit_with(self)?;
322+
}
323+
}
324+
}
325+
326+
_ => {
327+
ty.super_visit_with(self)?;
328+
}
329+
}
330+
331+
ControlFlow::CONTINUE
332+
}
333+
272334
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
273335
if let ty::ConstKind::Unevaluated(..) = c.kind() {
274336
// FIXME(#72219) We currently don't detect lifetimes within substs
@@ -291,12 +353,15 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
291353
type BreakTy = Ty<'tcx>;
292354

293355
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
294-
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
356+
debug!(?t, "root_visit_ty");
295357
if t == self.opaque_identity_ty {
296358
ControlFlow::CONTINUE
297359
} else {
298-
t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
299-
.map_break(|FoundParentLifetime| t)
360+
t.visit_with(&mut FindParentLifetimeVisitor {
361+
tcx: self.tcx,
362+
parent_count: self.generics.parent_count as u32,
363+
})
364+
.map_break(|FoundParentLifetime| t)
300365
}
301366
}
302367
}
@@ -329,14 +394,18 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
329394

330395
if let ItemKind::OpaqueTy(hir::OpaqueTy {
331396
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
397+
in_trait,
332398
..
333399
}) = item.kind
334400
{
401+
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
402+
let opaque_identity_ty = if in_trait {
403+
tcx.mk_projection(def_id.to_def_id(), substs)
404+
} else {
405+
tcx.mk_opaque(def_id.to_def_id(), substs)
406+
};
335407
let mut visitor = ProhibitOpaqueVisitor {
336-
opaque_identity_ty: tcx.mk_opaque(
337-
def_id.to_def_id(),
338-
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
339-
),
408+
opaque_identity_ty,
340409
generics: tcx.generics_of(def_id),
341410
tcx,
342411
selftys: vec![],
@@ -345,10 +414,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
345414
.explicit_item_bounds(def_id)
346415
.iter()
347416
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
348-
debug!(
349-
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
350-
prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
351-
);
352417

353418
if let Some(ty) = prohibit_opaque.break_value() {
354419
visitor.visit_item(&item);

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ fn label_msg_span(
261261
}
262262
}
263263

264+
#[instrument(level = "trace", skip(tcx))]
264265
pub fn unexpected_hidden_region_diagnostic<'tcx>(
265266
tcx: TyCtxt<'tcx>,
266267
span: Span,

compiler/rustc_infer/src/infer/opaque_types.rs

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -332,32 +332,11 @@ impl<'tcx> InferCtxt<'tcx> {
332332
concrete_ty: Ty<'tcx>,
333333
span: Span,
334334
) {
335-
let def_id = opaque_type_key.def_id;
336-
337-
let tcx = self.tcx;
338-
339335
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
340-
341336
debug!(?concrete_ty);
342337

343-
let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
344-
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
345-
// We lower
346-
//
347-
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
348-
//
349-
// into
350-
//
351-
// type foo::<'p0..'pn>::Foo<'q0..'qm>
352-
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
353-
//
354-
// For these types we only iterate over `'l0..lm` below.
355-
tcx.generics_of(def_id).parent_count
356-
}
357-
// These opaque type inherit all lifetime parameters from their
358-
// parent, so we have to check them all.
359-
hir::OpaqueTyOrigin::TyAlias => 0,
360-
};
338+
let variances = self.tcx.variances_of(opaque_type_key.def_id);
339+
debug!(?variances);
361340

362341
// For a case like `impl Foo<'a, 'b>`, we would generate a constraint
363342
// `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
@@ -370,9 +349,12 @@ impl<'tcx> InferCtxt<'tcx> {
370349
// type can be equal to any of the region parameters of the
371350
// opaque type definition.
372351
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
373-
opaque_type_key.substs[first_own_region..]
352+
opaque_type_key
353+
.substs
374354
.iter()
375-
.filter_map(|arg| match arg.unpack() {
355+
.enumerate()
356+
.filter(|(i, _)| variances[*i] == ty::Variance::Invariant)
357+
.filter_map(|(_, arg)| match arg.unpack() {
376358
GenericArgKind::Lifetime(r) => Some(r),
377359
GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
378360
})
@@ -381,6 +363,7 @@ impl<'tcx> InferCtxt<'tcx> {
381363
);
382364

383365
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
366+
tcx: self.tcx,
384367
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
385368
});
386369
}
@@ -440,11 +423,12 @@ impl<'tcx> InferCtxt<'tcx> {
440423
//
441424
// We ignore any type parameters because impl trait values are assumed to
442425
// capture all the in-scope type parameters.
443-
struct ConstrainOpaqueTypeRegionVisitor<OP> {
426+
struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
427+
tcx: TyCtxt<'tcx>,
444428
op: OP,
445429
}
446430

447-
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
431+
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
448432
where
449433
OP: FnMut(ty::Region<'tcx>),
450434
{
@@ -490,6 +474,31 @@ where
490474
substs.as_generator().yield_ty().visit_with(self);
491475
substs.as_generator().resume_ty().visit_with(self);
492476
}
477+
478+
ty::Opaque(def_id, ref substs) => {
479+
// Skip lifetime paramters that are not captures.
480+
let variances = self.tcx.variances_of(*def_id);
481+
482+
for (v, s) in std::iter::zip(variances, substs.iter()) {
483+
if *v != ty::Variance::Bivariant {
484+
s.visit_with(self);
485+
}
486+
}
487+
}
488+
489+
ty::Projection(proj)
490+
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
491+
{
492+
// Skip lifetime paramters that are not captures.
493+
let variances = self.tcx.variances_of(proj.item_def_id);
494+
495+
for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
496+
if *v != ty::Variance::Bivariant {
497+
s.visit_with(self);
498+
}
499+
}
500+
}
501+
493502
_ => {
494503
ty.super_visit_with(self);
495504
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,8 +1338,8 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
13381338
// HACK: The HIR lowering for async fn does not generate
13391339
// any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
13401340
// would now fail to compile. We should probably just make hir lowering fill this in properly.
1341-
OpaqueTyOrigin::AsyncFn(_) => map.collect(),
1342-
OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
1341+
OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::AsyncFn(_) => map.collect(),
1342+
OpaqueTyOrigin::TyAlias => {
13431343
// Opaque types may only use regions that are bound. So for
13441344
// ```rust
13451345
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;

compiler/rustc_middle/src/ty/relate.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,26 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
170170
tcx.mk_substs(params)
171171
}
172172

173+
#[instrument(level = "trace", skip(relation), ret)]
174+
fn relate_opaque_item_substs<'tcx, R: TypeRelation<'tcx>>(
175+
relation: &mut R,
176+
def_id: DefId,
177+
a_subst: SubstsRef<'tcx>,
178+
b_subst: SubstsRef<'tcx>,
179+
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
180+
let tcx = relation.tcx();
181+
let variances = tcx.variances_of(def_id);
182+
debug!(?variances);
183+
184+
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
185+
let variance = variances[i];
186+
let variance_info = ty::VarianceDiagInfo::default();
187+
relation.relate_with_variance(variance, variance_info, a, b)
188+
});
189+
190+
tcx.mk_substs(params)
191+
}
192+
173193
impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
174194
fn relate<R: TypeRelation<'tcx>>(
175195
relation: &mut R,
@@ -561,7 +581,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
561581
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
562582
if a_def_id == b_def_id =>
563583
{
564-
let substs = relate_substs(relation, a_substs, b_substs)?;
584+
let substs = relate_opaque_item_substs(relation, a_def_id, a_substs, b_substs)?;
565585
Ok(tcx.mk_opaque(a_def_id, substs))
566586
}
567587

0 commit comments

Comments
 (0)