From 4fde2415b5e74f5d0e5dd0b2c9dbb18d1c5520bc Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Apr 2024 17:40:40 +0000 Subject: [PATCH 1/3] elaborate obligations in coherence --- .../src/traits/coherence.rs | 7 ++-- src/tools/tidy/src/issues.txt | 1 - ...unnormalizable-projection-0.classic.stderr | 2 +- ...unnormalizable-projection-1.classic.stderr | 2 +- .../normalize-for-errors.current.stderr | 1 + tests/ui/coherence/normalize-for-errors.rs | 1 + .../super-traits/super-trait-knowable-1.rs | 18 ++++++++++ .../super-traits/super-trait-knowable-2.rs | 33 +++++++++++++++++++ ...super-trait-knowable-nested.current.stderr | 13 ++++++++ .../super-trait-knowable-nested.next.stderr | 13 ++++++++ .../super-trait-knowable-nested.rs | 22 +++++++++++++ tests/ui/issues/issue-48728.rs | 7 +++- .../coherence-fulfill-overflow.stderr | 5 +-- 13 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 tests/ui/coherence/super-traits/super-trait-knowable-1.rs create mode 100644 tests/ui/coherence/super-traits/super-trait-knowable-2.rs create mode 100644 tests/ui/coherence/super-traits/super-trait-knowable-nested.current.stderr create mode 100644 tests/ui/coherence/super-traits/super-trait-knowable-nested.next.stderr create mode 100644 tests/ui/coherence/super-traits/super-trait-knowable-nested.rs diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 59725ce9de096..680d641773564 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -358,9 +358,12 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( ) -> IntersectionHasImpossibleObligations<'tcx> { let infcx = selcx.infcx; + // Elaborate obligations in case the current obligation is unknowable, + // but its super trait bound is not. See #124532 for more details. + let obligations = util::elaborate(infcx.tcx, obligations.iter().cloned()); if infcx.next_trait_solver() { let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations.iter().cloned()); + ocx.register_obligations(obligations); let errors_and_ambiguities = ocx.select_all_or_error(); // We only care about the obligations that are *definitely* true errors. // Ambiguities do not prove the disjointness of two impls. @@ -387,7 +390,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( for obligation in obligations { // We use `evaluate_root_obligation` to correctly track intercrate // ambiguity clauses. - let evaluation_result = selcx.evaluate_root_obligation(obligation); + let evaluation_result = selcx.evaluate_root_obligation(&obligation); match evaluation_result { Ok(result) => { diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index a931782e8ccbe..cda5613536242 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -4061,7 +4061,6 @@ ui/traits/issue-6128.rs ui/traits/issue-6334.rs ui/traits/issue-65284-suggest-generic-trait-bound.rs ui/traits/issue-65673.rs -ui/traits/issue-66768.rs ui/traits/issue-68295.rs ui/traits/issue-7013.rs ui/traits/issue-70944.rs diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr index 2ffb6000ec822..f0953e40602a4 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr @@ -11,8 +11,8 @@ LL | | for<'a> >::Assoc: WhereBound, LL | impl Trait for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` | - = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` = note: downstream crates may implement trait `WhereBound` for type ` as WithAssoc<'a>>::Assoc` + = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr index 49b236f9d2aa2..43f01b7e58813 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr @@ -11,8 +11,8 @@ LL | | for<'a> Box<>::Assoc>: WhereBound, LL | impl Trait for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` | - = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box< as WithAssoc<'a>>::Assoc>` + = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr index dcbb73bd1ff10..e273a4db1da77 100644 --- a/tests/ui/coherence/normalize-for-errors.current.stderr +++ b/tests/ui/coherence/normalize-for-errors.current.stderr @@ -8,6 +8,7 @@ LL | impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Ite | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)` | = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + = note: upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions error: aborting due to 1 previous error diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs index 2288118676ab3..d212d85427ab8 100644 --- a/tests/ui/coherence/normalize-for-errors.rs +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -18,5 +18,6 @@ impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} //~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, //~| NOTE conflicting implementation for `(Box<(MyType,)>, //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions +//[current]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-1.rs b/tests/ui/coherence/super-traits/super-trait-knowable-1.rs new file mode 100644 index 0000000000000..0e56084d6548f --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-1.rs @@ -0,0 +1,18 @@ +// Added in #124532. While `(): Super` is knowable, `(): Sub` is not. +// +// We therefore elaborate super trait bounds in the implicit negative +// overlap check. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +trait Super {} +trait Sub: Super {} + +trait Overlap {} +impl> Overlap for U {} +impl Overlap for () {} + +fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-2.rs b/tests/ui/coherence/super-traits/super-trait-knowable-2.rs new file mode 100644 index 0000000000000..d1f2e8d1c1a15 --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-2.rs @@ -0,0 +1,33 @@ +// A regression test for pyella-0.1.5 which broke when +// enabling the new solver in coherence. +// +// `Tensor: TensorValue` is knowable while `Tensor: TensorOp` +// may be implemented downstream. We previously didn't check the +// super trait bound in coherence, causing these impls to overlap. +// +// However, we did fail to normalize ` {} +pub trait TensorOp: TensorValue {} + +pub struct Tensor; +impl TensorCompare for Tensor {} +impl TensorCompare for T1 +where + T1: TensorOp, + T1::Unmasked: Sized, +{} + + +fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-nested.current.stderr b/tests/ui/coherence/super-traits/super-trait-knowable-nested.current.stderr new file mode 100644 index 0000000000000..3cdf782286aea --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-nested.current.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()` + --> $DIR/super-trait-knowable-nested.rs:19:1 + | +LL | impl> Overlap for U {} + | ------------------------------------- first implementation here +LL | impl Overlap for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + | + = note: downstream crates may implement trait `Bound<_>` for type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-nested.next.stderr b/tests/ui/coherence/super-traits/super-trait-knowable-nested.next.stderr new file mode 100644 index 0000000000000..3cdf782286aea --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-nested.next.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()` + --> $DIR/super-trait-knowable-nested.rs:19:1 + | +LL | impl> Overlap for U {} + | ------------------------------------- first implementation here +LL | impl Overlap for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + | + = note: downstream crates may implement trait `Bound<_>` for type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-nested.rs b/tests/ui/coherence/super-traits/super-trait-knowable-nested.rs new file mode 100644 index 0000000000000..73e7c9a12bea4 --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-nested.rs @@ -0,0 +1,22 @@ +// Unlike in `super-trait-knowable-1.rs`, the knowable +// super trait bound is in a nested goal and we currently +// only elaborate in the root. This can, and should, be# +// changed in the future. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Super {} +trait Sub: Super {} + +trait Bound {} + +impl, U> Bound for T {} + +trait Overlap {} +impl> Overlap for U {} +impl Overlap for () {} +//~^ ERROR conflicting implementations of trait `Overlap<_>` for type `()` + +fn main() {} diff --git a/tests/ui/issues/issue-48728.rs b/tests/ui/issues/issue-48728.rs index cbdc10bd2e1ea..48e688cbd36fd 100644 --- a/tests/ui/issues/issue-48728.rs +++ b/tests/ui/issues/issue-48728.rs @@ -1,7 +1,12 @@ // Regression test for #48728, an ICE that occurred computing // coherence "help" information. -#[derive(Clone)] //~ ERROR conflicting implementations of trait `Clone` +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +#[derive(Clone)] struct Node(Box); impl Clone for Node<[T]> { diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr index 6e68646fbe4f4..3f0369bac5882 100644 --- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr @@ -1,11 +1,12 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>>` +error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/coherence-fulfill-overflow.rs:12:1 | LL | impl Trait for W {} | ------------------------------------- first implementation here LL | impl Trait for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>>>` | + = note: overflow evaluating the requirement `W>>>>: TwoW` = note: overflow evaluating the requirement `W>>>: TwoW` = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) From c565a0ad5ef892eaf475e781e1706eca5526de50 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 1 May 2024 17:30:27 +0000 Subject: [PATCH 2/3] remove unreachable code --- compiler/rustc_trait_selection/src/traits/select/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index dc005982695a1..d4c676c47bcd0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1868,11 +1868,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - // Drop otherwise equivalent non-const fn pointer candidates - (FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => { - DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_) - } - ( ParamCandidate(ref other_cand), ImplCandidate(..) From 03d9e8473a72b066284fc45e1850ab9ccc43c889 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 1 May 2024 18:22:45 +0000 Subject: [PATCH 3/3] refactor winnowing --- compiler/rustc_middle/src/traits/select.rs | 13 +- .../src/traits/select/candidate_assembly.rs | 10 +- .../src/traits/select/confirmation.rs | 4 +- .../src/traits/select/mod.rs | 187 ++++------------ tests/ui/associated-item/issue-105449.rs | 5 +- tests/ui/associated-item/issue-105449.stderr | 15 ++ tests/ui/lifetimes/issue-34979.rs | 4 +- tests/ui/lifetimes/issue-34979.stderr | 26 +-- tests/ui/traits/issue-66768.rs | 205 ------------------ .../ui/traits/normalize-conflicting-impls.rs | 3 + .../traits/normalize-conflicting-impls.stderr | 18 +- 11 files changed, 113 insertions(+), 377 deletions(-) create mode 100644 tests/ui/associated-item/issue-105449.stderr delete mode 100644 tests/ui/traits/issue-66768.rs diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index c8caf228ffb5b..fb1db30c5f3d8 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -121,7 +121,18 @@ pub enum SelectionCandidate<'tcx> { /// Implementation of transmutability trait. TransmutabilityCandidate, - ParamCandidate(ty::PolyTraitPredicate<'tcx>), + /// A candidate from the `ParamEnv`. + ParamCandidate { + /// The actual `where`-bound, e.g. `T: Trait`. + predicate: ty::PolyTraitPredicate<'tcx>, + /// `true` if the where-bound has no bound vars and does + /// not refer to any parameters or inference variables. + /// + /// We prefer all other candidates over global where-bounds. + /// Notably, global where-bounds do not shadow impls. + is_global: bool, + }, + ImplCandidate(DefId), AutoImplCandidate, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 40d206b92b8df..13374616745d2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -251,16 +251,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); // Keep only those bounds which may apply, and propagate overflow if it occurs. - for bound in matching_bounds { - if bound.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity { + for predicate in matching_bounds { + if predicate.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity + { continue; } // FIXME(oli-obk): it is suspicious that we are dropping the constness and // polarity here. - let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; + let wc = self.where_clause_may_apply(stack, predicate.map_bound(|t| t.trait_ref))?; if wc.may_apply() { - candidates.vec.push(ParamCandidate(bound)); + let is_global = predicate.is_global() && !predicate.has_bound_vars(); + candidates.vec.push(ParamCandidate { predicate, is_global }); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 22e0ee3834476..686db6e14f2e8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -56,9 +56,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, data) } - ParamCandidate(param) => { + ParamCandidate { predicate, is_global: _ } => { let obligations = - self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); + self.confirm_param_candidate(obligation, predicate.map_bound(|t| t.trait_ref)); ImplSource::Param(obligations) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d4c676c47bcd0..01ff1a68d5eb4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1575,7 +1575,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(), + Ok(Some(SelectionCandidate::ParamCandidate { predicate, .. })) => { + !predicate.has_infer() + } _ => true, } } @@ -1827,23 +1829,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> { return DropVictim::Yes; } - // Check if a bound would previously have been removed when normalizing - // the param_env so that it can be given the lowest priority. See - // #50825 for the motivation for this. - let is_global = - |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); - - // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, - // `DiscriminantKindCandidate`, `ConstDestructCandidate` - // to anything else. - // - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. match (&other.candidate, &victim.candidate) { - // FIXME(@jswrenn): this should probably be more sophisticated - (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, - - // (*) + // Prefer `BuiltinCandidate { has_nested: false }`, `ConstDestructCandidate` + // to anything else. + // + // This is a fix for #53123 and prevents winnowing from accidentally extending the + // lifetime of a variable. + ( + BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), + BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), + ) => bug!("two trivial builtin candidates: {other:?} {victim:?}"), (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => { DropVictim::Yes } @@ -1851,7 +1846,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { DropVictim::No } - (ParamCandidate(other), ParamCandidate(victim)) => { + // Global bounds from the where clause should be ignored + // here (see issue #50825). + (ParamCandidate { is_global: true, .. }, ParamCandidate { is_global: true, .. }) => { + DropVictim::No + } + (_, ParamCandidate { is_global: true, .. }) => DropVictim::Yes, + (ParamCandidate { is_global: true, .. }, _) => DropVictim::No, + + ( + ParamCandidate { is_global: false, predicate: other }, + ParamCandidate { is_global: false, predicate: victim }, + ) => { let same_except_bound_vars = other.skip_binder().trait_ref == victim.skip_binder().trait_ref && other.skip_binder().polarity == victim.skip_binder().polarity @@ -1868,63 +1874,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - ( - ParamCandidate(ref other_cand), - ImplCandidate(..) - | AutoImplCandidate - | ClosureCandidate { .. } - | AsyncClosureCandidate - | AsyncFnKindHelperCandidate - | CoroutineCandidate - | FutureCandidate - | IteratorCandidate - | AsyncIteratorCandidate - | FnPointerCandidate { .. } - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | TraitUpcastingUnsizeCandidate(_) - | BuiltinCandidate { .. } - | TraitAliasCandidate - | ObjectCandidate(_) - | ProjectionCandidate(_), - ) => { - // We have a where clause so don't go around looking - // for impls. Arbitrarily give param candidates priority - // over projection and object candidates. - // - // Global bounds from the where clause should be ignored - // here (see issue #50825). - DropVictim::drop_if(!is_global(other_cand)) - } - (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } - } - ( - ImplCandidate(_) - | AutoImplCandidate - | ClosureCandidate { .. } - | AsyncClosureCandidate - | AsyncFnKindHelperCandidate - | CoroutineCandidate - | FutureCandidate - | IteratorCandidate - | AsyncIteratorCandidate - | FnPointerCandidate { .. } - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | TraitUpcastingUnsizeCandidate(_) - | BuiltinCandidate { has_nested: true } - | TraitAliasCandidate, - ParamCandidate(ref victim_cand), - ) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - DropVictim::drop_if( - is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(), - ) - } + (ParamCandidate { is_global: false, .. }, _) => DropVictim::Yes, + (_, ParamCandidate { is_global: false, .. }) => DropVictim::No, (ProjectionCandidate(i), ProjectionCandidate(j)) | (ObjectCandidate(i), ObjectCandidate(j)) => { @@ -1937,44 +1888,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { bug!("Have both object and projection candidate") } - // Arbitrarily give projection and object candidates priority. - ( - ObjectCandidate(_) | ProjectionCandidate(_), - ImplCandidate(..) - | AutoImplCandidate - | ClosureCandidate { .. } - | AsyncClosureCandidate - | AsyncFnKindHelperCandidate - | CoroutineCandidate - | FutureCandidate - | IteratorCandidate - | AsyncIteratorCandidate - | FnPointerCandidate { .. } - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | TraitUpcastingUnsizeCandidate(_) - | BuiltinCandidate { .. } - | TraitAliasCandidate, - ) => DropVictim::Yes, + // Arbitrarily give projection candidates priority. + (ProjectionCandidate(_), _) => DropVictim::Yes, + (_, ProjectionCandidate(_)) => DropVictim::No, - ( - ImplCandidate(..) - | AutoImplCandidate - | ClosureCandidate { .. } - | AsyncClosureCandidate - | AsyncFnKindHelperCandidate - | CoroutineCandidate - | FutureCandidate - | IteratorCandidate - | AsyncIteratorCandidate - | FnPointerCandidate { .. } - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | TraitUpcastingUnsizeCandidate(_) - | BuiltinCandidate { .. } - | TraitAliasCandidate, - ObjectCandidate(_) | ProjectionCandidate(_), - ) => DropVictim::No, + // Need to prioritize builtin trait object impls as + // `::type_id` should use the vtable method + // and not the method provided by the user-defined impl + // `impl Any for T { .. }`. + // + // cc #57893 + (ObjectCandidate(_), _) => DropVictim::Yes, + (_, ObjectCandidate(_)) => DropVictim::No, (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => { // See if we can toss out `victim` based on specialization. @@ -2054,37 +1979,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - (AutoImplCandidate, ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate) => { - DropVictim::No - } - - (AutoImplCandidate, _) | (_, AutoImplCandidate) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other global candidates: {:?} {:?}", - other, - victim - ); - } - - // Everything else is ambiguous + // Treat all non-trivial builtin impls and user-defined impls the same way. ( ImplCandidate(_) - | ClosureCandidate { .. } - | AsyncClosureCandidate - | AsyncFnKindHelperCandidate - | CoroutineCandidate - | FutureCandidate - | IteratorCandidate - | AsyncIteratorCandidate - | FnPointerCandidate { .. } - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | TraitUpcastingUnsizeCandidate(_) + | AutoImplCandidate | BuiltinCandidate { has_nested: true } - | TraitAliasCandidate, - ImplCandidate(_) - | ClosureCandidate { .. } | AsyncClosureCandidate | AsyncFnKindHelperCandidate | CoroutineCandidate @@ -2092,11 +1991,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | IteratorCandidate | AsyncIteratorCandidate | FnPointerCandidate { .. } - | BuiltinObjectCandidate + | ClosureCandidate { .. } + | TraitAliasCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) - | BuiltinCandidate { has_nested: true } - | TraitAliasCandidate, + | TransmutabilityCandidate + | BuiltinObjectCandidate, + _, ) => DropVictim::No, } } diff --git a/tests/ui/associated-item/issue-105449.rs b/tests/ui/associated-item/issue-105449.rs index 5ccc317562bc6..c5562a3090835 100644 --- a/tests/ui/associated-item/issue-105449.rs +++ b/tests/ui/associated-item/issue-105449.rs @@ -1,13 +1,14 @@ -//@ check-pass //@ compile-flags: -C debug_assertions=yes -Zunstable-options -#[allow(dead_code)] +// This is a mutated variant of #66768 which has been removed +// as it no longer tests the original issue. fn problematic_function() where DefaultAlloc: FinAllok, { let e = Edge2dElement; let _ = Into::::into(e.map_reference_coords()); + //~^ ERROR the trait bound `Point: From<(Ure, R1, MStorage)>` is not satisfied } impl Allocator for DefaultAlloc { type Buffer = MStorage; diff --git a/tests/ui/associated-item/issue-105449.stderr b/tests/ui/associated-item/issue-105449.stderr new file mode 100644 index 0000000000000..cfb4c8bb66a36 --- /dev/null +++ b/tests/ui/associated-item/issue-105449.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `Point: From<(Ure, R1, MStorage)>` is not satisfied + --> $DIR/issue-105449.rs:10:33 + | +LL | let _ = Into::::into(e.map_reference_coords()); + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<(Ure, R1, MStorage)>` is not implemented for `Point`, which is required by `(Ure, R1, MStorage): Into` + | | + | required by a bound introduced by this call + | + = help: the trait `From<(Ure, Space, >::Buffer)>` is implemented for `Point` + = help: for that trait implementation, expected `Space`, found `R1` + = note: required for `(Ure, R1, MStorage)` to implement `Into` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lifetimes/issue-34979.rs b/tests/ui/lifetimes/issue-34979.rs index 252486dd92192..08b2f9ffcc477 100644 --- a/tests/ui/lifetimes/issue-34979.rs +++ b/tests/ui/lifetimes/issue-34979.rs @@ -3,7 +3,7 @@ impl<'a, T> Foo for &'a T {} struct Ctx<'a>(&'a ()) where - &'a (): Foo, //~ ERROR: type annotations needed - &'static (): Foo; + &'a (): Foo, + &'static (): Foo; //~ ERROR: mismatched types fn main() {} diff --git a/tests/ui/lifetimes/issue-34979.stderr b/tests/ui/lifetimes/issue-34979.stderr index 0877f1548a842..99aac7ac3b994 100644 --- a/tests/ui/lifetimes/issue-34979.stderr +++ b/tests/ui/lifetimes/issue-34979.stderr @@ -1,20 +1,18 @@ -error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo` - --> $DIR/issue-34979.rs:6:13 +error[E0308]: mismatched types + --> $DIR/issue-34979.rs:7:18 | -LL | &'a (): Foo, - | ^^^ +LL | &'static (): Foo; + | ^^^ lifetime mismatch | -note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found - --> $DIR/issue-34979.rs:2:1 + = note: expected trait `<&'static () as Foo>` + found trait `<&'a () as Foo>` +note: the lifetime `'a` as defined here... + --> $DIR/issue-34979.rs:4:12 | -LL | impl<'a, T> Foo for &'a T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | &'a (): Foo, - | ^^^ -LL | &'static (): Foo; - | ^^^ +LL | struct Ctx<'a>(&'a ()) + | ^^ + = note: ...does not necessarily outlive the static lifetime error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/issue-66768.rs b/tests/ui/traits/issue-66768.rs deleted file mode 100644 index dc9fe361019a2..0000000000000 --- a/tests/ui/traits/issue-66768.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Regression test for #66768. -//@ check-pass -#![allow(dead_code)] -//-^ "dead code" is needed to reproduce the issue. - -use std::marker::PhantomData; -use std::ops::{Add, Mul}; - -fn problematic_function(material_surface_element: Edge2dElement) -where - DefaultAllocator: FiniteElementAllocator, -{ - let _: Point2 = material_surface_element.map_reference_coords().into(); -} - -impl ArrayLength for UTerm { - type ArrayType = (); -} -impl> ArrayLength for UInt { - type ArrayType = GenericArrayImplEven; -} -impl> ArrayLength for UInt { - type ArrayType = GenericArrayImplOdd; -} -impl Add for UTerm { - type Output = U; - fn add(self, _: U) -> Self::Output { - unimplemented!() - } -} -impl Add> for UInt -where - Ul: Add, -{ - type Output = UInt, B1>; - fn add(self, _: UInt) -> Self::Output { - unimplemented!() - } -} -impl Mul for UTerm { - type Output = UTerm; - fn mul(self, _: U) -> Self { - unimplemented!() - } -} -impl Mul> for UInt -where - Ul: Mul>, -{ - type Output = UInt>, B0>; - fn mul(self, _: UInt) -> Self::Output { - unimplemented!() - } -} -impl Mul> for UInt -where - Ul: Mul>, - UInt>, B0>: Add>, -{ - type Output = Sum>, B0>, UInt>; - fn mul(self, _: UInt) -> Self::Output { - unimplemented!() - } -} -impl Allocator for DefaultAllocator -where - R: DimName, - C: DimName, - R::Value: Mul, - Prod: ArrayLength, -{ - type Buffer = ArrayStorage; - fn allocate_uninitialized(_: R, _: C) -> Self::Buffer { - unimplemented!() - } - fn allocate_from_iterator(_: R, _: C, _: I) -> Self::Buffer { - unimplemented!() - } -} -impl Allocator for DefaultAllocator { - type Buffer = VecStorage; - fn allocate_uninitialized(_: Dynamic, _: C) -> Self::Buffer { - unimplemented!() - } - fn allocate_from_iterator(_: Dynamic, _: C, _: I) -> Self::Buffer { - unimplemented!() - } -} -impl DimName for DimU1 { - type Value = U1; - fn name() -> Self { - unimplemented!() - } -} -impl DimName for DimU2 { - type Value = U2; - fn name() -> Self { - unimplemented!() - } -} -impl From> for Point -where - DefaultAllocator: Allocator, -{ - fn from(_: VectorN) -> Self { - unimplemented!() - } -} -impl FiniteElementAllocator for DefaultAllocator where - DefaultAllocator: Allocator + Allocator -{ -} -impl ReferenceFiniteElement for Edge2dElement { - type NodalDim = DimU1; -} -impl FiniteElement for Edge2dElement { - fn map_reference_coords(&self) -> Vector2 { - unimplemented!() - } -} - -type Owned = >::Buffer; -type MatrixMN = Matrix>; -type VectorN = MatrixMN; -type Vector2 = VectorN; -type Point2 = Point; -type U1 = UInt; -type U2 = UInt, B0>; -type Sum = >::Output; -type Prod = >::Output; - -struct GenericArray> { - _data: U::ArrayType, -} -struct GenericArrayImplEven { - _parent2: U, - _marker: T, -} -struct GenericArrayImplOdd { - _parent2: U, - _data: T, -} -struct B0; -struct B1; -struct UTerm; -struct UInt { - _marker: PhantomData<(U, B)>, -} -struct DefaultAllocator; -struct Dynamic; -struct DimU1; -struct DimU2; -struct Matrix { - _data: S, - _phantoms: PhantomData<(N, R, C)>, -} -struct ArrayStorage -where - R: DimName, - C: DimName, - R::Value: Mul, - Prod: ArrayLength, -{ - _data: GenericArray>, -} -struct VecStorage { - _data: N, - _nrows: R, - _ncols: C, -} -struct Point -where - DefaultAllocator: Allocator, -{ - _coords: VectorN, -} -struct Edge2dElement; - -trait ArrayLength { - type ArrayType; -} -trait Allocator { - type Buffer; - fn allocate_uninitialized(nrows: R, ncols: C) -> Self::Buffer; - fn allocate_from_iterator(nrows: R, ncols: C, iter: I) -> Self::Buffer; -} -trait DimName { - type Value; - fn name() -> Self; -} -trait FiniteElementAllocator: - Allocator + Allocator -{ -} -trait ReferenceFiniteElement { - type NodalDim; -} -trait FiniteElement: ReferenceFiniteElement -where - DefaultAllocator: FiniteElementAllocator, -{ - fn map_reference_coords(&self) -> VectorN; -} - -fn main() {} diff --git a/tests/ui/traits/normalize-conflicting-impls.rs b/tests/ui/traits/normalize-conflicting-impls.rs index 454b2fd015357..24185e213b6d4 100644 --- a/tests/ui/traits/normalize-conflicting-impls.rs +++ b/tests/ui/traits/normalize-conflicting-impls.rs @@ -1,8 +1,11 @@ +// This is a mutated variant of #66768 which has been removed +// as it no longer tests the original issue. fn problematic_function(material_surface_element: ()) where DefaultAllocator: FiniteElementAllocator<(), Space>, { let _: Point2 = material_surface_element.map_reference_coords().into(); + //~^ ERROR the trait bound `Point: From>` is not satisfied } impl Allocator for DefaultAllocator diff --git a/tests/ui/traits/normalize-conflicting-impls.stderr b/tests/ui/traits/normalize-conflicting-impls.stderr index 9a66fe00c3fe4..d3fa5162128fd 100644 --- a/tests/ui/traits/normalize-conflicting-impls.stderr +++ b/tests/ui/traits/normalize-conflicting-impls.stderr @@ -1,11 +1,11 @@ error[E0220]: associated type `Value` not found for `R` - --> $DIR/normalize-conflicting-impls.rs:10:8 + --> $DIR/normalize-conflicting-impls.rs:13:8 | LL | R::Value: DimName, | ^^^^^ associated type `Value` not found error[E0119]: conflicting implementations of trait `Allocator<_, ()>` for type `DefaultAllocator` - --> $DIR/normalize-conflicting-impls.rs:14:1 + --> $DIR/normalize-conflicting-impls.rs:17:1 | LL | / impl Allocator for DefaultAllocator LL | | where @@ -15,7 +15,17 @@ LL | | R::Value: DimName, LL | impl Allocator for DefaultAllocator {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `DefaultAllocator` -error: aborting due to 2 previous errors +error[E0277]: the trait bound `Point: From>` is not satisfied + --> $DIR/normalize-conflicting-impls.rs:7:74 + | +LL | let _: Point2 = material_surface_element.map_reference_coords().into(); + | ^^^^ the trait `From>` is not implemented for `Point`, which is required by `Matrix<()>: Into<_>` + | + = help: the trait `From>::Buffer>>` is implemented for `Point` + = help: for that trait implementation, expected `>::Buffer`, found `()` + = note: required for `Matrix<()>` to implement `Into>` + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0119, E0220. +Some errors have detailed explanations: E0119, E0220, E0277. For more information about an error, try `rustc --explain E0119`.