Skip to content

Commit 6cb1358

Browse files
authored
Rollup merge of #110454 - oli-obk:limited_impl_trait_in_assoc_type, r=compiler-errors
Require impl Trait in associated types to appear in method signatures This implements the limited version of TAIT that was proposed in #107645 (comment) Similar to `impl Trait` in return types, `impl Trait` in associated types may only be used within the impl block which it is a part of. To make everything simpler and forward compatible to getting desugared to a plain type alias impl trait in the future, we're requiring that any associated functions or constants that want to register hidden types must be using the associated type in their signature (type of the constant or argument/return type of the associated method. Where bounds mentioning the associated type are ignored). We have preexisting tests checking that this works transitively across multiple associated types in situations like ```rust impl Foo for Bar { type A = impl Trait; type B = impl Iterator<Item = Self::A>; fn foo() -> Self::B { ...... } } ```
2 parents 9850584 + 4e92f76 commit 6cb1358

36 files changed

+560
-68
lines changed

compiler/rustc_ast_lowering/src/item.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
305305
);
306306
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
307307
}
308-
Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
308+
Some(ty) => this.lower_ty(
309+
ty,
310+
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
311+
),
309312
},
310313
);
311314
hir::ItemKind::TyAlias(ty, generics)
@@ -852,7 +855,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
852855
hir::ImplItemKind::Type(ty)
853856
}
854857
Some(ty) => {
855-
let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
858+
let ty = this.lower_ty(
859+
ty,
860+
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
861+
);
856862
hir::ImplItemKind::Type(ty)
857863
}
858864
},

compiler/rustc_ast_lowering/src/lib.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ enum ImplTraitContext {
247247
in_trait: bool,
248248
},
249249
/// Impl trait in type aliases.
250-
TypeAliasesOpaqueTy,
250+
TypeAliasesOpaqueTy { in_assoc_ty: bool },
251251
/// `impl Trait` is unstably accepted in this position.
252252
FeatureGated(ImplTraitPosition, Symbol),
253253
/// `impl Trait` is not accepted in this position.
@@ -1407,14 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14071407
*in_trait,
14081408
itctx,
14091409
),
1410-
ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
1411-
span,
1412-
hir::OpaqueTyOrigin::TyAlias,
1413-
*def_node_id,
1414-
bounds,
1415-
false,
1416-
itctx,
1417-
),
1410+
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
1411+
.lower_opaque_impl_trait(
1412+
span,
1413+
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
1414+
*def_node_id,
1415+
bounds,
1416+
false,
1417+
itctx,
1418+
),
14181419
ImplTraitContext::Universal => {
14191420
let span = t.span;
14201421
self.create_def(
@@ -1534,13 +1535,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15341535
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
15351536
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
15361537
// exactly which ones those are.
1537-
let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
1538-
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
1539-
Vec::new()
1540-
} else {
1541-
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
1542-
// we only keep the lifetimes that appear in the `impl Debug` itself:
1543-
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
1538+
let lifetimes_to_remap = match origin {
1539+
hir::OpaqueTyOrigin::TyAlias { .. } => {
1540+
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
1541+
Vec::new()
1542+
}
1543+
hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
1544+
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
1545+
// we only keep the lifetimes that appear in the `impl Debug` itself:
1546+
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
1547+
}
15441548
};
15451549
debug!(?lifetimes_to_remap);
15461550

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
265265

266266
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
267267
// on stable and we'd break that.
268-
let OpaqueTyOrigin::TyAlias = origin else {
268+
let OpaqueTyOrigin::TyAlias { .. } = origin else {
269269
return definition_ty;
270270
};
271271
let def_id = opaque_type_key.def_id;
@@ -360,7 +360,7 @@ fn check_opaque_type_parameter_valid(
360360
// which would error here on all of the `'static` args.
361361
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
362362
// Check these
363-
OpaqueTyOrigin::TyAlias => {}
363+
OpaqueTyOrigin::TyAlias { .. } => {}
364364
}
365365
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
366366
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();

compiler/rustc_hir/src/hir.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2662,7 +2662,10 @@ pub enum OpaqueTyOrigin {
26622662
/// `async fn`
26632663
AsyncFn(LocalDefId),
26642664
/// type aliases: `type Foo = impl Trait;`
2665-
TyAlias,
2665+
TyAlias {
2666+
/// associated types in impl blocks for traits.
2667+
in_assoc_ty: bool,
2668+
},
26662669
}
26672670

26682671
/// The various kinds of types recognized by the compiler.

compiler/rustc_hir_analysis/src/check/check.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ fn check_opaque_meets_bounds<'tcx>(
397397
) {
398398
let defining_use_anchor = match *origin {
399399
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
400-
hir::OpaqueTyOrigin::TyAlias => def_id,
400+
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
401401
};
402402
let param_env = tcx.param_env(defining_use_anchor);
403403

@@ -455,10 +455,10 @@ fn check_opaque_meets_bounds<'tcx>(
455455
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
456456
// We don't have to check them here because their well-formedness follows from the WF of
457457
// the projection input types in the defining- and use-sites.
458-
hir::OpaqueTyOrigin::TyAlias
458+
hir::OpaqueTyOrigin::TyAlias { .. }
459459
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
460460
// Can have different predicates to their defining use
461-
hir::OpaqueTyOrigin::TyAlias => {
461+
hir::OpaqueTyOrigin::TyAlias { .. } => {
462462
let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
463463
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
464464
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);

compiler/rustc_hir_analysis/src/check/dropck.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, ErrorGuaranteed};
66
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
77
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
88
use rustc_middle::ty::subst::SubstsRef;
9-
use rustc_middle::ty::util::IgnoreRegions;
9+
use rustc_middle::ty::util::CheckRegions;
1010
use rustc_middle::ty::{self, TyCtxt};
1111
use rustc_trait_selection::traits::{self, ObligationCtxt};
1212

@@ -81,7 +81,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
8181
self_type_did: DefId,
8282
adt_to_impl_substs: SubstsRef<'tcx>,
8383
) -> Result<(), ErrorGuaranteed> {
84-
let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, IgnoreRegions::No) else {
84+
let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else {
8585
return Ok(())
8686
};
8787

compiler/rustc_hir_analysis/src/coherence/orphan.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, DelayDm};
66
use rustc_errors::{Diagnostic, ErrorGuaranteed};
77
use rustc_hir as hir;
88
use rustc_middle::ty::subst::InternalSubsts;
9-
use rustc_middle::ty::util::IgnoreRegions;
9+
use rustc_middle::ty::util::CheckRegions;
1010
use rustc_middle::ty::{
1111
self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
1212
TypeVisitor,
@@ -507,7 +507,7 @@ fn lint_auto_trait_impl<'tcx>(
507507
// Impls which completely cover a given root type are fine as they
508508
// disable auto impls entirely. So only lint if the substs
509509
// are not a permutation of the identity substs.
510-
let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
510+
let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else {
511511
// ok
512512
return;
513513
};

compiler/rustc_hir_analysis/src/collect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1483,7 +1483,7 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorK
14831483
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
14841484
match tcx.hir().get_by_def_id(def_id) {
14851485
Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
1486-
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
1486+
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
14871487
}
14881488
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
14891489
}

compiler/rustc_hir_analysis/src/collect/generics_of.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
159159
}
160160
Some(fn_def_id.to_def_id())
161161
}
162-
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
162+
ItemKind::OpaqueTy(hir::OpaqueTy {
163+
origin: hir::OpaqueTyOrigin::TyAlias { .. },
164+
..
165+
}) => {
163166
let parent_id = tcx.hir().get_parent_item(hir_id);
164167
assert_ne!(parent_id, hir::CRATE_OWNER_ID);
165168
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ pub(super) fn type_param_predicates(
721721
| ItemKind::TyAlias(_, generics)
722722
| ItemKind::OpaqueTy(OpaqueTy {
723723
generics,
724-
origin: hir::OpaqueTyOrigin::TyAlias,
724+
origin: hir::OpaqueTyOrigin::TyAlias { .. },
725725
..
726726
})
727727
| ItemKind::Enum(_, generics)

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
526526
});
527527
}
528528
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
529-
origin: hir::OpaqueTyOrigin::TyAlias, ..
529+
origin: hir::OpaqueTyOrigin::TyAlias { .. },
530+
..
530531
}) => {
531532
// Opaque types are visited when we visit the
532533
// `TyKind::OpaqueDef`, so that they have the lifetimes from
@@ -707,7 +708,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
707708
let opaque_ty = self.tcx.hir().item(item_id);
708709
match &opaque_ty.kind {
709710
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
710-
origin: hir::OpaqueTyOrigin::TyAlias,
711+
origin: hir::OpaqueTyOrigin::TyAlias { .. },
711712
..
712713
}) => {
713714
intravisit::walk_ty(self, ty);

compiler/rustc_hir_analysis/src/collect/type_of.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
426426
let substs = InternalSubsts::identity_for_item(tcx, def_id);
427427
tcx.mk_adt(def, substs)
428428
}
429-
ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
430-
find_opaque_ty_constraints_for_tait(tcx, def_id)
431-
}
429+
ItemKind::OpaqueTy(OpaqueTy {
430+
origin: hir::OpaqueTyOrigin::TyAlias { .. },
431+
..
432+
}) => find_opaque_ty_constraints_for_tait(tcx, def_id),
432433
// Opaque types desugared from `impl Trait`.
433434
ItemKind::OpaqueTy(OpaqueTy {
434435
origin:

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

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::TypeErrCtxt;
22
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
33
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
44
use rustc_hir as hir;
5+
use rustc_hir::def::DefKind;
56
use rustc_middle::traits::ObligationCauseCode;
67
use rustc_middle::ty::error::ExpectedFound;
78
use rustc_middle::ty::print::Printer;
@@ -256,6 +257,15 @@ impl<T> Trait<T> for X {
256257
);
257258
}
258259
}
260+
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => {
261+
if tcx.is_type_alias_impl_trait(alias.def_id) {
262+
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
263+
diag.span_note(tcx.def_span(body_owner_def_id), "\
264+
this item must have the opaque type in its signature \
265+
in order to be able to register hidden types");
266+
}
267+
}
268+
}
259269
(ty::FnPtr(_), ty::FnDef(def, _))
260270
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
261271
diag.note(

compiler/rustc_infer/src/infer/opaque_types.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl<'tcx> InferCtxt<'tcx> {
149149
// no one encounters it in practice.
150150
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
151151
// where it is of no concern, so we only check for TAITs.
152-
if let Some(OpaqueTyOrigin::TyAlias) =
152+
if let Some(OpaqueTyOrigin::TyAlias { .. }) =
153153
b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
154154
{
155155
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
@@ -381,8 +381,12 @@ impl<'tcx> InferCtxt<'tcx> {
381381
// Anonymous `impl Trait`
382382
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
383383
// Named `type Foo = impl Bar;`
384-
hir::OpaqueTyOrigin::TyAlias => {
385-
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
384+
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
385+
if in_assoc_ty {
386+
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
387+
} else {
388+
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
389+
}
386390
}
387391
};
388392
in_definition_scope.then_some(origin)

compiler/rustc_metadata/src/rmeta/encoder.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1641,9 +1641,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16411641
}
16421642
hir::ItemKind::OpaqueTy(ref opaque) => {
16431643
self.encode_explicit_item_bounds(def_id);
1644-
self.tables
1645-
.is_type_alias_impl_trait
1646-
.set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
1644+
self.tables.is_type_alias_impl_trait.set(
1645+
def_id.index,
1646+
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }),
1647+
);
16471648
}
16481649
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
16491650
self.tables.impl_defaultness.set_some(def_id.index, *defaultness);

compiler/rustc_middle/src/query/erase.rs

+4
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
172172
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
173173
}
174174

175+
impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
176+
type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
177+
}
178+
175179
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
176180
type Result = [u8; size_of::<(&'static (), &'static ())>()];
177181
}

compiler/rustc_middle/src/query/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,15 @@ rustc_queries! {
236236
cache_on_disk_if { key.is_local() }
237237
}
238238

239+
query opaque_types_defined_by(
240+
key: LocalDefId
241+
) -> &'tcx [LocalDefId] {
242+
desc {
243+
|tcx| "computing the opaque types defined by `{}`",
244+
tcx.def_path_str(key.to_def_id())
245+
}
246+
}
247+
239248
/// Returns the list of bounds that can be used for
240249
/// `SelectionCandidate::ProjectionCandidate(_)` and
241250
/// `ProjectionTyCandidate::TraitDef`.

compiler/rustc_middle/src/ty/mod.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,18 @@ impl<'tcx> TyCtxt<'tcx> {
24762476
}
24772477
}
24782478

2479+
/// Returns the `DefId` of the item within which the `impl Trait` is declared.
2480+
/// For type-alias-impl-trait this is the `type` alias.
2481+
/// For impl-trait-in-assoc-type this is the assoc type.
2482+
/// For return-position-impl-trait this is the function.
2483+
pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId {
2484+
// Find the surrounding item (type alias or assoc type)
2485+
while let DefKind::OpaqueTy = self.def_kind(def_id) {
2486+
def_id = self.local_parent(def_id);
2487+
}
2488+
def_id
2489+
}
2490+
24792491
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
24802492
if self.def_kind(def_id) != DefKind::AssocFn {
24812493
return false;
@@ -2520,7 +2532,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId>
25202532
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
25212533
Some(parent)
25222534
}
2523-
hir::OpaqueTyOrigin::TyAlias => None,
2535+
hir::OpaqueTyOrigin::TyAlias { .. } => None,
25242536
};
25252537
}
25262538
}

compiler/rustc_middle/src/ty/normalize_erasing_regions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl<'tcx> TyCtxt<'tcx> {
3232
///
3333
/// This should only be used outside of type inference. For example,
3434
/// it assumes that normalization will succeed.
35-
#[tracing::instrument(level = "debug", skip(self, param_env))]
35+
#[tracing::instrument(level = "debug", skip(self, param_env), ret)]
3636
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
3737
where
3838
T: TypeFoldable<TyCtxt<'tcx>>,

compiler/rustc_middle/src/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> {
12651265

12661266
/// Extracts the underlying trait reference and own substs from this projection.
12671267
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
1268-
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
1268+
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs
12691269
pub fn trait_ref_and_own_substs(
12701270
self,
12711271
tcx: TyCtxt<'tcx>,

0 commit comments

Comments
 (0)