Auto merge of #72412 - VFLashM:issue-72408-nested-closures-exponential, r=tmandry
Issue 72408 nested closures exponential This fixes #72408. Nested closures were resulting in exponential compilation time. This PR is enhancing asymptotic complexity, but also increasing the constant, so I would love to see perf run results.
This commit is contained in:
commit
fdc3405c20
22 changed files with 344 additions and 82 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