Auto merge of #76843 - kornelski:longtypetofile, r=ecstatic-morse
Let user see the full type of type-length limit error Seeing the full type of the error is sometimes essential to diagnosing the problem, but the type itself is too long to be displayed in the terminal in a useful fashion. This change solves this dilemma by writing the full offending type name to a file, and displays this filename as a note. > note: the full type name been written to '$TEST_BUILD_DIR/issues/issue-22638/issue-22638.long-type.txt' Closes #76777
This commit is contained in:
commit
0433fdf93b
@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType;
|
||||
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
|
||||
use smallvec::SmallVec;
|
||||
use std::iter;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum MonoItemCollectionMode {
|
||||
@ -420,27 +421,38 @@ 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)..],
|
||||
);
|
||||
/// 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.
|
||||
///
|
||||
/// If the type name is longer than before+after, it will be written to a file.
|
||||
fn shrunk_instance_name(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: &Instance<'tcx>,
|
||||
before: usize,
|
||||
after: usize,
|
||||
) -> (String, Option<PathBuf>) {
|
||||
let s = instance.to_string();
|
||||
|
||||
// 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 }
|
||||
}
|
||||
if s.chars().nth(before + after + 1).is_some() {
|
||||
// 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()));
|
||||
|
||||
// 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)
|
||||
let shrunk = format!(
|
||||
"{before}...{after}",
|
||||
before = &s[..positions().nth(before).unwrap_or(s.len())],
|
||||
after = &s[positions().rev().nth(after).unwrap_or(0)..],
|
||||
);
|
||||
|
||||
let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None);
|
||||
let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
|
||||
|
||||
(shrunk, written_to_path)
|
||||
} else {
|
||||
(s, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_recursion_limit<'tcx>(
|
||||
@ -465,15 +477,16 @@ 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 `{}`",
|
||||
shrunk_instance_name(&instance),
|
||||
);
|
||||
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
|
||||
let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
|
||||
let mut err = tcx.sess.struct_span_fatal(span, &error);
|
||||
err.span_note(
|
||||
tcx.def_span(def_id),
|
||||
&format!("`{}` defined here", tcx.def_path_str(def_id)),
|
||||
);
|
||||
if let Some(path) = written_to_path {
|
||||
err.note(&format!("the full type name has been written to '{}'", path.display()));
|
||||
}
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
@ -502,12 +515,13 @@ 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) {
|
||||
let msg = format!(
|
||||
"reached the type-length limit while instantiating `{}`",
|
||||
shrunk_instance_name(&instance),
|
||||
);
|
||||
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
|
||||
let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
|
||||
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
|
||||
diag.note(&format!(
|
||||
if let Some(path) = written_to_path {
|
||||
diag.note(&format!("the full type name has been written to '{}'", path.display()));
|
||||
}
|
||||
diag.help(&format!(
|
||||
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
|
||||
type_length
|
||||
));
|
||||
|
@ -1,4 +1,5 @@
|
||||
// build-fail
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
trait ToOpt: Sized {
|
||||
fn to_option(&self) -> Option<Self>;
|
||||
|
@ -1,14 +1,15 @@
|
||||
error: reached the recursion limit while instantiating `function::<Option<Option<Option<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
||||
--> $DIR/infinite-instantiation.rs:21:9
|
||||
--> $DIR/infinite-instantiation.rs:22:9
|
||||
|
|
||||
LL | function(counter - 1, t.to_option());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `function` defined here
|
||||
--> $DIR/infinite-instantiation.rs:19:1
|
||||
--> $DIR/infinite-instantiation.rs:20:1
|
||||
|
|
||||
LL | fn function<T:ToOpt + Clone>(counter: usize, t: T) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
// build-fail
|
||||
// normalize-stderr-test: "<\[closure@.+`" -> "$$CLOSURE`"
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
|
@ -1,14 +1,15 @@
|
||||
error: reached the recursion limit while instantiating `A::matches::$CLOSURE`
|
||||
--> $DIR/issue-22638.rs:55:9
|
||||
--> $DIR/issue-22638.rs:56:9
|
||||
|
|
||||
LL | a.matches(f)
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: `A::matches` defined here
|
||||
--> $DIR/issue-22638.rs:14:5
|
||||
--> $DIR/issue-22638.rs:15:5
|
||||
|
|
||||
LL | pub fn matches<F: Fn()>(&self, f: &F) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-22638/issue-22638.long-type.txt'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// build-fail
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
trait Mirror {
|
||||
type Image;
|
||||
|
@ -1,14 +1,15 @@
|
||||
error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse`
|
||||
--> $DIR/issue-37311.rs:16:9
|
||||
--> $DIR/issue-37311.rs:17:9
|
||||
|
|
||||
LL | (self, self).recurse();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `<T as Foo>::recurse` defined here
|
||||
--> $DIR/issue-37311.rs:15:5
|
||||
--> $DIR/issue-37311.rs:16:5
|
||||
|
|
||||
LL | fn recurse(&self) {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// build-fail
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
fn main() {
|
||||
rec(Empty);
|
||||
|
@ -1,16 +1,17 @@
|
||||
error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>`
|
||||
--> $DIR/issue-67552.rs:27:9
|
||||
--> $DIR/issue-67552.rs:28:9
|
||||
|
|
||||
LL | rec(identity(&mut it))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `rec` defined here
|
||||
--> $DIR/issue-67552.rs:20:1
|
||||
--> $DIR/issue-67552.rs:21:1
|
||||
|
|
||||
LL | / fn rec<T>(mut it: T)
|
||||
LL | | where
|
||||
LL | | T: Iterator,
|
||||
| |________________^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// recursions.
|
||||
|
||||
// build-fail
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
fn generic<T>() { //~ WARN function cannot return without recursing
|
||||
generic::<Option<T>>();
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: function cannot return without recursing
|
||||
--> $DIR/issue-8727.rs:6:1
|
||||
--> $DIR/issue-8727.rs:7:1
|
||||
|
|
||||
LL | fn generic<T>() {
|
||||
| ^^^^^^^^^^^^^^^ cannot return without recursing
|
||||
@ -10,16 +10,17 @@ LL | generic::<Option<T>>();
|
||||
= help: a `loop` may express intention better if this is on purpose
|
||||
|
||||
error: reached the recursion limit while instantiating `generic::<Option<Option<Option<O...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
||||
--> $DIR/issue-8727.rs:7:5
|
||||
--> $DIR/issue-8727.rs:8:5
|
||||
|
|
||||
LL | generic::<Option<T>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `generic` defined here
|
||||
--> $DIR/issue-8727.rs:6:1
|
||||
--> $DIR/issue-8727.rs:7:1
|
||||
|
|
||||
LL | fn generic<T>() {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt'
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
|
@ -2,7 +2,9 @@
|
||||
// no free regions or type parameters.
|
||||
// Codegen however, has to error for the infinitely many `drop_in_place`
|
||||
// functions it has been asked to create.
|
||||
|
||||
// build-fail
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
struct S<T> {
|
||||
t: T,
|
||||
|
@ -21,6 +21,7 @@ LL | | // SAFETY: see comment above
|
||||
LL | | unsafe { drop_in_place(to_drop) }
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
// build-fail
|
||||
// compile-flags:-C overflow-checks=off
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
enum Nil {NilValue}
|
||||
struct Cons<T> {head:isize, tail:T}
|
||||
|
@ -1,14 +1,15 @@
|
||||
error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
||||
--> $DIR/recursion.rs:17:11
|
||||
--> $DIR/recursion.rs:18:11
|
||||
|
|
||||
LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `test` defined here
|
||||
--> $DIR/recursion.rs:15:1
|
||||
--> $DIR/recursion.rs:16:1
|
||||
|
|
||||
LL | fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
// build-fail
|
||||
// error-pattern: reached the type-length limit while instantiating
|
||||
// normalize-stderr-test: ".nll/" -> "/"
|
||||
|
||||
// Test that the type length limit can be changed.
|
||||
|
||||
|
@ -4,7 +4,8 @@ error: reached the type-length limit while instantiating `std::mem::drop::<Optio
|
||||
LL | pub fn drop<T>(_x: T) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: consider adding a `#![type_length_limit="8"]` attribute to your crate
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
||||
= help: consider adding a `#![type_length_limit="8"]` attribute to your crate
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user