diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 1d57fd9e4b285..0cc886a2c1909 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -749,14 +749,19 @@ fn receiver_is_dispatchable<'tcx>( let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args); clauses.push(trait_predicate.upcast(tcx)); - // U satisfies `Trait`'s where-bounds. + // U satisfies Trait's trait bounds. When normalizing `U: Trait`, aliases + // in the arguments of supertrait bounds can generate trait obligations which may only be + // be provable using where-clauses from Trait (#161621). clauses.extend( tcx.clauses_of(trait_def_id) .instantiate(tcx, args) .clauses .into_iter() - .map(Unnormalized::skip_norm_wip), + .map(Unnormalized::skip_norm_wip) + .filter(|clause| matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(_))), ); + // FIXME(@dianne): we need projection clauses too in some form, but adding them all + // unmodified can introduce ambiguity (#163550) let meta_sized_predicate = { let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, DUMMY_SP); diff --git a/tests/ui/dyn-compatibility/dispatchability-placeholder-does-not-satisfy-bounds.rs b/tests/ui/dyn-compatibility/dispatchability-placeholder-does-not-satisfy-bounds.rs new file mode 100644 index 0000000000000..c899c66056839 --- /dev/null +++ b/tests/ui/dyn-compatibility/dispatchability-placeholder-does-not-satisfy-bounds.rs @@ -0,0 +1,24 @@ +//! Tests for specific instances of that don't +//! pass yet. See `dispatchability-placeholder-satisfies-bounds.rs` for context. +// FIXME(@dianne): this should be gone soon +//@ known-bug: unknown + +trait HasAssoc { + type Assoc; +} + +trait Parent {} + +trait NotDynCompatible +where + // We need to be able to normalize this for RustaceansAreAwesome in order to prove + // `<(RustaceansAreAwesome,) as HasAssoc>::Assoc: Owned` for the projection in the argument to + // the `Self: Parent<...>` supertrait bound. Currently a projection clause for it is missing + // from the `ParamEnv`. + (Self,): HasAssoc, + Self: Parent<<<(Self,) as HasAssoc>::Assoc as ToOwned>::Owned>, +{ + fn f(&self); +} + +fn main() {} diff --git a/tests/ui/dyn-compatibility/dispatchability-placeholder-does-not-satisfy-bounds.stderr b/tests/ui/dyn-compatibility/dispatchability-placeholder-does-not-satisfy-bounds.stderr new file mode 100644 index 0000000000000..3b2b8c62e8994 --- /dev/null +++ b/tests/ui/dyn-compatibility/dispatchability-placeholder-does-not-satisfy-bounds.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `<(RustaceansAreAwesome,) as HasAssoc>::Assoc: Clone` is not satisfied + --> $DIR/dispatchability-placeholder-does-not-satisfy-bounds.rs:21:5 + | +LL | fn f(&self); + | ^^^^^^^^^^^^ the trait `Clone` is not implemented for `<(RustaceansAreAwesome,) as HasAssoc>::Assoc` + | + = note: required for `<(RustaceansAreAwesome,) as HasAssoc>::Assoc` to implement `ToOwned` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-compatibility/dispatchability-placeholder-satisfies-bounds.rs b/tests/ui/dyn-compatibility/dispatchability-placeholder-satisfies-bounds.rs index 421b9a512c1e4..611e1cb59d4ab 100644 --- a/tests/ui/dyn-compatibility/dispatchability-placeholder-satisfies-bounds.rs +++ b/tests/ui/dyn-compatibility/dispatchability-placeholder-satisfies-bounds.rs @@ -1,11 +1,15 @@ -//! Regression tests for . When checking whether -//! method receivers for a trait `Trait` are dynamically dispatchable, we use a placeholder type in -//! place of `dyn Trait` to avoid a cycle (as that would require determining whether `Trait` is dyn- -//! compatible). This placeholder must satisfy `Trait`'s where-bounds to avoid errors in param- -//! environment normalization. +//! Regression tests for and similar. When +//! checking whether method receivers for a trait `Trait` are dynamically dispatchable, we (at the +//! time of writing) use a placeholder type called `RustaceansAreAwesome` in place of `dyn Trait` to +//! avoid a cycle (as using `dyn Trait` requires determining whether `Trait` is dyn-compatible). We +//! assume that `RustaceansAreAwesome` implements `Trait`, so when normalizing the param-environment +//! we construct, we may have to prove obligations for aliases encountered in arguments to super- +//! trait bounds. It's possible for these to only be provable using clauses from `Trait` or its +//! supertraits that would be necessary for `RustaceansAreAwesome` to implement `Trait`. //@ check-pass -// Test 1 +// This works for `Self: Super<...Ty::::Assoc...>` after the `where`. +// We need to assume `(Args, RustaceansAreAwesome::Output): SignatureToFnPtr`. use std::ops::Deref; @@ -22,7 +26,8 @@ where fn method(&self); } -// Test 2 +// This works for `Trait: Super<...Ty::Assoc...>` before the `where`. +// We need to assume `A: Associator`. trait Associator { type Point; @@ -34,4 +39,60 @@ trait Trait + ?Sized>: Marker { fn method(&self); } +// Regression test for : we need to be careful with +// projection clauses involving `RustaceansAreAwesome`. Here, if we simply assumed that +// `::RowIndex == ::RowIndex`, we'd end up with +// ambiguity, as we also assume `::RowIndex == ::RowIndex`.`Self` +// stands in for the `Self` type of the impl we're imagining dispatching to (pretending +// `RustaceansAreAwesome` is a trait object). + +pub trait Matrix { + type Coordinates; +} + +pub trait Matrix2D: Matrix::RowIndex> { + type RowIndex; +} + +pub trait Transposable>: Matrix2D { + fn transpose(&self) -> T; +} + +// An example where we can't add any additional projections without introducing ambiguity: we don't +// want to assume `<() as HasAssoc>::Assoc` is both `Self` and `RustaceansAreAwesome`. At the time +// of writing, we let `<() as HasAssoc>::Assoc` normalize to `Self` during receiver dispatchability +// checking. This should be fine, since to call methods on a `dyn TechnicallyDynCompatible`, we'd +// need `<() as HasAssoc>::Assoc` to be `dyn TechnicallyDynCompatible`. This is the same reasoning +// that lets us assume `RustaceansAreAwesome` implements its trait at all: to use the trait object, +// it must implement the trait; otherwise, receiver dispatchability doesn't mean much. + +trait HasAssoc { + type Assoc; +} + +impl HasAssoc for () { + type Assoc = (); +} + +trait Parent {} + +trait TechnicallyDynCompatible +where + (): HasAssoc, + Self: Parent<<() as HasAssoc>::Assoc>, +{ + fn f(&self) {} +} + +// Since we have `TechnincallyDynCompatible` defined, let's keep its dyn-compatibility from breaking +// accidentally (and also sanity-check the above comment). + +impl Parent<()> for () {} +impl TechnicallyDynCompatible for () {} + +fn technically_dyn_compatible_is_dyn_compatible() { + let x: &dyn TechnicallyDynCompatible = &(); + // We can't call `x.f()` since `<() as HasAssoc>::Assoc` isn't `dyn TechnicallyDynCompatible`. +} + fn main() {}