Rollup merge of #136328 - estebank:long-ty-path, r=jieyouxu,lqd

Rework "long type names" printing logic

Make it so more type-system types can be printed in a shortened version (like `Predicate`s).

Centralize printing the information about the "full type name path".

Make the "long type path" for the file where long types are written part of `Diag`, so that it becomes easier to keep track of it, and ensure it will always will be printed out last in the diagnostic by making its addition to the output implicit.

Tweak the shortening of types in "expected/found" labels.

Remove dead file `note.rs`.
This commit is contained in:
Matthias Krüger 2025-02-02 12:31:56 +01:00 committed by GitHub
commit 39efaa09d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 332 additions and 741 deletions

View file

@ -92,9 +92,6 @@ borrowck_lifetime_constraints_error =
borrowck_limitations_implies_static =
due to current limitations in the borrow checker, this implies a `'static` lifetime
borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console
borrowck_long_type_full_path = the full type name has been written to '{$path}'
borrowck_move_closure_suggestion =
consider adding 'move' keyword before the nested closure

View file

@ -289,8 +289,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
None => "value".to_owned(),
};
if needs_note {
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(ty, &mut path);
let ty = self.infcx.tcx.short_string(ty, err.long_ty_path());
if let Some(local) = place.as_local() {
let span = self.body.local_decls[local].source_info.span;
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
@ -306,11 +305,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
place: &note_msg,
});
};
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
}
if let UseSpans::FnSelfUse {

View file

@ -596,19 +596,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_cloning(err, place_ty, expr, None);
}
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty,
place: &place_desc,
span,
});
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
} else {
binds_to.sort();
binds_to.dedup();
@ -635,19 +629,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_cloning(err, place_ty, expr, Some(use_spans));
}
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty,
place: &place_desc,
span: use_span,
});
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
use_spans.args_subdiag(err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
@ -845,19 +833,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_cloning(err, bind_to.ty, expr, None);
}
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path);
let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty,
place: place_desc,
span: binding_span,
});
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
}
}

View file

@ -458,13 +458,6 @@ pub(crate) enum OnClosureNote<'a> {
},
}
#[derive(Subdiagnostic)]
#[note(borrowck_long_type_full_path)]
#[note(borrowck_long_type_consider_verbose)]
pub(crate) struct LongTypePath {
pub(crate) path: String,
}
#[derive(Subdiagnostic)]
pub(crate) enum TypeNoCopy<'a> {
#[label(borrowck_ty_no_impl_copy)]

View file

@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::path::PathBuf;
use std::thread::panicking;
use rustc_data_structures::fx::FxIndexMap;
@ -301,6 +302,7 @@ pub struct DiagInner {
pub is_lint: Option<IsLint>,
pub long_ty_path: Option<PathBuf>,
/// With `-Ztrack_diagnostics` enabled,
/// we print where in rustc this error was emitted.
pub(crate) emitted_at: DiagLocation,
@ -324,6 +326,7 @@ impl DiagInner {
args: Default::default(),
sort_span: DUMMY_SP,
is_lint: None,
long_ty_path: None,
emitted_at: DiagLocation::caller(),
}
}
@ -1293,9 +1296,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
/// `self`.
fn take_diag(&mut self) -> DiagInner {
if let Some(path) = &self.long_ty_path {
self.note(format!(
"the full name for the type has been written to '{}'",
path.display()
));
self.note("consider using `--verbose` to print the full type name to the console");
}
Box::into_inner(self.diag.take().unwrap())
}
/// This method allows us to access the path of the file where "long types" are written to.
///
/// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
/// and if it has been then we add a note mentioning the file where the "long types" were
/// written to.
///
/// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
/// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
/// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
/// user where we wrote the file to is only printed once at most, *and* it makes it much harder
/// to forget to set it.
///
/// If the diagnostic hasn't been created before a "short ty string" is created, then you should
/// ensure that this method is called to set it `*diag.long_ty_path() = path`.
///
/// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
/// scope, `diag.long_ty_path()` should be called once somewhere close by.
pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
&mut self.long_ty_path
}
/// Most `emit_producing_guarantee` functions use this as a starting point.
fn emit_producing_nothing(mut self) {
let diag = self.take_diag();

View file

@ -5,6 +5,7 @@
use core::ops::ControlFlow;
use std::borrow::Cow;
use std::path::PathBuf;
use hir::Expr;
use rustc_ast::ast::Mutability;
@ -362,14 +363,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
let mut file = None;
let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file);
let mut err = struct_span_code_err!(
self.dcx(),
rcvr_expr.span,
E0599,
"cannot write into `{}`",
ty_str
self.tcx.short_string(rcvr_ty, &mut file),
);
*err.long_ty_path() = file;
err.span_note(
rcvr_expr.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
@ -380,11 +381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"a writer is needed before this format string",
);
};
if let Some(file) = file {
err.note(format!("the full type name has been written to '{}'", file.display()));
err.note("consider using `--verbose` to print the full type name to the console");
}
err
}
@ -595,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
} else {
(
tcx.short_ty_string(rcvr_ty, &mut ty_file),
tcx.short_string(rcvr_ty, &mut ty_file),
with_forced_trimmed_paths!(rcvr_ty.to_string()),
)
};
@ -624,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
item_name,
&short_ty_str,
&mut ty_file,
) {
return guar;
}
@ -635,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_kind,
item_name,
&short_ty_str,
&mut ty_file,
) {
return guar;
}
@ -728,10 +726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty_str = short_ty_str;
}
if let Some(file) = ty_file {
err.note(format!("the full type name has been written to '{}'", file.display(),));
err.note("consider using `--verbose` to print the full type name to the console");
}
if rcvr_ty.references_error() {
err.downgrade_to_delayed_bug();
}
@ -1314,7 +1308,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
let mut long_ty_file = None;
let (primary_message, label, notes) = if unimplemented_traits.len() == 1
&& unimplemented_traits_only
{
@ -1329,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let OnUnimplementedNote { message, label, notes, .. } = self
.err_ctxt()
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
.on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
(message, label, notes)
})
.unwrap()
@ -1343,15 +1336,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
err.primary_message(primary_message);
if let Some(file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
err.note(
"consider using `--verbose` to print the full type name to the console",
);
}
if let Some(label) = label {
custom_span_label = true;
err.span_label(span, label);
@ -2403,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
item_name: Ident,
ty_str: &str,
long_ty_path: &mut Option<PathBuf>,
) -> Result<(), ErrorGuaranteed> {
if let SelfSource::MethodCall(expr) = source {
for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
@ -2460,7 +2445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
span,
ty_str: ty_str.to_string(),
method_name: item_name.as_str().to_string(),
@ -2469,7 +2454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
left: range_span.shrink_to_lo(),
right: range_span.shrink_to_hi(),
}),
}));
});
*err.long_ty_path() = long_ty_path.take();
return Err(err.emit());
}
}
}
@ -2486,6 +2473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_kind: &str,
item_name: Ident,
ty_str: &str,
long_ty_path: &mut Option<PathBuf>,
) -> Result<(), ErrorGuaranteed> {
let found_candidate = all_traits(self.tcx)
.into_iter()
@ -2526,6 +2514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name,
ty_str
);
*err.long_ty_path() = long_ty_path.take();
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
match expr.kind {
ExprKind::Lit(lit) => {

View file

@ -10,8 +10,8 @@ use rustc_hir::def::{CtorOf, DefKind};
use rustc_macros::extension;
pub use rustc_type_ir::error::ExpectedFound;
use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths};
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::print::{FmtPrinter, Print, with_forced_trimmed_paths};
use crate::ty::{self, Lift, Ty, TyCtxt};
pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>;
@ -159,8 +159,8 @@ impl<'tcx> Ty<'tcx> {
ty::Error(_) => "type error".into(),
_ => {
let width = tcx.sess.diagnostic_width();
let length_limit = std::cmp::max(width / 4, 15);
format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into()
let length_limit = std::cmp::max(width / 4, 40);
format!("`{}`", tcx.string_with_limit(self, length_limit)).into()
}
}
}
@ -213,10 +213,14 @@ impl<'tcx> Ty<'tcx> {
}
impl<'tcx> TyCtxt<'tcx> {
pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String {
pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String
where
T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy,
<T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
{
let mut type_limit = 50;
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
cx.pretty_print_type(ty)
self.lift(p).expect("could not lift for printing").print(cx)
})
.expect("could not write to `String`");
if regular.len() <= length_limit {
@ -231,7 +235,10 @@ impl<'tcx> TyCtxt<'tcx> {
hir::def::Namespace::TypeNS,
rustc_session::Limit(type_limit),
);
cx.pretty_print_type(ty).expect("could not write to `String`");
self.lift(p)
.expect("could not lift for printing")
.print(&mut cx)
.expect("could not print type");
cx.into_buffer()
});
if short.len() <= length_limit || type_limit == 0 {
@ -242,9 +249,17 @@ impl<'tcx> TyCtxt<'tcx> {
short
}
pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String {
/// When calling this after a `Diag` is constructed, the preferred way of doing so is
/// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps
/// the existence of a "long type" anywhere in the diagnostic, so the note telling the user
/// where we wrote the file to is only printed once.
pub fn short_string<'a, T>(self, p: T, path: &mut Option<PathBuf>) -> String
where
T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy + Hash,
<T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
{
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
cx.pretty_print_type(ty)
self.lift(p).expect("could not lift for printing").print(cx)
})
.expect("could not write to `String`");
@ -257,13 +272,13 @@ impl<'tcx> TyCtxt<'tcx> {
if regular.len() <= width * 2 / 3 {
return regular;
}
let short = self.ty_string_with_limit(ty, length_limit);
let short = self.string_with_limit(p, length_limit);
if regular == short {
return regular;
}
// Ensure we create an unique file for the type passed in when we create a file.
let mut s = DefaultHasher::new();
ty.hash(&mut s);
p.hash(&mut s);
let hash = s.finish();
*path = Some(path.take().unwrap_or_else(|| {
self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None)

View file

@ -105,6 +105,10 @@ pub trait Printer<'tcx>: Sized {
args: &[GenericArg<'tcx>],
) -> Result<(), PrintError>;
fn should_truncate(&mut self) -> bool {
false
}
// Defaults (should not be overridden):
#[instrument(skip(self), level = "debug")]

View file

@ -865,7 +865,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
p!(write("{{"));
if !self.tcx().sess.verbose_internals() {
p!("coroutine witness");
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
let span = self.tcx().def_span(did);
p!(write(
@ -887,26 +886,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
p!(write("{{"));
if !self.should_print_verbose() {
p!(write("closure"));
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), args));
} else {
let span = self.tcx().def_span(did);
let preference = if with_forced_trimmed_paths() {
FileNameDisplayPreference::Short
} else {
FileNameDisplayPreference::Remapped
};
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx().sess.source_map().span_to_string(span, preference)
));
}
if self.should_truncate() {
write!(self, "@...}}")?;
return Ok(());
} else {
p!(write("@"), print_def_path(did, args));
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), args));
} else {
let span = self.tcx().def_span(did);
let preference = if with_forced_trimmed_paths() {
FileNameDisplayPreference::Short
} else {
FileNameDisplayPreference::Remapped
};
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx().sess.source_map().span_to_string(span, preference)
));
}
} else {
p!(write("@"), print_def_path(did, args));
}
}
} else {
p!(print_def_path(did, args));
@ -942,7 +945,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
"coroutine from coroutine-closure should have CoroutineSource::Closure"
),
}
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), args));
@ -1994,7 +1996,6 @@ pub struct FmtPrinterData<'a, 'tcx> {
binder_depth: usize,
printed_type_count: usize,
type_length_limit: Limit,
truncated: bool,
pub region_highlight_mode: RegionHighlightMode<'tcx>,
@ -2046,7 +2047,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
binder_depth: 0,
printed_type_count: 0,
type_length_limit,
truncated: false,
region_highlight_mode: RegionHighlightMode::default(),
ty_infer_name_resolver: None,
const_infer_name_resolver: None,
@ -2183,16 +2183,49 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
}
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
if self.type_length_limit.value_within_limit(self.printed_type_count) {
self.printed_type_count += 1;
self.pretty_print_type(ty)
} else {
self.truncated = true;
write!(self, "...")?;
Ok(())
match ty.kind() {
ty::Tuple(tys) if tys.len() == 0 && self.should_truncate() => {
// Don't truncate `()`.
self.printed_type_count += 1;
self.pretty_print_type(ty)
}
ty::Adt(..)
| ty::Foreign(_)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Tuple(_)
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Error(_)
if self.should_truncate() =>
{
// We only truncate types that we know are likely to be much longer than 3 chars.
// There's no point in replacing `i32` or `!`.
write!(self, "...")?;
Ok(())
}
_ => {
self.printed_type_count += 1;
self.pretty_print_type(ty)
}
}
}
fn should_truncate(&mut self) -> bool {
!self.type_length_limit.value_within_limit(self.printed_type_count)
}
fn print_dyn_existential(
&mut self,
predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@ -2942,7 +2975,7 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
}
}
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
pub struct TraitPredPrintWithBoundConstness<'tcx>(
ty::TraitPredicate<'tcx>,
Option<ty::BoundConstness>,

View file

@ -25,8 +25,6 @@ mir_build_borrow_of_moved_value = borrow of moved value
.occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
.value_borrowed_label = value borrowed here after move
.suggestion = borrow this binding in the pattern to avoid moving the value
.full_type_name = the full type name has been written to '{$path}'
.consider_verbose = consider using `--verbose` to print the full type name to the console
mir_build_call_to_deprecated_safe_fn_requires_unsafe =
call to deprecated safe function `{$function}` is unsafe and requires unsafe block

View file

@ -839,10 +839,6 @@ pub(crate) struct BorrowOfMovedValue {
pub(crate) ty: String,
#[suggestion(code = "ref ", applicability = "machine-applicable")]
pub(crate) suggest_borrowing: Option<Span>,
#[note(mir_build_full_type_name)]
#[note(mir_build_consider_verbose)]
pub(crate) has_path: bool,
pub(crate) path: String,
}
#[derive(Diagnostic)]

View file

@ -797,16 +797,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
});
if !conflicts_ref.is_empty() {
let mut path = None;
let ty = cx.tcx.short_ty_string(ty, &mut path);
sess.dcx().emit_err(BorrowOfMovedValue {
let ty = cx.tcx.short_string(ty, &mut path);
let mut err = sess.dcx().create_err(BorrowOfMovedValue {
binding_span: pat.span,
conflicts_ref,
name: Ident::new(name, pat.span),
ty,
suggest_borrowing: Some(pat.span.shrink_to_lo()),
has_path: path.is_some(),
path: path.map(|p| p.display().to_string()).unwrap_or_default(),
});
*err.long_ty_path() = path;
err.emit();
}
return;
}

View file

@ -435,7 +435,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
terr: TypeError<'tcx>,
param_env: Option<ParamEnv<'tcx>>,
path: &mut Option<PathBuf>,
) {
match *cause.code() {
ObligationCauseCode::Pattern {
@ -458,7 +457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
format!("this is an iterator with items of type `{}`", args.type_at(0)),
);
} else {
let expected_ty = self.tcx.short_ty_string(expected_ty, path);
let expected_ty = self.tcx.short_string(expected_ty, err.long_ty_path());
err.span_label(span, format!("this expression has type `{expected_ty}`"));
}
}
@ -1545,7 +1544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
(false, Mismatch::Fixed("existential projection"))
}
};
let Some(vals) = self.values_str(values, cause) else {
let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else {
// Derived error. Cancel the emitter.
// NOTE(eddyb) this was `.cancel()`, but `diag`
// is borrowed, so we can't fully defuse it.
@ -1600,9 +1599,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return;
}
let mut path = None;
if let Some((expected, found, p)) = expected_found {
path = p;
if let Some((expected, found)) = expected_found {
let (expected_label, found_label, exp_found) = match exp_found {
Mismatch::Variable(ef) => (
ef.expected.prefix_string(self.tcx),
@ -1878,11 +1875,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path);
if let Some(path) = path {
diag.note(format!("the full type name has been written to '{}'", path.display()));
diag.note("consider using `--verbose` to print the full type name to the console");
}
self.note_error_origin(diag, cause, exp_found, terr, param_env);
debug!(?diag);
}
@ -1891,6 +1884,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
trace: &TypeTrace<'tcx>,
terr: TypeError<'tcx>,
path: &mut Option<PathBuf>,
) -> Vec<TypeErrorAdditionalDiags> {
let mut suggestions = Vec::new();
let span = trace.cause.span;
@ -1969,7 +1963,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
})
| ObligationCauseCode::BlockTailExpression(.., source)) = code
&& let hir::MatchSource::TryDesugar(_) = source
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause)
&& let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path)
{
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
found: found_ty.content(),
@ -2048,12 +2042,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
let span = trace.cause.span;
let mut path = None;
let failure_code = trace.cause.as_failure_code_diag(
terr,
span,
self.type_error_additional_suggestions(&trace, terr),
self.type_error_additional_suggestions(&trace, terr, &mut path),
);
let mut diag = self.dcx().create_err(failure_code);
*diag.long_ty_path() = path;
self.note_type_err(
&mut diag,
&trace.cause,
@ -2098,10 +2094,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
values: ValuePairs<'tcx>,
cause: &ObligationCause<'tcx>,
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
file: &mut Option<PathBuf>,
) -> Option<(DiagStyledString, DiagStyledString)> {
match values {
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found),
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file),
ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
@ -2111,7 +2108,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
found: exp_found.found.print_trait_sugared(),
};
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,
@ -2133,9 +2130,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
(None, None)
};
let (exp, fnd) =
self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2);
Some((exp, fnd, None))
Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2))
}
}
}
@ -2143,7 +2138,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn expected_found_str_term(
&self,
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
path: &mut Option<PathBuf>,
) -> Option<(DiagStyledString, DiagStyledString)> {
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
@ -2158,21 +2154,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let len = self.tcx.sess().diagnostic_width() + 40;
let exp_s = exp.content();
let fnd_s = fnd.content();
let mut path = None;
if exp_s.len() > len {
let exp_s = self.tcx.short_ty_string(expected, &mut path);
let exp_s = self.tcx.short_string(expected, path);
exp = DiagStyledString::highlighted(exp_s);
}
if fnd_s.len() > len {
let fnd_s = self.tcx.short_ty_string(found, &mut path);
let fnd_s = self.tcx.short_string(found, path);
fnd = DiagStyledString::highlighted(fnd_s);
}
(exp, fnd, path)
(exp, fnd)
}
_ => (
DiagStyledString::highlighted(exp_found.expected.to_string()),
DiagStyledString::highlighted(exp_found.found.to_string()),
None,
),
})
}
@ -2181,7 +2175,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn expected_found_str<T: fmt::Display + TypeFoldable<TyCtxt<'tcx>>>(
&self,
exp_found: ty::error::ExpectedFound<T>,
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
) -> Option<(DiagStyledString, DiagStyledString)> {
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
@ -2190,7 +2184,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
Some((
DiagStyledString::highlighted(exp_found.expected.to_string()),
DiagStyledString::highlighted(exp_found.found.to_string()),
None,
))
}

View file

@ -713,7 +713,7 @@ impl<'tcx> InferSourceKind<'tcx> {
if ty.is_closure() {
("closure", closure_as_fn_str(infcx, ty), path)
} else if !ty.is_ty_or_numeric_infer() {
("normal", infcx.tcx.short_ty_string(ty, &mut path), path)
("normal", infcx.tcx.short_string(ty, &mut path), path)
} else {
("other", String::new(), path)
}

View file

@ -1,422 +0,0 @@
use rustc_errors::{Diag, Subdiagnostic};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
use rustc_span::kw;
use tracing::debug;
use super::ObligationCauseAsDiagArg;
use crate::error_reporting::infer::{TypeErrCtxt, note_and_explain_region};
use crate::errors::{
FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData,
RegionOriginNote, WhereClauseSuggestions, note_and_explain,
};
use crate::fluent_generated as fluent;
use crate::infer::{self, SubregionOrigin};
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
span: trace.cause.span,
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
}
.add_to_diag(err),
infer::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err)
}
infer::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diag(err);
}
infer::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
msg: fluent::infer_reference_outlives_referent,
name: &self.ty_to_string(ty),
continues: false,
}
.add_to_diag(err);
}
infer::RelateParamBound(span, ty, opt_span) => {
RegionOriginNote::WithName {
span,
msg: fluent::infer_relate_param_bound,
name: &self.ty_to_string(ty),
continues: opt_span.is_some(),
}
.add_to_diag(err);
if let Some(span) = opt_span {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
.add_to_diag(err);
}
}
infer::RelateRegionParamBound(span, _) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
.add_to_diag(err);
}
infer::CompareImplItemObligation { span, .. } => {
RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
.add_to_diag(err);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
self.note_region_origin(err, parent);
}
infer::AscribeUserTypeProvePredicate(span) => {
RegionOriginNote::Plain {
span,
msg: fluent::infer_ascribe_user_type_prove_predicate,
}
.add_to_diag(err);
}
}
}
pub(super) fn report_concrete_failure(
&self,
generic_param_scope: LocalDefId,
origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
) -> Diag<'a> {
let mut err = match origin {
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, terr);
match (*sub, *sup) {
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
(ty::RePlaceholder(_), _) => {
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"",
sup,
" doesn't meet the lifetime requirements",
None,
);
}
(_, ty::RePlaceholder(_)) => {
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"the required lifetime does not necessarily outlive ",
sub,
"",
None,
);
}
_ => {
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"",
sup,
"...",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"...does not necessarily outlive ",
sub,
"",
None,
);
}
}
err
}
infer::Reborrow(span) => {
let reference_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::RefValidFor,
note_and_explain::SuffixKind::Continues,
);
let content_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::ContentValidFor,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(OutlivesContent {
span,
notes: reference_valid.into_iter().chain(content_valid).collect(),
})
}
infer::RelateObjectBound(span) => {
let object_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::TypeObjValidFor,
note_and_explain::SuffixKind::Empty,
);
let pointer_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::SourcePointerValidFor,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(OutlivesBound {
span,
notes: object_valid.into_iter().chain(pointer_valid).collect(),
})
}
infer::RelateParamBound(span, ty, opt_span) => {
let prefix = match *sub {
ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
_ => note_and_explain::PrefixKind::TypeOutlive,
};
let suffix = if opt_span.is_some() {
note_and_explain::SuffixKind::ReqByBinding
} else {
note_and_explain::SuffixKind::Empty
};
let note = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
opt_span,
prefix,
suffix,
);
self.dcx().create_err(FulfillReqLifetime {
span,
ty: self.resolve_vars_if_possible(ty),
note,
})
}
infer::RelateRegionParamBound(span, _) => {
let param_instantiated = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::LfParamInstantiatedWith,
note_and_explain::SuffixKind::Empty,
);
let param_must_outlive = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::LfParamMustOutlive,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(LfBoundNotSatisfied {
span,
notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
})
}
infer::ReferenceOutlivesReferent(ty, span) => {
let pointer_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::PointerValidFor,
note_and_explain::SuffixKind::Empty,
);
let data_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::DataValidFor,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(RefLongerThanData {
span,
ty: self.resolve_vars_if_possible(ty),
notes: pointer_valid.into_iter().chain(data_valid).collect(),
})
}
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
let mut err = self.infcx.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
&format!("`{sup}: {sub}`"),
);
// We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
&& generics.where_clause_span.contains(span)
{
self.suggest_copy_trait_method_bounds(
trait_item_def_id,
impl_item_def_id,
&mut err,
);
}
err
}
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
// Don't mention the item name if it's an RPITIT, since that'll just confuse
// folks.
if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) {
let trait_item_span = self.tcx.def_span(trait_item_def_id);
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
err.span_label(
trait_item_span,
format!("definition of `{item_name}` from trait"),
);
}
self.suggest_copy_trait_method_bounds(
trait_item_def_id,
impl_item_def_id,
&mut err,
);
err
}
infer::AscribeUserTypeProvePredicate(span) => {
let instantiated = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::LfInstantiatedWith,
note_and_explain::SuffixKind::Empty,
);
let must_outlive = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::LfMustOutlive,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(LfBoundNotSatisfied {
span,
notes: instantiated.into_iter().chain(must_outlive).collect(),
})
}
};
if sub.is_error() || sup.is_error() {
err.downgrade_to_delayed_bug();
}
err
}
pub fn suggest_copy_trait_method_bounds(
&self,
trait_item_def_id: DefId,
impl_item_def_id: LocalDefId,
err: &mut Diag<'_>,
) {
// FIXME(compiler-errors): Right now this is only being used for region
// predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
// but right now it's not really very smart when it comes to implicit `Sized`
// predicates and bounds on the trait itself.
let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
else {
return;
};
let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
return;
};
let trait_args = trait_ref
.instantiate_identity()
// Replace the explicit self type with `Self` for better suggestion rendering
.with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
.args;
let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
.rebase_onto(self.tcx, impl_def_id, trait_args);
let Ok(trait_predicates) =
self.tcx
.explicit_predicates_of(trait_item_def_id)
.instantiate_own(self.tcx, trait_item_args)
.map(|(pred, _)| {
if pred.is_suggestable(self.tcx, false) {
Ok(pred.to_string())
} else {
Err(())
}
})
.collect::<Result<Vec<_>, ()>>()
else {
return;
};
let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
return;
};
let suggestion = if trait_predicates.is_empty() {
WhereClauseSuggestions::Remove { span: generics.where_clause_span }
} else {
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
WhereClauseSuggestions::CopyPredicates {
span: generics.where_clause_span,
space,
trait_predicates: trait_predicates.join(", "),
}
};
err.subdiagnostic(suggestion);
}
pub(super) fn report_placeholder_failure(
&self,
generic_param_scope: LocalDefId,
placeholder_origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
) -> Diag<'a> {
// I can't think how to do better than this right now. -nikomatsakis
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
match placeholder_origin {
infer::Subtype(box ref trace)
if matches!(
&trace.cause.code().peel_derives(),
ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..)
) =>
{
// Hack to get around the borrow checker because trace.cause has an `Rc`.
if let ObligationCauseCode::WhereClause(_, span)
| ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
&trace.cause.code().peel_derives()
&& !span.is_dummy()
{
let span = *span;
self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
.with_span_note(span, "the lifetime requirement is introduced here")
} else {
unreachable!(
"control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
)
}
}
infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
return self.report_and_explain_type_error(trace, terr);
}
_ => {
return self.report_concrete_failure(
generic_param_scope,
placeholder_origin,
sub,
sup,
);
}
}
}
}

View file

@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
span: trace.cause.span,
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)),
expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()),
}
.add_to_diag(err),
infer::Reborrow(span) => {
@ -946,10 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
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, &sup_trace.cause)
&& let Some((sub_expected, sub_found, _)) =
self.values_str(sub_trace.values, &sup_trace.cause)
&& let Some((sup_expected, sup_found)) =
self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
&& let Some((sub_expected, sub_found)) =
self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path())
&& sub_expected == sup_expected
&& sub_found == sup_found
{

View file

@ -163,6 +163,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let predicate = self.resolve_vars_if_possible(obligation.predicate);
let span = obligation.cause.span;
let mut file = None;
debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
@ -245,7 +246,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
span,
E0283,
"type annotations needed: cannot satisfy `{}`",
predicate,
self.tcx.short_string(predicate, &mut file),
)
};
@ -292,7 +293,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.cancel();
return e;
}
err.note(format!("cannot satisfy `{predicate}`"));
let pred = self.tcx.short_string(predicate, &mut file);
err.note(format!("cannot satisfy `{pred}`"));
let impl_candidates =
self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
if impl_candidates.len() < 40 {
@ -526,6 +528,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.iter()
.chain(Some(data.term.into_arg()))
.find(|g| g.has_non_region_infer());
let predicate = self.tcx.short_string(predicate, &mut file);
if let Some(arg) = arg {
self.emit_inference_failure_err(
obligation.cause.body_id,
@ -541,8 +544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
"type annotations needed: cannot satisfy `{predicate}`",
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
@ -567,12 +569,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err
} else {
// If we can't find a generic parameter, just print a generic error
let predicate = self.tcx.short_string(predicate, &mut file);
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
"type annotations needed: cannot satisfy `{predicate}`",
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
@ -592,6 +594,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(e) = self.tainted_by_errors() {
return e;
}
let alias = self.tcx.short_string(alias, &mut file);
struct_span_code_err!(
self.dcx(),
span,
@ -605,16 +608,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(e) = self.tainted_by_errors() {
return e;
}
let predicate = self.tcx.short_string(predicate, &mut file);
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
"type annotations needed: cannot satisfy `{predicate}`",
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
};
*err.long_ty_path() = file;
self.note_obligation_cause(&mut err, obligation);
err.emit()
}

View file

@ -1,5 +1,6 @@
use core::ops::ControlFlow;
use std::borrow::Cow;
use std::path::PathBuf;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::FxHashMap;
@ -9,7 +10,6 @@ use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions,
pluralize, struct_span_code_err,
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, LangItem, Node};
@ -20,8 +20,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{
FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
PrintTraitRefExt as _, with_forced_trimmed_paths,
PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _,
with_forced_trimmed_paths,
};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
use rustc_middle::{bug, span_bug};
@ -60,6 +60,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
) -> ErrorGuaranteed {
let tcx = self.tcx;
let mut span = obligation.cause.span;
let mut long_ty_file = None;
let mut err = match *error {
SelectionError::Unimplemented => {
@ -169,11 +170,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Err(guar) = self.fn_arg_obligation(&obligation) {
return guar;
}
let mut file = None;
let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| {
let t = self.tcx.short_ty_string(t, &mut file);
let t = self.tcx.short_string(t, &mut long_ty_file);
(
format!(" in `{t}`"),
format!("within `{t}`, "),
@ -181,12 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
)
})
.unwrap_or_default();
let file_note = file.as_ref().map(|file| format!(
"the full trait has been written to '{}'",
file.display(),
));
let mut long_ty_file = None;
let OnUnimplementedNote {
message,
@ -223,6 +217,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
None,
append_const_msg,
post_message,
&mut long_ty_file,
);
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
@ -251,14 +246,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
*err.long_ty_path() = long_ty_file;
if let Some(long_ty_file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
long_ty_file.display(),
));
err.note("consider using `--verbose` to print the full type name to the console");
}
let mut suggested = false;
if is_try_conversion {
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
@ -309,7 +298,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return err.emit();
}
file_note.map(|note| err.note(note));
if let Some(s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
@ -762,14 +750,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref: predicate.trait_ref,
polarity: ty::PredicatePolarity::Positive,
});
let mut file = None;
let err_msg = self.get_standard_error_message(
trait_ref,
None,
Some(predicate.constness()),
None,
String::new(),
&mut file,
);
let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
*diag.long_ty_path() = file;
if !self.predicate_may_hold(&Obligation::new(
self.tcx,
ObligationCause::dummy(),
@ -1381,6 +1372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
_ => (None, error.err),
};
let mut file = None;
let (msg, span, closure_span) = values
.and_then(|(predicate, normalized_term, expected_term)| {
self.maybe_detailed_projection_msg(
@ -1388,24 +1380,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
predicate,
normalized_term,
expected_term,
&mut file,
)
})
.unwrap_or_else(|| {
let mut cx = FmtPrinter::new_with_limit(
self.tcx,
Namespace::TypeNS,
rustc_session::Limit(10),
);
(
with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
cx.into_buffer()
})),
with_forced_trimmed_paths!(format!(
"type mismatch resolving `{}`",
self.tcx
.short_string(self.resolve_vars_if_possible(predicate), &mut file),
)),
obligation.cause.span,
None,
)
});
let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}");
*diag.long_ty_path() = file;
if let Some(span) = closure_span {
// Mark the closure decl so that it is seen even if we are pointing at the return
// type or expression.
@ -1471,15 +1461,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
ty.span,
with_forced_trimmed_paths!(Cow::from(format!(
"type mismatch resolving `{}`",
{
let mut cx = FmtPrinter::new_with_limit(
self.tcx,
Namespace::TypeNS,
rustc_session::Limit(5),
);
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
cx.into_buffer()
}
self.tcx.short_string(
self.resolve_vars_if_possible(predicate),
diag.long_ty_path()
),
))),
true,
)),
@ -1512,6 +1497,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
projection_term: ty::AliasTerm<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
file: &mut Option<PathBuf>,
) -> Option<(String, Span, Option<Span>)> {
let trait_def_id = projection_term.trait_def_id(self.tcx);
let self_ty = projection_term.self_ty();
@ -1552,7 +1538,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
let item = match self_ty.kind() {
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
_ => self_ty.to_string(),
_ => self.tcx.short_string(self_ty, file),
};
Some((format!(
"expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
@ -1984,8 +1970,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
StringPart::normal(" implemented for `"),
]);
if types_content.0 == types_content.1 {
let ty =
self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None);
let ty = self
.tcx
.short_string(obligation_trait_ref.self_ty(), err.long_ty_path());
msg.push(StringPart::normal(ty));
} else {
msg.extend(types.0.0);
@ -2342,7 +2329,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// First, attempt to add note to this error with an async-await-specific
// message, and fall back to regular note otherwise.
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@ -2351,15 +2337,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
&mut long_ty_file,
);
if let Some(file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
err.note("consider using `--verbose` to print the full type name to the console");
}
self.suggest_unsized_bound_if_applicable(err, obligation);
if let Some(span) = err.span.primary_span()
&& let Some(mut diag) =
@ -2403,6 +2381,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
predicate_constness: Option<ty::BoundConstness>,
append_const_msg: Option<AppendConstMessage>,
post_message: String,
long_ty_file: &mut Option<PathBuf>,
) -> String {
message
.and_then(|cannot_do_this| {
@ -2426,7 +2405,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.unwrap_or_else(|| {
format!(
"the trait bound `{}` is not satisfied{post_message}",
trait_predicate.print_with_bound_constness(predicate_constness)
self.tcx.short_string(
trait_predicate.print_with_bound_constness(predicate_constness),
long_ty_file,
),
)
})
}

View file

@ -306,7 +306,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..) = code
{
let mut long_ty_file = None;
self.note_obligation_cause_code(
error.obligation.cause.body_id,
&mut diag,
@ -315,17 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
code,
&mut vec![],
&mut Default::default(),
&mut long_ty_file,
);
if let Some(file) = long_ty_file {
diag.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
diag.note(
"consider using `--verbose` to print the full type name to the console",
);
}
}
diag.emit()
}

View file

@ -932,7 +932,7 @@ impl<'tcx> OnUnimplementedFormatString {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
if let Some(ty) = trait_ref.args[param.index as usize].as_type() {
tcx.short_ty_string(ty, long_ty_file)
tcx.short_string(ty, long_ty_file)
} else {
trait_ref.args[param.index as usize].to_string()
}

View file

@ -141,7 +141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation.cause.span,
suggest_increasing_limit,
|err| {
let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@ -150,17 +149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
&mut long_ty_file,
);
if let Some(file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
err.note(
"consider using `--verbose` to print the full type name to the console",
);
}
},
);
}

View file

@ -3,7 +3,6 @@
use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::iter;
use std::path::PathBuf;
use itertools::{EitherOrBoth, Itertools};
use rustc_abi::ExternAbi;
@ -1297,30 +1296,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Because of this, we modify the error to refer to the original obligation and
// return early in the caller.
let msg = format!("the trait bound `{old_pred}` is not satisfied");
let msg = format!(
"the trait bound `{}` is not satisfied",
self.tcx.short_string(old_pred, err.long_ty_path()),
);
let self_ty_str =
self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
if has_custom_message {
err.note(msg);
} else {
err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
}
let mut file = None;
err.span_label(
span,
format!(
"the trait `{}` is not implemented for `{}`",
old_pred.print_modifiers_and_trait_path(),
self.tcx.short_ty_string(old_pred.self_ty().skip_binder(), &mut file),
"the trait `{}` is not implemented for `{self_ty_str}`",
old_pred.print_modifiers_and_trait_path()
),
);
if let Some(file) = file {
err.note(format!(
"the full type name has been written to '{}'",
file.display()
));
err.note(
"consider using `--verbose` to print full type name to the console",
);
}
if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
err.span_suggestions(
@ -2689,7 +2682,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Add a note for the item obligation that remains - normally a note pointing to the
// bound that introduced the obligation (e.g. `T: Send`).
debug!(?next_code);
let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@ -2698,7 +2690,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
next_code.unwrap(),
&mut Vec::new(),
&mut Default::default(),
&mut long_ty_file,
);
}
@ -2711,7 +2702,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
long_ty_file: &mut Option<PathBuf>,
) where
T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
{
@ -2965,9 +2955,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
ObligationCauseCode::Coercion { source, target } => {
let source =
tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
tcx.short_string(self.resolve_vars_if_possible(source), err.long_ty_path());
let target =
tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file);
tcx.short_string(self.resolve_vars_if_possible(target), err.long_ty_path());
err.note(with_forced_trimmed_paths!(format!(
"required for the cast from `{source}` to `{target}`",
)));
@ -3252,7 +3242,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
if !is_upvar_tys_infer_tuple {
let ty_str = tcx.short_ty_string(ty, long_ty_file);
let ty_str = tcx.short_string(ty, err.long_ty_path());
let msg = format!("required because it appears within the type `{ty_str}`");
match ty.kind() {
ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
@ -3330,7 +3320,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&data.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
} else {
@ -3343,7 +3332,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
cause_code.peel_derives(),
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
@ -3353,7 +3341,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
let parent_def_id = parent_trait_pred.def_id();
let self_ty_str =
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path());
let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
let mut is_auto_trait = false;
@ -3449,8 +3437,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
count,
pluralize!(count)
));
let self_ty = tcx
.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
let self_ty = tcx.short_string(
parent_trait_pred.skip_binder().self_ty(),
err.long_ty_path(),
);
err.note(format!(
"required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path()
@ -3466,7 +3456,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&data.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
@ -3505,7 +3494,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&data.derived.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
@ -3519,7 +3507,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&data.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
@ -3536,7 +3523,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&data.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
@ -3551,7 +3537,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
nested,
obligated_types,
seen_requirements,
long_ty_file,
)
});
let mut multispan = MultiSpan::from(span);
@ -3582,7 +3567,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
@ -3622,7 +3606,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
ObligationCauseCode::OpaqueReturnType(expr_info) => {
let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file);
let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
let expr = tcx.hir().expect_expr(hir_id);
(expr_ty, expr)
} else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
@ -3637,7 +3621,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
&& self.can_eq(param_env, pred.self_ty(), expr_ty)
{
let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file);
let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
(expr_ty, expr)
} else {
return;
@ -5231,7 +5215,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
format!(
"{pre_message}the trait `{}` is not implemented for{desc} `{}`",
trait_predicate.print_modifiers_and_trait_path(),
tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None),
tcx.short_string(trait_predicate.self_ty().skip_binder(), &mut None),
)
} else {
// "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is

View file

@ -29,7 +29,7 @@ error[E0308]: mismatched types
--> $DIR/coerce-expect-unsized-ascribed.rs:14:27
|
LL | let _ = type_ascribe!(Box::new( { |x| (x as u8) }), Box<dyn Fn(i32) -> _>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:14:39}>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@...}>`
|
= note: expected struct `Box<dyn Fn(i32) -> u8>`
found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:14:39: 14:42}>`
@ -85,7 +85,7 @@ error[E0308]: mismatched types
--> $DIR/coerce-expect-unsized-ascribed.rs:22:27
|
LL | let _ = type_ascribe!(&{ |x| (x as u8) }, &dyn Fn(i32) -> _);
| ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@coerce-expect-unsized-ascribed.rs:22:30}`
| ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@...}`
|
= note: expected reference `&dyn Fn(i32) -> u8`
found reference `&{closure@$DIR/coerce-expect-unsized-ascribed.rs:22:30: 22:33}`
@ -123,7 +123,7 @@ error[E0308]: mismatched types
--> $DIR/coerce-expect-unsized-ascribed.rs:27:27
|
LL | let _ = type_ascribe!(Box::new(|x| (x as u8)), Box<dyn Fn(i32) -> _>);
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:27:36}>`
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@...}>`
|
= note: expected struct `Box<dyn Fn(i32) -> u8>`
found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:27:36: 27:39}>`

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ...>>, ...>>, ...> as Future>::Error == Foo`
error[E0271]: type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
--> $DIR/E0271.rs:20:5
|
LL | / Box::new(
@ -7,14 +7,16 @@ LL | | Err::<(), _>(
LL | | Ok::<_, ()>(
... |
LL | | )
| |_____^ type mismatch resolving `<Result<Result<(), Result<Result<(), ...>, ...>>, ...> as Future>::Error == Foo`
| |_____^ type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
|
note: expected this to be `Foo`
--> $DIR/E0271.rs:10:18
|
LL | type Error = E;
| ^
= note: required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`
= note: required for the cast from `Box<Result<..., ()>>` to `Box<...>`
= note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.ascii/E0271.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error: aborting due to 1 previous error

View file

@ -1,6 +1,6 @@
//@ revisions: ascii unicode
//@[ascii] compile-flags: --diagnostic-width=40
//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40
//@[ascii] compile-flags: --diagnostic-width=40 -Zwrite-long-types-to-disk=yes
//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 -Zwrite-long-types-to-disk=yes
//@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
trait Future {
type Error;

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ...>>, ...>>, ...> as Future>::Error == Foo`
error[E0271]: type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
╭▸ $DIR/E0271.rs:20:5
LL │ ┏ Box::new(
@ -7,14 +7,16 @@ LL │ ┃ Err::<(), _>(
LL │ ┃ Ok::<_, ()>(
‡ ┃
LL │ ┃ )
│ ┗━━━━━┛ type mismatch resolving `<Result<Result<(), Result<Result<(), ...>, ...>>, ...> as Future>::Error == Foo`
│ ┗━━━━━┛ type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
╰╴
note: expected this to be `Foo`
╭▸ $DIR/E0271.rs:10:18
LL │ type Error = E;
│ ━
╰ note: required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`
├ note: required for the cast from `Box<Result<..., ()>>` to `Box<...>`
├ note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.unicode/E0271.long-type-hash.txt'
╰ note: consider using `--verbose` to print the full type name to the console
error: aborting due to 1 previous error

View file

@ -16,11 +16,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok...
LL | | Ok("")
LL | | ))))))))))))))))))))))))))))))
LL | | ))))))))))))))))))))))))))))));
| |__________________________________^ expected `Atype<Btype<..., ...>, ...>`, found `Result<Result<..., ...>, ...>`
| |__________________________________^ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `Result<Result<Result<..., _>, _>, _>`
|
= note: expected struct `Atype<Btype<..., ...>, ...>`
found enum `Result<Result<..., ...>, ...>`
= note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: expected struct `Atype<Btype<..., i32>, i32>`
found enum `Result<Result<..., _>, _>`
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0308]: mismatched types
@ -32,11 +32,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(...
LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
LL | | ))))))))))))))))))))))))))))))
LL | | ))))))))))))))))))))))));
| |____________________________^ expected `Option<Result<..., ...>>`, found `Result<Result<..., ...>, ...>`
| |____________________________^ expected `Option<Result<Option<Option<...>>, _>>`, found `Result<Result<Result<..., _>, _>, _>`
|
= note: expected enum `Option<Result<..., ...>>`
found enum `Result<Result<..., ...>, ...>`
= note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: expected enum `Option<Result<Option<...>, _>>`
found enum `Result<Result<..., _>, _>`
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0308]: mismatched types
@ -50,13 +50,13 @@ LL | | Atype<
... |
LL | | i32
LL | | > = ();
| | - ^^ expected `Atype<Btype<..., ...>, ...>`, found `()`
| | - ^^ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `()`
| |_____|
| expected due to this
|
= note: expected struct `Atype<Btype<..., ...>, ...>`
= note: expected struct `Atype<Btype<..., i32>, i32>`
found unit type `()`
= note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0308]: mismatched types
@ -70,11 +70,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(...
LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
LL | | ))))))))))))))))))))))))))))))
LL | | ))))))))))))))))))))))));
| |____________________________^ expected `()`, found `Result<Result<..., ...>, ...>`
| |____________________________^ expected `()`, found `Result<Result<Result<..., _>, _>, _>`
|
= note: expected unit type `()`
found enum `Result<Result<..., ...>, ...>`
= note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
found enum `Result<Result<..., _>, _>`
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error: aborting due to 4 previous errors

View file

@ -16,11 +16,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O…
LL │ ┃ Ok("")
LL │ ┃ ))))))))))))))))))))))))))))))
LL │ ┃ ))))))))))))))))))))))))))))));
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype<Btype<..., ...>, ...>`, found `Result<Result<..., ...>, ...>`
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `Result<Result<Result<..., _>, _>, _>`
├ note: expected struct `Atype<Btype<..., ...>, ...>`
│ found enum `Result<Result<..., ...>, ...>`
├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
├ note: expected struct `Atype<Btype<..., i32>, i32>`
│ found enum `Result<Result<..., _>, _>`
├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
╰ note: consider using `--verbose` to print the full type name to the console
error[E0308]: mismatched types
@ -32,11 +32,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok…
LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
LL │ ┃ ))))))))))))))))))))))))))))))
LL │ ┃ ))))))))))))))))))))))));
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option<Result<..., ...>>`, found `Result<Result<..., ...>, ...>`
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option<Result<Option<Option<...>>, _>>`, found `Result<Result<Result<..., _>, _>, _>`
├ note: expected enum `Option<Result<..., ...>>`
│ found enum `Result<Result<..., ...>, ...>`
├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
├ note: expected enum `Option<Result<Option<...>, _>>`
│ found enum `Result<Result<..., _>, _>`
├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
╰ note: consider using `--verbose` to print the full type name to the console
error[E0308]: mismatched types
@ -50,13 +50,13 @@ LL │ │ Atype<
‡ │
LL │ │ i32
LL │ │ > = ();
│ │ │ ━━ expected `Atype<Btype<..., ...>, ...>`, found `()`
│ │ │ ━━ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `()`
│ └─────┤
│ expected due to this
├ note: expected struct `Atype<Btype<..., ...>, ...>`
├ note: expected struct `Atype<Btype<..., i32>, i32>`
│ found unit type `()`
├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
╰ note: consider using `--verbose` to print the full type name to the console
error[E0308]: mismatched types
@ -70,11 +70,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok…
LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
LL │ ┃ ))))))))))))))))))))))))))))))
LL │ ┃ ))))))))))))))))))))))));
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result<Result<..., ...>, ...>`
│ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result<Result<Result<..., _>, _>, _>`
├ note: expected unit type `()`
│ found enum `Result<Result<..., ...>, ...>`
├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
│ found enum `Result<Result<..., _>, _>`
├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
╰ note: consider using `--verbose` to print the full type name to the console
error: aborting due to 4 previous errors

View file

@ -0,0 +1,15 @@
//@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
// The regex below normalizes the long type file name to make it suitable for compare-modes.
//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'"
type A = (i32, i32, i32, i32);
type B = (A, A, A, A);
type C = (B, B, B, B);
type D = (C, C, C, C);
trait Trait {}
fn require_trait<T: Trait>() {}
fn main() {
require_trait::<D>(); //~ ERROR the trait bound `(...
}

View file

@ -0,0 +1,23 @@
error[E0277]: the trait bound `(..., ..., ..., ...): Trait` is not satisfied
--> $DIR/long-e0277.rs:14:21
|
LL | require_trait::<D>();
| ^ unsatisfied trait bound
|
= help: the trait `Trait` is not implemented for `(..., ..., ..., ...)`
help: this trait has no implementations, consider adding one
--> $DIR/long-e0277.rs:9:1
|
LL | trait Trait {}
| ^^^^^^^^^^^
note: required by a bound in `require_trait`
--> $DIR/long-e0277.rs:11:21
|
LL | fn require_trait<T: Trait>() {}
| ^^^^^ required by this bound in `require_trait`
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -2,13 +2,13 @@ error[E0382]: use of moved value: `x`
--> $DIR/non-copy-type-moved.rs:16:14
|
LL | fn foo(x: D) {
| - move occurs because `x` has type `((..., ..., ..., ...), ..., ..., ...)`, which does not implement the `Copy` trait
| - move occurs because `x` has type `(..., ..., ..., ...)`, which does not implement the `Copy` trait
LL | let _a = x;
| - value moved here
LL | let _b = x;
| ^ value used here after move
|
= note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
help: consider cloning the value if the performance cost is acceptable
|

View file

@ -12,7 +12,7 @@ fn foo(x: D) {
//~^ NOTE this expression has type `((...,
//~| NOTE expected `((...,
//~| NOTE expected tuple
//~| NOTE the full type name has been written to
//~| NOTE the full name for the type has been written to
//~| NOTE consider using `--verbose` to print the full type name to the console
}

View file

@ -8,7 +8,7 @@ LL | let () = x;
|
= note: expected tuple `((..., ..., ..., ...), ..., ..., ...)`
found unit type `()`
= note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
error: aborting due to 1 previous error

View file

@ -11,7 +11,7 @@ LL | | ),
LL | | ) {
| |_- expected `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` because of return type
LL | f
| ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&...)))`, found `&dyn Fn(u32)`
| ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&...))))`, found `&dyn Fn(u32)`
|
= note: expected reference `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))`
found reference `&dyn Fn(u32)`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/box-future-wrong-output.rs:20:39
|
LL | let _: BoxFuture<'static, bool> = async {}.boxed();
| ------------------------ ^^^^^^^^^^^^^^^^ expected `bool`, found `()`
| ------------------------ ^^^^^^^^^^^^^^^^ expected `Pin<Box<...>>`, found `Pin<Box<dyn Future<Output = ()> + Send>>`
| |
| expected due to this
|

View file

@ -32,7 +32,7 @@ error[E0308]: mismatched types
LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
| - found this type parameter
LL | Pin::new(x)
| -------- ^ expected `Box<dyn Future<Output = ...> + Send>`, found type parameter `F`
| -------- ^ expected `Box<dyn Future<Output = i32> + Send>`, found type parameter `F`
| |
| arguments to this function are incorrect
| help: use `Box::pin` to pin and box this expression: `Box::pin`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-107860.rs:3:36
|
LL | async fn str<T>(T: &str) -> &str { &str }
| ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<...>}`
| ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<_>}`
|
= note: expected reference `&str`
found reference `&for<'a> fn(&'a str) -> impl Future<Output = &'a str> {str::<_>}`

View file

@ -2,7 +2,7 @@ error[E0271]: type mismatch resolving `<dyn Pointee<Metadata = ()> as Pointee>::
--> $DIR/ice-with-dyn-pointee-errors.rs:9:33
|
LL | unknown_sized_object_ptr_in(x)
| --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ...>>`
| --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ()>>`
| |
| required by a bound introduced by this call
|

View file

@ -110,7 +110,7 @@ error[E0308]: mismatched types
--> $DIR/pretty.rs:36:79
|
LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x }
| - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>`
| - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = &u8>`
| |
| help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
|
@ -132,7 +132,7 @@ error[E0308]: mismatched types
--> $DIR/pretty.rs:38:73
|
LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x }
| - ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>`
| - ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = u8>`
| |
| help: try adding a return type: `-> &dyn AnyDifferentBinders<Assoc = u8>`
|

View file

@ -13,8 +13,6 @@ LL | | ))))))))))),
LL | | )))))))))))
| |_______________- return type was inferred to be `Option<Option<Option<...>>>` here
|
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
= note: consider using `--verbose` to print the full type name to the console
= help: the trait `std::fmt::Display` is not implemented for `Option<Option<Option<...>>>`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'

View file

@ -6,7 +6,7 @@ LL | map.insert(1, Struct::do_something);
| |
| ... which causes `map` to have type `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
LL | Self { map }
| ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>`
| ^^^ expected `HashMap<u16, fn(u8) -> Pin<Box<...>>>`, found `HashMap<{integer}, ...>`
|
= note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`

View file

@ -2,7 +2,7 @@
fn foo() { //~ HELP try adding a return type
vec!['a'].iter().map(|c| c)
//~^ ERROR mismatched types [E0308]
//~| NOTE expected `()`, found `Map<Iter<'_, char>, ...>`
//~| NOTE expected `()`, found `Map<Iter<'_, char>, {closure@...}>`
//~| NOTE expected unit type `()`
//~| HELP consider using a semicolon here
}

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/return_type_containing_closure.rs:3:5
|
LL | vec!['a'].iter().map(|c| c)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map<Iter<'_, char>, ...>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map<Iter<'_, char>, {closure@...}>`
|
= note: expected unit type `()`
found struct `Map<std::slice::Iter<'_, char>, {closure@$DIR/return_type_containing_closure.rs:3:26: 3:29}>`