Auto merge of #145396 - compiler-errors:revert-method-pref, r=lcnr

[BETA] Revert "Use DeepRejectCtxt in assemble_inherent_candidates_from_param"

Fixes https://github.com/rust-lang/rust/issues/145185.

Backporting this to stable and beta in favor of https://github.com/rust-lang/rust/pull/145262#issuecomment-3188760251.

r? lcnr
This commit is contained in:
bors 2025-08-16 22:47:14 +00:00
commit 47b72a3455
7 changed files with 118 additions and 58 deletions

View file

@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]

View file

@ -1,4 +1,3 @@
use std::assert_matches::debug_assert_matches;
use std::cell::{Cell, RefCell};
use std::cmp::max;
use std::ops::Deref;
@ -16,7 +15,7 @@ use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk,
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::middle::stability;
use rustc_middle::ty::elaborate::supertrait_def_ids;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
use rustc_middle::ty::{
self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind,
ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast,
@ -803,8 +802,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
);
}
}
ty::Param(_) => {
self.assemble_inherent_candidates_from_param(raw_self_ty);
ty::Param(p) => {
self.assemble_inherent_candidates_from_param(p);
}
ty::Bool
| ty::Char
@ -905,16 +904,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
fn assemble_inherent_candidates_from_param(&mut self, param_ty: Ty<'tcx>) {
debug_assert_matches!(param_ty.kind(), ty::Param(_));
let tcx = self.tcx;
fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(trait_predicate) => DeepRejectCtxt::relate_rigid_rigid(tcx)
.types_may_unify(param_ty, trait_predicate.trait_ref.self_ty())
.then(|| bound_predicate.rebind(trait_predicate.trait_ref)),
ty::ClauseKind::Trait(trait_predicate) => {
match *trait_predicate.trait_ref.self_ty().kind() {
ty::Param(p) if p == param_ty => {
Some(bound_predicate.rebind(trait_predicate.trait_ref))
}
_ => None,
}
}
ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::TypeOutlives(_)
| ty::ClauseKind::Projection(_)

View file

@ -0,0 +1,30 @@
error[E0034]: multiple applicable items in scope
--> $DIR/rigid-alias-bound-is-not-inherent.rs:42:7
|
LL | x.method();
| ^^^^^^ multiple `method` found
|
note: candidate #1 is defined in the trait `Trait1`
--> $DIR/rigid-alias-bound-is-not-inherent.rs:21:5
|
LL | fn method(&self) {
| ^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T`
--> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5
|
LL | fn method(&self) {
| ^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - x.method();
LL + Trait1::method(&x);
|
help: disambiguate the method for candidate #2
|
LL - x.method();
LL + Trait2::method(&x);
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View file

@ -0,0 +1,30 @@
error[E0034]: multiple applicable items in scope
--> $DIR/rigid-alias-bound-is-not-inherent.rs:42:7
|
LL | x.method();
| ^^^^^^ multiple `method` found
|
note: candidate #1 is defined in the trait `Trait1`
--> $DIR/rigid-alias-bound-is-not-inherent.rs:21:5
|
LL | fn method(&self) {
| ^^^^^^^^^^^^^^^^
note: candidate #2 is defined in the trait `Trait2`
--> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5
|
LL | fn method(&self) {
| ^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - x.method();
LL + Trait1::method(&x);
|
help: disambiguate the method for candidate #2
|
LL - x.method();
LL + Trait2::method(&x);
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View file

@ -0,0 +1,46 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// See the code below.
//
// We were using `DeepRejectCtxt` to ensure that `assemble_inherent_candidates_from_param`
// did not rely on the param-env being eagerly normalized. Since aliases unify with all
// types, this meant that a rigid param-env candidate like `<T as Deref>::Target: Trait1`
// would be registered as a "WhereClauseCandidate", which is treated as inherent. Since
// we evaluate these candidates for all self types in the deref chain, this candidate
// would be satisfied for `<T as Deref>::Target`, meaning that it would be preferred over
// an "extension" candidate like `<T as Deref>::Target: Trait2` even though it holds.
// This is problematic, since it causes ambiguities to be broken somewhat arbitrarily.
// And as a side-effect, it also caused our computation of "used" traits to be miscalculated
// since inherent candidates don't count as an import usage.
use std::ops::Deref;
trait Trait1 {
fn method(&self) {
println!("1");
}
}
trait Trait2 {
fn method(&self) {
println!("2");
}
}
impl<T: Other + ?Sized> Trait2 for T {}
trait Other {}
fn foo<T>(x: T)
where
T: Deref,
<T as Deref>::Target: Trait1 + Other,
{
// Make sure that we don't prefer methods from where clauses for rigid aliases,
// just for params. We could revisit this behavior, but it would be a lang change.
x.method();
//~^ ERROR multiple applicable items in scope
}
fn main() {}

View file

@ -1,29 +0,0 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/214>.
// See comment below.
trait A {
fn hello(&self) {}
}
trait B {
fn hello(&self) {}
}
impl<T> A for T {}
impl<T> B for T {}
fn test<F, R>(q: F::Item)
where
F: Iterator<Item = R>,
// We want to prefer `A` for `R.hello()`
F::Item: A,
{
q.hello();
}
fn main() {}

View file

@ -1,17 +0,0 @@
//@ check-pass
//@ compile-flags: -Znext-solver
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/214>.
fn execute<K, F, R>(q: F::Item) -> R
where
F: Iterator<Item = R>,
// Both of the below bounds should be considered for `.into()`, and then be combined
// into a single `R: Into<?0>` bound which can be inferred to `?0 = R`.
F::Item: Into<K>,
R: Into<String>,
{
q.into()
}
fn main() {}