Skip to content

Commit 086bdbb

Browse files
authored
Rollup merge of #104922 - estebank:fur-elize, r=oli-obk
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.
2 parents 7632db0 + 34b3c49 commit 086bdbb

File tree

15 files changed

+316
-101
lines changed

15 files changed

+316
-101
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4348,6 +4348,7 @@ dependencies = [
43484348
"rustc_span",
43494349
"rustc_target",
43504350
"smallvec",
4351+
"termize",
43514352
"tracing",
43524353
"winapi",
43534354
]

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

+103-78
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;
@@ -1352,10 +1353,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
13521353
.map(|(mod_str, _)| mod_str.len() + separator_len)
13531354
.sum();
13541355

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

13601358
if split_idx >= min_len {
13611359
// paths are identical, highlight everything
@@ -1366,7 +1364,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
13661364
} else {
13671365
let (common, uniq1) = t1_str.split_at(split_idx);
13681366
let (_, uniq2) = t2_str.split_at(split_idx);
1369-
debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2);
1367+
debug!(?common, ?uniq1, ?uniq2, "cmp");
13701368

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

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

1704-
if let Some((expected, found)) = expected_found {
1699+
if let Some((expected, found, exp_p, found_p)) = expected_found {
17051700
let (expected_label, found_label, exp_found) = match exp_found {
17061701
Mismatch::Variable(ef) => (
17071702
ef.expected.prefix_string(self.tcx),
@@ -1818,32 +1813,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
18181813
}
18191814
TypeError::Sorts(values) => {
18201815
let extra = expected == found;
1821-
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
1822-
(true, ty::Opaque(def_id, _)) => {
1823-
let sm = self.tcx.sess.source_map();
1824-
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1825-
format!(
1826-
" (opaque type at <{}:{}:{}>)",
1827-
sm.filename_for_diagnostics(&pos.file.name),
1828-
pos.line,
1829-
pos.col.to_usize() + 1,
1830-
)
1831-
}
1832-
(true, ty::Projection(proj))
1833-
if self.tcx.def_kind(proj.item_def_id)
1834-
== DefKind::ImplTraitPlaceholder =>
1835-
{
1836-
let sm = self.tcx.sess.source_map();
1837-
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
1838-
format!(
1839-
" (trait associated opaque type at <{}:{}:{}>)",
1840-
sm.filename_for_diagnostics(&pos.file.name),
1841-
pos.line,
1842-
pos.col.to_usize() + 1,
1843-
)
1816+
let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
1817+
let mut s = match (extra, ty.kind()) {
1818+
(true, ty::Opaque(def_id, _)) => {
1819+
let sm = self.tcx.sess.source_map();
1820+
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1821+
format!(
1822+
" (opaque type at <{}:{}:{}>)",
1823+
sm.filename_for_diagnostics(&pos.file.name),
1824+
pos.line,
1825+
pos.col.to_usize() + 1,
1826+
)
1827+
}
1828+
(true, ty::Projection(proj))
1829+
if self.tcx.def_kind(proj.item_def_id)
1830+
== DefKind::ImplTraitPlaceholder =>
1831+
{
1832+
let sm = self.tcx.sess.source_map();
1833+
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
1834+
format!(
1835+
" (trait associated opaque type at <{}:{}:{}>)",
1836+
sm.filename_for_diagnostics(&pos.file.name),
1837+
pos.line,
1838+
pos.col.to_usize() + 1,
1839+
)
1840+
}
1841+
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
1842+
(false, _) => "".to_string(),
1843+
};
1844+
if let Some(path) = path {
1845+
s.push_str(&format!(
1846+
"\nthe full type name has been written to '{}'",
1847+
path.display(),
1848+
));
18441849
}
1845-
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
1846-
(false, _) => "".to_string(),
1850+
s
18471851
};
18481852
if !(values.expected.is_simple_text() && values.found.is_simple_text())
18491853
|| (exp_found.map_or(false, |ef| {
@@ -1865,8 +1869,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
18651869
expected,
18661870
&found_label,
18671871
found,
1868-
&sort_string(values.expected),
1869-
&sort_string(values.found),
1872+
&sort_string(values.expected, exp_p),
1873+
&sort_string(values.found, found_p),
18701874
);
18711875
}
18721876
}
@@ -2339,7 +2343,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23392343
let code = trace.cause.code();
23402344
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
23412345
&& let hir::MatchSource::TryDesugar = source
2342-
&& let Some((expected_ty, found_ty)) = self.values_str(trace.values)
2346+
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
23432347
{
23442348
err.note(&format!(
23452349
"`?` operator cannot convert from `{}` to `{}`",
@@ -2455,7 +2459,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24552459
fn values_str(
24562460
&self,
24572461
values: ValuePairs<'tcx>,
2458-
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
2462+
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
2463+
{
24592464
match values {
24602465
infer::Regions(exp_found) => self.expected_found_str(exp_found),
24612466
infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
@@ -2465,7 +2470,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24652470
found: exp_found.found.print_only_trait_path(),
24662471
};
24672472
match self.expected_found_str(pretty_exp_found) {
2468-
Some((expected, found)) if expected == found => {
2473+
Some((expected, found, _, _)) if expected == found => {
24692474
self.expected_found_str(exp_found)
24702475
}
24712476
ret => ret,
@@ -2477,7 +2482,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24772482
found: exp_found.found.print_only_trait_path(),
24782483
};
24792484
match self.expected_found_str(pretty_exp_found) {
2480-
Some((expected, found)) if expected == found => {
2485+
Some((expected, found, _, _)) if expected == found => {
24812486
self.expected_found_str(exp_found)
24822487
}
24832488
ret => ret,
@@ -2489,17 +2494,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24892494
fn expected_found_str_term(
24902495
&self,
24912496
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
2492-
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
2497+
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
2498+
{
24932499
let exp_found = self.resolve_vars_if_possible(exp_found);
24942500
if exp_found.references_error() {
24952501
return None;
24962502
}
24972503

24982504
Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
2499-
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
2505+
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
2506+
let (mut exp, mut fnd) = self.cmp(expected, found);
2507+
// Use the terminal width as the basis to determine when to compress the printed
2508+
// out type, but give ourselves some leeway to avoid ending up creating a file for
2509+
// a type that is somewhat shorter than the path we'd write to.
2510+
let len = self.tcx.sess().diagnostic_width() + 40;
2511+
let exp_s = exp.content();
2512+
let fnd_s = fnd.content();
2513+
let mut exp_p = None;
2514+
let mut fnd_p = None;
2515+
if exp_s.len() > len {
2516+
let (exp_s, exp_path) = self.tcx.short_ty_string(expected);
2517+
exp = DiagnosticStyledString::highlighted(exp_s);
2518+
exp_p = exp_path;
2519+
}
2520+
if fnd_s.len() > len {
2521+
let (fnd_s, fnd_path) = self.tcx.short_ty_string(found);
2522+
fnd = DiagnosticStyledString::highlighted(fnd_s);
2523+
fnd_p = fnd_path;
2524+
}
2525+
(exp, fnd, exp_p, fnd_p)
2526+
}
25002527
_ => (
25012528
DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
25022529
DiagnosticStyledString::highlighted(exp_found.found.to_string()),
2530+
None,
2531+
None,
25032532
),
25042533
})
25052534
}
@@ -2508,7 +2537,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
25082537
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
25092538
&self,
25102539
exp_found: ty::error::ExpectedFound<T>,
2511-
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
2540+
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
2541+
{
25122542
let exp_found = self.resolve_vars_if_possible(exp_found);
25132543
if exp_found.references_error() {
25142544
return None;
@@ -2517,6 +2547,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
25172547
Some((
25182548
DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
25192549
DiagnosticStyledString::highlighted(exp_found.found.to_string()),
2550+
None,
2551+
None,
25202552
))
25212553
}
25222554

@@ -2850,36 +2882,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
28502882
debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
28512883
debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
28522884

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

2878-
err.note_expected_found(&"", sup_expected, &"", sup_found);
2879-
err.emit();
2880-
return;
2881-
}
2882-
}
2905+
err.note_expected_found(&"", sup_expected, &"", sup_found);
2906+
err.emit();
2907+
return;
28832908
}
28842909

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

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

+1-1
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

+20-11
Original file line numberDiff line numberDiff line change
@@ -986,23 +986,32 @@ 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 width = self.sess.diagnostic_width();
990+
let length_limit = width.saturating_sub(30);
991+
let mut type_limit = 50;
991992
let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
992993
.pretty_print_type(ty)
993994
.expect("could not write to `String`")
994995
.into_buffer();
995-
if regular.len() <= length_limit {
996+
if regular.len() <= width {
996997
return (regular, None);
997998
}
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();
999+
let mut short;
1000+
loop {
1001+
// Look for the longest properly trimmed path that still fits in lenght_limit.
1002+
short = FmtPrinter::new_with_limit(
1003+
self,
1004+
hir::def::Namespace::TypeNS,
1005+
rustc_session::Limit(type_limit),
1006+
)
1007+
.pretty_print_type(ty)
1008+
.expect("could not write to `String`")
1009+
.into_buffer();
1010+
if short.len() <= length_limit || type_limit == 0 {
1011+
break;
1012+
}
1013+
type_limit -= 1;
1014+
}
10061015
if regular == short {
10071016
return (regular, None);
10081017
}

compiler/rustc_session/Cargo.toml

+1
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

+11
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)