Add span for struct tail recursion limit error

This commit is contained in:
Tawan Muadmuenwai 2025-09-15 21:24:57 +07:00
parent d1ed52b1f5
commit 6912631d3e
No known key found for this signature in database
GPG key ID: 27F6C60590B3B9DA
19 changed files with 111 additions and 65 deletions

View file

@ -230,8 +230,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location: impl NormalizeLocation,
) -> Ty<'tcx> {
let tcx = self.tcx();
let body = self.body;
let cause = ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
);
if self.infcx.next_trait_solver() {
let body = self.body;
let param_env = self.infcx.param_env;
// FIXME: Make this into a real type op?
self.fully_perform_op(
@ -241,10 +247,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|ocx| {
let structurally_normalize = |ty| {
ocx.structurally_normalize_ty(
&ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
),
&cause,
param_env,
ty,
)
@ -253,6 +256,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let tail = tcx.struct_tail_raw(
ty,
&cause,
structurally_normalize,
|| {},
);
@ -265,7 +269,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
} else {
let mut normalize = |ty| self.normalize(ty, location);
let tail = tcx.struct_tail_raw(ty, &mut normalize, || {});
let tail = tcx.struct_tail_raw(ty, &cause, &mut normalize, || {});
normalize(tail)
}
}

View file

@ -1,6 +1,7 @@
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
@ -196,6 +197,7 @@ fn reconstruct_place_meta<'tcx>(
// Traverse the type, and update `last_valtree` as we go.
let tail = tcx.struct_tail_raw(
layout.ty,
&ObligationCause::dummy(),
|ty| ty,
|| {
let branches = last_valtree.unwrap_branch();

View file

@ -1,3 +1,4 @@
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
@ -74,8 +75,14 @@ impl<'a, 'tcx> Expectation<'tcx> {
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
/// for examples of where this comes up,.
pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
let span = match ty.kind() {
ty::Adt(adt_def, _) => fcx.tcx.def_span(adt_def.did()),
_ => fcx.tcx.def_span(fcx.body_id),
};
let cause = ObligationCause::misc(span, fcx.body_id);
// FIXME: This is not right, even in the old solver...
match fcx.tcx.struct_tail_raw(ty, |ty| ty, || {}).kind() {
match fcx.tcx.struct_tail_raw(ty, &cause, |ty| ty, || {}).kind() {
ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
_ => ExpectHasType(ty),
}

View file

@ -424,6 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !ty.references_error() {
let tail = self.tcx.struct_tail_raw(
ty,
&self.misc(span),
|ty| {
if self.next_trait_solver() {
self.try_structurally_resolve_type(span, ty)

View file

@ -71,6 +71,8 @@ pub enum TypeMismatchReason {
#[diag(middle_recursion_limit_reached)]
#[help]
pub(crate) struct RecursionLimitReached<'tcx> {
#[primary_span]
pub span: Span,
pub ty: Ty<'tcx>,
pub suggested_limit: rustc_hir::limit::Limit,
}

View file

@ -22,6 +22,7 @@ use {rustc_abi as abi, rustc_hir as hir};
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::query::TyCtxtAt;
use crate::traits::ObligationCause;
use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};
@ -384,6 +385,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
let tail = tcx.struct_tail_raw(
pointee,
&ObligationCause::dummy(),
|ty| match tcx.try_normalize_erasing_regions(typing_env, ty) {
Ok(ty) => ty,
Err(e) => Ty::new_error_with_message(

View file

@ -23,6 +23,7 @@ use ty::util::IntTypeExt;
use super::GenericParamDefKind;
use crate::infer::canonical::Canonical;
use crate::traits::ObligationCause;
use crate::ty::InferTy::*;
use crate::ty::{
self, AdtDef, BoundRegionKind, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv,
@ -1640,7 +1641,7 @@ impl<'tcx> Ty<'tcx> {
tcx: TyCtxt<'tcx>,
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Result<Ty<'tcx>, Ty<'tcx>> {
let tail = tcx.struct_tail_raw(self, normalize, || {});
let tail = tcx.struct_tail_raw(self, &ObligationCause::dummy(), normalize, || {});
match tail.kind() {
// Sized types
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))

View file

@ -24,6 +24,7 @@ use super::TypingEnv;
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir;
use crate::query::Providers;
use crate::traits::ObligationCause;
use crate::ty::layout::{FloatExt, IntegerExt};
use crate::ty::{
self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
@ -216,7 +217,12 @@ impl<'tcx> TyCtxt<'tcx> {
typing_env: ty::TypingEnv<'tcx>,
) -> Ty<'tcx> {
let tcx = self;
tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(typing_env, ty), || {})
tcx.struct_tail_raw(
ty,
&ObligationCause::dummy(),
|ty| tcx.normalize_erasing_regions(typing_env, ty),
|| {},
)
}
/// Returns true if a type has metadata.
@ -248,6 +254,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn struct_tail_raw(
self,
mut ty: Ty<'tcx>,
cause: &ObligationCause<'tcx>,
mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
// This is currently used to allow us to walk a ValTree
// in lockstep with the type in order to get the ValTree branch that
@ -261,9 +268,11 @@ impl<'tcx> TyCtxt<'tcx> {
Limit(0) => Limit(2),
limit => limit * 2,
};
let reported = self
.dcx()
.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit });
let reported = self.dcx().emit_err(crate::error::RecursionLimitReached {
span: cause.span,
ty,
suggested_limit,
});
return Ty::new_error(self, reported);
}
match *ty.kind() {

View file

@ -1057,6 +1057,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
Some(LangItem::PointeeTrait) => {
let tail = selcx.tcx().struct_tail_raw(
self_ty,
&obligation.cause,
|ty| {
// We throw away any obligations we get from this, since we normalize
// and confirm these obligations once again during confirmation

View file

@ -10,6 +10,7 @@ use rustc_hashes::Hash64;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::layout::{
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
};
@ -390,30 +391,31 @@ fn layout_of_uncached<'tcx>(
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
let metadata_ty =
match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) {
Ok(metadata_ty) => metadata_ty,
Err(mut err) => {
// Usually `<Ty as Pointee>::Metadata` can't be normalized because
// its struct tail cannot be normalized either, so try to get a
// more descriptive layout error here, which will lead to less confusing
// diagnostics.
//
// We use the raw struct tail function here to get the first tail
// that is an alias, which is likely the cause of the normalization
// error.
match tcx.try_normalize_erasing_regions(
cx.typing_env,
tcx.struct_tail_raw(pointee, |ty| ty, || {}),
) {
Ok(_) => {}
Err(better_err) => {
err = better_err;
}
let metadata_ty = match tcx
.try_normalize_erasing_regions(cx.typing_env, pointee_metadata)
{
Ok(metadata_ty) => metadata_ty,
Err(mut err) => {
// Usually `<Ty as Pointee>::Metadata` can't be normalized because
// its struct tail cannot be normalized either, so try to get a
// more descriptive layout error here, which will lead to less confusing
// diagnostics.
//
// We use the raw struct tail function here to get the first tail
// that is an alias, which is likely the cause of the normalization
// error.
match tcx.try_normalize_erasing_regions(
cx.typing_env,
tcx.struct_tail_raw(pointee, &ObligationCause::dummy(), |ty| ty, || {}),
) {
Ok(_) => {}
Err(better_err) => {
err = better_err;
}
return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
}
};
return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
}
};
let metadata_layout = cx.layout_of(metadata_ty)?;
// If the metadata is a 1-zst, then the pointer is thin.

View file

@ -353,6 +353,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)
let tail = tcx.struct_tail_raw(
tcx.type_of(impl_def_id).instantiate_identity(),
&cause,
|ty| {
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
Ty::new_error_with_message(

View file

@ -1,3 +1,6 @@
//~ ERROR reached the recursion limit finding the struct tail for `K`
//~| ERROR reached the recursion limit finding the struct tail for `Bottom`
// Test that the recursion limit can be changed and that the compiler
// suggests a fix. In this case, we have a long chain of Deref impls
// which will cause an overflow during the autoderef loop.
@ -9,6 +12,7 @@
macro_rules! link {
($outer:ident, $inner:ident) => {
struct $outer($inner);
//~^ ERROR reached the recursion limit finding the struct tail for `Bottom`
impl $outer {
fn new() -> $outer {
@ -51,6 +55,3 @@ fn main() {
let x: &Bottom = &t; //~ ERROR mismatched types
//~^ error recursion limit
}
//~? ERROR reached the recursion limit finding the struct tail for `K`
//~? ERROR reached the recursion limit finding the struct tail for `Bottom`

View file

@ -6,8 +6,20 @@ error: reached the recursion limit finding the struct tail for `Bottom`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
error: reached the recursion limit finding the struct tail for `Bottom`
--> $DIR/recursion_limit_deref.rs:14:9
|
LL | struct $outer($inner);
| ^^^^^^^^^^^^^^^^^^^^^^
...
LL | link!(A, B);
| ----------- in this macro invocation
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
= note: this error originates in the macro `link` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0055]: reached the recursion limit while auto-dereferencing `J`
--> $DIR/recursion_limit_deref.rs:51:22
--> $DIR/recursion_limit_deref.rs:55:22
|
LL | let x: &Bottom = &t;
| ^^ deref recursion limit reached
@ -15,7 +27,7 @@ LL | let x: &Bottom = &t;
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit_deref`)
error[E0308]: mismatched types
--> $DIR/recursion_limit_deref.rs:51:22
--> $DIR/recursion_limit_deref.rs:55:22
|
LL | let x: &Bottom = &t;
| ------- ^^ expected `&Bottom`, found `&Top`
@ -25,7 +37,7 @@ LL | let x: &Bottom = &t;
= note: expected reference `&Bottom`
found reference `&Top`
error: aborting due to 4 previous errors
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0055, E0308.
For more information about an error, try `rustc --explain E0055`.

View file

@ -1,4 +1,17 @@
//~ ERROR reached the recursion limit while instantiating `<VirtualWrapper<
//~ ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit while instantiating `<VirtualWrapper<..., 1> as MyTrait>::virtualize`
//@ build-fail
//@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes
@ -72,16 +85,3 @@ fn main() {
let test = SomeData([0; 256]);
test.virtualize();
}
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`

View file

@ -18,7 +18,7 @@ error: reached the recursion limit finding the struct tail for `[u8; 256]`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<..., 1>>`
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:18
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:38:18
|
LL | unsafe { virtualize_my_trait(L, self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -46,7 +46,7 @@ error: reached the recursion limit finding the struct tail for `SomeData<256>`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<..., 1>>`
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:18
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:38:18
|
LL | unsafe { virtualize_my_trait(L, self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -74,7 +74,7 @@ error: reached the recursion limit finding the struct tail for `VirtualWrapper<S
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<..., 1>>`
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:18
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:38:18
|
LL | unsafe { virtualize_my_trait(L, self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -85,7 +85,7 @@ LL | unsafe { virtualize_my_trait(L, self) }
error: reached the recursion limit while instantiating `<VirtualWrapper<..., 1> as MyTrait>::virtualize`
|
note: `<VirtualWrapper<T, L> as MyTrait>::virtualize` defined here
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:24:5
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:37:5
|
LL | fn virtualize(&self) -> &dyn MyTrait {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,6 +1,7 @@
struct Take(Take);
//~^ ERROR has infinite size
//~| ERROR cycle
//~| ERROR reached the recursion limit finding the struct tail for `Take`
// check that we don't hang trying to find the tail of a recursive struct (#79437)
fn foo() -> Take {
@ -15,5 +16,3 @@ struct Foo { //~ ERROR has infinite size
struct Bar<T>([T; 1]);
fn main() {}
//~? ERROR reached the recursion limit finding the struct tail for `Take`

View file

@ -10,7 +10,7 @@ LL | struct Take(Box<Take>);
| ++++ +
error[E0072]: recursive type `Foo` has infinite size
--> $DIR/infinite-struct.rs:11:1
--> $DIR/infinite-struct.rs:12:1
|
LL | struct Foo {
| ^^^^^^^^^^
@ -23,6 +23,10 @@ LL | x: Bar<Box<Foo>>,
| ++++ +
error: reached the recursion limit finding the struct tail for `Take`
--> $DIR/infinite-struct.rs:1:1
|
LL | struct Take(Take);
| ^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`

View file

@ -1,3 +1,4 @@
//~ ERROR reached the recursion limit finding the struct tail for `Bottom`
//@ check-fail
//@ compile-flags: --crate-type lib -Cdebuginfo=2
@ -40,5 +41,3 @@ link!(J, K);
link!(K, Bottom);
fn main() {}
//~? ERROR reached the recursion limit finding the struct tail for `Bottom`

View file

@ -1,3 +1,4 @@
//~ ERROR reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
// Regression test for #129541
//@ revisions: unique_curr unique_next multiple_curr multiple_next
@ -24,5 +25,3 @@ struct Hello {
}
fn main() {}
//~? ERROR reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`