Skip to content

Commit ad23f30

Browse files
Rollup merge of #118268 - compiler-errors:pretty-print, r=estebank
Pretty print `Fn<(..., ...)>` trait refs with parentheses (almost) always It's almost always better, at least in diagnostics, to print `Fn(i32, u32)` instead of `Fn<(i32, u32)>`. Related to but doesn't fix #118225. That needs a separate fix.
2 parents 19bf749 + f6c30b3 commit ad23f30

File tree

21 files changed

+101
-66
lines changed

21 files changed

+101
-66
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -1182,10 +1182,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11821182
if let Some(bound_span) = bound_span {
11831183
err.span_label(
11841184
bound_span,
1185-
format!(
1186-
"ambiguous `{assoc_name}` from `{}`",
1187-
bound.print_only_trait_path(),
1188-
),
1185+
format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
11891186
);
11901187
if let Some(constraint) = &is_equality {
11911188
where_bounds.push(format!(

compiler/rustc_hir_analysis/src/astconv/object_safety.rs

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
106106
trait here instead: `trait NewTrait: {} {{}}`",
107107
regular_traits
108108
.iter()
109+
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
109110
.map(|t| t.trait_ref().print_only_trait_path().to_string())
110111
.collect::<Vec<_>>()
111112
.join(" + "),

compiler/rustc_hir_analysis/src/coherence/unsafety.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
2323
tcx.def_span(def_id),
2424
E0199,
2525
"implementing the trait `{}` is not unsafe",
26-
trait_ref.print_only_trait_path()
26+
trait_ref.print_trait_sugared()
2727
)
2828
.span_suggestion_verbose(
2929
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
@@ -40,13 +40,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
4040
tcx.def_span(def_id),
4141
E0200,
4242
"the trait `{}` requires an `unsafe impl` declaration",
43-
trait_ref.print_only_trait_path()
43+
trait_ref.print_trait_sugared()
4444
)
4545
.note(format!(
4646
"the trait `{}` enforces invariants that the compiler can't check. \
4747
Review the trait documentation and make sure this implementation \
4848
upholds those invariants before adding the `unsafe` keyword",
49-
trait_ref.print_only_trait_path()
49+
trait_ref.print_trait_sugared()
5050
))
5151
.span_suggestion_verbose(
5252
item.span.shrink_to_lo(),
@@ -69,7 +69,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
6969
"the trait `{}` enforces invariants that the compiler can't check. \
7070
Review the trait documentation and make sure this implementation \
7171
upholds those invariants before adding the `unsafe` keyword",
72-
trait_ref.print_only_trait_path()
72+
trait_ref.print_trait_sugared()
7373
))
7474
.span_suggestion_verbose(
7575
item.span.shrink_to_lo(),

compiler/rustc_hir_typeck/src/method/suggest.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2288,7 +2288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22882288
ty::Adt(def, _) if def.did().is_local() => {
22892289
spans.push_span_label(
22902290
self.tcx.def_span(def.did()),
2291-
format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
2291+
format!("must implement `{}`", pred.trait_ref.print_trait_sugared()),
22922292
);
22932293
}
22942294
_ => {}
@@ -2299,7 +2299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22992299
let msg = if preds.len() == 1 {
23002300
format!(
23012301
"an implementation of `{}` might be missing for `{}`",
2302-
preds[0].trait_ref.print_only_trait_path(),
2302+
preds[0].trait_ref.print_trait_sugared(),
23032303
preds[0].self_ty()
23042304
)
23052305
} else {

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2219,8 +2219,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22192219
infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
22202220
infer::PolyTraitRefs(exp_found) => {
22212221
let pretty_exp_found = ty::error::ExpectedFound {
2222-
expected: exp_found.expected.print_only_trait_path(),
2223-
found: exp_found.found.print_only_trait_path(),
2222+
expected: exp_found.expected.print_trait_sugared(),
2223+
found: exp_found.found.print_trait_sugared(),
22242224
};
22252225
match self.expected_found_str(pretty_exp_found) {
22262226
Some((expected, found, _, _)) if expected == found => {

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

+45-1
Original file line numberDiff line numberDiff line change
@@ -2640,6 +2640,23 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
26402640
}
26412641
}
26422642

2643+
/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
2644+
/// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds.
2645+
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2646+
pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>);
2647+
2648+
impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintSugared<'tcx> {
2649+
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
2650+
self.to_string().into_diagnostic_arg()
2651+
}
2652+
}
2653+
2654+
impl<'tcx> fmt::Debug for TraitRefPrintSugared<'tcx> {
2655+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2656+
fmt::Display::fmt(self, f)
2657+
}
2658+
}
2659+
26432660
/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
26442661
/// the trait name. That is, it will print `Trait` instead of
26452662
/// `<T as Trait<U>>`.
@@ -2657,6 +2674,10 @@ impl<'tcx> ty::TraitRef<'tcx> {
26572674
TraitRefPrintOnlyTraitPath(self)
26582675
}
26592676

2677+
pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> {
2678+
TraitRefPrintSugared(self)
2679+
}
2680+
26602681
pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
26612682
TraitRefPrintOnlyTraitName(self)
26622683
}
@@ -2666,6 +2687,10 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
26662687
pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
26672688
self.map_bound(|tr| tr.print_only_trait_path())
26682689
}
2690+
2691+
pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
2692+
self.map_bound(|tr| tr.print_trait_sugared())
2693+
}
26692694
}
26702695

26712696
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
@@ -2745,6 +2770,7 @@ forward_display_to_print! {
27452770
ty::PolyExistentialTraitRef<'tcx>,
27462771
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
27472772
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
2773+
ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>,
27482774
ty::Binder<'tcx, ty::FnSig<'tcx>>,
27492775
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
27502776
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
@@ -2844,6 +2870,24 @@ define_print_and_forward_display! {
28442870
p!(print_def_path(self.0.def_id, self.0.args));
28452871
}
28462872

2873+
TraitRefPrintSugared<'tcx> {
2874+
if !with_no_queries()
2875+
&& let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id)
2876+
&& let ty::Tuple(args) = self.0.args.type_at(1).kind()
2877+
{
2878+
p!(write("{}", kind.as_str()), "(");
2879+
for (i, arg) in args.iter().enumerate() {
2880+
if i > 0 {
2881+
p!(", ");
2882+
}
2883+
p!(print(arg));
2884+
}
2885+
p!(")");
2886+
} else {
2887+
p!(print_def_path(self.0.def_id, self.0.args));
2888+
}
2889+
}
2890+
28472891
TraitRefPrintOnlyTraitName<'tcx> {
28482892
p!(print_def_path(self.0.def_id, &[]));
28492893
}
@@ -2892,7 +2936,7 @@ define_print_and_forward_display! {
28922936
if let ty::ImplPolarity::Negative = self.polarity {
28932937
p!("!");
28942938
}
2895-
p!(print(self.trait_ref.print_only_trait_path()))
2939+
p!(print(self.trait_ref.print_trait_sugared()))
28962940
}
28972941

28982942
ty::ProjectionPredicate<'tcx> {

compiler/rustc_trait_selection/src/traits/coherence.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ fn overlap<'tcx>(
245245
let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
246246
format!(
247247
"of `{}` for `{}`",
248-
trait_ref.print_only_trait_path(),
248+
trait_ref.print_trait_sugared(),
249249
trait_ref.self_ty()
250250
)
251251
}

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

+1-8
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
184184
flags.push((sym::cause, Some("MainFunctionType".to_string())));
185185
}
186186

187-
if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id)
188-
&& let ty::Tuple(args) = trait_ref.args.type_at(1).kind()
189-
{
190-
let args = args.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ");
191-
flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str()))));
192-
} else {
193-
flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string())));
194-
}
187+
flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string())));
195188

196189
// Add all types without trimmed paths or visible paths, ensuring they end up with
197190
// their "canonical" def path.

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
622622
span.shrink_to_hi(),
623623
format!(
624624
"the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
625-
cand.print_only_trait_path(),
625+
cand.print_trait_sugared(),
626626
cand.self_ty(),
627627
),
628628
format!(" as {}", cand.self_ty()),
@@ -1785,7 +1785,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
17851785
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
17861786
});
17871787
err.highlighted_help(vec![
1788-
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
1788+
(format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
17891789
("is".to_string(), Style::Highlight),
17901790
(" implemented for `".to_string(), Style::NoStyle),
17911791
(cand.self_ty().to_string(), Style::Highlight),
@@ -1821,7 +1821,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
18211821
_ => (" implemented for `", ""),
18221822
};
18231823
err.highlighted_help(vec![
1824-
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
1824+
(format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
18251825
("is".to_string(), Style::Highlight),
18261826
(desc.to_string(), Style::NoStyle),
18271827
(cand.self_ty().to_string(), Style::Highlight),
@@ -1854,7 +1854,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
18541854
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
18551855
err.help(format!(
18561856
"the following {other}types implement trait `{}`:{}{}",
1857-
trait_ref.print_only_trait_path(),
1857+
trait_ref.print_trait_sugared(),
18581858
candidates[..end].join(""),
18591859
if candidates.len() > 9 {
18601860
format!("\nand {} others", candidates.len() - 8)

compiler/rustc_trait_selection/src/traits/select/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> {
7878
IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => {
7979
format!(
8080
"downstream crates may implement trait `{trait_desc}`{self_desc}",
81-
trait_desc = trait_ref.print_only_trait_path(),
81+
trait_desc = trait_ref.print_trait_sugared(),
8282
self_desc = if let Some(self_ty) = self_ty {
8383
format!(" for type `{self_ty}`")
8484
} else {
@@ -90,7 +90,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> {
9090
format!(
9191
"upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \
9292
in future versions",
93-
trait_desc = trait_ref.print_only_trait_path(),
93+
trait_desc = trait_ref.print_trait_sugared(),
9494
self_desc = if let Some(self_ty) = self_ty {
9595
format!(" for type `{self_ty}`")
9696
} else {

compiler/rustc_trait_selection/src/traits/specialize/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ fn report_conflicting_impls<'tcx>(
412412
let msg = DelayDm(|| {
413413
format!(
414414
"conflicting implementations of trait `{}`{}{}",
415-
overlap.trait_ref.print_only_trait_path(),
415+
overlap.trait_ref.print_trait_sugared(),
416416
overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
417417
match used_to_be_allowed {
418418
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",

tests/ui/error-codes/E0401.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ error[E0283]: type annotations needed
5555
LL | bfnr(x);
5656
| ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr`
5757
|
58-
= note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`:
58+
= note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`:
5959
- impl<A, F> Fn<A> for &F
6060
where A: Tuple, F: Fn<A>, F: ?Sized;
6161
- impl<Args, F, A> Fn<Args> for Box<F, A>

tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
44
LL | foo(bar, "string", |s| s.len() == 5);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
66
|
7-
= note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>`
8-
found trait `for<'a> FnOnce<(&'a &str,)>`
7+
= note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)`
8+
found trait `for<'a> FnOnce(&'a &str)`
99
note: this closure does not fulfill the lifetime requirements
1010
--> $DIR/issue-71955.rs:45:24
1111
|
@@ -23,8 +23,8 @@ error[E0308]: mismatched types
2323
LL | foo(bar, "string", |s| s.len() == 5);
2424
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
2525
|
26-
= note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>`
27-
found trait `for<'a> FnOnce<(&'a &str,)>`
26+
= note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)`
27+
found trait `for<'a> FnOnce(&'a &str)`
2828
note: this closure does not fulfill the lifetime requirements
2929
--> $DIR/issue-71955.rs:45:24
3030
|
@@ -42,8 +42,8 @@ error[E0308]: mismatched types
4242
LL | foo(baz, "string", |s| s.0.len() == 5);
4343
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
4444
|
45-
= note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>`
46-
found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>`
45+
= note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)`
46+
found trait `for<'a> FnOnce(&'a Wrapper<'_>)`
4747
note: this closure does not fulfill the lifetime requirements
4848
--> $DIR/issue-71955.rs:48:24
4949
|
@@ -61,8 +61,8 @@ error[E0308]: mismatched types
6161
LL | foo(baz, "string", |s| s.0.len() == 5);
6262
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
6363
|
64-
= note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>`
65-
found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>`
64+
= note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)`
65+
found trait `for<'a> FnOnce(&'a Wrapper<'_>)`
6666
note: this closure does not fulfill the lifetime requirements
6767
--> $DIR/issue-71955.rs:48:24
6868
|

tests/ui/lifetimes/issue-105675.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
44
LL | thing(f);
55
| ^^^^^^^^ one type is more general than the other
66
|
7-
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>`
8-
found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>`
7+
= note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
8+
found trait `for<'a> FnOnce(&u32, &'a u32, u32)`
99
note: this closure does not fulfill the lifetime requirements
1010
--> $DIR/issue-105675.rs:4:13
1111
|
@@ -27,8 +27,8 @@ error[E0308]: mismatched types
2727
LL | thing(f);
2828
| ^^^^^^^^ one type is more general than the other
2929
|
30-
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>`
31-
found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>`
30+
= note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
31+
found trait `for<'a> FnOnce(&u32, &'a u32, u32)`
3232
note: this closure does not fulfill the lifetime requirements
3333
--> $DIR/issue-105675.rs:4:13
3434
|
@@ -46,8 +46,8 @@ error[E0308]: mismatched types
4646
LL | thing(f);
4747
| ^^^^^^^^ one type is more general than the other
4848
|
49-
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>`
50-
found trait `FnOnce<(&u32, &u32, u32)>`
49+
= note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
50+
found trait `FnOnce(&u32, &u32, u32)`
5151
note: this closure does not fulfill the lifetime requirements
5252
--> $DIR/issue-105675.rs:8:13
5353
|
@@ -69,8 +69,8 @@ error[E0308]: mismatched types
6969
LL | thing(f);
7070
| ^^^^^^^^ one type is more general than the other
7171
|
72-
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>`
73-
found trait `FnOnce<(&u32, &u32, u32)>`
72+
= note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
73+
found trait `FnOnce(&u32, &u32, u32)`
7474
note: this closure does not fulfill the lifetime requirements
7575
--> $DIR/issue-105675.rs:8:13
7676
|

tests/ui/lifetimes/issue-79187-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ error[E0308]: mismatched types
3131
LL | take_foo(|a| a);
3232
| ^^^^^^^^^^^^^^^ one type is more general than the other
3333
|
34-
= note: expected trait `for<'a> Fn<(&'a i32,)>`
35-
found trait `Fn<(&i32,)>`
34+
= note: expected trait `for<'a> Fn(&'a i32)`
35+
found trait `Fn(&i32)`
3636
note: this closure does not fulfill the lifetime requirements
3737
--> $DIR/issue-79187-2.rs:8:14
3838
|

tests/ui/lifetimes/issue-79187.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
44
LL | thing(f);
55
| ^^^^^^^^ one type is more general than the other
66
|
7-
= note: expected trait `for<'a> FnOnce<(&'a u32,)>`
8-
found trait `FnOnce<(&u32,)>`
7+
= note: expected trait `for<'a> FnOnce(&'a u32)`
8+
found trait `FnOnce(&u32)`
99
note: this closure does not fulfill the lifetime requirements
1010
--> $DIR/issue-79187.rs:4:13
1111
|

tests/ui/lifetimes/lifetime-errors/issue_74400.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ error[E0308]: mismatched types
1818
LL | f(data, identity)
1919
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
2020
|
21-
= note: expected trait `for<'a> Fn<(&'a T,)>`
22-
found trait `Fn<(&T,)>`
21+
= note: expected trait `for<'a> Fn(&'a T)`
22+
found trait `Fn(&T)`
2323
note: the lifetime requirement is introduced here
2424
--> $DIR/issue_74400.rs:8:34
2525
|

0 commit comments

Comments
 (0)