Rollup merge of #153614 - lcnr:find-param-in-clause-ambig, r=BoxyUwU

`FindParamInClause` handle edge-cases

If normalization is ambiguous, we want to treat the where-bound as non-global. The affected code should pretty much always have other errors in that case. It does make reasoning about trait solver cycles and rerunning more confusing and just feels wrong ™️ I encountered this while looking into `ml-kem` (https://github.com/rust-lang/trait-system-refactor-initiative/issues/246). I don't know whether this matters in practice and don't care to look into it too deeply.

We also want to properly handle concrete aliases which mention to something mentioning a generic parameter due to another where-bound.

r? @BoxyUwU
This commit is contained in:
Jonathan Brouwer
2026-04-02 22:13:52 +02:00
committed by GitHub
5 changed files with 128 additions and 31 deletions
@@ -9,7 +9,6 @@
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::SolverTraitLangItem;
use rustc_type_ir::search_graph::CandidateHeadUsages;
use rustc_type_ir::solve::Certainty::Maybe;
use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind};
use rustc_type_ir::{
self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -1286,28 +1285,34 @@ fn visit_ty(&mut self, ty: ty::Ty<I>) -> Self::Result {
return ControlFlow::Break(Err(NoSolution));
};
if let ty::Placeholder(p) = ty.kind() {
if p.universe() == ty::UniverseIndex::ROOT {
ControlFlow::Break(Ok(Certainty::Yes))
} else {
ControlFlow::Continue(())
match ty.kind() {
ty::Placeholder(p) => {
if p.universe() == ty::UniverseIndex::ROOT {
ControlFlow::Break(Ok(Certainty::Yes))
} else {
ControlFlow::Continue(())
}
}
} else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
self.recursion_depth += 1;
if self.recursion_depth > self.ecx.cx().recursion_limit() {
return ControlFlow::Break(Ok(Maybe {
cause: MaybeCause::Overflow {
suggest_increasing_limit: true,
keep_constraints: false,
},
opaque_types_jank: OpaqueTypesJank::AllGood,
}));
ty::Infer(_) => ControlFlow::Break(Ok(Certainty::AMBIGUOUS)),
_ if ty.has_type_flags(
TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_INFER | TypeFlags::HAS_ALIAS,
) =>
{
self.recursion_depth += 1;
if self.recursion_depth > self.ecx.cx().recursion_limit() {
return ControlFlow::Break(Ok(Certainty::Maybe {
cause: MaybeCause::Overflow {
suggest_increasing_limit: true,
keep_constraints: false,
},
opaque_types_jank: OpaqueTypesJank::AllGood,
}));
}
let result = ty.super_visit_with(self);
self.recursion_depth -= 1;
result
}
let result = ty.super_visit_with(self);
self.recursion_depth -= 1;
result
} else {
ControlFlow::Continue(())
_ => ControlFlow::Continue(()),
}
}
@@ -1317,16 +1322,23 @@ fn visit_const(&mut self, ct: I::Const) -> Self::Result {
return ControlFlow::Break(Err(NoSolution));
};
if let ty::ConstKind::Placeholder(p) = ct.kind() {
if p.universe() == ty::UniverseIndex::ROOT {
ControlFlow::Break(Ok(Certainty::Yes))
} else {
ControlFlow::Continue(())
match ct.kind() {
ty::ConstKind::Placeholder(p) => {
if p.universe() == ty::UniverseIndex::ROOT {
ControlFlow::Break(Ok(Certainty::Yes))
} else {
ControlFlow::Continue(())
}
}
} else if ct.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
ct.super_visit_with(self)
} else {
ControlFlow::Continue(())
ty::ConstKind::Infer(_) => ControlFlow::Break(Ok(Certainty::AMBIGUOUS)),
_ if ct.has_type_flags(
TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_INFER | TypeFlags::HAS_ALIAS,
) =>
{
// FIXME(mgca): we should also check the recursion limit here
ct.super_visit_with(self)
}
_ => ControlFlow::Continue(()),
}
}
@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/is-global-norm-concrete-alias-to-generic.rs:26:5
|
LL | fn foo<T>(x: <(*const T,) as Id>::This) -> (*const T,)
| ----------- expected `(*const T,)` because of return type
...
LL | x
| ^ expected `(*const T,)`, found associated type
|
= note: expected tuple `(*const T,)`
found associated type `<(*const T,) as Id>::This`
= help: consider constraining the associated type `<(*const T,) as Id>::This` to `(*const T,)`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
= note: the associated type `<(*const T,) as Id>::This` is defined as `(*const T,)` in the implementation, but the where-bound `(*const T,)` shadows this definition
see issue #152409 <https://github.com/rust-lang/rust/issues/152409> for more information
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/is-global-norm-concrete-alias-to-generic.rs:26:5
|
LL | fn foo<T>(x: <(*const T,) as Id>::This) -> (*const T,)
| ----------- expected `(*const T,)` because of return type
...
LL | x
| ^ types differ
|
= note: expected tuple `(*const T,)`
found associated type `<(*const T,) as Id>::This`
= help: consider constraining the associated type `<(*const T,) as Id>::This` to `(*const T,)`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
= note: the associated type `<(*const T,) as Id>::This` is defined as `(*const T,)` in the implementation, but the where-bound `(*const T,)` shadows this definition
see issue #152409 <https://github.com/rust-lang/rust/issues/152409> for more information
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
@@ -0,0 +1,29 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// A regression test making sure that where-bounds with concrete aliases
// which normalize to something mentioning a generic parameters are
// considered non-global.
//
// When checking this, we previously didn't recur into types if they didn't
// mention any generic parameters, causing us to consider the `(<() as Id>::This,): Id`
// where-bound as global, even though it normalizes to `(T,): Id`.
trait Id {
type This;
}
impl<T> Id for T {
type This = T;
}
fn foo<T>(x: <(*const T,) as Id>::This) -> (*const T,)
where
(): Id<This = *const T>,
(<() as Id>::This,): Id,
{
x //~ ERROR mismatched types
}
fn main() {}
@@ -4,6 +4,24 @@ error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: Trait`
LL | <T as Trait>::Assoc: Trait,
| ^^^^^
error: aborting due to 1 previous error
error[E0275]: overflow evaluating whether `<T as Trait>::Assoc` is well-formed
--> $DIR/normalize-param-env-4.rs:19:26
|
LL | <T as Trait>::Assoc: Trait,
| ^^^^^
error[E0275]: overflow evaluating the requirement `T: Trait`
--> $DIR/normalize-param-env-4.rs:32:19
|
LL | impls_trait::<T>();
| ^
|
note: required by a bound in `impls_trait`
--> $DIR/normalize-param-env-4.rs:15:19
|
LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0275`.