diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index b4054f8ff5edd..fd5302dc75b13 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -1,46 +1,60 @@ use rustc_data_structures::fx::FxHashSet; -use crate::ty::{PolyTraitRef, TyCtxt}; +use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, ToPredicate, TyCtxt}; -/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits. +/// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition. +/// /// This only exists in `rustc_middle` because the more powerful elaborator depends on /// `rustc_infer` for elaborating outlives bounds -- this should only be used for pretty /// printing. +pub fn super_predicates_for_pretty_printing<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: PolyTraitRef<'tcx>, +) -> impl Iterator> { + let clause = trait_ref.to_predicate(tcx); + Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] } +} + +/// Like [`super_predicates_for_pretty_printing`], except it only returns traits and filters out +/// all other [`Clause`]s. pub fn supertraits_for_pretty_printing<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: PolyTraitRef<'tcx>, ) -> impl Iterator> { - Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] } + super_predicates_for_pretty_printing(tcx, trait_ref).filter_map(|clause| { + clause.as_trait_clause().map(|trait_clause| trait_clause.to_poly_trait_ref()) + }) } struct Elaborator<'tcx> { tcx: TyCtxt<'tcx>, - visited: FxHashSet>, - stack: Vec>, + visited: FxHashSet>, + stack: Vec>, } impl<'tcx> Elaborator<'tcx> { fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) { - let supertrait_refs = self - .tcx - .super_predicates_of(trait_ref.def_id()) - .predicates - .into_iter() - .flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause()) - .map(|t| t.map_bound(|pred| pred.trait_ref)) - .filter(|supertrait_ref| self.visited.insert(*supertrait_ref)); - - self.stack.extend(supertrait_refs); + let super_predicates = + self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( + |&(pred, _)| { + let clause = pred.subst_supertrait(self.tcx, &trait_ref); + self.visited.insert(clause).then_some(clause) + }, + ); + + self.stack.extend(super_predicates); } } impl<'tcx> Iterator for Elaborator<'tcx> { - type Item = PolyTraitRef<'tcx>; + type Item = Clause<'tcx>; - fn next(&mut self) -> Option> { - if let Some(trait_ref) = self.stack.pop() { - self.elaborate(trait_ref); - Some(trait_ref) + fn next(&mut self) -> Option> { + if let Some(clause) = self.stack.pop() { + if let Some(trait_clause) = clause.as_trait_clause() { + self.elaborate(trait_clause.to_poly_trait_ref()); + } + Some(clause) } else { None } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c0bfd2380ade0..f90703e61844e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,7 +1,7 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::query::IntoQueryParam; use crate::query::Providers; -use crate::traits::util::supertraits_for_pretty_printing; +use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing}; use crate::ty::GenericArgKind; use crate::ty::{ ConstInt, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, @@ -1255,8 +1255,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Generate the main trait ref, including associated types. let mut first = true; - if let Some(principal) = predicates.principal() { - self.wrap_binder(&principal, |principal, cx| { + if let Some(bound_principal) = predicates.principal() { + self.wrap_binder(&bound_principal, |principal, cx| { define_scoped_cx!(cx); p!(print_def_path(principal.def_id, &[])); @@ -1281,19 +1281,53 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, // in order to place the projections inside the `<...>`. if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_cx = Ty::new_fresh(cx.tcx(), 0); - let principal = principal.with_self_ty(cx.tcx(), dummy_cx); + let principal_with_self = + principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); let args = cx .tcx() - .generics_of(principal.def_id) - .own_args_no_defaults(cx.tcx(), principal.args); - - let mut projections: Vec<_> = predicates.projection_bounds().collect(); - projections.sort_by_cached_key(|proj| { - cx.tcx().item_name(proj.item_def_id()).to_string() - }); + .generics_of(principal_with_self.def_id) + .own_args_no_defaults(cx.tcx(), principal_with_self.args); + + let bound_principal_with_self = bound_principal + .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); + + let super_projections: Vec<_> = + super_predicates_for_pretty_printing(cx.tcx(), bound_principal_with_self) + .filter_map(|clause| clause.as_projection_clause()) + .collect(); + + let mut projections: Vec<_> = predicates + .projection_bounds() + .filter(|&proj| { + // Filter out projections that are implied by the super predicates. + let proj_is_implied = super_projections.iter().any(|&super_proj| { + let super_proj = super_proj.map_bound(|super_proj| { + ty::ExistentialProjection::erase_self_ty(cx.tcx(), super_proj) + }); + + // This function is sometimes called on types with erased and + // anonymized regions, but the super projections can still + // contain named regions. So we erase and anonymize everything + // here to compare the types modulo regions below. + let proj = cx.tcx().erase_regions(proj); + let proj = cx.tcx().anonymize_bound_vars(proj); + let super_proj = cx.tcx().erase_regions(super_proj); + let super_proj = cx.tcx().anonymize_bound_vars(super_proj); + + proj == super_proj + }); + !proj_is_implied + }) + .map(|proj| { + // Skip the binder, because we don't want to print the binder in + // front of the associated item. + proj.skip_binder() + }) + .collect(); + + projections + .sort_by_cached_key(|proj| cx.tcx().item_name(proj.def_id).to_string()); if !args.is_empty() || !projections.is_empty() { p!(generic_delimiters(|cx| { diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs new file mode 100644 index 0000000000000..8958871ed5d72 --- /dev/null +++ b/tests/ui/traits/object/pretty.rs @@ -0,0 +1,37 @@ +// Test for pretty-printing trait object types. + +trait Super { + type Assoc; +} +trait Any: Super {} +trait Fixed: Super {} +trait FixedSub: Fixed {} +trait FixedStatic: Super {} + +trait SuperGeneric<'a> { + type Assoc2; +} +trait AnyGeneric<'a>: SuperGeneric<'a> {} +trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {} +trait FixedGeneric2<'a>: Super {} +trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {} +trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} +trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} + +fn dyn_super(x: &dyn Super) { x } //~ERROR mismatched types +fn dyn_any(x: &dyn Any) { x } //~ERROR mismatched types +fn dyn_fixed(x: &dyn Fixed) { x } //~ERROR mismatched types +fn dyn_fixed_multi(x: &dyn Fixed) { x } //~ERROR mismatched types +fn dyn_fixed_sub(x: &dyn FixedSub) { x } //~ERROR mismatched types +fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types + +fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types +fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types +fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types +fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types +fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types +fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types +fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } //~ERROR mismatched types +fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } //~ERROR mismatched types + +fn main() {} diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr new file mode 100644 index 0000000000000..bc645e5f9677d --- /dev/null +++ b/tests/ui/traits/object/pretty.stderr @@ -0,0 +1,157 @@ +error[E0308]: mismatched types + --> $DIR/pretty.rs:21:43 + | +LL | fn dyn_super(x: &dyn Super) { x } + | - ^ expected `()`, found `&dyn Super` + | | + | help: try adding a return type: `-> &dyn Super` + | + = note: expected unit type `()` + found reference `&dyn Super` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:22:39 + | +LL | fn dyn_any(x: &dyn Any) { x } + | - ^ expected `()`, found `&dyn Any` + | | + | help: try adding a return type: `-> &dyn Any` + | + = note: expected unit type `()` + found reference `&dyn Any` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:23:31 + | +LL | fn dyn_fixed(x: &dyn Fixed) { x } + | - ^ expected `()`, found `&dyn Fixed` + | | + | help: try adding a return type: `-> &dyn Fixed` + | + = note: expected unit type `()` + found reference `&dyn Fixed` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:24:50 + | +LL | fn dyn_fixed_multi(x: &dyn Fixed) { x } + | - ^ expected `()`, found `&dyn Fixed` + | | + | help: try adding a return type: `-> &dyn Fixed` + | + = note: expected unit type `()` + found reference `&dyn Fixed` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:25:38 + | +LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x } + | - ^ expected `()`, found `&dyn FixedSub` + | | + | help: try adding a return type: `-> &dyn FixedSub` + | + = note: expected unit type `()` + found reference `&dyn FixedSub` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:26:44 + | +LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x } + | - ^ expected `()`, found `&dyn FixedStatic` + | | + | help: try adding a return type: `-> &dyn FixedStatic` + | + = note: expected unit type `()` + found reference `&dyn FixedStatic` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:28:75 + | +LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } + | - ^ expected `()`, found `&dyn SuperGeneric<'a, Assoc2 = &u8>` + | | + | help: try adding a return type: `-> &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>` + | + = note: expected unit type `()` + found reference `&dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:29:71 + | +LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } + | - ^ expected `()`, found `&dyn AnyGeneric<'a, Assoc2 = &u8>` + | | + | help: try adding a return type: `-> &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>` + | + = note: expected unit type `()` + found reference `&dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:30:60 + | +LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } + | - ^ expected `()`, found `&dyn FixedGeneric1<'a>` + | | + | help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a>` + | + = note: expected unit type `()` + found reference `&dyn for<'a> FixedGeneric1<'a>` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:31:60 + | +LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } + | - ^ expected `()`, found `&dyn FixedGeneric2<'a>` + | | + | help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>` + | + = note: expected unit type `()` + found reference `&dyn for<'a> FixedGeneric2<'a>` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:32:79 + | +LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } + | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>` + | | + | help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` + | + = note: expected unit type `()` + found reference `&dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:33:40 + | +LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } + | - ^ expected `()`, found `&dyn FixedHrtb` + | | + | help: try adding a return type: `-> &dyn FixedHrtb` + | + = note: expected unit type `()` + found reference `&dyn FixedHrtb` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:34:73 + | +LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } + | - ^ expected `()`, found `&dyn AnyDifferentBinders` + | | + | help: try adding a return type: `-> &dyn AnyDifferentBinders` + | + = note: expected unit type `()` + found reference `&dyn AnyDifferentBinders` + +error[E0308]: mismatched types + --> $DIR/pretty.rs:35:65 + | +LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } + | - ^ expected `()`, found `&dyn FixedDifferentBinders` + | | + | help: try adding a return type: `-> &dyn FixedDifferentBinders` + | + = note: expected unit type `()` + found reference `&dyn FixedDifferentBinders` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/wf/hir-wf-canonicalized.rs b/tests/ui/wf/hir-wf-canonicalized.rs index bdb84409d009d..eac238f0fcab1 100644 --- a/tests/ui/wf/hir-wf-canonicalized.rs +++ b/tests/ui/wf/hir-wf-canonicalized.rs @@ -9,8 +9,8 @@ trait Callback: Fn(&Bar<'_, T>, &T::V) {} struct Bar<'a, T> { callback: Box>>>, //~^ ERROR the trait bound `Bar<'a, T>: Foo` is not satisfied - //~| ERROR the trait bound `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied - //~| ERROR the size for values of type `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time + //~| ERROR the trait bound `(dyn Callback, Output = ()> + 'static): Foo` is not satisfied + //~| ERROR the size for values of type `(dyn Callback, Output = ()> + 'static)` cannot be known at compilation time } impl Bar<'_, Bar<'_, T>> {} diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr index 4dca1f65232e2..8938801ce3d97 100644 --- a/tests/ui/wf/hir-wf-canonicalized.stderr +++ b/tests/ui/wf/hir-wf-canonicalized.stderr @@ -10,11 +10,11 @@ help: this trait has no implementations, consider adding one LL | trait Foo { | ^^^^^^^^^ -error[E0277]: the trait bound `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied +error[E0277]: the trait bound `(dyn Callback, Output = ()> + 'static): Foo` is not satisfied --> $DIR/hir-wf-canonicalized.rs:10:15 | LL | callback: Box>>>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback, Output = ()> + 'static)` | help: this trait has no implementations, consider adding one --> $DIR/hir-wf-canonicalized.rs:3:1 @@ -22,13 +22,13 @@ help: this trait has no implementations, consider adding one LL | trait Foo { | ^^^^^^^^^ -error[E0277]: the size for values of type `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Callback, Output = ()> + 'static)` cannot be known at compilation time --> $DIR/hir-wf-canonicalized.rs:10:15 | LL | callback: Box>>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Callback, for<'b, 'c, 'd> Output = ()> + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Callback, Output = ()> + 'static)` note: required by an implicit `Sized` bound in `Bar` --> $DIR/hir-wf-canonicalized.rs:9:16 |