Skip to content

Commit 81b6851

Browse files
Make TAITs capture all higher-ranked lifetimes in scope
1 parent bfe762e commit 81b6851

File tree

17 files changed

+118
-148
lines changed

17 files changed

+118
-148
lines changed

compiler/rustc_ast_lowering/src/item.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
275275
}
276276
Some(ty) => this.lower_ty(
277277
ty,
278-
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
278+
ImplTraitContext::TypeAliasesOpaqueTy {
279+
origin: hir::OpaqueTyOrigin::TyAlias {
280+
parent: this.local_def_id(id),
281+
in_assoc_ty: false,
282+
},
283+
},
279284
),
280285
},
281286
);
@@ -936,7 +941,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
936941
Some(ty) => {
937942
let ty = this.lower_ty(
938943
ty,
939-
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
944+
ImplTraitContext::TypeAliasesOpaqueTy {
945+
origin: hir::OpaqueTyOrigin::TyAlias {
946+
parent: this.local_def_id(i.id),
947+
in_assoc_ty: true,
948+
},
949+
},
940950
);
941951
hir::ImplItemKind::Type(ty)
942952
}

compiler/rustc_ast_lowering/src/lib.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@ enum ImplTraitContext {
271271
fn_kind: FnDeclKind,
272272
},
273273
/// Impl trait in type aliases.
274-
TypeAliasesOpaqueTy { in_assoc_ty: bool },
274+
TypeAliasesOpaqueTy {
275+
/// Origin: Always OpaqueTyOrigin::TypeAliasImplTrait
276+
origin: hir::OpaqueTyOrigin,
277+
},
275278
/// `impl Trait` is unstably accepted in this position.
276279
FeatureGated(ImplTraitPosition, Symbol),
277280
/// `impl Trait` is not accepted in this position.
@@ -1426,15 +1429,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14261429
Some(fn_kind),
14271430
itctx,
14281431
),
1429-
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
1430-
.lower_opaque_impl_trait(
1431-
span,
1432-
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
1433-
*def_node_id,
1434-
bounds,
1435-
None,
1436-
itctx,
1437-
),
1432+
ImplTraitContext::TypeAliasesOpaqueTy { origin } => self
1433+
.lower_opaque_impl_trait(span, origin, *def_node_id, bounds, None, itctx),
14381434
ImplTraitContext::Universal => {
14391435
let span = t.span;
14401436

@@ -1553,9 +1549,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15531549

15541550
let captured_lifetimes_to_duplicate = match origin {
15551551
hir::OpaqueTyOrigin::TyAlias { .. } => {
1556-
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
1557-
// lifetimes, since we don't have the issue that any are late-bound.
1558-
Vec::new()
1552+
// type alias impl trait and associated type position impl trait were
1553+
// decided to capture all in-scope lifetimes, which we collect for
1554+
// all opaques during resolution.
1555+
self.resolver
1556+
.take_extra_lifetime_params(opaque_ty_node_id)
1557+
.into_iter()
1558+
.map(|(ident, id, _)| Lifetime { id, ident })
1559+
.collect()
15591560
}
15601561
hir::OpaqueTyOrigin::FnReturn(..) => {
15611562
if matches!(

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,17 @@ fn check_opaque_type_parameter_valid(
367367
span: Span,
368368
) -> Result<(), ErrorGuaranteed> {
369369
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
370-
let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
371-
OpaqueTyOrigin::TyAlias { .. } => true,
372-
OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
370+
let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin {
371+
OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true),
372+
OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false),
373373
};
374374

375-
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
375+
let parent_generics = tcx.generics_of(parent);
376376
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
377-
for (i, arg) in opaque_type_key.args.iter().enumerate() {
377+
378+
// Only check the parent generics, which will ignore any of the
379+
// duplicated lifetime args that come from reifying late-bounds.
380+
for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() {
378381
if let Err(guar) = arg.error_reported() {
379382
return Err(guar);
380383
}
@@ -395,7 +398,7 @@ fn check_opaque_type_parameter_valid(
395398
seen_params.entry(arg).or_default().push(i);
396399
} else {
397400
// Prevent `fn foo() -> Foo<u32>` from being defining.
398-
let opaque_param = opaque_generics.param_at(i, tcx);
401+
let opaque_param = parent_generics.param_at(i, tcx);
399402
let kind = opaque_param.kind.descr();
400403

401404
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
@@ -409,10 +412,10 @@ fn check_opaque_type_parameter_valid(
409412

410413
for (_, indices) in seen_params {
411414
if indices.len() > 1 {
412-
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
415+
let descr = parent_generics.param_at(indices[0], tcx).kind.descr();
413416
let spans: Vec<_> = indices
414417
.into_iter()
415-
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
418+
.map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id))
416419
.collect();
417420
#[allow(rustc::diagnostic_outside_of_impl)]
418421
#[allow(rustc::untranslatable_diagnostic)]

compiler/rustc_hir/src/hir.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2562,6 +2562,8 @@ pub enum OpaqueTyOrigin {
25622562
AsyncFn(LocalDefId),
25632563
/// type aliases: `type Foo = impl Trait;`
25642564
TyAlias {
2565+
/// The type alias or associated type parent of the TAIT/ATPIT
2566+
parent: LocalDefId,
25652567
/// associated types in impl blocks for traits.
25662568
in_assoc_ty: bool,
25672569
},

compiler/rustc_hir_analysis/src/check/check.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,9 @@ fn check_opaque_meets_bounds<'tcx>(
339339
origin: &hir::OpaqueTyOrigin,
340340
) -> Result<(), ErrorGuaranteed> {
341341
let defining_use_anchor = match *origin {
342-
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
343-
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
342+
hir::OpaqueTyOrigin::FnReturn(did)
343+
| hir::OpaqueTyOrigin::AsyncFn(did)
344+
| hir::OpaqueTyOrigin::TyAlias { parent: did, .. } => did,
344345
};
345346
let param_env = tcx.param_env(defining_use_anchor);
346347

@@ -351,14 +352,14 @@ fn check_opaque_meets_bounds<'tcx>(
351352
let ocx = ObligationCtxt::new(&infcx);
352353

353354
let args = match *origin {
354-
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
355-
GenericArgs::identity_for_item(tcx, parent).extend_to(
356-
tcx,
357-
def_id.to_def_id(),
358-
|param, _| tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into(),
359-
)
360-
}
361-
hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id),
355+
hir::OpaqueTyOrigin::FnReturn(parent)
356+
| hir::OpaqueTyOrigin::AsyncFn(parent)
357+
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
358+
tcx, parent,
359+
)
360+
.extend_to(tcx, def_id.to_def_id(), |param, _| {
361+
tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into()
362+
}),
362363
};
363364

364365
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+5-51
Original file line numberDiff line numberDiff line change
@@ -514,38 +514,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
514514
// These sorts of items have no lifetime parameters at all.
515515
intravisit::walk_item(self, item);
516516
}
517-
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
518-
origin: hir::OpaqueTyOrigin::TyAlias { .. },
519-
..
520-
}) => {
521-
// Opaque types are visited when we visit the
522-
// `TyKind::OpaqueDef`, so that they have the lifetimes from
523-
// their parent opaque_ty in scope.
524-
//
525-
// The core idea here is that since OpaqueTys are generated with the impl Trait as
526-
// their owner, we can keep going until we find the Item that owns that. We then
527-
// conservatively add all resolved lifetimes. Otherwise we run into problems in
528-
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
529-
let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
530-
let resolved_lifetimes: &ResolveBoundVars =
531-
self.tcx.resolve_bound_vars(parent_item);
532-
// We need to add *all* deps, since opaque tys may want them from *us*
533-
for (&owner, defs) in resolved_lifetimes.defs.iter() {
534-
defs.iter().for_each(|(&local_id, region)| {
535-
self.map.defs.insert(hir::HirId { owner, local_id }, *region);
536-
});
537-
}
538-
for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() {
539-
late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
540-
self.record_late_bound_vars(
541-
hir::HirId { owner, local_id },
542-
late_bound_vars.clone(),
543-
);
544-
});
545-
}
546-
}
547517
hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
548-
origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent),
518+
origin:
519+
hir::OpaqueTyOrigin::FnReturn(parent)
520+
| hir::OpaqueTyOrigin::AsyncFn(parent)
521+
| hir::OpaqueTyOrigin::TyAlias { parent, .. },
549522
generics,
550523
..
551524
}) => {
@@ -683,26 +656,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
683656
// the opaque_ty generics
684657
let opaque_ty = self.tcx.hir().item(item_id);
685658
match &opaque_ty.kind {
686-
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
687-
origin: hir::OpaqueTyOrigin::TyAlias { .. },
688-
..
689-
}) => {
690-
intravisit::walk_ty(self, ty);
691-
692-
// Elided lifetimes and late-bound lifetimes (from the parent)
693-
// are not allowed in non-return position impl Trait
694-
let scope = Scope::LateBoundary {
695-
s: &Scope::TraitRefBoundary { s: self.scope },
696-
what: "type alias impl trait",
697-
};
698-
self.with(scope, |this| intravisit::walk_item(this, opaque_ty));
699-
700-
return;
701-
}
702-
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
703-
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
704-
..
705-
}) => {}
659+
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {}
706660
i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
707661
};
708662

compiler/rustc_hir_analysis/src/collect/type_of.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -544,11 +544,11 @@ pub(super) fn type_of_opaque(
544544
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
545545
Node::Item(item) => match item.kind {
546546
ItemKind::OpaqueTy(OpaqueTy {
547-
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
547+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. },
548548
..
549549
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
550550
ItemKind::OpaqueTy(OpaqueTy {
551-
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
551+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. },
552552
..
553553
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
554554
// Opaque types desugared from `impl Trait`.

compiler/rustc_hir_analysis/src/variance/mod.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
125125

126126
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
127127
// lifetime generics.
128-
let variances = std::iter::repeat(ty::Invariant).take(generics.count());
129-
130-
let mut variances: Vec<_> = match tcx.opaque_type_origin(item_def_id) {
131-
rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {
132-
variances.collect()
133-
}
134-
// But TAIT are invariant for all generics
135-
rustc_hir::OpaqueTyOrigin::TyAlias { .. } => return tcx.arena.alloc_from_iter(variances),
136-
};
128+
let mut variances = vec![ty::Invariant; generics.count()];
137129

138130
// Mark all lifetimes from parent generics as unused (Bivariant).
139131
// This will be overridden later if required.

compiler/rustc_infer/src/infer/opaque_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ impl<'tcx> InferCtxt<'tcx> {
391391
// Anonymous `impl Trait`
392392
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
393393
// Named `type Foo = impl Bar;`
394-
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
394+
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
395395
if in_assoc_ty {
396396
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
397397
} else {

compiler/rustc_middle/src/ty/mod.rs

-12
Original file line numberDiff line numberDiff line change
@@ -1934,18 +1934,6 @@ impl<'tcx> TyCtxt<'tcx> {
19341934
matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
19351935
}
19361936

1937-
/// Returns the `DefId` of the item within which the `impl Trait` is declared.
1938-
/// For type-alias-impl-trait this is the `type` alias.
1939-
/// For impl-trait-in-assoc-type this is the assoc type.
1940-
/// For return-position-impl-trait this is the function.
1941-
pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId {
1942-
// Find the surrounding item (type alias or assoc type)
1943-
while let DefKind::OpaqueTy = self.def_kind(def_id) {
1944-
def_id = self.local_parent(def_id);
1945-
}
1946-
def_id
1947-
}
1948-
19491937
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
19501938
if self.def_kind(def_id) != DefKind::AssocFn {
19511939
return false;

compiler/rustc_ty_utils/src/opaque_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
141141
trace!(?origin);
142142
match origin {
143143
rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
144-
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
144+
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
145145
if !in_assoc_ty {
146146
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
147147
return;

tests/ui/type-alias-impl-trait/escaping-bound-var.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub trait Trait<'a> {
77
trait Test<'a> {}
88

99
pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
10-
//~^ ERROR cannot capture late-bound lifetime in type alias impl trait
10+
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
1111

1212
impl Trait<'_> for () {
1313
type Assoc = ();
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
error: cannot capture late-bound lifetime in type alias impl trait
2-
--> $DIR/escaping-bound-var.rs:9:57
1+
error: higher kinded lifetime bounds on nested opaque types are not supported yet
2+
--> $DIR/escaping-bound-var.rs:9:25
33
|
44
LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
5-
| -- lifetime defined here ^^
5+
| ^^
6+
|
7+
note: lifetime declared here
8+
--> $DIR/escaping-bound-var.rs:9:25
9+
|
10+
LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
11+
| ^^
612

713
error: aborting due to 1 previous error
814

tests/ui/type-alias-impl-trait/self-referential.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
1212
type Foo<'a, 'b> = (i32, impl PartialEq<Foo<'a, 'b>> + std::fmt::Debug);
1313

1414
fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
15-
//~^ ERROR can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0})`
15+
//~^ ERROR can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
1616
(42, i)
1717
}
1818

1919
type Moo<'a, 'b> = (i32, impl PartialEq<Moo<'b, 'a>> + std::fmt::Debug);
2020

2121
fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
22-
//~^ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
22+
//~^ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
2323
(42, i)
2424
}
2525

tests/ui/type-alias-impl-trait/self-referential.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,28 @@ LL | i
1010
= help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
1111
= help: the trait `PartialEq` is implemented for `i32`
1212

13-
error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0})`
13+
error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
1414
--> $DIR/self-referential.rs:14:31
1515
|
1616
LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
17-
| ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0})`
17+
| ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
1818
LL |
1919
LL | (42, i)
2020
| ------- return type was inferred to be `(i32, &i32)` here
2121
|
22-
= help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0})>` is not implemented for `&i32`
22+
= help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)>` is not implemented for `&i32`
2323
= help: the trait `PartialEq` is implemented for `i32`
2424

25-
error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
25+
error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
2626
--> $DIR/self-referential.rs:21:31
2727
|
2828
LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
29-
| ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0})`
29+
| ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
3030
LL |
3131
LL | (42, i)
3232
| ------- return type was inferred to be `(i32, &i32)` here
3333
|
34-
= help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32`
34+
= help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)>` is not implemented for `&i32`
3535
= help: the trait `PartialEq` is implemented for `i32`
3636

3737
error: aborting due to 3 previous errors

0 commit comments

Comments
 (0)