Skip to content

Commit 4d2ec8c

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).
1 parent 3014e79 commit 4d2ec8c

37 files changed

+226
-119
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,9 +1129,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11291129
);
11301130
}
11311131
} else {
1132+
let trait_ =
1133+
tcx.short_string(bound.print_only_trait_path(), err.long_ty_path());
11321134
err.note(format!(
1133-
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`",
1134-
bound.print_only_trait_path(),
1135+
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`",
11351136
));
11361137
}
11371138
}

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
375375
}
376376
}
377377

378-
fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
379-
let mut file = None;
378+
fn suggest_missing_writer(
379+
&self,
380+
rcvr_ty: Ty<'tcx>,
381+
rcvr_expr: &hir::Expr<'tcx>,
382+
mut file: Option<PathBuf>,
383+
) -> Diag<'_> {
380384
let mut err = struct_span_code_err!(
381385
self.dcx(),
382386
rcvr_expr.span,
@@ -682,7 +686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
682686
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
683687
}) && item_ident.name == sym::write_fmt;
684688
let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
685-
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
689+
self.suggest_missing_writer(rcvr_ty, rcvr_expr, ty_file)
686690
} else {
687691
let mut err = self.dcx().create_err(NoAssociatedItem {
688692
span,
@@ -697,6 +701,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
697701
ty_str: ty_str_reported.clone(),
698702
trait_missing_method,
699703
});
704+
*err.long_ty_path() = ty_file;
700705

701706
if is_method {
702707
self.suggest_use_shadowed_binding_with_method(
@@ -1338,7 +1343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13381343
}
13391344
let OnUnimplementedNote { message, label, notes, .. } = self
13401345
.err_ctxt()
1341-
.on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
1346+
.on_unimplemented_note(trait_ref, &obligation, err.long_ty_path());
13421347
(message, label, notes)
13431348
})
13441349
.unwrap()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3063,7 +3063,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
30633063
}
30643064
}
30653065

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

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

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
208208
performs a conversion on the error value \
209209
using the `From` trait";
210210
let (message, notes, append_const_msg) = if is_try_conversion {
211+
let ty = self.tcx.short_string(
212+
main_trait_predicate.skip_binder().self_ty(),
213+
&mut long_ty_file,
214+
);
211215
// We have a `-> Result<_, E1>` and `gives_E2()?`.
212216
(
213-
Some(format!(
214-
"`?` couldn't convert the error to `{}`",
215-
main_trait_predicate.skip_binder().self_ty(),
216-
)),
217+
Some(format!("`?` couldn't convert the error to `{ty}`")),
217218
vec![question_mark_message.to_owned()],
218219
Some(AppendConstMessage::Default),
219220
)
220221
} else if is_question_mark {
222+
let main_trait_predicate =
223+
self.tcx.short_string(main_trait_predicate, &mut long_ty_file);
221224
// Similar to the case above, but in this case the conversion is for a
222225
// trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when
223226
// `E: Error` isn't met.
@@ -233,7 +236,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
233236
(message, notes, append_const_msg)
234237
};
235238

236-
let err_msg = self.get_standard_error_message(
239+
let err_msg = || self.get_standard_error_message(
237240
main_trait_predicate,
238241
message,
239242
None,
@@ -258,15 +261,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
258261
);
259262
}
260263
GetSafeTransmuteErrorAndReason::Default => {
261-
(err_msg, None)
264+
(err_msg(), None)
262265
}
263266
GetSafeTransmuteErrorAndReason::Error {
264267
err_msg,
265268
safe_transmute_explanation,
266269
} => (err_msg, safe_transmute_explanation),
267270
}
268271
} else {
269-
(err_msg, None)
272+
(err_msg(), None)
270273
};
271274

272275
let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
@@ -279,15 +282,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
279282

280283
if let Some(ret_span) = self.return_type_span(&obligation) {
281284
if is_try_conversion {
285+
let ty = self.tcx.short_string(
286+
main_trait_predicate.skip_binder().self_ty(),
287+
err.long_ty_path(),
288+
);
282289
err.span_label(
283290
ret_span,
284-
format!(
285-
"expected `{}` because of this",
286-
main_trait_predicate.skip_binder().self_ty()
287-
),
291+
format!("expected `{ty}` because of this"),
288292
);
289293
} else if is_question_mark {
290-
err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this"));
294+
let main_trait_predicate =
295+
self.tcx.short_string(main_trait_predicate, err.long_ty_path());
296+
err.span_label(
297+
ret_span,
298+
format!("required `{main_trait_predicate}` because of this"),
299+
);
291300
}
292301
}
293302

@@ -414,11 +423,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
414423
} else {
415424
vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
416425
};
426+
let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path());
427+
let ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path());
417428
err.multipart_suggestion(
418429
format!(
419-
"the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
420-
cand.print_trait_sugared(),
421-
cand.self_ty(),
430+
"the trait `{trait_}` is implemented for fn pointer \
431+
`{ty}`, try casting using `as`",
422432
),
423433
suggestion,
424434
Applicability::MaybeIncorrect,
@@ -522,7 +532,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
522532
<https://github.com/rust-lang/rust/issues/48950> \
523533
for more information)",
524534
);
525-
err.help("did you intend to use the type `()` here instead?");
535+
err.help("you might have intended to use the type `()` here instead");
526536
}
527537
}
528538

@@ -720,10 +730,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
720730
}
721731

722732
SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => {
733+
let expected_ty_str = self.tcx.short_string(expected_ty, &mut long_ty_file);
734+
let ct_str = self.tcx.short_string(ct, &mut long_ty_file);
723735
let mut diag = self.dcx().struct_span_err(
724736
span,
725-
format!("the constant `{ct}` is not of type `{expected_ty}`"),
737+
format!("the constant `{ct_str}` is not of type `{expected_ty_str}`"),
726738
);
739+
diag.long_ty_path = long_ty_file;
727740

728741
self.note_type_err(
729742
&mut diag,
@@ -1116,9 +1129,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11161129
.must_apply_modulo_regions()
11171130
{
11181131
if !suggested {
1132+
let err_ty = self.tcx.short_string(err_ty, err.long_ty_path());
11191133
err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
11201134
}
11211135
} else {
1136+
let err_ty = self.tcx.short_string(err_ty, err.long_ty_path());
11221137
err.span_label(
11231138
span,
11241139
format!(
@@ -1154,12 +1169,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11541169
);
11551170
}
11561171
(ty::Adt(def, _), None) if def.did().is_local() => {
1172+
let trait_path = self.tcx.short_string(
1173+
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
1174+
err.long_ty_path(),
1175+
);
11571176
err.span_note(
11581177
self.tcx.def_span(def.did()),
1159-
format!(
1160-
"`{self_ty}` needs to implement `{}`",
1161-
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
1162-
),
1178+
format!("`{self_ty}` needs to implement `{trait_path}`"),
11631179
);
11641180
}
11651181
(ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
@@ -1193,13 +1209,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11931209
bug!()
11941210
};
11951211

1212+
let mut file = None;
1213+
let ty_str = self.tcx.short_string(ty, &mut file);
11961214
let mut diag = match ty.kind() {
11971215
ty::Float(_) => {
11981216
struct_span_code_err!(
11991217
self.dcx(),
12001218
span,
12011219
E0741,
1202-
"`{ty}` is forbidden as the type of a const generic parameter",
1220+
"`{ty_str}` is forbidden as the type of a const generic parameter",
12031221
)
12041222
}
12051223
ty::FnPtr(..) => {
@@ -1224,7 +1242,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12241242
self.dcx(),
12251243
span,
12261244
E0741,
1227-
"`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
1245+
"`{ty_str}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
12281246
);
12291247
// Only suggest derive if this isn't a derived obligation,
12301248
// and the struct is local.
@@ -1256,21 +1274,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12561274
self.dcx(),
12571275
span,
12581276
E0741,
1259-
"`{ty}` can't be used as a const parameter type",
1277+
"`{ty_str}` can't be used as a const parameter type",
12601278
)
12611279
}
12621280
};
1281+
diag.long_ty_path = file;
12631282

12641283
let mut code = obligation.cause.code();
12651284
let mut pred = obligation.predicate.as_trait_clause();
12661285
while let Some((next_code, next_pred)) = code.parent_with_predicate() {
12671286
if let Some(pred) = pred {
12681287
self.enter_forall(pred, |pred| {
1269-
diag.note(format!(
1270-
"`{}` must implement `{}`, but it does not",
1271-
pred.self_ty(),
1272-
pred.print_modifiers_and_trait_path()
1273-
));
1288+
let ty = self.tcx.short_string(pred.self_ty(), diag.long_ty_path());
1289+
let trait_path = self
1290+
.tcx
1291+
.short_string(pred.print_modifiers_and_trait_path(), diag.long_ty_path());
1292+
diag.note(format!("`{ty}` must implement `{trait_path}`, but it does not"));
12741293
})
12751294
}
12761295
code = next_code;
@@ -1624,15 +1643,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
16241643
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
16251644
_ => self.tcx.short_string(self_ty, file),
16261645
};
1646+
let expected_ty = self.tcx.short_string(expected_ty, file);
1647+
let normalized_ty = self.tcx.short_string(normalized_ty, file);
16271648
Some((format!(
16281649
"expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`",
16291650
), span, closure_span))
16301651
} else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) {
1652+
let self_ty = self.tcx.short_string(self_ty, file);
1653+
let expected_ty = self.tcx.short_string(expected_ty, file);
1654+
let normalized_ty = self.tcx.short_string(normalized_ty, file);
16311655
Some((format!(
16321656
"expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
16331657
resolves to `{normalized_ty}`"
16341658
), span, None))
16351659
} else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
1660+
let self_ty = self.tcx.short_string(self_ty, file);
1661+
let expected_ty = self.tcx.short_string(expected_ty, file);
1662+
let normalized_ty = self.tcx.short_string(normalized_ty, file);
16361663
Some((format!(
16371664
"expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
16381665
yields `{normalized_ty}`"
@@ -2095,12 +2122,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
20952122

20962123
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
20972124
let exp_found = self.resolve_vars_if_possible(*exp_found);
2125+
let expected =
2126+
self.tcx.short_string(exp_found.expected, err.long_ty_path());
2127+
let found = self.tcx.short_string(exp_found.found, err.long_ty_path());
20982128
err.highlighted_help(vec![
20992129
StringPart::normal("for that trait implementation, "),
21002130
StringPart::normal("expected `"),
2101-
StringPart::highlighted(exp_found.expected.to_string()),
2131+
StringPart::highlighted(expected),
21022132
StringPart::normal("`, found `"),
2103-
StringPart::highlighted(exp_found.found.to_string()),
2133+
StringPart::highlighted(found),
21042134
StringPart::normal("`"),
21052135
]);
21062136
self.suggest_function_pointers_impl(None, &exp_found, err);
@@ -2133,11 +2163,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21332163
(ty::FnPtr(..), _) => (" implemented for fn pointer `", ""),
21342164
_ => (" implemented for `", ""),
21352165
};
2166+
let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path());
2167+
let self_ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path());
21362168
err.highlighted_help(vec![
2137-
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
2169+
StringPart::normal(format!("the trait `{trait_}` ",)),
21382170
StringPart::highlighted("is"),
21392171
StringPart::normal(desc),
2140-
StringPart::highlighted(cand.self_ty().to_string()),
2172+
StringPart::highlighted(self_ty),
21412173
StringPart::normal("`"),
21422174
StringPart::normal(mention_castable),
21432175
]);
@@ -2157,9 +2189,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21572189
.into_iter()
21582190
.map(|c| {
21592191
if all_traits_equal {
2160-
format!("\n {}", c.self_ty())
2192+
format!("\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path()))
21612193
} else {
2162-
format!("\n `{}` implements `{}`", c.self_ty(), c.print_only_trait_path())
2194+
format!(
2195+
"\n `{}` implements `{}`",
2196+
self.tcx.short_string(c.self_ty(), err.long_ty_path()),
2197+
self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()),
2198+
)
21632199
}
21642200
})
21652201
.collect();
@@ -2606,8 +2642,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
26062642
dst_min_align,
26072643
} => {
26082644
format!(
2609-
"the minimum alignment of `{src}` ({src_min_align}) should \
2610-
be greater than that of `{dst}` ({dst_min_align})"
2645+
"the minimum alignment of `{src}` ({src_min_align}) should be \
2646+
greater than that of `{dst}` ({dst_min_align})"
26112647
)
26122648
}
26132649
rustc_transmute::Reason::DstIsMoreUnique => {

0 commit comments

Comments
 (0)