diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index c8caf228ffb5..fb1db30c5f3d 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 40d206b92b8d..13374616745d 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 22e0ee383447..686db6e14f2e 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 d4c676c47bcd..01ff1a68d5eb 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 5ccc317562bc..c5562a309083 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 000000000000..cfb4c8bb66a3 --- /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 252486dd9219..08b2f9ffcc47 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 0877f1548a84..99aac7ac3b99 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 dc9fe361019a..000000000000 --- 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 454b2fd01535..24185e213b6d 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 9a66fe00c3fe..d3fa5162128f 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`.