From cf299ddb6e0f1b0ddc737805df49952d41e03754 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Mar 2024 17:52:53 +0000 Subject: [PATCH 1/3] Make TAITs capture all higher-ranked lifetimes in scope --- compiler/rustc_ast_lowering/src/item.rs | 14 ++++- compiler/rustc_ast_lowering/src/lib.rs | 27 ++++----- .../src/region_infer/opaque_types.rs | 19 ++++--- compiler/rustc_hir/src/hir.rs | 2 + .../rustc_hir_analysis/src/check/check.rs | 21 +++---- .../src/collect/resolve_bound_vars.rs | 56 ++----------------- .../rustc_hir_analysis/src/collect/type_of.rs | 4 +- .../rustc_hir_analysis/src/variance/mod.rs | 10 +--- .../rustc_infer/src/infer/opaque_types/mod.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 12 ---- compiler/rustc_ty_utils/src/opaque_types.rs | 2 +- .../escaping-bound-var.rs | 2 +- .../escaping-bound-var.stderr | 12 +++- .../type-alias-impl-trait/self-referential.rs | 4 +- .../self-referential.stderr | 12 ++-- tests/ui/type-alias-impl-trait/variance.rs | 30 +++++----- .../ui/type-alias-impl-trait/variance.stderr | 45 +++++++++------ 17 files changed, 122 insertions(+), 152 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 01b1e6fcaff64..fbd35dd07ef8d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -275,7 +275,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } Some(ty) => this.lower_ty( ty, - ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false }, + ImplTraitContext::TypeAliasesOpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(id), + in_assoc_ty: false, + }, + }, ), }, ); @@ -936,7 +941,12 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(ty) => { let ty = this.lower_ty( ty, - ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true }, + ImplTraitContext::TypeAliasesOpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(i.id), + in_assoc_ty: true, + }, + }, ); hir::ImplItemKind::Type(ty) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 03ad75ca8b4a4..584f8b4691153 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -271,7 +271,10 @@ enum ImplTraitContext { fn_kind: FnDeclKind, }, /// Impl trait in type aliases. - TypeAliasesOpaqueTy { in_assoc_ty: bool }, + TypeAliasesOpaqueTy { + /// Origin: Always OpaqueTyOrigin::TypeAliasImplTrait + origin: hir::OpaqueTyOrigin, + }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -1426,15 +1429,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Some(fn_kind), itctx, ), - ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self - .lower_opaque_impl_trait( - span, - hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, - *def_node_id, - bounds, - None, - itctx, - ), + ImplTraitContext::TypeAliasesOpaqueTy { origin } => self + .lower_opaque_impl_trait(span, origin, *def_node_id, bounds, None, itctx), ImplTraitContext::Universal => { let span = t.span; @@ -1553,9 +1549,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let captured_lifetimes_to_duplicate = match origin { hir::OpaqueTyOrigin::TyAlias { .. } => { - // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any - // lifetimes, since we don't have the issue that any are late-bound. - Vec::new() + // type alias impl trait and associated type position impl trait were + // decided to capture all in-scope lifetimes, which we collect for + // all opaques during resolution. + self.resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) + .collect() } hir::OpaqueTyOrigin::FnReturn(..) => { if matches!( diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4b096a592344a..12b02c7fcfa1d 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -367,14 +367,17 @@ fn check_opaque_type_parameter_valid( span: Span, ) -> Result<(), ErrorGuaranteed> { let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); - let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin { - OpaqueTyOrigin::TyAlias { .. } => true, - OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false, + let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin { + OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true), + OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false), }; - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let parent_generics = tcx.generics_of(parent); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); - for (i, arg) in opaque_type_key.args.iter().enumerate() { + + // Only check the parent generics, which will ignore any of the + // duplicated lifetime args that come from reifying late-bounds. + for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() { if let Err(guar) = arg.error_reported() { return Err(guar); } @@ -395,7 +398,7 @@ fn check_opaque_type_parameter_valid( seen_params.entry(arg).or_default().push(i); } else { // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); + let opaque_param = parent_generics.param_at(i, tcx); let kind = opaque_param.kind.descr(); return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { @@ -409,10 +412,10 @@ fn check_opaque_type_parameter_valid( for (_, indices) in seen_params { if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let descr = parent_generics.param_at(indices[0], tcx).kind.descr(); let spans: Vec<_> = indices .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id)) .collect(); #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3dac6880f17e1..180af3943b346 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2562,6 +2562,8 @@ pub enum OpaqueTyOrigin { AsyncFn(LocalDefId), /// type aliases: `type Foo = impl Trait;` TyAlias { + /// The type alias or associated type parent of the TAIT/ATPIT + parent: LocalDefId, /// associated types in impl blocks for traits. in_assoc_ty: bool, }, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 748571c12b3df..a5731a6c21e96 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -339,8 +339,9 @@ fn check_opaque_meets_bounds<'tcx>( origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { - hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, - hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), + hir::OpaqueTyOrigin::FnReturn(did) + | hir::OpaqueTyOrigin::AsyncFn(did) + | hir::OpaqueTyOrigin::TyAlias { parent: did, .. } => did, }; let param_env = tcx.param_env(defining_use_anchor); @@ -351,14 +352,14 @@ fn check_opaque_meets_bounds<'tcx>( let ocx = ObligationCtxt::new(&infcx); let args = match *origin { - hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => { - GenericArgs::identity_for_item(tcx, parent).extend_to( - tcx, - def_id.to_def_id(), - |param, _| tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into(), - ) - } - hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id), + hir::OpaqueTyOrigin::FnReturn(parent) + | hir::OpaqueTyOrigin::AsyncFn(parent) + | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item( + tcx, parent, + ) + .extend_to(tcx, def_id.to_def_id(), |param, _| { + tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into() + }), }; let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index ad8ec1036efee..607ada8b5edaa 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -514,38 +514,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { .. }, - .. - }) => { - // Opaque types are visited when we visit the - // `TyKind::OpaqueDef`, so that they have the lifetimes from - // their parent opaque_ty in scope. - // - // The core idea here is that since OpaqueTys are generated with the impl Trait as - // their owner, we can keep going until we find the Item that owns that. We then - // conservatively add all resolved lifetimes. Otherwise we run into problems in - // cases like `type Foo<'a> = impl Bar`. - let parent_item = self.tcx.hir().get_parent_item(item.hir_id()); - let resolved_lifetimes: &ResolveBoundVars = - self.tcx.resolve_bound_vars(parent_item); - // We need to add *all* deps, since opaque tys may want them from *us* - for (&owner, defs) in resolved_lifetimes.defs.iter() { - defs.iter().for_each(|(&local_id, region)| { - self.map.defs.insert(hir::HirId { owner, local_id }, *region); - }); - } - for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() { - late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| { - self.record_late_bound_vars( - hir::HirId { owner, local_id }, - late_bound_vars.clone(), - ); - }); - } - } hir::ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent), + origin: + hir::OpaqueTyOrigin::FnReturn(parent) + | hir::OpaqueTyOrigin::AsyncFn(parent) + | hir::OpaqueTyOrigin::TyAlias { parent, .. }, generics, .. }) => { @@ -683,26 +656,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // the opaque_ty generics let opaque_ty = self.tcx.hir().item(item_id); match &opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { .. }, - .. - }) => { - intravisit::walk_ty(self, ty); - - // Elided lifetimes and late-bound lifetimes (from the parent) - // are not allowed in non-return position impl Trait - let scope = Scope::LateBoundary { - s: &Scope::TraitRefBoundary { s: self.scope }, - what: "type alias impl trait", - }; - self.with(scope, |this| intravisit::walk_item(this, opaque_ty)); - - return; - } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..), - .. - }) => {} + hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {} i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 2217e5280a736..3d54dd6f9f6b0 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -553,11 +553,11 @@ pub(super) fn type_of_opaque( Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) { Node::Item(item) => match item.kind { ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false }, + origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. }, .. }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true }, + origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. }, .. }) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id), // Opaque types desugared from `impl Trait`. diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 9618c6d8011ff..42885b0c83282 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -125,15 +125,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt // lifetime generics. - let variances = std::iter::repeat(ty::Invariant).take(generics.count()); - - let mut variances: Vec<_> = match tcx.opaque_type_origin(item_def_id) { - rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => { - variances.collect() - } - // But TAIT are invariant for all generics - rustc_hir::OpaqueTyOrigin::TyAlias { .. } => return tcx.arena.alloc_from_iter(variances), - }; + let mut variances = vec![ty::Invariant; generics.count()]; // Mark all lifetimes from parent generics as unused (Bivariant). // This will be overridden later if required. diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index b6f3c38cb3f01..3d6829ba6579f 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -391,7 +391,7 @@ impl<'tcx> InferCtxt<'tcx> { // Anonymous `impl Trait` hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id, // Named `type Foo = impl Bar;` - hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => { if in_assoc_ty { self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id) } else { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4edec0e6951cd..5c2d3973d61dd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1940,18 +1940,6 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) } - /// Returns the `DefId` of the item within which the `impl Trait` is declared. - /// For type-alias-impl-trait this is the `type` alias. - /// For impl-trait-in-assoc-type this is the assoc type. - /// For return-position-impl-trait this is the function. - pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId { - // Find the surrounding item (type alias or assoc type) - while let DefKind::OpaqueTy = self.def_kind(def_id) { - def_id = self.local_parent(def_id); - } - def_id - } - pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { if self.def_kind(def_id) != DefKind::AssocFn { return false; diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index c6448b4f661d7..3dcc8382289f5 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -141,7 +141,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { trace!(?origin); match origin { rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {} - rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => { if !in_assoc_ty { if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { return; diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs index bf27e76db2b4d..b030ce39d1dfc 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs @@ -7,7 +7,7 @@ pub trait Trait<'a> { trait Test<'a> {} pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; -//~^ ERROR cannot capture late-bound lifetime in type alias impl trait +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet impl Trait<'_> for () { type Assoc = (); diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr index 7dce067d39c68..706de37e9f3c7 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr @@ -1,8 +1,14 @@ -error: cannot capture late-bound lifetime in type alias impl trait - --> $DIR/escaping-bound-var.rs:9:57 +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/escaping-bound-var.rs:9:25 | LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; - | -- lifetime defined here ^^ + | ^^ + | +note: lifetime declared here + --> $DIR/escaping-bound-var.rs:9:25 + | +LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; + | ^^ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential.rs b/tests/ui/type-alias-impl-trait/self-referential.rs index 3090f7733d24d..2bd450e6c8609 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.rs +++ b/tests/ui/type-alias-impl-trait/self-referential.rs @@ -12,14 +12,14 @@ fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { type Foo<'a, 'b> = (i32, impl PartialEq> + std::fmt::Debug); fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { - //~^ ERROR can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0})` + //~^ ERROR can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` (42, i) } type Moo<'a, 'b> = (i32, impl PartialEq> + std::fmt::Debug); fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> { - //~^ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` + //~^ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` (42, i) } diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr index 27506b8d06f80..396237c78980c 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential.stderr @@ -10,28 +10,28 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` = help: the trait `PartialEq` is implemented for `i32` -error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0})` +error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` --> $DIR/self-referential.rs:14:31 | LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { - | ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0})` + | ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` LL | LL | (42, i) | ------- return type was inferred to be `(i32, &i32)` here | - = help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0})>` is not implemented for `&i32` + = help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)>` is not implemented for `&i32` = help: the trait `PartialEq` is implemented for `i32` -error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` +error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` --> $DIR/self-referential.rs:21:31 | LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> { - | ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0})` + | ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` LL | LL | (42, i) | ------- return type was inferred to be `(i32, &i32)` here | - = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32` + = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)>` is not implemented for `&i32` = help: the trait `PartialEq` is implemented for `i32` error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs index eae5e5fdde2b8..457c4affb9d22 100644 --- a/tests/ui/type-alias-impl-trait/variance.rs +++ b/tests/ui/type-alias-impl-trait/variance.rs @@ -5,21 +5,21 @@ trait Captures<'a> {} impl Captures<'_> for T {} -type NotCapturedEarly<'a> = impl Sized; //~ [o] +type NotCapturedEarly<'a> = impl Sized; //~ [*, o] //~^ ERROR: unconstrained opaque type -type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ [o] +type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ [*, o] //~^ ERROR: unconstrained opaque type -// TAIT does *not* capture `'b` -type NotCapturedLate<'a> = dyn for<'b> Iterator; //~ [o] -//~^ ERROR: unconstrained opaque type +type NotCapturedLate<'a> = dyn for<'b> Iterator; //~ [*, o, o] +//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level +//~| ERROR: unconstrained opaque type -// TAIT does *not* capture `'b` -type Captured<'a> = dyn for<'b> Iterator>; //~ [o] -//~^ ERROR: unconstrained opaque type +type Captured<'a> = dyn for<'b> Iterator>; //~ [*, o, o] +//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level +//~| ERROR: unconstrained opaque type -type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR [o, o, o] +type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR [*, *, o, o, o] //~^ ERROR: unconstrained opaque type trait Foo<'i> { @@ -31,24 +31,24 @@ trait Foo<'i> { } impl<'i> Foo<'i> for &'i () { - type ImplicitCapture<'a> = impl Sized; //~ [o, o] + type ImplicitCapture<'a> = impl Sized; //~ [*, *, o, o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [o, o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [*, *, o, o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [o, o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [*, *, o, o] //~^ ERROR: unconstrained opaque type } impl<'i> Foo<'i> for () { - type ImplicitCapture<'a> = impl Sized; //~ [o, o] + type ImplicitCapture<'a> = impl Sized; //~ [*, *, o, o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [o, o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [*, *, o, o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [o, o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [*, *, o, o] //~^ ERROR: unconstrained opaque type } diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr index 914541fcf66ee..eafe583e89c26 100644 --- a/tests/ui/type-alias-impl-trait/variance.stderr +++ b/tests/ui/type-alias-impl-trait/variance.stderr @@ -1,3 +1,15 @@ +error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level + --> $DIR/variance.rs:14:36 + | +LL | type NotCapturedLate<'a> = dyn for<'b> Iterator; + | ^^ + +error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level + --> $DIR/variance.rs:18:29 + | +LL | type Captured<'a> = dyn for<'b> Iterator>; + | ^^ + error: unconstrained opaque type --> $DIR/variance.rs:8:29 | @@ -15,7 +27,7 @@ LL | type CapturedEarly<'a> = impl Sized + Captures<'a>; = note: `CapturedEarly` must be used in combination with a concrete type within the same module error: unconstrained opaque type - --> $DIR/variance.rs:15:56 + --> $DIR/variance.rs:14:56 | LL | type NotCapturedLate<'a> = dyn for<'b> Iterator; | ^^^^^^^^^^ @@ -23,7 +35,7 @@ LL | type NotCapturedLate<'a> = dyn for<'b> Iterator; = note: `NotCapturedLate` must be used in combination with a concrete type within the same module error: unconstrained opaque type - --> $DIR/variance.rs:19:49 + --> $DIR/variance.rs:18:49 | LL | type Captured<'a> = dyn for<'b> Iterator>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -86,71 +98,72 @@ LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | = note: `ExplicitCaptureFromGat` must be used in combination with a concrete type within the same impl -error: [o] +error: [*, o] --> $DIR/variance.rs:8:29 | LL | type NotCapturedEarly<'a> = impl Sized; | ^^^^^^^^^^ -error: [o] +error: [*, o] --> $DIR/variance.rs:11:26 | LL | type CapturedEarly<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o] - --> $DIR/variance.rs:15:56 +error: [*, o, o] + --> $DIR/variance.rs:14:56 | LL | type NotCapturedLate<'a> = dyn for<'b> Iterator; | ^^^^^^^^^^ -error: [o] - --> $DIR/variance.rs:19:49 +error: [*, o, o] + --> $DIR/variance.rs:18:49 | LL | type Captured<'a> = dyn for<'b> Iterator>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o, o] +error: [*, *, o, o, o] --> $DIR/variance.rs:22:27 | LL | type Bar<'a, 'b: 'b, T> = impl Sized; | ^^^^^^^^^^ -error: [o, o] +error: [*, *, o, o] --> $DIR/variance.rs:34:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: [o, o] +error: [*, *, o, o] --> $DIR/variance.rs:37:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o] +error: [*, *, o, o] --> $DIR/variance.rs:40:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o] +error: [*, *, o, o] --> $DIR/variance.rs:45:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: [o, o] +error: [*, *, o, o] --> $DIR/variance.rs:48:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o] +error: [*, *, o, o] --> $DIR/variance.rs:51:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 22 previous errors +error: aborting due to 24 previous errors +For more information about this error, try `rustc --explain E0657`. From 99df5a2b425c12ece7fd241f410719f7dfd2da97 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Mar 2024 18:44:55 +0000 Subject: [PATCH 2/3] Simplify ImplTraitContext --- compiler/rustc_ast_lowering/src/item.rs | 6 ++-- compiler/rustc_ast_lowering/src/lib.rs | 43 ++++++++++--------------- compiler/rustc_ast_lowering/src/path.rs | 2 +- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fbd35dd07ef8d..523001381864d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -275,11 +275,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } Some(ty) => this.lower_ty( ty, - ImplTraitContext::TypeAliasesOpaqueTy { + ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { parent: this.local_def_id(id), in_assoc_ty: false, }, + fn_kind: None, }, ), }, @@ -941,11 +942,12 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(ty) => { let ty = this.lower_ty( ty, - ImplTraitContext::TypeAliasesOpaqueTy { + ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { parent: this.local_def_id(i.id), in_assoc_ty: true, }, + fn_kind: None, }, ); hir::ImplItemKind::Type(ty) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 584f8b4691153..94e1e06a95453 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -265,15 +265,11 @@ enum ImplTraitContext { /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// - ReturnPositionOpaqueTy { - /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, - origin: hir::OpaqueTyOrigin, - fn_kind: FnDeclKind, - }, - /// Impl trait in type aliases. - TypeAliasesOpaqueTy { - /// Origin: Always OpaqueTyOrigin::TypeAliasImplTrait + OpaqueTy { origin: hir::OpaqueTyOrigin, + /// Only used to change the lifetime capture rules, since + /// RPITIT captures all in scope, RPIT does not. + fn_kind: Option, }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), @@ -1078,9 +1074,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Disallow ATB in dyn types if self.is_in_dyn_type { let suggestion = match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { .. } - | ImplTraitContext::TypeAliasesOpaqueTy { .. } - | ImplTraitContext::Universal => { + ImplTraitContext::OpaqueTy { .. } | ImplTraitContext::Universal => { let bound_end_span = constraint .gen_args .as_ref() @@ -1420,17 +1414,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self - .lower_opaque_impl_trait( - span, - origin, - *def_node_id, - bounds, - Some(fn_kind), - itctx, - ), - ImplTraitContext::TypeAliasesOpaqueTy { origin } => self - .lower_opaque_impl_trait(span, origin, *def_node_id, bounds, None, itctx), + ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( + span, + origin, + *def_node_id, + bounds, + fn_kind, + itctx, + ), ImplTraitContext::Universal => { let span = t.span; @@ -1824,9 +1815,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Trait - | FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy { + | FnDeclKind::Impl => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)), - fn_kind: kind, + fn_kind: Some(kind), }, FnDeclKind::ExternFn => { ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn) @@ -1920,9 +1911,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output, coro, opaque_ty_span, - ImplTraitContext::ReturnPositionOpaqueTy { + ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - fn_kind, + fn_kind: Some(fn_kind), }, ); arena_vec![this; bound] diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 48941a232c266..aeeb4bf9e763a 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -423,7 +423,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^ // ``` - FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) => { + FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { if self.tcx.features().impl_trait_in_fn_trait_return { self.lower_ty(ty, itctx) } else { From 74d5bbbf94418d87def5acd89343b63d36ada5e0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Mar 2024 18:48:13 +0000 Subject: [PATCH 3/3] Rename some functions to represent their generalized behavior --- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../src/collect/predicates_of.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 20 +++++++++---------- compiler/rustc_ty_utils/src/implied_bounds.rs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a5731a6c21e96..1b24c2b61fd07 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -358,7 +358,7 @@ fn check_opaque_meets_bounds<'tcx>( tcx, parent, ) .extend_to(tcx, def_id.to_def_id(), |param, _| { - tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into() + tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into() }), }; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index f70bb8c4289f6..2675eacc06e19 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -339,7 +339,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>( predicates: &mut Vec<(ty::Clause<'tcx>, Span)>, ) { for param in opaque_own_params { - let orig_lifetime = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); + let orig_lifetime = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); if let ty::ReEarlyParam(..) = *orig_lifetime { let dup_lifetime = ty::Region::new_early_param( tcx, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4f8e4aa90f403..4a04e6771805c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1254,7 +1254,7 @@ impl<'tcx> TyCtxt<'tcx> { if self.def_kind(scope) == DefKind::OpaqueTy { // Lifetime params of opaque types are synthetic and thus irrelevant to // diagnostics. Map them back to their origin! - region = self.map_rpit_lifetime_to_fn_lifetime(def_id); + region = self.map_opaque_lifetime_to_parent_lifetime(def_id); continue; } break (scope, ty::BrNamed(def_id.into(), self.item_name(def_id.into()))); @@ -2219,31 +2219,31 @@ impl<'tcx> TyCtxt<'tcx> { ) } - /// Given the def-id of an early-bound lifetime on an RPIT corresponding to + /// Given the def-id of an early-bound lifetime on an opaque corresponding to /// a duplicated captured lifetime, map it back to the early- or late-bound /// lifetime of the function from which it originally as captured. If it is /// a late-bound lifetime, this will represent the liberated (`ReLateParam`) lifetime /// of the signature. // FIXME(RPITIT): if we ever synthesize new lifetimes for RPITITs and not just // re-use the generics of the opaque, this function will need to be tweaked slightly. - pub fn map_rpit_lifetime_to_fn_lifetime( + pub fn map_opaque_lifetime_to_parent_lifetime( self, - mut rpit_lifetime_param_def_id: LocalDefId, + mut opaque_lifetime_param_def_id: LocalDefId, ) -> ty::Region<'tcx> { debug_assert!( - matches!(self.def_kind(rpit_lifetime_param_def_id), DefKind::LifetimeParam), - "{rpit_lifetime_param_def_id:?} is a {}", - self.def_descr(rpit_lifetime_param_def_id.to_def_id()) + matches!(self.def_kind(opaque_lifetime_param_def_id), DefKind::LifetimeParam), + "{opaque_lifetime_param_def_id:?} is a {}", + self.def_descr(opaque_lifetime_param_def_id.to_def_id()) ); loop { - let parent = self.local_parent(rpit_lifetime_param_def_id); + let parent = self.local_parent(opaque_lifetime_param_def_id); let hir::OpaqueTy { lifetime_mapping, .. } = self.hir_node_by_def_id(parent).expect_item().expect_opaque_ty(); let Some((lifetime, _)) = lifetime_mapping .iter() - .find(|(_, duplicated_param)| *duplicated_param == rpit_lifetime_param_def_id) + .find(|(_, duplicated_param)| *duplicated_param == opaque_lifetime_param_def_id) else { bug!("duplicated lifetime param should be present"); }; @@ -2256,7 +2256,7 @@ impl<'tcx> TyCtxt<'tcx> { // of the opaque we mapped from. Continue mapping. if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) { debug_assert_eq!(self.parent(parent.to_def_id()), new_parent); - rpit_lifetime_param_def_id = ebv.expect_local(); + opaque_lifetime_param_def_id = ebv.expect_local(); continue; } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 191671bcc1edd..87462963c27c5 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -71,7 +71,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' // the end of the list corresponding to the opaque's generics. for param in &generics.params[tcx.generics_of(fn_def_id).params.len()..] { let orig_lt = - tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); + tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); if matches!(*orig_lt, ty::ReLateParam(..)) { mapping.insert( orig_lt,