Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect long types in E0308 and write them to disk #104922

Merged
merged 6 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4298,6 +4298,7 @@ dependencies = [
"rustc_span",
"rustc_target",
"smallvec",
"termize",
"tracing",
"winapi",
]
Expand Down
181 changes: 103 additions & 78 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use rustc_middle::ty::{
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::{ControlFlow, Deref};
use std::path::PathBuf;
use std::{cmp, fmt, iter};

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

debug!(
"cmp: separator_len={}, split_idx={}, min_len={}",
separator_len, split_idx, min_len
);
debug!(?separator_len, ?split_idx, ?min_len, "cmp");

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

values.0.push_normal(common);
values.0.push_highlighted(uniq1);
Expand Down Expand Up @@ -1658,17 +1656,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
};
let vals = match self.values_str(values) {
Some((expected, found)) => Some((expected, found)),
None => {
// Derived error. Cancel the emitter.
// NOTE(eddyb) this was `.cancel()`, but `diag`
// is borrowed, so we can't fully defuse it.
diag.downgrade_to_delayed_bug();
return;
}
let Some(vals) = self.values_str(values) else {
// Derived error. Cancel the emitter.
// NOTE(eddyb) this was `.cancel()`, but `diag`
// is borrowed, so we can't fully defuse it.
diag.downgrade_to_delayed_bug();
return;
};
(vals, exp_found, is_simple_error, Some(values))
(Some(vals), exp_found, is_simple_error, Some(values))
}
};

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

if let Some((expected, found)) = expected_found {
if let Some((expected, found, exp_p, found_p)) = expected_found {
let (expected_label, found_label, exp_found) = match exp_found {
Mismatch::Variable(ef) => (
ef.expected.prefix_string(self.tcx),
Expand Down Expand Up @@ -1817,32 +1812,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
TypeError::Sorts(values) => {
let extra = expected == found;
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => {
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
" (opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
}
(true, ty::Projection(proj))
if self.tcx.def_kind(proj.item_def_id)
== DefKind::ImplTraitPlaceholder =>
{
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
format!(
" (trait associated opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
let mut s = match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => {
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
" (opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
}
(true, ty::Projection(proj))
if self.tcx.def_kind(proj.item_def_id)
== DefKind::ImplTraitPlaceholder =>
{
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
format!(
" (trait associated opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
}
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
(false, _) => "".to_string(),
};
if let Some(path) = path {
s.push_str(&format!(
"\nthe full type name has been written to '{}'",
path.display(),
));
}
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
(false, _) => "".to_string(),
s
};
if !(values.expected.is_simple_text() && values.found.is_simple_text())
|| (exp_found.map_or(false, |ef| {
Expand All @@ -1864,8 +1868,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
expected,
&found_label,
found,
&sort_string(values.expected),
&sort_string(values.found),
&sort_string(values.expected, exp_p),
&sort_string(values.found, found_p),
);
}
}
Expand Down Expand Up @@ -2338,7 +2342,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let code = trace.cause.code();
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
&& let hir::MatchSource::TryDesugar = source
&& let Some((expected_ty, found_ty)) = self.values_str(trace.values)
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
{
err.note(&format!(
"`?` operator cannot convert from `{}` to `{}`",
Expand Down Expand Up @@ -2454,7 +2458,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn values_str(
&self,
values: ValuePairs<'tcx>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
{
match values {
infer::Regions(exp_found) => self.expected_found_str(exp_found),
infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
Expand All @@ -2464,7 +2469,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
found: exp_found.found.print_only_trait_path(),
};
match self.expected_found_str(pretty_exp_found) {
Some((expected, found)) if expected == found => {
Some((expected, found, _, _)) if expected == found => {
self.expected_found_str(exp_found)
}
ret => ret,
Expand All @@ -2476,7 +2481,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
found: exp_found.found.print_only_trait_path(),
};
match self.expected_found_str(pretty_exp_found) {
Some((expected, found)) if expected == found => {
Some((expected, found, _, _)) if expected == found => {
self.expected_found_str(exp_found)
}
ret => ret,
Expand All @@ -2488,17 +2493,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn expected_found_str_term(
&self,
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
{
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
}

Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
let (mut exp, mut fnd) = self.cmp(expected, found);
// Use the terminal width as the basis to determine when to compress the printed
// out type, but give ourselves some leeway to avoid ending up creating a file for
// a type that is somewhat shorter than the path we'd write to.
let len = self.tcx.sess().diagnostic_width() + 40;
let exp_s = exp.content();
let fnd_s = fnd.content();
let mut exp_p = None;
let mut fnd_p = None;
if exp_s.len() > len {
let (exp_s, exp_path) = self.tcx.short_ty_string(expected);
exp = DiagnosticStyledString::highlighted(exp_s);
exp_p = exp_path;
}
if fnd_s.len() > len {
let (fnd_s, fnd_path) = self.tcx.short_ty_string(found);
fnd = DiagnosticStyledString::highlighted(fnd_s);
fnd_p = fnd_path;
}
(exp, fnd, exp_p, fnd_p)
}
_ => (
DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
DiagnosticStyledString::highlighted(exp_found.found.to_string()),
None,
None,
),
})
}
Expand All @@ -2507,7 +2536,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
&self,
exp_found: ty::error::ExpectedFound<T>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
{
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
Expand All @@ -2516,6 +2546,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
Some((
DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
DiagnosticStyledString::highlighted(exp_found.found.to_string()),
None,
None,
))
}

Expand Down Expand Up @@ -2849,36 +2881,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);

if let (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) =
(&sup_origin, &sub_origin)
if let infer::Subtype(ref sup_trace) = sup_origin
&& let infer::Subtype(ref sub_trace) = sub_origin
&& let Some((sup_expected, sup_found, _, _)) = self.values_str(sup_trace.values)
&& let Some((sub_expected, sub_found, _, _)) = self.values_str(sub_trace.values)
&& sub_expected == sup_expected
&& sub_found == sup_found
{
debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace);
debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace);
debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values);
debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);

if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) =
(self.values_str(sup_trace.values), self.values_str(sub_trace.values))
{
if sub_expected == sup_expected && sub_found == sup_found {
note_and_explain_region(
self.tcx,
&mut err,
"...but the lifetime must also be valid for ",
sub_region,
"...",
None,
);
err.span_note(
sup_trace.cause.span,
&format!("...so that the {}", sup_trace.cause.as_requirement_str()),
);
note_and_explain_region(
self.tcx,
&mut err,
"...but the lifetime must also be valid for ",
sub_region,
"...",
None,
);
err.span_note(
sup_trace.cause.span,
&format!("...so that the {}", sup_trace.cause.as_requirement_str()),
);

err.note_expected_found(&"", sup_expected, &"", sup_found);
err.emit();
return;
}
}
err.note_expected_found(&"", sup_expected, &"", sup_found);
err.emit();
return;
}

self.note_region_origin(&mut err, &sup_origin);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/error_reporting/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
span: trace.cause.span,
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
expected_found: self.values_str(trace.values),
expected_found: self.values_str(trace.values).map(|(e, f, _, _)| (e, f)),
}
.add_to_diagnostic(err),
infer::Reborrow(span) => {
Expand Down
31 changes: 20 additions & 11 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,23 +986,32 @@ fn foo(&self) -> Self::T { String::new() }
}

pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
let length_limit = 50;
let type_limit = 4;
let width = self.sess.diagnostic_width();
let length_limit = width.saturating_sub(30);
let mut type_limit = 50;
let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
.pretty_print_type(ty)
.expect("could not write to `String`")
.into_buffer();
if regular.len() <= length_limit {
if regular.len() <= width {
return (regular, None);
}
let short = FmtPrinter::new_with_limit(
self,
hir::def::Namespace::TypeNS,
rustc_session::Limit(type_limit),
)
.pretty_print_type(ty)
.expect("could not write to `String`")
.into_buffer();
let mut short;
loop {
// Look for the longest properly trimmed path that still fits in lenght_limit.
short = FmtPrinter::new_with_limit(
self,
hir::def::Namespace::TypeNS,
rustc_session::Limit(type_limit),
)
.pretty_print_type(ty)
.expect("could not write to `String`")
.into_buffer();
if short.len() <= length_limit || type_limit == 0 {
break;
}
type_limit -= 1;
}
if regular == short {
return (regular, None);
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_session/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ rustc_fs_util = { path = "../rustc_fs_util" }
rustc_ast = { path = "../rustc_ast" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
smallvec = "1.8.1"
termize = "0.1.1"

[target.'cfg(unix)'.dependencies]
libc = "0.2"
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,17 @@ impl Session {
) -> Option<Symbol> {
attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
}

pub fn diagnostic_width(&self) -> usize {
let default_column_width = 140;
if let Some(width) = self.opts.diagnostic_width {
width
} else if self.opts.unstable_opts.ui_testing {
default_column_width
} else {
termize::dimensions().map_or(default_column_width, |(w, _)| w)
}
}
}

// JUSTIFICATION: defn of the suggested wrapper fns
Expand Down
Loading