Skip to content

Commit a059dd8

Browse files
authoredFeb 8, 2024
Rollup merge of rust-lang#120739 - lukas-code:pp-dyn-assoc, r=compiler-errors
improve pretty printing for associated items in trait objects * Don't print a binder in front of associated items, because it's not valid syntax. * e.g. print `dyn for<'a> Trait<'a, Assoc = &'a u8>` instead of `dyn for<'a> Trait<'a, for<'a> Assoc = &'a u8>`. * Don't print associated items that are implied by a supertrait bound. * e.g. if we have `trait Sub: Super<Assoc = u8> {}`, then just print `dyn Sub` instead of `dyn Sub<Assoc = u8>`. I've added the test in the first commit, so you can see the diff of the compiler output in the second commit.
2 parents 87e1e05 + c636c7a commit a059dd8

File tree

6 files changed

+281
-39
lines changed

6 files changed

+281
-39
lines changed
 

‎compiler/rustc_middle/src/traits/util.rs

+34-20
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,60 @@
11
use rustc_data_structures::fx::FxHashSet;
22

3-
use crate::ty::{PolyTraitRef, TyCtxt};
3+
use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, ToPredicate, TyCtxt};
44

5-
/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
5+
/// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition.
6+
///
67
/// This only exists in `rustc_middle` because the more powerful elaborator depends on
78
/// `rustc_infer` for elaborating outlives bounds -- this should only be used for pretty
89
/// printing.
10+
pub fn super_predicates_for_pretty_printing<'tcx>(
11+
tcx: TyCtxt<'tcx>,
12+
trait_ref: PolyTraitRef<'tcx>,
13+
) -> impl Iterator<Item = Clause<'tcx>> {
14+
let clause = trait_ref.to_predicate(tcx);
15+
Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] }
16+
}
17+
18+
/// Like [`super_predicates_for_pretty_printing`], except it only returns traits and filters out
19+
/// all other [`Clause`]s.
920
pub fn supertraits_for_pretty_printing<'tcx>(
1021
tcx: TyCtxt<'tcx>,
1122
trait_ref: PolyTraitRef<'tcx>,
1223
) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
13-
Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
24+
super_predicates_for_pretty_printing(tcx, trait_ref).filter_map(|clause| {
25+
clause.as_trait_clause().map(|trait_clause| trait_clause.to_poly_trait_ref())
26+
})
1427
}
1528

1629
struct Elaborator<'tcx> {
1730
tcx: TyCtxt<'tcx>,
18-
visited: FxHashSet<PolyTraitRef<'tcx>>,
19-
stack: Vec<PolyTraitRef<'tcx>>,
31+
visited: FxHashSet<Clause<'tcx>>,
32+
stack: Vec<Clause<'tcx>>,
2033
}
2134

2235
impl<'tcx> Elaborator<'tcx> {
2336
fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
24-
let supertrait_refs = self
25-
.tcx
26-
.super_predicates_of(trait_ref.def_id())
27-
.predicates
28-
.into_iter()
29-
.flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause())
30-
.map(|t| t.map_bound(|pred| pred.trait_ref))
31-
.filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
32-
33-
self.stack.extend(supertrait_refs);
37+
let super_predicates =
38+
self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map(
39+
|&(pred, _)| {
40+
let clause = pred.subst_supertrait(self.tcx, &trait_ref);
41+
self.visited.insert(clause).then_some(clause)
42+
},
43+
);
44+
45+
self.stack.extend(super_predicates);
3446
}
3547
}
3648

3749
impl<'tcx> Iterator for Elaborator<'tcx> {
38-
type Item = PolyTraitRef<'tcx>;
50+
type Item = Clause<'tcx>;
3951

40-
fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
41-
if let Some(trait_ref) = self.stack.pop() {
42-
self.elaborate(trait_ref);
43-
Some(trait_ref)
52+
fn next(&mut self) -> Option<Clause<'tcx>> {
53+
if let Some(clause) = self.stack.pop() {
54+
if let Some(trait_clause) = clause.as_trait_clause() {
55+
self.elaborate(trait_clause.to_poly_trait_ref());
56+
}
57+
Some(clause)
4458
} else {
4559
None
4660
}

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

+47-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
22
use crate::query::IntoQueryParam;
33
use crate::query::Providers;
4-
use crate::traits::util::supertraits_for_pretty_printing;
4+
use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing};
55
use crate::ty::GenericArgKind;
66
use crate::ty::{
77
ConstInt, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable,
@@ -1255,8 +1255,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
12551255
// Generate the main trait ref, including associated types.
12561256
let mut first = true;
12571257

1258-
if let Some(principal) = predicates.principal() {
1259-
self.wrap_binder(&principal, |principal, cx| {
1258+
if let Some(bound_principal) = predicates.principal() {
1259+
self.wrap_binder(&bound_principal, |principal, cx| {
12601260
define_scoped_cx!(cx);
12611261
p!(print_def_path(principal.def_id, &[]));
12621262

@@ -1281,19 +1281,53 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
12811281
// HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`,
12821282
// in order to place the projections inside the `<...>`.
12831283
if !resugared {
1284-
// Use a type that can't appear in defaults of type parameters.
1285-
let dummy_cx = Ty::new_fresh(cx.tcx(), 0);
1286-
let principal = principal.with_self_ty(cx.tcx(), dummy_cx);
1284+
let principal_with_self =
1285+
principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
12871286

12881287
let args = cx
12891288
.tcx()
1290-
.generics_of(principal.def_id)
1291-
.own_args_no_defaults(cx.tcx(), principal.args);
1292-
1293-
let mut projections: Vec<_> = predicates.projection_bounds().collect();
1294-
projections.sort_by_cached_key(|proj| {
1295-
cx.tcx().item_name(proj.item_def_id()).to_string()
1296-
});
1289+
.generics_of(principal_with_self.def_id)
1290+
.own_args_no_defaults(cx.tcx(), principal_with_self.args);
1291+
1292+
let bound_principal_with_self = bound_principal
1293+
.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
1294+
1295+
let super_projections: Vec<_> =
1296+
super_predicates_for_pretty_printing(cx.tcx(), bound_principal_with_self)
1297+
.filter_map(|clause| clause.as_projection_clause())
1298+
.collect();
1299+
1300+
let mut projections: Vec<_> = predicates
1301+
.projection_bounds()
1302+
.filter(|&proj| {
1303+
// Filter out projections that are implied by the super predicates.
1304+
let proj_is_implied = super_projections.iter().any(|&super_proj| {
1305+
let super_proj = super_proj.map_bound(|super_proj| {
1306+
ty::ExistentialProjection::erase_self_ty(cx.tcx(), super_proj)
1307+
});
1308+
1309+
// This function is sometimes called on types with erased and
1310+
// anonymized regions, but the super projections can still
1311+
// contain named regions. So we erase and anonymize everything
1312+
// here to compare the types modulo regions below.
1313+
let proj = cx.tcx().erase_regions(proj);
1314+
let proj = cx.tcx().anonymize_bound_vars(proj);
1315+
let super_proj = cx.tcx().erase_regions(super_proj);
1316+
let super_proj = cx.tcx().anonymize_bound_vars(super_proj);
1317+
1318+
proj == super_proj
1319+
});
1320+
!proj_is_implied
1321+
})
1322+
.map(|proj| {
1323+
// Skip the binder, because we don't want to print the binder in
1324+
// front of the associated item.
1325+
proj.skip_binder()
1326+
})
1327+
.collect();
1328+
1329+
projections
1330+
.sort_by_cached_key(|proj| cx.tcx().item_name(proj.def_id).to_string());
12971331

12981332
if !args.is_empty() || !projections.is_empty() {
12991333
p!(generic_delimiters(|cx| {

‎tests/ui/traits/object/pretty.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Test for pretty-printing trait object types.
2+
3+
trait Super {
4+
type Assoc;
5+
}
6+
trait Any: Super {}
7+
trait Fixed: Super<Assoc = u8> {}
8+
trait FixedSub: Fixed {}
9+
trait FixedStatic: Super<Assoc = &'static u8> {}
10+
11+
trait SuperGeneric<'a> {
12+
type Assoc2;
13+
}
14+
trait AnyGeneric<'a>: SuperGeneric<'a> {}
15+
trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {}
16+
trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {}
17+
trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {}
18+
trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {}
19+
trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {}
20+
21+
fn dyn_super(x: &dyn Super<Assoc = u8>) { x } //~ERROR mismatched types
22+
fn dyn_any(x: &dyn Any<Assoc = u8>) { x } //~ERROR mismatched types
23+
fn dyn_fixed(x: &dyn Fixed) { x } //~ERROR mismatched types
24+
fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x } //~ERROR mismatched types
25+
fn dyn_fixed_sub(x: &dyn FixedSub) { x } //~ERROR mismatched types
26+
fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types
27+
28+
fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
29+
fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
30+
fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types
31+
fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types
32+
fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types
33+
fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types
34+
fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types
35+
fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } //~ERROR mismatched types
36+
37+
fn main() {}

‎tests/ui/traits/object/pretty.stderr

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/pretty.rs:21:43
3+
|
4+
LL | fn dyn_super(x: &dyn Super<Assoc = u8>) { x }
5+
| - ^ expected `()`, found `&dyn Super<Assoc = u8>`
6+
| |
7+
| help: try adding a return type: `-> &dyn Super<Assoc = u8>`
8+
|
9+
= note: expected unit type `()`
10+
found reference `&dyn Super<Assoc = u8>`
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/pretty.rs:22:39
14+
|
15+
LL | fn dyn_any(x: &dyn Any<Assoc = u8>) { x }
16+
| - ^ expected `()`, found `&dyn Any<Assoc = u8>`
17+
| |
18+
| help: try adding a return type: `-> &dyn Any<Assoc = u8>`
19+
|
20+
= note: expected unit type `()`
21+
found reference `&dyn Any<Assoc = u8>`
22+
23+
error[E0308]: mismatched types
24+
--> $DIR/pretty.rs:23:31
25+
|
26+
LL | fn dyn_fixed(x: &dyn Fixed) { x }
27+
| - ^ expected `()`, found `&dyn Fixed`
28+
| |
29+
| help: try adding a return type: `-> &dyn Fixed`
30+
|
31+
= note: expected unit type `()`
32+
found reference `&dyn Fixed`
33+
34+
error[E0308]: mismatched types
35+
--> $DIR/pretty.rs:24:50
36+
|
37+
LL | fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x }
38+
| - ^ expected `()`, found `&dyn Fixed<Assoc = u16>`
39+
| |
40+
| help: try adding a return type: `-> &dyn Fixed<Assoc = u16>`
41+
|
42+
= note: expected unit type `()`
43+
found reference `&dyn Fixed<Assoc = u16>`
44+
45+
error[E0308]: mismatched types
46+
--> $DIR/pretty.rs:25:38
47+
|
48+
LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x }
49+
| - ^ expected `()`, found `&dyn FixedSub`
50+
| |
51+
| help: try adding a return type: `-> &dyn FixedSub`
52+
|
53+
= note: expected unit type `()`
54+
found reference `&dyn FixedSub`
55+
56+
error[E0308]: mismatched types
57+
--> $DIR/pretty.rs:26:44
58+
|
59+
LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x }
60+
| - ^ expected `()`, found `&dyn FixedStatic`
61+
| |
62+
| help: try adding a return type: `-> &dyn FixedStatic`
63+
|
64+
= note: expected unit type `()`
65+
found reference `&dyn FixedStatic`
66+
67+
error[E0308]: mismatched types
68+
--> $DIR/pretty.rs:28:75
69+
|
70+
LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x }
71+
| - ^ expected `()`, found `&dyn SuperGeneric<'a, Assoc2 = &u8>`
72+
| |
73+
| help: try adding a return type: `-> &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>`
74+
|
75+
= note: expected unit type `()`
76+
found reference `&dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>`
77+
78+
error[E0308]: mismatched types
79+
--> $DIR/pretty.rs:29:71
80+
|
81+
LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x }
82+
| - ^ expected `()`, found `&dyn AnyGeneric<'a, Assoc2 = &u8>`
83+
| |
84+
| help: try adding a return type: `-> &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>`
85+
|
86+
= note: expected unit type `()`
87+
found reference `&dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>`
88+
89+
error[E0308]: mismatched types
90+
--> $DIR/pretty.rs:30:60
91+
|
92+
LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x }
93+
| - ^ expected `()`, found `&dyn FixedGeneric1<'a>`
94+
| |
95+
| help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a>`
96+
|
97+
= note: expected unit type `()`
98+
found reference `&dyn for<'a> FixedGeneric1<'a>`
99+
100+
error[E0308]: mismatched types
101+
--> $DIR/pretty.rs:31:60
102+
|
103+
LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x }
104+
| - ^ expected `()`, found `&dyn FixedGeneric2<'a>`
105+
| |
106+
| help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>`
107+
|
108+
= note: expected unit type `()`
109+
found reference `&dyn for<'a> FixedGeneric2<'a>`
110+
111+
error[E0308]: mismatched types
112+
--> $DIR/pretty.rs:32:79
113+
|
114+
LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x }
115+
| - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>`
116+
| |
117+
| help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
118+
|
119+
= note: expected unit type `()`
120+
found reference `&dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
121+
122+
error[E0308]: mismatched types
123+
--> $DIR/pretty.rs:33:40
124+
|
125+
LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x }
126+
| - ^ expected `()`, found `&dyn FixedHrtb`
127+
| |
128+
| help: try adding a return type: `-> &dyn FixedHrtb`
129+
|
130+
= note: expected unit type `()`
131+
found reference `&dyn FixedHrtb`
132+
133+
error[E0308]: mismatched types
134+
--> $DIR/pretty.rs:34:73
135+
|
136+
LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x }
137+
| - ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>`
138+
| |
139+
| help: try adding a return type: `-> &dyn AnyDifferentBinders<Assoc = u8>`
140+
|
141+
= note: expected unit type `()`
142+
found reference `&dyn AnyDifferentBinders<Assoc = u8>`
143+
144+
error[E0308]: mismatched types
145+
--> $DIR/pretty.rs:35:65
146+
|
147+
LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x }
148+
| - ^ expected `()`, found `&dyn FixedDifferentBinders`
149+
| |
150+
| help: try adding a return type: `-> &dyn FixedDifferentBinders`
151+
|
152+
= note: expected unit type `()`
153+
found reference `&dyn FixedDifferentBinders`
154+
155+
error: aborting due to 14 previous errors
156+
157+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/wf/hir-wf-canonicalized.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ trait Callback<T: Foo>: Fn(&Bar<'_, T>, &T::V) {}
99
struct Bar<'a, T> {
1010
callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
1111
//~^ ERROR the trait bound `Bar<'a, T>: Foo` is not satisfied
12-
//~| ERROR the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
13-
//~| ERROR the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
12+
//~| ERROR the trait bound `(dyn Callback<Bar<'a, T>, Output = ()> + 'static): Foo` is not satisfied
13+
//~| ERROR the size for values of type `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)` cannot be known at compilation time
1414
}
1515

1616
impl<T: Foo> Bar<'_, Bar<'_, T>> {}

‎tests/ui/wf/hir-wf-canonicalized.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ help: this trait has no implementations, consider adding one
1010
LL | trait Foo {
1111
| ^^^^^^^^^
1212

13-
error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
13+
error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, Output = ()> + 'static): Foo` is not satisfied
1414
--> $DIR/hir-wf-canonicalized.rs:10:15
1515
|
1616
LL | callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)`
1818
|
1919
help: this trait has no implementations, consider adding one
2020
--> $DIR/hir-wf-canonicalized.rs:3:1
2121
|
2222
LL | trait Foo {
2323
| ^^^^^^^^^
2424

25-
error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
25+
error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)` cannot be known at compilation time
2626
--> $DIR/hir-wf-canonicalized.rs:10:15
2727
|
2828
LL | callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
3030
|
31-
= help: the trait `Sized` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
31+
= help: the trait `Sized` is not implemented for `(dyn Callback<Bar<'a, T>, Output = ()> + 'static)`
3232
note: required by an implicit `Sized` bound in `Bar`
3333
--> $DIR/hir-wf-canonicalized.rs:9:16
3434
|

0 commit comments

Comments
 (0)
Please sign in to comment.