Better handling for exponential-sized types in misc places
Mostly to fix ui/issues/issue-37311-type-length-limit/issue-37311.rs. Most parts of the compiler can handle deeply nested types with a lot of duplicates just fine, but some parts still attempt to naively traverse type tree. Before such problems were caught by type length limit check, but now these places will have to be changed to handle duplicated types gracefully.
This commit is contained in:
parent
2f3296192b
commit
17d2e3b5d2
12 changed files with 91 additions and 43 deletions
|
@ -418,6 +418,29 @@ fn record_accesses<'a, 'tcx: 'a>(
|
|||
inlining_map.lock_mut().record_accesses(caller, &accesses);
|
||||
}
|
||||
|
||||
// Shrinks string by keeping prefix and suffix of given sizes.
|
||||
fn shrink(s: String, before: usize, after: usize) -> String {
|
||||
// An iterator of all byte positions including the end of the string.
|
||||
let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
|
||||
|
||||
let shrunk = format!(
|
||||
"{before}...{after}",
|
||||
before = &s[..positions().nth(before).unwrap_or(s.len())],
|
||||
after = &s[positions().rev().nth(after).unwrap_or(0)..],
|
||||
);
|
||||
|
||||
// Only use the shrunk version if it's really shorter.
|
||||
// This also avoids the case where before and after slices overlap.
|
||||
if shrunk.len() < s.len() { shrunk } else { s }
|
||||
}
|
||||
|
||||
// Format instance name that is already known to be too long for rustc.
|
||||
// Show only the first and last 32 characters to avoid blasting
|
||||
// the user's terminal with thousands of lines of type-name.
|
||||
fn shrunk_instance_name(instance: &Instance<'tcx>) -> String {
|
||||
shrink(instance.to_string(), 32, 32)
|
||||
}
|
||||
|
||||
fn check_recursion_limit<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
|
@ -440,7 +463,10 @@ fn check_recursion_limit<'tcx>(
|
|||
// more than the recursion limit is assumed to be causing an
|
||||
// infinite expansion.
|
||||
if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
|
||||
let error = format!("reached the recursion limit while instantiating `{}`", instance);
|
||||
let error = format!(
|
||||
"reached the recursion limit while instantiating `{}`",
|
||||
shrunk_instance_name(&instance),
|
||||
);
|
||||
let mut err = tcx.sess.struct_span_fatal(span, &error);
|
||||
err.span_note(
|
||||
tcx.def_span(def_id),
|
||||
|
@ -474,26 +500,9 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
|
|||
//
|
||||
// Bail out in these cases to avoid that bad user experience.
|
||||
if !tcx.sess.type_length_limit().value_within_limit(type_length) {
|
||||
// The instance name is already known to be too long for rustc.
|
||||
// Show only the first and last 32 characters to avoid blasting
|
||||
// the user's terminal with thousands of lines of type-name.
|
||||
let shrink = |s: String, before: usize, after: usize| {
|
||||
// An iterator of all byte positions including the end of the string.
|
||||
let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
|
||||
|
||||
let shrunk = format!(
|
||||
"{before}...{after}",
|
||||
before = &s[..positions().nth(before).unwrap_or(s.len())],
|
||||
after = &s[positions().rev().nth(after).unwrap_or(0)..],
|
||||
);
|
||||
|
||||
// Only use the shrunk version if it's really shorter.
|
||||
// This also avoids the case where before and after slices overlap.
|
||||
if shrunk.len() < s.len() { shrunk } else { s }
|
||||
};
|
||||
let msg = format!(
|
||||
"reached the type-length limit while instantiating `{}`",
|
||||
shrink(instance.to_string(), 32, 32)
|
||||
shrunk_instance_name(&instance),
|
||||
);
|
||||
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
|
||||
diag.note(&format!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue