rustc_middle: Pretty-print negative bounds correctly

This commit is contained in:
León Orell Valerian Liehr 2023-12-27 17:57:55 +01:00
parent 32cea61c86
commit 977546d3fc
No known key found for this signature in database
GPG key ID: D17A07215F68E713
5 changed files with 173 additions and 21 deletions

View file

@ -912,7 +912,8 @@ fn pretty_print_opaque_impl_type(
let mut traits = FxIndexMap::default(); let mut traits = FxIndexMap::default();
let mut fn_traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default();
let mut is_sized = false; let mut has_sized_bound = false;
let mut has_negative_sized_bound = false;
let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) {
@ -922,13 +923,24 @@ fn pretty_print_opaque_impl_type(
ty::ClauseKind::Trait(pred) => { ty::ClauseKind::Trait(pred) => {
let trait_ref = bound_predicate.rebind(pred.trait_ref); let trait_ref = bound_predicate.rebind(pred.trait_ref);
// Don't print + Sized, but rather + ?Sized if absent. // Don't print `+ Sized`, but rather `+ ?Sized` if absent.
if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
is_sized = true; match pred.polarity {
continue; ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {
has_sized_bound = true;
continue;
}
ty::ImplPolarity::Negative => has_negative_sized_bound = true,
}
} }
self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); self.insert_trait_and_projection(
trait_ref,
pred.polarity,
None,
&mut traits,
&mut fn_traits,
);
} }
ty::ClauseKind::Projection(pred) => { ty::ClauseKind::Projection(pred) => {
let proj_ref = bound_predicate.rebind(pred); let proj_ref = bound_predicate.rebind(pred);
@ -939,6 +951,7 @@ fn pretty_print_opaque_impl_type(
self.insert_trait_and_projection( self.insert_trait_and_projection(
trait_ref, trait_ref,
ty::ImplPolarity::Positive,
Some(proj_ty), Some(proj_ty),
&mut traits, &mut traits,
&mut fn_traits, &mut fn_traits,
@ -955,7 +968,7 @@ fn pretty_print_opaque_impl_type(
let mut first = true; let mut first = true;
// Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized; let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;
for (fn_once_trait_ref, entry) in fn_traits { for (fn_once_trait_ref, entry) in fn_traits {
write!(self, "{}", if first { "" } else { " + " })?; write!(self, "{}", if first { "" } else { " + " })?;
@ -1002,18 +1015,21 @@ fn pretty_print_opaque_impl_type(
// trait_refs we collected in the OpaqueFnEntry as normal trait refs. // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
_ => { _ => {
if entry.has_fn_once { if entry.has_fn_once {
traits.entry(fn_once_trait_ref).or_default().extend( traits
// Group the return ty with its def id, if we had one. .entry((fn_once_trait_ref, ty::ImplPolarity::Positive))
entry .or_default()
.return_ty .extend(
.map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)), // Group the return ty with its def id, if we had one.
); entry.return_ty.map(|ty| {
(tcx.require_lang_item(LangItem::FnOnce, None), ty)
}),
);
} }
if let Some(trait_ref) = entry.fn_mut_trait_ref { if let Some(trait_ref) = entry.fn_mut_trait_ref {
traits.entry(trait_ref).or_default(); traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
} }
if let Some(trait_ref) = entry.fn_trait_ref { if let Some(trait_ref) = entry.fn_trait_ref {
traits.entry(trait_ref).or_default(); traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
} }
} }
} }
@ -1023,11 +1039,15 @@ fn pretty_print_opaque_impl_type(
} }
// Print the rest of the trait types (that aren't Fn* family of traits) // Print the rest of the trait types (that aren't Fn* family of traits)
for (trait_ref, assoc_items) in traits { for ((trait_ref, polarity), assoc_items) in traits {
write!(self, "{}", if first { "" } else { " + " })?; write!(self, "{}", if first { "" } else { " + " })?;
self.wrap_binder(&trait_ref, |trait_ref, cx| { self.wrap_binder(&trait_ref, |trait_ref, cx| {
define_scoped_cx!(cx); define_scoped_cx!(cx);
if polarity == ty::ImplPolarity::Negative {
p!("!");
}
p!(print(trait_ref.print_only_trait_name())); p!(print(trait_ref.print_only_trait_name()));
let generics = tcx.generics_of(trait_ref.def_id); let generics = tcx.generics_of(trait_ref.def_id);
@ -1094,9 +1114,15 @@ fn pretty_print_opaque_impl_type(
})?; })?;
} }
if !is_sized { let add_sized = has_sized_bound && (first || has_negative_sized_bound);
write!(self, "{}?Sized", if first { "" } else { " + " })?; let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound;
} else if first { if add_sized || add_maybe_sized {
if !first {
write!(self, " + ")?;
}
if add_maybe_sized {
write!(self, "?")?;
}
write!(self, "Sized")?; write!(self, "Sized")?;
} }
@ -1128,9 +1154,10 @@ fn pretty_print_opaque_impl_type(
fn insert_trait_and_projection( fn insert_trait_and_projection(
&mut self, &mut self,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
polarity: ty::ImplPolarity,
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>, proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
traits: &mut FxIndexMap< traits: &mut FxIndexMap<
ty::PolyTraitRef<'tcx>, (ty::PolyTraitRef<'tcx>, ty::ImplPolarity),
FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>, FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
>, >,
fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>, fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
@ -1139,7 +1166,10 @@ fn insert_trait_and_projection(
// If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
// super-trait ref and record it there. // super-trait ref and record it there.
if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() { // We skip negative Fn* bounds since they can't use parenthetical notation anyway.
if polarity == ty::ImplPolarity::Positive
&& let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
{
// If we have a FnOnce, then insert it into // If we have a FnOnce, then insert it into
if trait_def_id == fn_once_trait { if trait_def_id == fn_once_trait {
let entry = fn_traits.entry(trait_ref).or_default(); let entry = fn_traits.entry(trait_ref).or_default();
@ -1167,7 +1197,7 @@ fn insert_trait_and_projection(
} }
// Otherwise, just group our traits and projection types. // Otherwise, just group our traits and projection types.
traits.entry(trait_ref).or_default().extend(proj_ty); traits.entry((trait_ref, polarity)).or_default().extend(proj_ty);
} }
fn pretty_print_inherent_projection( fn pretty_print_inherent_projection(

View file

@ -0,0 +1,23 @@
// compile-flags: -Znext-solver
#![feature(negative_bounds, negative_impls)]
trait Trait {}
impl !Trait for () {}
fn produce() -> impl !Trait {}
fn consume(_: impl Trait) {}
fn main() {
consume(produce()); //~ ERROR the trait bound `impl !Trait: Trait` is not satisfied
}
fn weird0() -> impl Sized + !Sized {}
//~^ ERROR mismatched types
//~| ERROR type mismatch resolving `() == impl !Sized + Sized`
fn weird1() -> impl !Sized + Sized {}
//~^ ERROR mismatched types
//~| ERROR type mismatch resolving `() == impl !Sized + Sized`
fn weird2() -> impl !Sized {}
//~^ ERROR mismatched types
//~| ERROR type mismatch resolving `() == impl !Sized`

View file

@ -0,0 +1,69 @@
error[E0308]: mismatched types
--> $DIR/opaque-type-unsatisfied-bound.rs:15:36
|
LL | fn weird0() -> impl Sized + !Sized {}
| ------------------- ^^ types differ
| |
| the expected opaque type
|
= note: expected opaque type `impl !Sized + Sized`
found unit type `()`
error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
--> $DIR/opaque-type-unsatisfied-bound.rs:15:16
|
LL | fn weird0() -> impl Sized + !Sized {}
| ^^^^^^^^^^^^^^^^^^^ types differ
error[E0308]: mismatched types
--> $DIR/opaque-type-unsatisfied-bound.rs:18:36
|
LL | fn weird1() -> impl !Sized + Sized {}
| ------------------- ^^ types differ
| |
| the expected opaque type
|
= note: expected opaque type `impl !Sized + Sized`
found unit type `()`
error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
--> $DIR/opaque-type-unsatisfied-bound.rs:18:16
|
LL | fn weird1() -> impl !Sized + Sized {}
| ^^^^^^^^^^^^^^^^^^^ types differ
error[E0308]: mismatched types
--> $DIR/opaque-type-unsatisfied-bound.rs:21:28
|
LL | fn weird2() -> impl !Sized {}
| ----------- ^^ types differ
| |
| the expected opaque type
|
= note: expected opaque type `impl !Sized`
found unit type `()`
error[E0271]: type mismatch resolving `() == impl !Sized`
--> $DIR/opaque-type-unsatisfied-bound.rs:21:16
|
LL | fn weird2() -> impl !Sized {}
| ^^^^^^^^^^^ types differ
error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied
--> $DIR/opaque-type-unsatisfied-bound.rs:12:13
|
LL | consume(produce());
| ------- ^^^^^^^^^ the trait `Trait` is not implemented for `impl !Trait`
| |
| required by a bound introduced by this call
|
note: required by a bound in `consume`
--> $DIR/opaque-type-unsatisfied-bound.rs:9:20
|
LL | fn consume(_: impl Trait) {}
| ^^^^^ required by this bound in `consume`
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0271, E0277, E0308.
For more information about an error, try `rustc --explain E0271`.

View file

@ -0,0 +1,9 @@
// compile-flags: -Znext-solver
#![feature(negative_bounds, unboxed_closures)]
fn produce() -> impl !Fn<(u32,)> {}
//~^ ERROR mismatched types
//~| ERROR type mismatch resolving `() == impl !Fn<(u32,)>`
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0308]: mismatched types
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:34
|
LL | fn produce() -> impl !Fn<(u32,)> {}
| ---------------- ^^ types differ
| |
| the expected opaque type
|
= note: expected opaque type `impl !Fn<(u32,)>`
found unit type `()`
error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>`
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
|
LL | fn produce() -> impl !Fn<(u32,)> {}
| ^^^^^^^^^^^^^^^^ types differ
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0271, E0308.
For more information about an error, try `rustc --explain E0271`.