From 72bd174c43406068727e17cbf6fc2f4e1a36f6af Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 3 Feb 2025 02:38:56 +0000 Subject: [PATCH 1/2] Do not deduplicate list of associated types provided by dyn principal --- .../src/hir_ty_lowering/dyn_compatibility.rs | 127 ++++++++++++++---- compiler/rustc_middle/src/ty/relate.rs | 18 +-- compiler/rustc_type_ir/src/elaborate.rs | 15 +-- tests/crashes/125957.rs | 20 --- tests/crashes/132330.rs | 28 ---- .../associated-types-overridden-binding-2.rs | 2 +- ...sociated-types-overridden-binding-2.stderr | 14 +- .../associated-types-overridden-binding.rs | 1 + ...associated-types-overridden-binding.stderr | 13 +- .../closures/deduce-from-object-supertrait.rs | 18 +++ .../multiple-supers-should-work.rs | 21 +++ .../crash-due-to-projections-modulo-norm.rs} | 17 ++- .../incomplete-multiple-super-projection.rs | 32 +++++ ...ncomplete-multiple-super-projection.stderr | 12 ++ .../infer-shadows-implied-projection.rs} | 2 +- tests/ui/traits/object/outlives-super-proj.rs | 24 ++++ tests/ui/traits/object/pretty.stderr | 6 +- tests/ui/traits/object/redundant.rs | 12 ++ 18 files changed, 265 insertions(+), 117 deletions(-) delete mode 100644 tests/crashes/125957.rs delete mode 100644 tests/crashes/132330.rs create mode 100644 tests/ui/closures/deduce-from-object-supertrait.rs create mode 100644 tests/ui/dyn-compatibility/multiple-supers-should-work.rs rename tests/{crashes/126944.rs => ui/traits/object/crash-due-to-projections-modulo-norm.rs} (77%) create mode 100644 tests/ui/traits/object/incomplete-multiple-super-projection.rs create mode 100644 tests/ui/traits/object/incomplete-multiple-super-projection.stderr rename tests/{crashes/79590.rs => ui/traits/object/infer-shadows-implied-projection.rs} (92%) create mode 100644 tests/ui/traits/object/outlives-super-proj.rs create mode 100644 tests/ui/traits/object/redundant.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 830dca0d3cd53..3eb4945ebf80e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; @@ -58,9 +58,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let (trait_bounds, mut projection_bounds) = + let (elaborated_trait_bounds, elaborated_projection_bounds) = traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied()); - let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds + let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds .into_iter() .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); @@ -103,29 +103,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + // Map the projection bounds onto a key that makes it easy to remove redundant + // bounds that are constrained by supertraits of the principal def id. + // + // Also make sure we detect conflicting bounds from expanding a trait alias and + // also specifying it manually, like: + // ``` + // type Alias = Trait; + // let _: &dyn Alias = /* ... */; + // ``` + let mut projection_bounds = FxIndexMap::default(); + for (proj, proj_span) in elaborated_projection_bounds { + let key = ( + proj.skip_binder().projection_term.def_id, + tcx.anonymize_bound_vars( + proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)), + ), + ); + if let Some((old_proj, old_proj_span)) = + projection_bounds.insert(key, (proj, proj_span)) + && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj) + { + let item = tcx.item_name(proj.item_def_id()); + self.dcx() + .struct_span_err( + span, + format!( + "conflicting associated type bounds for `{item}` when \ + expanding trait alias" + ), + ) + .with_span_label( + old_proj_span, + format!("`{item}` is specified to be `{}` here", old_proj.term()), + ) + .with_span_label( + proj_span, + format!("`{item}` is specified to be `{}` here", proj.term()), + ) + .emit(); + } + } + let principal_trait = regular_traits.into_iter().next(); - let mut needed_associated_types = FxIndexSet::default(); - if let Some((principal_trait, spans)) = &principal_trait { - let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx); - for ClauseWithSupertraitSpan { pred, supertrait_span } in traits::elaborate( + let mut needed_associated_types = vec![]; + if let Some((principal_trait, ref spans)) = principal_trait { + let principal_trait = principal_trait.map_bound(|trait_pred| { + assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive); + trait_pred.trait_ref + }); + + for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate( tcx, - [ClauseWithSupertraitSpan::new(pred, *spans.last().unwrap())], + [ClauseWithSupertraitSpan::new( + ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx), + *spans.last().unwrap(), + )], ) .filter_only_self() { - debug!("observing object predicate `{pred:?}`"); + let clause = clause.instantiate_supertrait(tcx, principal_trait); + debug!("observing object predicate `{clause:?}`"); - let bound_predicate = pred.kind(); + let bound_predicate = clause.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + ty::ClauseKind::Trait(pred) => { // FIXME(negative_bounds): Handle this correctly... let trait_ref = tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref)); needed_associated_types.extend( - tcx.associated_items(trait_ref.def_id()) + tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() + // We only care about associated types. .filter(|item| item.kind == ty::AssocKind::Type) + // No RPITITs -- even with `async_fn_in_dyn_trait`, they are implicit. .filter(|item| !item.is_impl_trait_in_trait()) // If the associated type has a `where Self: Sized` bound, // we do not need to constrain the associated type. @@ -133,7 +185,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|item| (item.def_id, trait_ref)), ); } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { + ty::ClauseKind::Projection(pred) => { let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be instantiated with a // `trait_object_dummy_self`, so check for that. @@ -161,8 +213,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `dyn MyTrait`, which is uglier but works. See // the discussion in #56288 for alternatives. if !references_self { - // Include projections defined on supertraits. - projection_bounds.push((pred, supertrait_span)); + let key = ( + pred.skip_binder().projection_term.def_id, + tcx.anonymize_bound_vars( + pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)), + ), + ); + if !projection_bounds.contains_key(&key) { + projection_bounds.insert(key, (pred, supertrait_span)); + } } self.check_elaborated_projection_mentions_input_lifetimes( @@ -182,12 +241,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // types that we expect to be provided by the user, so the following loop // removes all the associated types that have a corresponding `Projection` // clause, either from expanding trait aliases or written by the user. - for &(projection_bound, span) in &projection_bounds { + for &(projection_bound, span) in projection_bounds.values() { let def_id = projection_bound.item_def_id(); - let trait_ref = tcx.anonymize_bound_vars( - projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)), - ); - needed_associated_types.swap_remove(&(def_id, trait_ref)); if tcx.generics_require_sized_self(def_id) { tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, @@ -198,9 +253,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + let mut missing_assoc_types = FxIndexSet::default(); + let projection_bounds: Vec<_> = needed_associated_types + .into_iter() + .filter_map(|key| { + if let Some(assoc) = projection_bounds.get(&key) { + Some(*assoc) + } else { + missing_assoc_types.insert(key); + None + } + }) + .collect(); + if let Err(guar) = self.check_for_required_assoc_tys( principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()), - needed_associated_types, + missing_assoc_types, potential_assoc_types, hir_bounds, ) { @@ -266,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) }); - let existential_projections = projection_bounds.iter().map(|(bound, _)| { + let existential_projections = projection_bounds.into_iter().map(|(bound, _)| { bound.map_bound(|mut b| { assert_eq!(b.projection_term.self_ty(), dummy_self); @@ -291,12 +359,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) }); - let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| { - assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive); - assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self); + let mut auto_trait_predicates: Vec<_> = auto_traits + .into_iter() + .map(|(trait_pred, _)| { + assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive); + assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self); - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id())) - }); + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id())) + }) + .collect(); + auto_trait_predicates.dedup(); // N.b. principal, projections, auto traits // FIXME: This is actually wrong with multiple principals in regards to symbol mangling @@ -306,7 +378,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .chain(auto_trait_predicates) .collect::>(); v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - v.dedup(); let existential_predicates = tcx.mk_poly_existential_predicates(&v); // Use explicitly-specified region bound, unless the bound is missing. diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index afdec7a86d445..1d1aad916bc21 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -79,20 +79,11 @@ impl<'tcx> Relate> for &'tcx ty::List RelateResult<'tcx, Self> { let tcx = relation.cx(); - - // FIXME: this is wasteful, but want to do a perf run to see how slow it is. - // We need to perform this deduplication as we sometimes generate duplicate projections - // in `a`. - let mut a_v: Vec<_> = a.into_iter().collect(); - let mut b_v: Vec<_> = b.into_iter().collect(); - a_v.dedup(); - b_v.dedup(); - if a_v.len() != b_v.len() { + if a.len() != b.len() { return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))); } - - let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { - match (ep_a.skip_binder(), ep_b.skip_binder()) { + let v = + iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) { (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), @@ -109,8 +100,7 @@ impl<'tcx> Relate> for &'tcx ty::List Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))), - } - }); + }); tcx.mk_poly_existential_predicates_from_iter(v) } } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 923b74abdfd2f..b11bcff1d8bbb 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -44,25 +44,22 @@ pub trait Elaboratable { } pub struct ClauseWithSupertraitSpan { - pub pred: I::Predicate, + pub clause: I::Clause, // Span of the supertrait predicatae that lead to this clause. pub supertrait_span: I::Span, } impl ClauseWithSupertraitSpan { - pub fn new(pred: I::Predicate, span: I::Span) -> Self { - ClauseWithSupertraitSpan { pred, supertrait_span: span } + pub fn new(clause: I::Clause, span: I::Span) -> Self { + ClauseWithSupertraitSpan { clause, supertrait_span: span } } } impl Elaboratable for ClauseWithSupertraitSpan { fn predicate(&self) -> ::Predicate { - self.pred + self.clause.as_predicate() } fn child(&self, clause: ::Clause) -> Self { - ClauseWithSupertraitSpan { - pred: clause.as_predicate(), - supertrait_span: self.supertrait_span, - } + ClauseWithSupertraitSpan { clause, supertrait_span: self.supertrait_span } } fn child_with_derived_cause( @@ -72,7 +69,7 @@ impl Elaboratable for ClauseWithSupertraitSpan { _parent_trait_pred: crate::Binder>, _index: usize, ) -> Self { - ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span } + ClauseWithSupertraitSpan { clause, supertrait_span } } } diff --git a/tests/crashes/125957.rs b/tests/crashes/125957.rs deleted file mode 100644 index e3abe5262eb90..0000000000000 --- a/tests/crashes/125957.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#125957 -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] -#![feature(associated_const_equality)] - -pub struct Equal(); - -pub enum ParseMode { - Raw, -} -pub trait Parse { - const PARSE_MODE: ParseMode; -} -pub trait RenderRaw: Parse {} - -trait GenericVec { - fn unwrap() -> dyn RenderRaw; -} - -fn main() {} diff --git a/tests/crashes/132330.rs b/tests/crashes/132330.rs deleted file mode 100644 index 3432685749d9d..0000000000000 --- a/tests/crashes/132330.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ known-bug: #132330 -//@compile-flags: -Znext-solver=globally - -trait Service { - type S; -} - -trait Framing { - type F; -} - -impl Framing for () { - type F = (); -} - -trait HttpService: Service {} - -type BoxService = Box>; - -fn build_server BoxService>(_: F) {} - -fn make_server() -> Box> { - unimplemented!() -} - -fn main() { - build_server(|| make_server()) -} diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.rs b/tests/ui/associated-types/associated-types-overridden-binding-2.rs index fed60ccf089d0..247724eaaf112 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.rs +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.rs @@ -4,5 +4,5 @@ trait I32Iterator = Iterator; fn main() { let _: &dyn I32Iterator = &vec![42].into_iter(); - //~^ ERROR expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` + //~^ ERROR conflicting associated type bounds } diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr index 4dfd275a19058..71a4a2610aac4 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,11 +1,13 @@ -error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/associated-types-overridden-binding-2.rs:6:43 +error: conflicting associated type bounds for `Item` when expanding trait alias + --> $DIR/associated-types-overridden-binding-2.rs:6:13 | +LL | trait I32Iterator = Iterator; + | ---------- `Item` is specified to be `i32` here +... LL | let _: &dyn I32Iterator = &vec![42].into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` - | - = note: required for the cast from `&std::vec::IntoIter` to `&dyn Iterator` + | ^^^^^^^^^^^^^^^^----------^ + | | + | `Item` is specified to be `u32` here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-types/associated-types-overridden-binding.rs b/tests/ui/associated-types/associated-types-overridden-binding.rs index 9a64a06c31bad..333a3e30c7dcf 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding.rs +++ b/tests/ui/associated-types/associated-types-overridden-binding.rs @@ -8,4 +8,5 @@ trait U32Iterator = I32Iterator; //~ ERROR type annotations needed fn main() { let _: &dyn I32Iterator; + //~^ ERROR conflicting associated type bounds } diff --git a/tests/ui/associated-types/associated-types-overridden-binding.stderr b/tests/ui/associated-types/associated-types-overridden-binding.stderr index dc087e4185fb6..3b20015dfcab3 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding.stderr @@ -22,6 +22,17 @@ note: required by a bound in `I32Iterator` LL | trait I32Iterator = Iterator; | ^^^^^^^^^^ required by this bound in `I32Iterator` -error: aborting due to 2 previous errors +error: conflicting associated type bounds for `Item` when expanding trait alias + --> $DIR/associated-types-overridden-binding.rs:10:13 + | +LL | trait I32Iterator = Iterator; + | ---------- `Item` is specified to be `i32` here +... +LL | let _: &dyn I32Iterator; + | ^^^^^^^^^^^^^^^^----------^ + | | + | `Item` is specified to be `u32` here + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/closures/deduce-from-object-supertrait.rs b/tests/ui/closures/deduce-from-object-supertrait.rs new file mode 100644 index 0000000000000..aff750dc62ea3 --- /dev/null +++ b/tests/ui/closures/deduce-from-object-supertrait.rs @@ -0,0 +1,18 @@ +//@ check-pass + +// This test checks that we look at consider the super traits of trait objects +// when deducing closure signatures. + +trait Foo: Fn(Bar) {} +impl Foo for T where T: Fn(Bar) {} + +struct Bar; +impl Bar { + fn bar(&self) {} +} + +fn main() { + let x: &dyn Foo = &|x| { + x.bar(); + }; +} diff --git a/tests/ui/dyn-compatibility/multiple-supers-should-work.rs b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs new file mode 100644 index 0000000000000..6f381da9a2200 --- /dev/null +++ b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs @@ -0,0 +1,21 @@ +//@ check-pass + +// We previously incorrectly deduplicated the list of projection bounds +// of trait objects, causing us to incorrectly reject this code, cc #136458. + +trait Sup { + type Assoc; +} + +impl Sup for () { + type Assoc = T; +} + +trait Trait: Sup + Sup {} + +impl Trait for () {} + +fn main() { + let x: &dyn Trait<(), _> = &(); + let y: &dyn Trait<_, ()> = x; +} diff --git a/tests/crashes/126944.rs b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs similarity index 77% rename from tests/crashes/126944.rs rename to tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs index c0c5622e26020..b1f7c4a600021 100644 --- a/tests/crashes/126944.rs +++ b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs @@ -1,9 +1,12 @@ -//@ known-bug: rust-lang/rust#126944 +//@ check-pass + +// Regression test for #126944. + // Step 1: Create two names for a single type: `Thing` and `AlsoThing` struct Thing; struct Dummy; -pub trait DummyTrait { +trait DummyTrait { type DummyType; } impl DummyTrait for Dummy { @@ -13,7 +16,7 @@ type AlsoThing = ::DummyType; // Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject` -pub trait SomeTrait { +trait SomeTrait { type Item; } type TraitObject = dyn SomeTrait; @@ -21,12 +24,12 @@ type AlsoTraitObject = dyn SomeTrait; // Step 3: Force the compiler to check whether the two names are the same type -pub trait Supertrait { +trait Supertrait { type Foo; } -pub trait Subtrait: Supertrait {} +trait Subtrait: Supertrait {} -pub trait HasOutput { +trait HasOutput { type Output; } @@ -36,3 +39,5 @@ where { todo!() } + +fn main() {} diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.rs b/tests/ui/traits/object/incomplete-multiple-super-projection.rs new file mode 100644 index 0000000000000..c7294eca4bdbe --- /dev/null +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.rs @@ -0,0 +1,32 @@ +// Regression test for #133361. + +trait Sup { + type Assoc; +} + +impl Sup for () { + type Assoc = T; +} +impl Dyn for () {} + +trait Dyn: Sup + Sup {} + +trait Trait { + type Assoc; +} +impl Trait for dyn Dyn<(), ()> { + type Assoc = &'static str; +} +impl Trait for dyn Dyn { +//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)` + type Assoc = usize; +} + +fn call(x: usize) -> as Trait>::Assoc { + x +} + +fn main() { + let x: &'static str = call::<(), ()>(0xDEADBEEF); + println!("{x}"); +} diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr new file mode 100644 index 0000000000000..b4271f70ed055 --- /dev/null +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)` + --> $DIR/incomplete-multiple-super-projection.rs:20:1 + | +LL | impl Trait for dyn Dyn<(), ()> { + | ------------------------------ first implementation here +... +LL | impl Trait for dyn Dyn { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/crashes/79590.rs b/tests/ui/traits/object/infer-shadows-implied-projection.rs similarity index 92% rename from tests/crashes/79590.rs rename to tests/ui/traits/object/infer-shadows-implied-projection.rs index b73864cce2349..628912c54faaa 100644 --- a/tests/crashes/79590.rs +++ b/tests/ui/traits/object/infer-shadows-implied-projection.rs @@ -1,4 +1,4 @@ -//@ known-bug: #79590 +//@ check-pass trait Database: Restriction {} diff --git a/tests/ui/traits/object/outlives-super-proj.rs b/tests/ui/traits/object/outlives-super-proj.rs new file mode 100644 index 0000000000000..15b67d9ab68e7 --- /dev/null +++ b/tests/ui/traits/object/outlives-super-proj.rs @@ -0,0 +1,24 @@ +//@ check-pass + +// Make sure that we still deduce outlives bounds from supertrait projections +// and require them for well-formedness. + +trait Trait { + type Assoc; +} + +trait Bar { + type Assoc; +} + +trait Foo<'a, T: 'a>: Bar { + +} + +fn outlives<'a, T: 'a>() {} + +fn implied_outlives<'a, T: Trait>(x: &dyn Foo<'a, T::Assoc>) { + outlives::<'a, T::Assoc>(); +} + +fn main() {} diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index 2f9fdf151f08c..37fe142951d89 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -154,12 +154,12 @@ error[E0308]: mismatched types --> $DIR/pretty.rs:41:56 | LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } - | - ^ expected `()`, found `&dyn HasGat = ()>` + | - ^ expected `()`, found `&dyn HasGat` | | - | help: try adding a return type: `-> &dyn HasGat = ()>` + | help: try adding a return type: `-> &dyn HasGat` | = note: expected unit type `()` - found reference `&dyn HasGat = ()>` + found reference `&dyn HasGat` error: aborting due to 14 previous errors; 1 warning emitted diff --git a/tests/ui/traits/object/redundant.rs b/tests/ui/traits/object/redundant.rs new file mode 100644 index 0000000000000..be07b15713898 --- /dev/null +++ b/tests/ui/traits/object/redundant.rs @@ -0,0 +1,12 @@ +//@ check-pass + +trait Foo: Bar {} +trait Bar { + type Out; +} + +fn w(x: &dyn Foo) { + let x: &dyn Foo = x; +} + +fn main() {} From a2a0cfe82563146325674b8d437f9f9f6e703703 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 5 Feb 2025 00:43:32 +0000 Subject: [PATCH 2/2] Assert that we always construct dyn types with the right number of projections --- compiler/rustc_middle/src/ty/relate.rs | 3 +++ compiler/rustc_middle/src/ty/sty.rs | 30 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 1d1aad916bc21..839c1c346a47b 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -79,6 +79,9 @@ impl<'tcx> Relate> for &'tcx ty::List RelateResult<'tcx, Self> { let tcx = relation.cx(); + // Fast path for when the auto traits do not match, or if the principals + // are from different traits and therefore the projections definitely don't + // match up. if a.len() != b.len() { return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8a31b2960188e..9eda760870716 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; +use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, elaborate}; use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; @@ -720,6 +720,34 @@ impl<'tcx> Ty<'tcx> { reg: ty::Region<'tcx>, repr: DynKind, ) -> Ty<'tcx> { + if cfg!(debug_assertions) { + let projection_count = obj.projection_bounds().count(); + let expected_count: usize = obj + .principal_def_id() + .into_iter() + .flat_map(|principal_def_id| { + // NOTE: This should agree with `needed_associated_types` in + // dyn trait lowering, or else we'll have ICEs. + elaborate::supertraits( + tcx, + ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)), + ) + .map(|principal| { + tcx.associated_items(principal.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| !item.is_impl_trait_in_trait()) + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) + .count() + }) + }) + .sum(); + assert_eq!( + projection_count, expected_count, + "expected {obj:?} to have {expected_count} projections, \ + but it has {projection_count}" + ); + } Ty::new(tcx, Dynamic(obj, reg, repr)) }