From b041dfe52760df6bba756e9f531772d18240314a Mon Sep 17 00:00:00 2001 From: Veera Date: Fri, 12 Apr 2024 12:25:48 -0400 Subject: [PATCH 1/2] Add test --- .../regions-outlives-for-recursive-types.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/ui/regions/regions-outlives-for-recursive-types.rs diff --git a/tests/ui/regions/regions-outlives-for-recursive-types.rs b/tests/ui/regions/regions-outlives-for-recursive-types.rs new file mode 100644 index 0000000000000..9011c40af91e0 --- /dev/null +++ b/tests/ui/regions/regions-outlives-for-recursive-types.rs @@ -0,0 +1,14 @@ +//@ check-pass + +#![allow(dead_code)] + +trait Bound { + type Assoc: Bound; +} + +struct Recurse<'a, T: Bound> { + first: &'a T, + value: &'a Recurse<'a, T::Assoc>, +} + +fn main() {} From c5f81a979eae02c5b4cb8cffd686fd1a41589e09 Mon Sep 17 00:00:00 2001 From: Veera Date: Fri, 12 Apr 2024 12:59:52 -0400 Subject: [PATCH 2/2] Don't Fold Self-Referential ADTs in `check_inferred_predicates()` --- .../src/outlives/implicit_infer.rs | 16 +++++++- .../rustc_hir_analysis/src/outlives/utils.rs | 40 ++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index e6c582667ba57..871f9cc6b8165 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -48,6 +48,7 @@ pub(super) fn infer_predicates( // requirements for adt_def. let field_ty = tcx.type_of(field_def.did).instantiate_identity(); let field_span = tcx.def_span(field_def.did); + let is_self_referential = is_self_referential(field_ty, adt_def); insert_required_predicates_to_be_wf( tcx, field_ty, @@ -55,6 +56,7 @@ pub(super) fn infer_predicates( &global_inferred_outlives, &mut item_required_predicates, &mut explicit_map, + is_self_referential, ); } } @@ -67,6 +69,7 @@ pub(super) fn infer_predicates( &global_inferred_outlives, &mut item_required_predicates, &mut explicit_map, + IsSelfReferential::No, ); } @@ -104,6 +107,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, + is_self_referential: IsSelfReferential, ) { for arg in ty.walk() { let leaf_ty = match arg.unpack() { @@ -133,6 +137,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( args, global_inferred_outlives, required_predicates, + is_self_referential, ); check_explicit_predicates( tcx, @@ -154,6 +159,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( alias.args, global_inferred_outlives, required_predicates, + is_self_referential, ); check_explicit_predicates( tcx, @@ -324,6 +330,7 @@ fn check_inferred_predicates<'tcx>( args: ty::GenericArgsRef<'tcx>, global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, + is_self_referential: IsSelfReferential, ) { // Load the current set of inferred and explicit predicates from `global_inferred_outlives` // and filter the ones that are `TypeOutlives`. @@ -335,8 +342,13 @@ fn check_inferred_predicates<'tcx>( for (&predicate, &span) in predicates.as_ref().skip_binder() { // `predicate` is `U: 'b` in the example above. // So apply the instantiation to get `T: 'a`. - let ty::OutlivesPredicate(arg, region) = - predicates.rebind(predicate).instantiate(tcx, args); + let ty::OutlivesPredicate(arg, region) = if is_self_referential.into() { + // However, for self referential ADTs, we don't instantiate + // to avoid issues like #118163 + predicate + } else { + predicates.rebind(predicate).instantiate(tcx, args) + }; insert_outlives_predicate(tcx, arg, region, span, required_predicates); } } diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index d3bb22d715d7b..ce04af7e712c6 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; -use rustc_middle::ty::{self, Region, Ty, TyCtxt}; +use rustc_middle::ty::{self, Adt, AdtDef, Ref, Region, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::Span; use smallvec::smallvec; @@ -182,3 +182,41 @@ fn is_free_region(region: Region<'_>) -> bool { } } } + +#[derive(Copy, Clone)] +pub(crate) enum IsSelfReferential { + Yes, + No, +} + +impl From for IsSelfReferential { + fn from(value: bool) -> Self { + match value { + true => IsSelfReferential::Yes, + false => IsSelfReferential::No, + } + } +} + +impl From for bool { + fn from(value: IsSelfReferential) -> Self { + match value { + IsSelfReferential::Yes => true, + IsSelfReferential::No => false, + } + } +} + +// Check if an ADT's field is a reference to the ADT itself. +// Example: `struct Recurse<'a, T>(T, &'a Recurse<'a, T>)` +// will return true +pub(crate) fn is_self_referential(field_ty: Ty<'_>, adt_def: AdtDef<'_>) -> IsSelfReferential { + if let Ref(_, ref_ty, _) = field_ty.kind() + && let Adt(field_ty_adt, _) = ref_ty.kind() + { + field_ty_adt.did() == adt_def.did() + } else { + false + } + .into() +}