Skip to content

Commit 255a0e9

Browse files
committed
rustc_middle: Pretty-print negative bounds correctly
1 parent 7f4a1a4 commit 255a0e9

File tree

5 files changed

+195
-22
lines changed

5 files changed

+195
-22
lines changed

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

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -912,23 +912,43 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
912912

913913
let mut traits = FxIndexMap::default();
914914
let mut fn_traits = FxIndexMap::default();
915-
let mut is_sized = false;
915+
let mut sizedness = Sizedness::Maybe;
916916
let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
917917

918+
enum Sizedness {
919+
Positive,
920+
Negative,
921+
Maybe,
922+
}
923+
918924
for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) {
919925
let bound_predicate = predicate.kind();
920926

921927
match bound_predicate.skip_binder() {
922928
ty::ClauseKind::Trait(pred) => {
923929
let trait_ref = bound_predicate.rebind(pred.trait_ref);
924930

925-
// Don't print + Sized, but rather + ?Sized if absent.
931+
// Don't print `+ Sized`, but rather `+ ?Sized` if absent.
926932
if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
927-
is_sized = true;
928-
continue;
933+
match pred.polarity {
934+
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {
935+
sizedness = Sizedness::Positive;
936+
continue;
937+
}
938+
ty::ImplPolarity::Negative if let Sizedness::Maybe = &sizedness => {
939+
sizedness = Sizedness::Negative;
940+
}
941+
_ => {}
942+
}
929943
}
930944

931-
self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
945+
self.insert_trait_and_projection(
946+
trait_ref,
947+
pred.polarity,
948+
None,
949+
&mut traits,
950+
&mut fn_traits,
951+
);
932952
}
933953
ty::ClauseKind::Projection(pred) => {
934954
let proj_ref = bound_predicate.rebind(pred);
@@ -939,6 +959,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
939959

940960
self.insert_trait_and_projection(
941961
trait_ref,
962+
ty::ImplPolarity::Positive,
942963
Some(proj_ty),
943964
&mut traits,
944965
&mut fn_traits,
@@ -955,7 +976,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
955976

956977
let mut first = true;
957978
// Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
958-
let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
979+
let paren_needed =
980+
fn_traits.len() > 1 || traits.len() > 0 || matches!(sizedness, Sizedness::Maybe);
959981

960982
for (fn_once_trait_ref, entry) in fn_traits {
961983
write!(self, "{}", if first { "" } else { " + " })?;
@@ -1002,18 +1024,21 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10021024
// trait_refs we collected in the OpaqueFnEntry as normal trait refs.
10031025
_ => {
10041026
if entry.has_fn_once {
1005-
traits.entry(fn_once_trait_ref).or_default().extend(
1006-
// Group the return ty with its def id, if we had one.
1007-
entry
1008-
.return_ty
1009-
.map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)),
1010-
);
1027+
traits
1028+
.entry((fn_once_trait_ref, ty::ImplPolarity::Positive))
1029+
.or_default()
1030+
.extend(
1031+
// Group the return ty with its def id, if we had one.
1032+
entry.return_ty.map(|ty| {
1033+
(tcx.require_lang_item(LangItem::FnOnce, None), ty)
1034+
}),
1035+
);
10111036
}
10121037
if let Some(trait_ref) = entry.fn_mut_trait_ref {
1013-
traits.entry(trait_ref).or_default();
1038+
traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
10141039
}
10151040
if let Some(trait_ref) = entry.fn_trait_ref {
1016-
traits.entry(trait_ref).or_default();
1041+
traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
10171042
}
10181043
}
10191044
}
@@ -1023,11 +1048,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10231048
}
10241049

10251050
// Print the rest of the trait types (that aren't Fn* family of traits)
1026-
for (trait_ref, assoc_items) in traits {
1051+
for ((trait_ref, polarity), assoc_items) in traits {
10271052
write!(self, "{}", if first { "" } else { " + " })?;
10281053

10291054
self.wrap_binder(&trait_ref, |trait_ref, cx| {
10301055
define_scoped_cx!(cx);
1056+
1057+
if polarity == ty::ImplPolarity::Negative {
1058+
p!("!");
1059+
}
10311060
p!(print(trait_ref.print_only_trait_name()));
10321061

10331062
let generics = tcx.generics_of(trait_ref.def_id);
@@ -1094,10 +1123,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10941123
})?;
10951124
}
10961125

1097-
if !is_sized {
1098-
write!(self, "{}?Sized", if first { "" } else { " + " })?;
1099-
} else if first {
1100-
write!(self, "Sized")?;
1126+
match sizedness {
1127+
Sizedness::Positive if first => write!(self, "Sized")?,
1128+
Sizedness::Maybe => write!(self, "{}?Sized", if first { "" } else { " + " })?,
1129+
_ => {}
11011130
}
11021131

11031132
if !with_forced_trimmed_paths() {
@@ -1128,9 +1157,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
11281157
fn insert_trait_and_projection(
11291158
&mut self,
11301159
trait_ref: ty::PolyTraitRef<'tcx>,
1160+
polarity: ty::ImplPolarity,
11311161
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
11321162
traits: &mut FxIndexMap<
1133-
ty::PolyTraitRef<'tcx>,
1163+
(ty::PolyTraitRef<'tcx>, ty::ImplPolarity),
11341164
FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
11351165
>,
11361166
fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
@@ -1139,7 +1169,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
11391169

11401170
// If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
11411171
// super-trait ref and record it there.
1142-
if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
1172+
// We skip negative Fn* bounds since they can't use parenthetical notation anyway.
1173+
if polarity == ty::ImplPolarity::Positive
1174+
&& let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
1175+
{
11431176
// If we have a FnOnce, then insert it into
11441177
if trait_def_id == fn_once_trait {
11451178
let entry = fn_traits.entry(trait_ref).or_default();
@@ -1167,7 +1200,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
11671200
}
11681201

11691202
// Otherwise, just group our traits and projection types.
1170-
traits.entry(trait_ref).or_default().extend(proj_ty);
1203+
traits.entry((trait_ref, polarity)).or_default().extend(proj_ty);
11711204
}
11721205

11731206
fn pretty_print_inherent_projection(
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// compile-flags: -Znext-solver
2+
3+
#![feature(negative_bounds, negative_impls)]
4+
//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
5+
6+
trait Trait {}
7+
impl !Trait for () {}
8+
9+
fn produce() -> impl !Trait {}
10+
fn consume(_: impl Trait) {}
11+
12+
fn main() {
13+
consume(produce()); //~ ERROR the trait bound `impl !Trait: Trait` is not satisfied
14+
}
15+
16+
fn weird0() -> impl Sized + !Sized {}
17+
//~^ ERROR mismatched types
18+
//~| ERROR type mismatch resolving `() == impl !Sized`
19+
fn weird1() -> impl Sized + !Sized {}
20+
//~^ ERROR mismatched types
21+
//~| ERROR type mismatch resolving `() == impl !Sized`
22+
fn weird2() -> impl !Sized + Sized {}
23+
//~^ ERROR mismatched types
24+
//~| ERROR type mismatch resolving `() == impl !Sized`
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/opaque-type-unsatisfied-bound.rs:3:12
3+
|
4+
LL | #![feature(negative_bounds, negative_impls)]
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/opaque-type-unsatisfied-bound.rs:16:36
11+
|
12+
LL | fn weird0() -> impl Sized + !Sized {}
13+
| ------------------- ^^ types differ
14+
| |
15+
| the expected opaque type
16+
|
17+
= note: expected opaque type `impl !Sized`
18+
found unit type `()`
19+
20+
error[E0271]: type mismatch resolving `() == impl !Sized`
21+
--> $DIR/opaque-type-unsatisfied-bound.rs:16:16
22+
|
23+
LL | fn weird0() -> impl Sized + !Sized {}
24+
| ^^^^^^^^^^^^^^^^^^^ types differ
25+
26+
error[E0308]: mismatched types
27+
--> $DIR/opaque-type-unsatisfied-bound.rs:19:36
28+
|
29+
LL | fn weird1() -> impl Sized + !Sized {}
30+
| ------------------- ^^ types differ
31+
| |
32+
| the expected opaque type
33+
|
34+
= note: expected opaque type `impl !Sized`
35+
found unit type `()`
36+
37+
error[E0271]: type mismatch resolving `() == impl !Sized`
38+
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16
39+
|
40+
LL | fn weird1() -> impl Sized + !Sized {}
41+
| ^^^^^^^^^^^^^^^^^^^ types differ
42+
43+
error[E0308]: mismatched types
44+
--> $DIR/opaque-type-unsatisfied-bound.rs:22:36
45+
|
46+
LL | fn weird2() -> impl !Sized + Sized {}
47+
| ------------------- ^^ types differ
48+
| |
49+
| the expected opaque type
50+
|
51+
= note: expected opaque type `impl !Sized`
52+
found unit type `()`
53+
54+
error[E0271]: type mismatch resolving `() == impl !Sized`
55+
--> $DIR/opaque-type-unsatisfied-bound.rs:22:16
56+
|
57+
LL | fn weird2() -> impl !Sized + Sized {}
58+
| ^^^^^^^^^^^^^^^^^^^ types differ
59+
60+
error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied
61+
--> $DIR/opaque-type-unsatisfied-bound.rs:13:13
62+
|
63+
LL | consume(produce());
64+
| ------- ^^^^^^^^^ the trait `Trait` is not implemented for `impl !Trait`
65+
| |
66+
| required by a bound introduced by this call
67+
|
68+
note: required by a bound in `consume`
69+
--> $DIR/opaque-type-unsatisfied-bound.rs:10:20
70+
|
71+
LL | fn consume(_: impl Trait) {}
72+
| ^^^^^ required by this bound in `consume`
73+
74+
error: aborting due to 7 previous errors; 1 warning emitted
75+
76+
Some errors have detailed explanations: E0271, E0277, E0308.
77+
For more information about an error, try `rustc --explain E0271`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: -Znext-solver
2+
3+
#![feature(negative_bounds, unboxed_closures)]
4+
//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
5+
6+
fn produce() -> impl !Fn<(u32,)> {}
7+
//~^ ERROR mismatched types
8+
//~| ERROR type mismatch resolving `() == impl !Fn<(u32,)>`
9+
10+
fn main() {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:3:12
3+
|
4+
LL | #![feature(negative_bounds, unboxed_closures)]
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:6:34
11+
|
12+
LL | fn produce() -> impl !Fn<(u32,)> {}
13+
| ---------------- ^^ types differ
14+
| |
15+
| the expected opaque type
16+
|
17+
= note: expected opaque type `impl !Fn<(u32,)>`
18+
found unit type `()`
19+
20+
error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>`
21+
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:6:17
22+
|
23+
LL | fn produce() -> impl !Fn<(u32,)> {}
24+
| ^^^^^^^^^^^^^^^^ types differ
25+
26+
error: aborting due to 2 previous errors; 1 warning emitted
27+
28+
Some errors have detailed explanations: E0271, E0308.
29+
For more information about an error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)