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
17 changed files with 71 additions and 40 deletions
|
@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType;
|
||||||
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
|
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum MonoItemCollectionMode {
|
pub enum MonoItemCollectionMode {
|
||||||
|
@ -420,8 +421,22 @@ fn record_accesses<'a, 'tcx: 'a>(
|
||||||
inlining_map.lock_mut().record_accesses(caller, &accesses);
|
inlining_map.lock_mut().record_accesses(caller, &accesses);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shrinks string by keeping prefix and suffix of given sizes.
|
/// Format instance name that is already known to be too long for rustc.
|
||||||
fn shrink(s: String, before: usize, after: usize) -> String {
|
/// 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 s.chars().nth(before + after + 1).is_some() {
|
||||||
// An iterator of all byte positions including the end of the 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 positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
|
||||||
|
|
||||||
|
@ -431,16 +446,13 @@ fn shrink(s: String, before: usize, after: usize) -> String {
|
||||||
after = &s[positions().rev().nth(after).unwrap_or(0)..],
|
after = &s[positions().rev().nth(after).unwrap_or(0)..],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only use the shrunk version if it's really shorter.
|
let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None);
|
||||||
// This also avoids the case where before and after slices overlap.
|
let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
|
||||||
if shrunk.len() < s.len() { shrunk } else { s }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format instance name that is already known to be too long for rustc.
|
(shrunk, written_to_path)
|
||||||
// Show only the first and last 32 characters to avoid blasting
|
} else {
|
||||||
// the user's terminal with thousands of lines of type-name.
|
(s, None)
|
||||||
fn shrunk_instance_name(instance: &Instance<'tcx>) -> String {
|
}
|
||||||
shrink(instance.to_string(), 32, 32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_recursion_limit<'tcx>(
|
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
|
// more than the recursion limit is assumed to be causing an
|
||||||
// infinite expansion.
|
// infinite expansion.
|
||||||
if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
|
if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
|
||||||
let error = format!(
|
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
|
||||||
"reached the recursion limit while instantiating `{}`",
|
let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
|
||||||
shrunk_instance_name(&instance),
|
|
||||||
);
|
|
||||||
let mut err = tcx.sess.struct_span_fatal(span, &error);
|
let mut err = tcx.sess.struct_span_fatal(span, &error);
|
||||||
err.span_note(
|
err.span_note(
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
&format!("`{}` defined here", tcx.def_path_str(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();
|
err.emit();
|
||||||
FatalError.raise();
|
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.
|
// Bail out in these cases to avoid that bad user experience.
|
||||||
if !tcx.sess.type_length_limit().value_within_limit(type_length) {
|
if !tcx.sess.type_length_limit().value_within_limit(type_length) {
|
||||||
let msg = format!(
|
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
|
||||||
"reached the type-length limit while instantiating `{}`",
|
let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
|
||||||
shrunk_instance_name(&instance),
|
|
||||||
);
|
|
||||||
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
|
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",
|
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
|
||||||
type_length
|
type_length
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
trait ToOpt: Sized {
|
trait ToOpt: Sized {
|
||||||
fn to_option(&self) -> Option<Self>;
|
fn to_option(&self) -> Option<Self>;
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
error: reached the recursion limit while instantiating `function::<Option<Option<Option<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
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());
|
LL | function(counter - 1, t.to_option());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `function` defined here
|
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) {
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
// normalize-stderr-test: "<\[closure@.+`" -> "$$CLOSURE`"
|
// normalize-stderr-test: "<\[closure@.+`" -> "$$CLOSURE`"
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
error: reached the recursion limit while instantiating `A::matches::$CLOSURE`
|
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)
|
LL | a.matches(f)
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `A::matches` defined here
|
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) {
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
trait Mirror {
|
trait Mirror {
|
||||||
type Image;
|
type Image;
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse`
|
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();
|
LL | (self, self).recurse();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `<T as Foo>::recurse` defined here
|
note: `<T as Foo>::recurse` defined here
|
||||||
--> $DIR/issue-37311.rs:15:5
|
--> $DIR/issue-37311.rs:16:5
|
||||||
|
|
|
|
||||||
LL | fn recurse(&self) {
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rec(Empty);
|
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>`
|
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))
|
LL | rec(identity(&mut it))
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `rec` defined here
|
note: `rec` defined here
|
||||||
--> $DIR/issue-67552.rs:20:1
|
--> $DIR/issue-67552.rs:21:1
|
||||||
|
|
|
|
||||||
LL | / fn rec<T>(mut it: T)
|
LL | / fn rec<T>(mut it: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
LL | | T: Iterator,
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// recursions.
|
// recursions.
|
||||||
|
|
||||||
// build-fail
|
// build-fail
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
fn generic<T>() { //~ WARN function cannot return without recursing
|
fn generic<T>() { //~ WARN function cannot return without recursing
|
||||||
generic::<Option<T>>();
|
generic::<Option<T>>();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
warning: function cannot return without recursing
|
warning: function cannot return without recursing
|
||||||
--> $DIR/issue-8727.rs:6:1
|
--> $DIR/issue-8727.rs:7:1
|
||||||
|
|
|
|
||||||
LL | fn generic<T>() {
|
LL | fn generic<T>() {
|
||||||
| ^^^^^^^^^^^^^^^ cannot return without recursing
|
| ^^^^^^^^^^^^^^^ cannot return without recursing
|
||||||
|
@ -10,16 +10,17 @@ LL | generic::<Option<T>>();
|
||||||
= help: a `loop` may express intention better if this is on purpose
|
= help: a `loop` may express intention better if this is on purpose
|
||||||
|
|
||||||
error: reached the recursion limit while instantiating `generic::<Option<Option<Option<O...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
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>>();
|
LL | generic::<Option<T>>();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `generic` defined here
|
note: `generic` defined here
|
||||||
--> $DIR/issue-8727.rs:6:1
|
--> $DIR/issue-8727.rs:7:1
|
||||||
|
|
|
|
||||||
LL | fn generic<T>() {
|
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
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
// no free regions or type parameters.
|
// no free regions or type parameters.
|
||||||
// Codegen however, has to error for the infinitely many `drop_in_place`
|
// Codegen however, has to error for the infinitely many `drop_in_place`
|
||||||
// functions it has been asked to create.
|
// functions it has been asked to create.
|
||||||
|
|
||||||
// build-fail
|
// build-fail
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
struct S<T> {
|
struct S<T> {
|
||||||
t: T,
|
t: T,
|
||||||
|
|
|
@ -21,6 +21,7 @@ LL | | // SAFETY: see comment above
|
||||||
LL | | unsafe { drop_in_place(to_drop) }
|
LL | | unsafe { drop_in_place(to_drop) }
|
||||||
LL | | }
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
// compile-flags:-C overflow-checks=off
|
// compile-flags:-C overflow-checks=off
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
enum Nil {NilValue}
|
enum Nil {NilValue}
|
||||||
struct Cons<T> {head:isize, tail:T}
|
struct Cons<T> {head:isize, tail:T}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
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})}
|
LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `test` defined here
|
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 {
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
// error-pattern: reached the type-length limit while instantiating
|
// error-pattern: reached the type-length limit while instantiating
|
||||||
|
// normalize-stderr-test: ".nll/" -> "/"
|
||||||
|
|
||||||
// Test that the type length limit can be changed.
|
// 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) {}
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue