1
Fork 0

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:
bors 2020-09-21 08:20:38 +00:00
commit 0433fdf93b
17 changed files with 71 additions and 40 deletions

View file

@ -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,27 +421,38 @@ 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
// An iterator of all byte positions including the end of the string. /// the user's terminal with thousands of lines of type-name.
let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); ///
/// If the type name is longer than before+after, it will be written to a file.
let shrunk = format!( fn shrunk_instance_name(
"{before}...{after}", tcx: TyCtxt<'tcx>,
before = &s[..positions().nth(before).unwrap_or(s.len())], instance: &Instance<'tcx>,
after = &s[positions().rev().nth(after).unwrap_or(0)..], before: usize,
); after: usize,
) -> (String, Option<PathBuf>) {
let s = instance.to_string();
// Only use the shrunk version if it's really shorter. // Only use the shrunk version if it's really shorter.
// This also avoids the case where before and after slices overlap. // 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. let shrunk = format!(
// Show only the first and last 32 characters to avoid blasting "{before}...{after}",
// the user's terminal with thousands of lines of type-name. before = &s[..positions().nth(before).unwrap_or(s.len())],
fn shrunk_instance_name(instance: &Instance<'tcx>) -> String { after = &s[positions().rev().nth(after).unwrap_or(0)..],
shrink(instance.to_string(), 32, 32) );
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>( 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
)); ));

View file

@ -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>;

View file

@ -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

View file

@ -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)]

View file

@ -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

View file

@ -1,4 +1,5 @@
// build-fail // build-fail
// normalize-stderr-test: ".nll/" -> "/"
trait Mirror { trait Mirror {
type Image; type Image;

View file

@ -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

View file

@ -1,4 +1,5 @@
// build-fail // build-fail
// normalize-stderr-test: ".nll/" -> "/"
fn main() { fn main() {
rec(Empty); rec(Empty);

View file

@ -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

View file

@ -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>>();

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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}

View file

@ -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

View file

@ -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.

View file

@ -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