1
Fork 0

Rollup merge of #121739 - jieyouxu:loooong-typename, r=estebank

Display short types for unimplemented trait

Shortens unimplemented trait diagnostics. Now shows:

```
error[E0277]: `Option<Option<Option<...>>>` doesn't implement `std::fmt::Display`
  --> $DIR/on_unimplemented_long_types.rs:4:17
   |
LL |   pub fn foo() -> impl std::fmt::Display {
   |                   ^^^^^^^^^^^^^^^^^^^^^^ `Option<Option<Option<...>>>` cannot be formatted with the default formatter
LL |
LL | /     Some(Some(Some(Some(Some(Some(Some(Some(Some(S...
LL | |         Some(Some(Some(Some(Some(Some(Some(Some(So...
LL | |             Some(Some(Some(Some(Some(Some(Some(Som...
LL | |                 Some(Some(Some(Some(Some(Some(Some...
...  |
LL | |         ))))))))))),
LL | |     )))))))))))
   | |_______________- return type was inferred to be `Option<Option<Option<...>>>` here
   |
   = 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

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
```

I'm not 100% sure if this is desirable, or if we should just let the long types remain long. This is also kinda a short-term bandaid solution. The real long term solution is to properly migrate `rustc_trait_selection`'s error reporting to use translatable diagnostics and then properly handle type name printing.

Fixes #121687.
This commit is contained in:
Matthias Krüger 2024-03-02 10:09:36 +01:00 committed by GitHub
commit 3432d1b087
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 117 additions and 50 deletions

View file

@ -1049,6 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n"); bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
let actual_prefix = rcvr_ty.prefix_string(self.tcx); let actual_prefix = rcvr_ty.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len()); info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
let mut long_ty_file = None;
let (primary_message, label) = if unimplemented_traits.len() == 1 let (primary_message, label) = if unimplemented_traits.len() == 1
&& unimplemented_traits_only && unimplemented_traits_only
{ {
@ -1061,8 +1062,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Avoid crashing. // Avoid crashing.
return (None, None); return (None, None);
} }
let OnUnimplementedNote { message, label, .. } = let OnUnimplementedNote { message, label, .. } = self
self.err_ctxt().on_unimplemented_note(trait_ref, &obligation); .err_ctxt()
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
(message, label) (message, label)
}) })
.unwrap() .unwrap()
@ -1076,6 +1078,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) )
}); });
err.primary_message(primary_message); 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 { if let Some(label) = label {
custom_span_label = true; custom_span_label = true;
err.span_label(span, label); err.span_label(span, label);

View file

@ -16,6 +16,7 @@ use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span; use rustc_span::Span;
use std::iter; use std::iter;
use std::path::PathBuf;
use crate::errors::{ use crate::errors::{
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
@ -110,6 +111,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&self, &self,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
long_ty_file: &mut Option<PathBuf>,
) -> OnUnimplementedNote { ) -> OnUnimplementedNote {
let (def_id, args) = self let (def_id, args) = self
.impl_similar_to(trait_ref, obligation) .impl_similar_to(trait_ref, obligation)
@ -265,7 +267,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
})); }));
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_ref, &flags) command.evaluate(self.tcx, trait_ref, &flags, long_ty_file)
} else { } else {
OnUnimplementedNote::default() OnUnimplementedNote::default()
} }
@ -657,6 +659,7 @@ impl<'tcx> OnUnimplementedDirective {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>, trait_ref: ty::TraitRef<'tcx>,
options: &[(Symbol, Option<String>)], options: &[(Symbol, Option<String>)],
long_ty_file: &mut Option<PathBuf>,
) -> OnUnimplementedNote { ) -> OnUnimplementedNote {
let mut message = None; let mut message = None;
let mut label = None; let mut label = None;
@ -669,6 +672,7 @@ impl<'tcx> OnUnimplementedDirective {
options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect(); options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect();
for command in self.subcommands.iter().chain(Some(self)).rev() { for command in self.subcommands.iter().chain(Some(self)).rev() {
debug!(?command);
if let Some(ref condition) = command.condition if let Some(ref condition) = command.condition
&& !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| { && !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| {
let value = cfg.value.map(|v| { let value = cfg.value.map(|v| {
@ -680,7 +684,12 @@ impl<'tcx> OnUnimplementedDirective {
span: cfg.span, span: cfg.span,
is_diagnostic_namespace_variant: false is_diagnostic_namespace_variant: false
} }
.format(tcx, trait_ref, &options_map) .format(
tcx,
trait_ref,
&options_map,
long_ty_file
)
) )
}); });
@ -709,10 +718,14 @@ impl<'tcx> OnUnimplementedDirective {
} }
OnUnimplementedNote { OnUnimplementedNote {
label: label.map(|l| l.format(tcx, trait_ref, &options_map)), label: label.map(|l| l.format(tcx, trait_ref, &options_map, long_ty_file)),
message: message.map(|m| m.format(tcx, trait_ref, &options_map)), message: message.map(|m| m.format(tcx, trait_ref, &options_map, long_ty_file)),
notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, &options_map)).collect(), notes: notes
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), .into_iter()
.map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file))
.collect(),
parent_label: parent_label
.map(|e_s| e_s.format(tcx, trait_ref, &options_map, long_ty_file)),
append_const_msg, append_const_msg,
} }
} }
@ -814,6 +827,7 @@ impl<'tcx> OnUnimplementedFormatString {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>, trait_ref: ty::TraitRef<'tcx>,
options: &FxHashMap<Symbol, String>, options: &FxHashMap<Symbol, String>,
long_ty_file: &mut Option<PathBuf>,
) -> String { ) -> String {
let name = tcx.item_name(trait_ref.def_id); let name = tcx.item_name(trait_ref.def_id);
let trait_str = tcx.def_path_str(trait_ref.def_id); let trait_str = tcx.def_path_str(trait_ref.def_id);
@ -824,8 +838,12 @@ impl<'tcx> OnUnimplementedFormatString {
.filter_map(|param| { .filter_map(|param| {
let value = match param.kind { let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { 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)
} else {
trait_ref.args[param.index as usize].to_string() trait_ref.args[param.index as usize].to_string()
} }
}
GenericParamDefKind::Lifetime => return None, GenericParamDefKind::Lifetime => return None,
}; };
let name = param.name; let name = param.name;

View file

@ -2671,6 +2671,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
) where ) where
T: ToPredicate<'tcx>, T: ToPredicate<'tcx>,
{ {
let mut long_ty_file = None;
let tcx = self.tcx; let tcx = self.tcx;
let predicate = predicate.to_predicate(tcx); let predicate = predicate.to_predicate(tcx);
match *cause_code { match *cause_code {
@ -2853,21 +2855,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
} }
ObligationCauseCode::Coercion { source, target } => { ObligationCauseCode::Coercion { source, target } => {
let mut file = None; let source =
let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file); tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file);
let target = tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file); let target =
tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut long_ty_file);
err.note(with_forced_trimmed_paths!(format!( err.note(with_forced_trimmed_paths!(format!(
"required for the cast from `{source}` to `{target}`", "required for the cast from `{source}` to `{target}`",
))); )));
if let Some(file) = 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",
);
}
} }
ObligationCauseCode::RepeatElementCopy { ObligationCauseCode::RepeatElementCopy {
is_constable, is_constable,
@ -3170,8 +3164,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Don't print the tuple of capture types // Don't print the tuple of capture types
'print: { 'print: {
if !is_upvar_tys_infer_tuple { if !is_upvar_tys_infer_tuple {
let mut file = None; let ty_str = tcx.short_ty_string(ty, &mut long_ty_file);
let ty_str = tcx.short_ty_string(ty, &mut file);
let msg = format!("required because it appears within the type `{ty_str}`"); let msg = format!("required because it appears within the type `{ty_str}`");
match ty.kind() { match ty.kind() {
ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
@ -3269,9 +3262,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut parent_trait_pred = let mut parent_trait_pred =
self.resolve_vars_if_possible(data.derived.parent_trait_pred); self.resolve_vars_if_possible(data.derived.parent_trait_pred);
let parent_def_id = parent_trait_pred.def_id(); let parent_def_id = parent_trait_pred.def_id();
let mut file = None; let self_ty_str = tcx
let self_ty_str = .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut long_ty_file);
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); 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 msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
let mut is_auto_trait = false; let mut is_auto_trait = false;
@ -3329,15 +3321,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
}; };
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",
);
}
let mut parent_predicate = parent_trait_pred; let mut parent_predicate = parent_trait_pred;
let mut data = &data.derived; let mut data = &data.derived;
let mut count = 0; let mut count = 0;
@ -3378,22 +3361,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
count, count,
pluralize!(count) pluralize!(count)
)); ));
let mut file = None; let self_ty = tcx.short_ty_string(
let self_ty = parent_trait_pred.skip_binder().self_ty(),
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); &mut long_ty_file,
);
err.note(format!( err.note(format!(
"required for `{self_ty}` to implement `{}`", "required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path() parent_trait_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 the full type name to the console",
);
}
} }
// #74711: avoid a stack overflow // #74711: avoid a stack overflow
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
@ -3502,7 +3477,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
ObligationCauseCode::OpaqueReturnType(expr_info) => { ObligationCauseCode::OpaqueReturnType(expr_info) => {
if let Some((expr_ty, expr_span)) = expr_info { if let Some((expr_ty, expr_span)) = expr_info {
let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty)); let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
err.span_label( err.span_label(
expr_span, expr_span,
with_forced_trimmed_paths!(format!( with_forced_trimmed_paths!(format!(
@ -3512,6 +3487,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
} }
} }
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");
}
} }
#[instrument( #[instrument(

View file

@ -395,6 +395,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
kind: _, kind: _,
} = *obligation.cause.code() } = *obligation.cause.code()
{ {
debug!("ObligationCauseCode::CompareImplItemObligation");
return self.report_extra_impl_obligation( return self.report_extra_impl_obligation(
span, span,
impl_item_def_id, impl_item_def_id,
@ -445,18 +446,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
) )
}) })
.unwrap_or_default(); .unwrap_or_default();
let file_note = file.map(|file| format!( let file_note = file.as_ref().map(|file| format!(
"the full trait has been written to '{}'", "the full trait has been written to '{}'",
file.display(), file.display(),
)); ));
let mut long_ty_file = None;
let OnUnimplementedNote { let OnUnimplementedNote {
message, message,
label, label,
notes, notes,
parent_label, parent_label,
append_const_msg, append_const_msg,
} = self.on_unimplemented_note(trait_ref, &obligation); } = self.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
let have_alt_message = message.is_some() || label.is_some(); let have_alt_message = message.is_some() || label.is_some();
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
let is_unsize = let is_unsize =
@ -511,6 +515,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
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; let mut suggested = false;
if is_try_conversion { if is_try_conversion {
suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err);
@ -758,6 +769,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return err.emit(); return err.emit();
} }
err err
} }

View file

@ -0,0 +1,17 @@
//@ compile-flags: --diagnostic-width=60 -Z write-long-types-to-disk=yes
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
pub fn foo() -> impl std::fmt::Display {
//~^ ERROR doesn't implement `std::fmt::Display`
Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
Some(Some(Some(Some(Some(Some(Some(Some(())))))))),
))))))))))),
))))))))))),
))))))))))),
)))))))))))
}
fn main() {}

View file

@ -0,0 +1,25 @@
error[E0277]: `Option<Option<Option<...>>>` doesn't implement `std::fmt::Display`
--> $DIR/on_unimplemented_long_types.rs:4:17
|
LL | pub fn foo() -> impl std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^^ `Option<Option<Option<...>>>` cannot be formatted with the default formatter
LL |
LL | / Some(Some(Some(Some(Some(Some(Some(Some(Some(S...
LL | | Some(Some(Some(Some(Some(Some(Some(Some(So...
LL | | Some(Some(Some(Some(Some(Some(Some(Som...
LL | | Some(Some(Some(Some(Some(Some(Some...
... |
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/traits/on_unimplemented_long_types/on_unimplemented_long_types.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/traits/on_unimplemented_long_types/on_unimplemented_long_types.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`.