Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d4d18d2

Browse files
authoredMar 8, 2024
Rollup merge of rust-lang#122103 - compiler-errors:taits-capture-everything, r=oli-obk
Make TAITs and ATPITs capture late-bound lifetimes in scope This generalizes the behavior that RPITs have, where they duplicate their in-scope lifetimes so that they will always *reify* late-bound lifetimes that they capture. This allows TAITs and ATPITs to properly error when they capture in-scope late-bound lifetimes. r? `@oli-obk` cc `@aliemjay` Fixes rust-lang#122093 and therefore rust-lang#120700 (comment)
2 parents d16c55d + 74d5bbb commit d4d18d2

File tree

21 files changed

+148
-185
lines changed

21 files changed

+148
-185
lines changed
 

‎compiler/rustc_ast_lowering/src/item.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
275275
}
276276
Some(ty) => this.lower_ty(
277277
ty,
278-
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
278+
ImplTraitContext::OpaqueTy {
279+
origin: hir::OpaqueTyOrigin::TyAlias {
280+
parent: this.local_def_id(id),
281+
in_assoc_ty: false,
282+
},
283+
fn_kind: None,
284+
},
279285
),
280286
},
281287
);
@@ -936,7 +942,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
936942
Some(ty) => {
937943
let ty = this.lower_ty(
938944
ty,
939-
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
945+
ImplTraitContext::OpaqueTy {
946+
origin: hir::OpaqueTyOrigin::TyAlias {
947+
parent: this.local_def_id(i.id),
948+
in_assoc_ty: true,
949+
},
950+
fn_kind: None,
951+
},
940952
);
941953
hir::ImplItemKind::Type(ty)
942954
}

‎compiler/rustc_ast_lowering/src/lib.rs

+25-33
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,12 @@ enum ImplTraitContext {
265265
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
266266
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
267267
///
268-
ReturnPositionOpaqueTy {
269-
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
268+
OpaqueTy {
270269
origin: hir::OpaqueTyOrigin,
271-
fn_kind: FnDeclKind,
270+
/// Only used to change the lifetime capture rules, since
271+
/// RPITIT captures all in scope, RPIT does not.
272+
fn_kind: Option<FnDeclKind>,
272273
},
273-
/// Impl trait in type aliases.
274-
TypeAliasesOpaqueTy { in_assoc_ty: bool },
275274
/// `impl Trait` is unstably accepted in this position.
276275
FeatureGated(ImplTraitPosition, Symbol),
277276
/// `impl Trait` is not accepted in this position.
@@ -1075,9 +1074,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10751074
// Disallow ATB in dyn types
10761075
if self.is_in_dyn_type {
10771076
let suggestion = match itctx {
1078-
ImplTraitContext::ReturnPositionOpaqueTy { .. }
1079-
| ImplTraitContext::TypeAliasesOpaqueTy { .. }
1080-
| ImplTraitContext::Universal => {
1077+
ImplTraitContext::OpaqueTy { .. } | ImplTraitContext::Universal => {
10811078
let bound_end_span = constraint
10821079
.gen_args
10831080
.as_ref()
@@ -1417,24 +1414,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14171414
TyKind::ImplTrait(def_node_id, bounds) => {
14181415
let span = t.span;
14191416
match itctx {
1420-
ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self
1421-
.lower_opaque_impl_trait(
1422-
span,
1423-
origin,
1424-
*def_node_id,
1425-
bounds,
1426-
Some(fn_kind),
1427-
itctx,
1428-
),
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-
),
1417+
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
1418+
span,
1419+
origin,
1420+
*def_node_id,
1421+
bounds,
1422+
fn_kind,
1423+
itctx,
1424+
),
14381425
ImplTraitContext::Universal => {
14391426
let span = t.span;
14401427

@@ -1553,9 +1540,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15531540

15541541
let captured_lifetimes_to_duplicate = match origin {
15551542
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()
1543+
// type alias impl trait and associated type position impl trait were
1544+
// decided to capture all in-scope lifetimes, which we collect for
1545+
// all opaques during resolution.
1546+
self.resolver
1547+
.take_extra_lifetime_params(opaque_ty_node_id)
1548+
.into_iter()
1549+
.map(|(ident, id, _)| Lifetime { id, ident })
1550+
.collect()
15591551
}
15601552
hir::OpaqueTyOrigin::FnReturn(..) => {
15611553
if matches!(
@@ -1823,9 +1815,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18231815
FnDeclKind::Fn
18241816
| FnDeclKind::Inherent
18251817
| FnDeclKind::Trait
1826-
| FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy {
1818+
| FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
18271819
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
1828-
fn_kind: kind,
1820+
fn_kind: Some(kind),
18291821
},
18301822
FnDeclKind::ExternFn => {
18311823
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
@@ -1919,9 +1911,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19191911
output,
19201912
coro,
19211913
opaque_ty_span,
1922-
ImplTraitContext::ReturnPositionOpaqueTy {
1914+
ImplTraitContext::OpaqueTy {
19231915
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
1924-
fn_kind,
1916+
fn_kind: Some(fn_kind),
19251917
},
19261918
);
19271919
arena_vec![this; bound]

‎compiler/rustc_ast_lowering/src/path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
423423
// fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
424424
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
425425
// ```
426-
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) => {
426+
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
427427
if self.tcx.features().impl_trait_in_fn_trait_return {
428428
self.lower_ty(ty, itctx)
429429
} else {

‎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_opaque_lifetime_to_parent_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/predicates_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>(
339339
predicates: &mut Vec<(ty::Clause<'tcx>, Span)>,
340340
) {
341341
for param in opaque_own_params {
342-
let orig_lifetime = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local());
342+
let orig_lifetime = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local());
343343
if let ty::ReEarlyParam(..) = *orig_lifetime {
344344
let dup_lifetime = ty::Region::new_early_param(
345345
tcx,

‎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
@@ -553,11 +553,11 @@ pub(super) fn type_of_opaque(
553553
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
554554
Node::Item(item) => match item.kind {
555555
ItemKind::OpaqueTy(OpaqueTy {
556-
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
556+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. },
557557
..
558558
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
559559
ItemKind::OpaqueTy(OpaqueTy {
560-
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
560+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. },
561561
..
562562
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
563563
// 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/mod.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 {
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.