Skip to content

Commit 9919665

Browse files
committed
Use tcx.short_string() in more diagnostics
`TyCtxt::short_string` ensures that user visible type paths aren't overwhelming on the terminal output, and properly saves the long name to disk as a side-channel. We already use these throughout the compiler and have been using them as needed when users find cases where the output is verbose. This is a proactive search of some cases to use `short_string`. We add support for shortening the path of "trait path only". Every manual use of `short_string` is a bright marker that that error should be using structured diagnostics instead (as they have proper handling of long types without the maintainer having to think abou tthem). When we don't actually print out a shortened type we don't need the "use `--verbose`" note. On E0599 show type identity to avoid expanding the receiver's generic parameters. Unify wording on `long_ty_path` everywhere.
1 parent 2fd855f commit 9919665

File tree

68 files changed

+397
-339
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+397
-339
lines changed

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
13821382
&mut self.long_ty_path
13831383
}
13841384

1385+
pub fn with_long_ty_path(mut self, long_ty_path: Option<PathBuf>) -> Self {
1386+
self.long_ty_path = long_ty_path;
1387+
self
1388+
}
1389+
13851390
/// Most `emit_producing_guarantee` functions use this as a starting point.
13861391
fn emit_producing_nothing(mut self) {
13871392
let diag = self.take_diag();

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,9 +1135,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11351135
);
11361136
}
11371137
} else {
1138+
let trait_ =
1139+
tcx.short_string(bound.print_only_trait_path(), err.long_ty_path());
11381140
err.note(format!(
1139-
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`",
1140-
bound.print_only_trait_path(),
1141+
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`",
11411142
));
11421143
}
11431144
}

compiler/rustc_hir_typeck/messages.ftl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ hir_typeck_lossy_provenance_ptr2int =
159159
.suggestion = use `.addr()` to obtain the address of a pointer
160160
.help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
161161
162-
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
162+
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty}`
163163
164164
hir_typeck_naked_asm_outside_naked_fn =
165165
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
@@ -184,7 +184,7 @@ hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback af
184184
hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access
185185
.help = specify the type explicitly
186186
187-
hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
187+
hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty}`{$trait_missing_method ->
188188
[true] {""}
189189
*[other] {" "}in the current scope
190190
}

compiler/rustc_hir_typeck/src/errors.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ pub(crate) enum ExplicitDestructorCallSugg {
200200

201201
#[derive(Diagnostic)]
202202
#[diag(hir_typeck_missing_parentheses_in_range, code = E0689)]
203-
pub(crate) struct MissingParenthesesInRange {
203+
pub(crate) struct MissingParenthesesInRange<'tcx> {
204204
#[primary_span]
205205
#[label(hir_typeck_missing_parentheses_in_range)]
206206
pub span: Span,
207-
pub ty_str: String,
207+
pub ty: Ty<'tcx>,
208208
pub method_name: String,
209209
#[subdiagnostic]
210210
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
@@ -828,13 +828,13 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
828828

829829
#[derive(Diagnostic)]
830830
#[diag(hir_typeck_no_associated_item, code = E0599)]
831-
pub(crate) struct NoAssociatedItem {
831+
pub(crate) struct NoAssociatedItem<'tcx> {
832832
#[primary_span]
833833
pub span: Span,
834834
pub item_kind: &'static str,
835835
pub item_ident: Ident,
836836
pub ty_prefix: Cow<'static, str>,
837-
pub ty_str: String,
837+
pub ty: Ty<'tcx>,
838838
pub trait_missing_method: bool,
839839
}
840840

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 53 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -376,16 +376,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
376376
}
377377
}
378378

379-
fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
380-
let mut file = None;
379+
fn suggest_missing_writer(
380+
&self,
381+
rcvr_ty: Ty<'tcx>,
382+
rcvr_expr: &hir::Expr<'tcx>,
383+
mut long_ty_path: Option<PathBuf>,
384+
) -> Diag<'_> {
381385
let mut err = struct_span_code_err!(
382386
self.dcx(),
383387
rcvr_expr.span,
384388
E0599,
385389
"cannot write into `{}`",
386-
self.tcx.short_string(rcvr_ty, &mut file),
390+
self.tcx.short_string(rcvr_ty, &mut long_ty_path),
387391
);
388-
*err.long_ty_path() = file;
392+
*err.long_ty_path() = long_ty_path;
389393
err.span_note(
390394
rcvr_expr.span,
391395
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
@@ -403,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
403407
&self,
404408
self_source: SelfSource<'tcx>,
405409
method_name: Ident,
406-
ty_str_reported: &str,
410+
ty: Ty<'tcx>,
407411
err: &mut Diag<'_>,
408412
) {
409413
#[derive(Debug)]
@@ -478,7 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
478482
}
479483

480484
// If the shadowed binding has an itializer expression,
481-
// use the initializer expression'ty to try to find the method again.
485+
// use the initializer expression's ty to try to find the method again.
482486
// For example like: `let mut x = Vec::new();`,
483487
// `Vec::new()` is the itializer expression.
484488
if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
@@ -566,17 +570,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
566570
let mut span = MultiSpan::from_span(sugg_let.span);
567571
span.push_span_label(sugg_let.span,
568572
format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
573+
574+
let ty = self.tcx.short_string(ty, err.long_ty_path());
569575
span.push_span_label(
570576
self.tcx.hir_span(recv_id),
571-
format!(
572-
"earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
573-
),
577+
format!("earlier `{rcvr_name}` shadowed here with type `{ty}`"),
574578
);
575579
err.span_note(
576580
span,
577581
format!(
578582
"there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
579-
that has method `{method_name}` available"
583+
that has method `{method_name}` available"
580584
),
581585
);
582586
}
@@ -602,15 +606,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
602606
let tcx = self.tcx;
603607
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
604608
let mut ty_file = None;
605-
let (ty_str, short_ty_str) =
606-
if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
607-
(predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
608-
} else {
609-
(
610-
tcx.short_string(rcvr_ty, &mut ty_file),
611-
with_forced_trimmed_paths!(rcvr_ty.to_string()),
612-
)
613-
};
614609
let is_method = mode == Mode::MethodCall;
615610
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
616611
let similar_candidate = no_match_data.similar_candidate;
@@ -629,15 +624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
629624

630625
// We could pass the file for long types into these two, but it isn't strictly necessary
631626
// given how targeted they are.
632-
if let Err(guar) = self.report_failed_method_call_on_range_end(
633-
tcx,
634-
rcvr_ty,
635-
source,
636-
span,
637-
item_ident,
638-
&short_ty_str,
639-
&mut ty_file,
640-
) {
627+
if let Err(guar) =
628+
self.report_failed_method_call_on_range_end(tcx, rcvr_ty, source, span, item_ident)
629+
{
641630
return guar;
642631
}
643632
if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var(
@@ -647,44 +636,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
647636
span,
648637
item_kind,
649638
item_ident,
650-
&short_ty_str,
651639
&mut ty_file,
652640
) {
653641
return guar;
654642
}
655643
span = item_ident.span;
656644

657-
// Don't show generic arguments when the method can't be found in any implementation (#81576).
658-
let mut ty_str_reported = ty_str.clone();
659-
if let ty::Adt(_, generics) = rcvr_ty.kind() {
660-
if generics.len() > 0 {
661-
let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
662-
let candidate_found = autoderef.any(|(ty, _)| {
663-
if let ty::Adt(adt_def, _) = ty.kind() {
664-
self.tcx
665-
.inherent_impls(adt_def.did())
666-
.into_iter()
667-
.any(|def_id| self.associated_value(*def_id, item_ident).is_some())
668-
} else {
669-
false
670-
}
671-
});
672-
let has_deref = autoderef.step_count() > 0;
673-
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
674-
if let Some((path_string, _)) = ty_str.split_once('<') {
675-
ty_str_reported = path_string.to_string();
676-
}
677-
}
678-
}
679-
}
680-
681645
let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
682646
tcx.is_diagnostic_item(sym::write_macro, def_id)
683647
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
684648
}) && item_ident.name == sym::write_fmt;
685649
let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
686-
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
650+
self.suggest_missing_writer(rcvr_ty, rcvr_expr, ty_file)
687651
} else {
652+
// Don't show expanded generic arguments when the method can't be found in any
653+
// implementation (#81576).
654+
let mut ty = rcvr_ty;
655+
if let ty::Adt(def, generics) = rcvr_ty.kind() {
656+
if generics.len() > 0 {
657+
let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
658+
let candidate_found = autoderef.any(|(ty, _)| {
659+
if let ty::Adt(adt_def, _) = ty.kind() {
660+
self.tcx
661+
.inherent_impls(adt_def.did())
662+
.into_iter()
663+
.any(|def_id| self.associated_value(*def_id, item_ident).is_some())
664+
} else {
665+
false
666+
}
667+
});
668+
let has_deref = autoderef.step_count() > 0;
669+
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
670+
ty = self.tcx.at(span).type_of(def.did()).instantiate_identity();
671+
}
672+
}
673+
}
674+
688675
let mut err = self.dcx().create_err(NoAssociatedItem {
689676
span,
690677
item_kind,
@@ -695,16 +682,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
695682
} else {
696683
rcvr_ty.prefix_string(self.tcx)
697684
},
698-
ty_str: ty_str_reported.clone(),
685+
ty,
699686
trait_missing_method,
700687
});
701688

702689
if is_method {
703690
self.suggest_use_shadowed_binding_with_method(
704-
source,
705-
item_ident,
706-
&ty_str_reported,
707-
&mut err,
691+
source, item_ident, rcvr_ty, &mut err,
708692
);
709693
}
710694

@@ -734,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
734718

735719
err
736720
};
721+
737722
if tcx.sess.source_map().is_multiline(sugg_span) {
738723
err.span_label(sugg_span.with_hi(span.lo()), "");
739724
}
@@ -750,6 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
750735
}
751736

752737
if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll {
738+
let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
753739
err.help(format!(
754740
"method `poll` found on `Pin<&mut {ty_str}>`, \
755741
see documentation for `std::pin::Pin`"
@@ -1339,14 +1325,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13391325
}
13401326
let OnUnimplementedNote { message, label, notes, .. } = self
13411327
.err_ctxt()
1342-
.on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
1328+
.on_unimplemented_note(trait_ref, &obligation, err.long_ty_path());
13431329
(message, label, notes)
13441330
})
13451331
.unwrap()
13461332
} else {
13471333
(None, None, Vec::new())
13481334
};
13491335
let primary_message = primary_message.unwrap_or_else(|| {
1336+
let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
13501337
format!(
13511338
"the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \
13521339
but its trait bounds were not satisfied"
@@ -1409,6 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14091396
let mut find_candidate_for_method = false;
14101397

14111398
let mut label_span_not_found = |err: &mut Diag<'_>| {
1399+
let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
14121400
if unsatisfied_predicates.is_empty() {
14131401
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
14141402
let is_string_or_ref_str = match rcvr_ty.kind() {
@@ -2520,8 +2508,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25202508
source: SelfSource<'tcx>,
25212509
span: Span,
25222510
item_name: Ident,
2523-
ty_str: &str,
2524-
long_ty_path: &mut Option<PathBuf>,
25252511
) -> Result<(), ErrorGuaranteed> {
25262512
if let SelfSource::MethodCall(expr) = source {
25272513
for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) {
@@ -2583,18 +2569,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25832569
);
25842570
if pick.is_ok() {
25852571
let range_span = parent_expr.span.with_hi(expr.span.hi());
2586-
let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
2572+
return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
25872573
span,
2588-
ty_str: ty_str.to_string(),
2574+
ty: actual,
25892575
method_name: item_name.as_str().to_string(),
25902576
add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
25912577
func_name: item_name.name.as_str().to_string(),
25922578
left: range_span.shrink_to_lo(),
25932579
right: range_span.shrink_to_hi(),
25942580
}),
2595-
});
2596-
*err.long_ty_path() = long_ty_path.take();
2597-
return Err(err.emit());
2581+
}));
25982582
}
25992583
}
26002584
}
@@ -2610,7 +2594,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26102594
span: Span,
26112595
item_kind: &str,
26122596
item_name: Ident,
2613-
ty_str: &str,
26142597
long_ty_path: &mut Option<PathBuf>,
26152598
) -> Result<(), ErrorGuaranteed> {
26162599
let found_candidate = all_traits(self.tcx)
@@ -2643,14 +2626,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26432626
&& !actual.has_concrete_skeleton()
26442627
&& let SelfSource::MethodCall(expr) = source
26452628
{
2629+
let ty_str = self.tcx.short_string(actual, long_ty_path);
26462630
let mut err = struct_span_code_err!(
26472631
self.dcx(),
26482632
span,
26492633
E0689,
2650-
"can't call {} `{}` on ambiguous numeric type `{}`",
2651-
item_kind,
2652-
item_name,
2653-
ty_str
2634+
"can't call {item_kind} `{item_name}` on ambiguous numeric type `{ty_str}`"
26542635
);
26552636
*err.long_ty_path() = long_ty_path.take();
26562637
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2987,7 +2987,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
29872987
}
29882988
}
29892989

2990-
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2990+
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
29912991
pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);
29922992

29932993
impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {

compiler/rustc_trait_selection/messages.ftl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,6 @@ trait_selection_fps_remove_ref = consider removing the reference
171171
trait_selection_fps_use_ref = consider using a reference
172172
trait_selection_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
173173
174-
trait_selection_full_type_written = the full type name has been written to '{$path}'
175-
176174
trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to previous definition of `{$option_name}`
177175
.other_label = `{$option_name}` is first declared here
178176
.label = `{$option_name}` is already declared here

0 commit comments

Comments
 (0)