Skip to content

Commit 7674ede

Browse files
committed
Detect long types in E0308 and write them to disk
On type error with long types, print an abridged type and write the full type to disk. Print the widest possible short type while still fitting in the terminal.
1 parent 8a09420 commit 7674ede

File tree

16 files changed

+314
-101
lines changed

16 files changed

+314
-101
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4298,6 +4298,7 @@ dependencies = [
42984298
"rustc_span",
42994299
"rustc_target",
43004300
"smallvec",
4301+
"termize",
43014302
"tracing",
43024303
"winapi",
43034304
]

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 100 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ use rustc_middle::ty::{
8080
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
8181
use rustc_target::spec::abi;
8282
use std::ops::{ControlFlow, Deref};
83+
use std::path::PathBuf;
8384
use std::{cmp, fmt, iter};
8485

8586
mod note;
@@ -1351,10 +1352,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
13511352
.map(|(mod_str, _)| mod_str.len() + separator_len)
13521353
.sum();
13531354

1354-
debug!(
1355-
"cmp: separator_len={}, split_idx={}, min_len={}",
1356-
separator_len, split_idx, min_len
1357-
);
1355+
debug!(?separator_len, ?split_idx, ?min_len, "cmp");
13581356

13591357
if split_idx >= min_len {
13601358
// paths are identical, highlight everything
@@ -1365,7 +1363,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
13651363
} else {
13661364
let (common, uniq1) = t1_str.split_at(split_idx);
13671365
let (_, uniq2) = t2_str.split_at(split_idx);
1368-
debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2);
1366+
debug!(?common, ?uniq1, ?uniq2, "cmp");
13691367

13701368
values.0.push_normal(common);
13711369
values.0.push_highlighted(uniq1);
@@ -1658,17 +1656,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
16581656
}
16591657
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
16601658
};
1661-
let vals = match self.values_str(values) {
1662-
Some((expected, found)) => Some((expected, found)),
1663-
None => {
1664-
// Derived error. Cancel the emitter.
1665-
// NOTE(eddyb) this was `.cancel()`, but `diag`
1666-
// is borrowed, so we can't fully defuse it.
1667-
diag.downgrade_to_delayed_bug();
1668-
return;
1669-
}
1659+
let Some(vals) = self.values_str(values) else {
1660+
// Derived error. Cancel the emitter.
1661+
// NOTE(eddyb) this was `.cancel()`, but `diag`
1662+
// is borrowed, so we can't fully defuse it.
1663+
diag.downgrade_to_delayed_bug();
1664+
return;
16701665
};
1671-
(vals, exp_found, is_simple_error, Some(values))
1666+
(Some(vals), exp_found, is_simple_error, Some(values))
16721667
}
16731668
};
16741669

@@ -1700,7 +1695,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
17001695
label_or_note(span, &terr.to_string());
17011696
}
17021697

1703-
if let Some((expected, found)) = expected_found {
1698+
if let Some((expected, found, exp_p, found_p)) = expected_found {
17041699
let (expected_label, found_label, exp_found) = match exp_found {
17051700
Mismatch::Variable(ef) => (
17061701
ef.expected.prefix_string(self.tcx),
@@ -1817,32 +1812,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
18171812
}
18181813
TypeError::Sorts(values) => {
18191814
let extra = expected == found;
1820-
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
1821-
(true, ty::Opaque(def_id, _)) => {
1822-
let sm = self.tcx.sess.source_map();
1823-
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1824-
format!(
1825-
" (opaque type at <{}:{}:{}>)",
1826-
sm.filename_for_diagnostics(&pos.file.name),
1827-
pos.line,
1828-
pos.col.to_usize() + 1,
1829-
)
1830-
}
1831-
(true, ty::Projection(proj))
1832-
if self.tcx.def_kind(proj.item_def_id)
1833-
== DefKind::ImplTraitPlaceholder =>
1834-
{
1835-
let sm = self.tcx.sess.source_map();
1836-
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
1837-
format!(
1838-
" (trait associated opaque type at <{}:{}:{}>)",
1839-
sm.filename_for_diagnostics(&pos.file.name),
1840-
pos.line,
1841-
pos.col.to_usize() + 1,
1842-
)
1815+
let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
1816+
let mut s = match (extra, ty.kind()) {
1817+
(true, ty::Opaque(def_id, _)) => {
1818+
let sm = self.tcx.sess.source_map();
1819+
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1820+
format!(
1821+
" (opaque type at <{}:{}:{}>)",
1822+
sm.filename_for_diagnostics(&pos.file.name),
1823+
pos.line,
1824+
pos.col.to_usize() + 1,
1825+
)
1826+
}
1827+
(true, ty::Projection(proj))
1828+
if self.tcx.def_kind(proj.item_def_id)
1829+
== DefKind::ImplTraitPlaceholder =>
1830+
{
1831+
let sm = self.tcx.sess.source_map();
1832+
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
1833+
format!(
1834+
" (trait associated opaque type at <{}:{}:{}>)",
1835+
sm.filename_for_diagnostics(&pos.file.name),
1836+
pos.line,
1837+
pos.col.to_usize() + 1,
1838+
)
1839+
}
1840+
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
1841+
(false, _) => "".to_string(),
1842+
};
1843+
if let Some(path) = path {
1844+
s.push_str(&format!(
1845+
"\nthe full type name has been written to '{}'",
1846+
path.display(),
1847+
));
18431848
}
1844-
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
1845-
(false, _) => "".to_string(),
1849+
s
18461850
};
18471851
if !(values.expected.is_simple_text() && values.found.is_simple_text())
18481852
|| (exp_found.map_or(false, |ef| {
@@ -1864,8 +1868,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
18641868
expected,
18651869
&found_label,
18661870
found,
1867-
&sort_string(values.expected),
1868-
&sort_string(values.found),
1871+
&sort_string(values.expected, exp_p),
1872+
&sort_string(values.found, found_p),
18691873
);
18701874
}
18711875
}
@@ -2338,7 +2342,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23382342
let code = trace.cause.code();
23392343
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
23402344
&& let hir::MatchSource::TryDesugar = source
2341-
&& let Some((expected_ty, found_ty)) = self.values_str(trace.values)
2345+
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
23422346
{
23432347
err.note(&format!(
23442348
"`?` operator cannot convert from `{}` to `{}`",
@@ -2454,7 +2458,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24542458
fn values_str(
24552459
&self,
24562460
values: ValuePairs<'tcx>,
2457-
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
2461+
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
2462+
{
24582463
match values {
24592464
infer::Regions(exp_found) => self.expected_found_str(exp_found),
24602465
infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
@@ -2464,7 +2469,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24642469
found: exp_found.found.print_only_trait_path(),
24652470
};
24662471
match self.expected_found_str(pretty_exp_found) {
2467-
Some((expected, found)) if expected == found => {
2472+
Some((expected, found, _, _)) if expected == found => {
24682473
self.expected_found_str(exp_found)
24692474
}
24702475
ret => ret,
@@ -2476,7 +2481,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24762481
found: exp_found.found.print_only_trait_path(),
24772482
};
24782483
match self.expected_found_str(pretty_exp_found) {
2479-
Some((expected, found)) if expected == found => {
2484+
Some((expected, found, _, _)) if expected == found => {
24802485
self.expected_found_str(exp_found)
24812486
}
24822487
ret => ret,
@@ -2488,17 +2493,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24882493
fn expected_found_str_term(
24892494
&self,
24902495
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
2491-
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
2496+
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
2497+
{
24922498
let exp_found = self.resolve_vars_if_possible(exp_found);
24932499
if exp_found.references_error() {
24942500
return None;
24952501
}
24962502

24972503
Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
2498-
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
2504+
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
2505+
let (mut exp, mut fnd) = self.cmp(expected, found);
2506+
let len = self.tcx.sess().diagnostic_width().saturating_sub(20);
2507+
let exp_s = exp.content();
2508+
let fnd_s = fnd.content();
2509+
let mut exp_p = None;
2510+
let mut fnd_p = None;
2511+
if exp_s.len() > len {
2512+
let (exp_s, exp_path) = self.tcx.short_ty_string(expected);
2513+
exp = DiagnosticStyledString::highlighted(exp_s);
2514+
exp_p = exp_path;
2515+
}
2516+
if fnd_s.len() > len {
2517+
let (fnd_s, fnd_path) = self.tcx.short_ty_string(found);
2518+
fnd = DiagnosticStyledString::highlighted(fnd_s);
2519+
fnd_p = fnd_path;
2520+
}
2521+
(exp, fnd, exp_p, fnd_p)
2522+
}
24992523
_ => (
25002524
DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
25012525
DiagnosticStyledString::highlighted(exp_found.found.to_string()),
2526+
None,
2527+
None,
25022528
),
25032529
})
25042530
}
@@ -2507,7 +2533,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
25072533
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
25082534
&self,
25092535
exp_found: ty::error::ExpectedFound<T>,
2510-
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
2536+
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
2537+
{
25112538
let exp_found = self.resolve_vars_if_possible(exp_found);
25122539
if exp_found.references_error() {
25132540
return None;
@@ -2516,6 +2543,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
25162543
Some((
25172544
DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
25182545
DiagnosticStyledString::highlighted(exp_found.found.to_string()),
2546+
None,
2547+
None,
25192548
))
25202549
}
25212550

@@ -2849,36 +2878,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
28492878
debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
28502879
debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
28512880

2852-
if let (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) =
2853-
(&sup_origin, &sub_origin)
2881+
if let infer::Subtype(ref sup_trace) = sup_origin
2882+
&& let infer::Subtype(ref sub_trace) = sub_origin
2883+
&& let Some((sup_expected, sup_found, _, _)) = self.values_str(sup_trace.values)
2884+
&& let Some((sub_expected, sub_found, _, _)) = self.values_str(sub_trace.values)
2885+
&& sub_expected == sup_expected
2886+
&& sub_found == sup_found
28542887
{
2855-
debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace);
2856-
debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace);
2857-
debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values);
2858-
debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);
2859-
2860-
if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) =
2861-
(self.values_str(sup_trace.values), self.values_str(sub_trace.values))
2862-
{
2863-
if sub_expected == sup_expected && sub_found == sup_found {
2864-
note_and_explain_region(
2865-
self.tcx,
2866-
&mut err,
2867-
"...but the lifetime must also be valid for ",
2868-
sub_region,
2869-
"...",
2870-
None,
2871-
);
2872-
err.span_note(
2873-
sup_trace.cause.span,
2874-
&format!("...so that the {}", sup_trace.cause.as_requirement_str()),
2875-
);
2888+
note_and_explain_region(
2889+
self.tcx,
2890+
&mut err,
2891+
"...but the lifetime must also be valid for ",
2892+
sub_region,
2893+
"...",
2894+
None,
2895+
);
2896+
err.span_note(
2897+
sup_trace.cause.span,
2898+
&format!("...so that the {}", sup_trace.cause.as_requirement_str()),
2899+
);
28762900

2877-
err.note_expected_found(&"", sup_expected, &"", sup_found);
2878-
err.emit();
2879-
return;
2880-
}
2881-
}
2901+
err.note_expected_found(&"", sup_expected, &"", sup_found);
2902+
err.emit();
2903+
return;
28822904
}
28832905

28842906
self.note_region_origin(&mut err, &sup_origin);

compiler/rustc_infer/src/infer/error_reporting/note.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1616
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
1717
span: trace.cause.span,
1818
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
19-
expected_found: self.values_str(trace.values),
19+
expected_found: self.values_str(trace.values).map(|(e, f, _, _)| (e, f)),
2020
}
2121
.add_to_diagnostic(err),
2222
infer::Reborrow(span) => {

compiler/rustc_middle/src/ty/error.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -986,23 +986,31 @@ fn foo(&self) -> Self::T { String::new() }
986986
}
987987

988988
pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
989-
let length_limit = 50;
990-
let type_limit = 4;
989+
let length_limit = self.sess.diagnostic_width().saturating_sub(20);
990+
let mut type_limit = 50;
991991
let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
992992
.pretty_print_type(ty)
993993
.expect("could not write to `String`")
994994
.into_buffer();
995995
if regular.len() <= length_limit {
996996
return (regular, None);
997997
}
998-
let short = FmtPrinter::new_with_limit(
999-
self,
1000-
hir::def::Namespace::TypeNS,
1001-
rustc_session::Limit(type_limit),
1002-
)
1003-
.pretty_print_type(ty)
1004-
.expect("could not write to `String`")
1005-
.into_buffer();
998+
let mut short;
999+
loop {
1000+
// Look for the longest properly trimmed path that still fits in lenght_limit.
1001+
short = FmtPrinter::new_with_limit(
1002+
self,
1003+
hir::def::Namespace::TypeNS,
1004+
rustc_session::Limit(type_limit),
1005+
)
1006+
.pretty_print_type(ty)
1007+
.expect("could not write to `String`")
1008+
.into_buffer();
1009+
if short.len() <= length_limit || type_limit == 0 {
1010+
break;
1011+
}
1012+
type_limit -= 1;
1013+
}
10061014
if regular == short {
10071015
return (regular, None);
10081016
}

compiler/rustc_session/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ rustc_fs_util = { path = "../rustc_fs_util" }
1818
rustc_ast = { path = "../rustc_ast" }
1919
rustc_lint_defs = { path = "../rustc_lint_defs" }
2020
smallvec = "1.8.1"
21+
termize = "0.1.1"
2122

2223
[target.'cfg(unix)'.dependencies]
2324
libc = "0.2"

compiler/rustc_session/src/session.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,17 @@ impl Session {
952952
) -> Option<Symbol> {
953953
attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
954954
}
955+
956+
pub fn diagnostic_width(&self) -> usize {
957+
let default_column_width = 140;
958+
if let Some(width) = self.opts.diagnostic_width {
959+
width
960+
} else if self.opts.unstable_opts.ui_testing {
961+
default_column_width
962+
} else {
963+
termize::dimensions().map_or(default_column_width, |(w, _)| w)
964+
}
965+
}
955966
}
956967

957968
// JUSTIFICATION: defn of the suggested wrapper fns

0 commit comments

Comments
 (0)