Skip to content

Commit 0f6fc44

Browse files
committed
rustc_middle: Pretty-print negative bounds correctly
1 parent 32cea61 commit 0f6fc44

File tree

5 files changed

+173
-21
lines changed

5 files changed

+173
-21
lines changed

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

+51-21
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,8 @@ 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 has_sized_bound = false;
916+
let mut has_negative_sized_bound = false;
916917
let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
917918

918919
for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) {
@@ -922,13 +923,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
922923
ty::ClauseKind::Trait(pred) => {
923924
let trait_ref = bound_predicate.rebind(pred.trait_ref);
924925

925-
// Don't print + Sized, but rather + ?Sized if absent.
926+
// Don't print `+ Sized`, but rather `+ ?Sized` if absent.
926927
if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
927-
is_sized = true;
928-
continue;
928+
match pred.polarity {
929+
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {
930+
has_sized_bound = true;
931+
continue;
932+
}
933+
ty::ImplPolarity::Negative => has_negative_sized_bound = true,
934+
}
929935
}
930936

931-
self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
937+
self.insert_trait_and_projection(
938+
trait_ref,
939+
pred.polarity,
940+
None,
941+
&mut traits,
942+
&mut fn_traits,
943+
);
932944
}
933945
ty::ClauseKind::Projection(pred) => {
934946
let proj_ref = bound_predicate.rebind(pred);
@@ -939,6 +951,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
939951

940952
self.insert_trait_and_projection(
941953
trait_ref,
954+
ty::ImplPolarity::Positive,
942955
Some(proj_ty),
943956
&mut traits,
944957
&mut fn_traits,
@@ -955,7 +968,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
955968

956969
let mut first = true;
957970
// 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;
971+
let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;
959972

960973
for (fn_once_trait_ref, entry) in fn_traits {
961974
write!(self, "{}", if first { "" } else { " + " })?;
@@ -1002,18 +1015,21 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10021015
// trait_refs we collected in the OpaqueFnEntry as normal trait refs.
10031016
_ => {
10041017
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-
);
1018+
traits
1019+
.entry((fn_once_trait_ref, ty::ImplPolarity::Positive))
1020+
.or_default()
1021+
.extend(
1022+
// Group the return ty with its def id, if we had one.
1023+
entry.return_ty.map(|ty| {
1024+
(tcx.require_lang_item(LangItem::FnOnce, None), ty)
1025+
}),
1026+
);
10111027
}
10121028
if let Some(trait_ref) = entry.fn_mut_trait_ref {
1013-
traits.entry(trait_ref).or_default();
1029+
traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
10141030
}
10151031
if let Some(trait_ref) = entry.fn_trait_ref {
1016-
traits.entry(trait_ref).or_default();
1032+
traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
10171033
}
10181034
}
10191035
}
@@ -1023,11 +1039,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10231039
}
10241040

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

10291045
self.wrap_binder(&trait_ref, |trait_ref, cx| {
10301046
define_scoped_cx!(cx);
1047+
1048+
if polarity == ty::ImplPolarity::Negative {
1049+
p!("!");
1050+
}
10311051
p!(print(trait_ref.print_only_trait_name()));
10321052

10331053
let generics = tcx.generics_of(trait_ref.def_id);
@@ -1094,9 +1114,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10941114
})?;
10951115
}
10961116

1097-
if !is_sized {
1098-
write!(self, "{}?Sized", if first { "" } else { " + " })?;
1099-
} else if first {
1117+
let add_sized = has_sized_bound && (first || has_negative_sized_bound);
1118+
let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound;
1119+
if add_sized || add_maybe_sized {
1120+
if !first {
1121+
write!(self, " + ")?;
1122+
}
1123+
if add_maybe_sized {
1124+
write!(self, "?")?;
1125+
}
11001126
write!(self, "Sized")?;
11011127
}
11021128

@@ -1128,9 +1154,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
11281154
fn insert_trait_and_projection(
11291155
&mut self,
11301156
trait_ref: ty::PolyTraitRef<'tcx>,
1157+
polarity: ty::ImplPolarity,
11311158
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
11321159
traits: &mut FxIndexMap<
1133-
ty::PolyTraitRef<'tcx>,
1160+
(ty::PolyTraitRef<'tcx>, ty::ImplPolarity),
11341161
FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
11351162
>,
11361163
fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
@@ -1139,7 +1166,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
11391166

11401167
// If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
11411168
// super-trait ref and record it there.
1142-
if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
1169+
// We skip negative Fn* bounds since they can't use parenthetical notation anyway.
1170+
if polarity == ty::ImplPolarity::Positive
1171+
&& let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
1172+
{
11431173
// If we have a FnOnce, then insert it into
11441174
if trait_def_id == fn_once_trait {
11451175
let entry = fn_traits.entry(trait_ref).or_default();
@@ -1167,7 +1197,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
11671197
}
11681198

11691199
// Otherwise, just group our traits and projection types.
1170-
traits.entry(trait_ref).or_default().extend(proj_ty);
1200+
traits.entry((trait_ref, polarity)).or_default().extend(proj_ty);
11711201
}
11721202

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

0 commit comments

Comments
 (0)