Rollup merge of #152146 - zedddie:mgca-improve-const-bindings-wfck, r=BoxyUwU

mGCA: Add associated const type check

rust-lang/rust#151642

r? BoxyUwU

I didn't bless tests just yet as it only fixes the dyn arm
This commit is contained in:
Matthias Krüger 2026-02-11 13:48:49 +01:00 committed by GitHub
commit 9a4ce0b5f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 167 additions and 3 deletions

View file

@ -1569,11 +1569,40 @@ pub(super) fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id:
let predicates = predicates.instantiate_identity(tcx);
let assoc_const_obligations: Vec<_> = predicates
.predicates
.iter()
.copied()
.zip(predicates.spans.iter().copied())
.filter_map(|(clause, sp)| {
let proj = clause.as_projection_clause()?;
let pred_binder = proj
.map_bound(|pred| {
pred.term.as_const().map(|ct| {
let assoc_const_ty = tcx
.type_of(pred.projection_term.def_id)
.instantiate(tcx, pred.projection_term.args);
ty::ClauseKind::ConstArgHasType(ct, assoc_const_ty)
})
})
.transpose();
pred_binder.map(|pred_binder| {
let cause = traits::ObligationCause::new(
sp,
wfcx.body_def_id,
ObligationCauseCode::WhereClause(def_id.to_def_id(), sp),
);
Obligation::new(tcx, cause, wfcx.param_env, pred_binder)
})
})
.collect();
assert_eq!(predicates.predicates.len(), predicates.spans.len());
let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp)
});
let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
let obligations: Vec<_> =
wf_obligations.chain(default_obligations).chain(assoc_const_obligations).collect();
wfcx.register_obligations(obligations);
}

View file

@ -951,6 +951,34 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
));
}
if !t.has_escaping_bound_vars() {
for projection in data.projection_bounds() {
let pred_binder = projection
.with_self_ty(tcx, t)
.map_bound(|p| {
p.term.as_const().map(|ct| {
let assoc_const_ty = tcx
.type_of(p.projection_term.def_id)
.instantiate(tcx, p.projection_term.args);
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(
ct,
assoc_const_ty,
))
})
})
.transpose();
if let Some(pred_binder) = pred_binder {
self.out.push(traits::Obligation::with_depth(
tcx,
self.cause(ObligationCauseCode::WellFormed(None)),
self.recursion_depth,
self.param_env,
pred_binder,
));
}
}
}
}
// Inference variables are the complicated case, since we don't

View file

@ -15,6 +15,7 @@ trait Trait {
struct Hold<T: ?Sized>(T);
trait Bound = Trait<Y = { Hold::<Self> }>;
//~^ ERROR the constant `Hold::<Self>` is not of type `i32`
fn main() {
let _: dyn Bound; //~ ERROR associated constant binding in trait object type mentions `Self`

View file

@ -1,5 +1,17 @@
error: the constant `Hold::<Self>` is not of type `i32`
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:17:21
|
LL | trait Bound = Trait<Y = { Hold::<Self> }>;
| ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found struct constructor
|
note: required by a const generic parameter in `Bound`
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:17:21
|
LL | trait Bound = Trait<Y = { Hold::<Self> }>;
| ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Bound`
error: associated constant binding in trait object type mentions `Self`
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:20:12
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:21:12
|
LL | trait Bound = Trait<Y = { Hold::<Self> }>;
| -------------------- this binding mentions `Self`
@ -7,5 +19,5 @@ LL | trait Bound = Trait<Y = { Hold::<Self> }>;
LL | let _: dyn Bound;
| ^^^^^^^^^ contains a mention of `Self`
error: aborting due to 1 previous error
error: aborting due to 2 previous errors

View file

@ -0,0 +1,11 @@
//! Check associated const binding with escaping bound vars doesn't cause ICE
//! (#151642)
//@ check-pass
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Trait2<'a> { type const ASSOC: i32; }
fn g(_: for<'a> fn(Box<dyn Trait2<'a, ASSOC = 10>>)) {}
fn main() {}

View file

@ -0,0 +1,11 @@
//! Check that we correctly handle associated const bindings
//! in `impl Trait` where the RHS is a const param (#151642).
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Trait { type const CT: bool; }
fn f<const N: i32>(_: impl Trait<CT = { N }>) {}
//~^ ERROR the constant `N` is not of type `bool`
fn main() {}

View file

@ -0,0 +1,14 @@
error: the constant `N` is not of type `bool`
--> $DIR/wf-mismatch-1.rs:9:34
|
LL | fn f<const N: i32>(_: impl Trait<CT = { N }>) {}
| ^^^^^^^^^^ expected `bool`, found `i32`
|
note: required by a const generic parameter in `f`
--> $DIR/wf-mismatch-1.rs:9:34
|
LL | fn f<const N: i32>(_: impl Trait<CT = { N }>) {}
| ^^^^^^^^^^ required by this const generic parameter in `f`
error: aborting due to 1 previous error

View file

@ -0,0 +1,13 @@
//! Check that we correctly handle associated const bindings
//! in `dyn Trait` where the RHS is a const param (#151642).
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Trait { type const CT: bool; }
fn f<const N: i32>() {
let _: dyn Trait<CT = { N }>;
//~^ ERROR the constant `N` is not of type `bool`
}
fn main() {}

View file

@ -0,0 +1,8 @@
error: the constant `N` is not of type `bool`
--> $DIR/wf-mismatch-2.rs:10:12
|
LL | let _: dyn Trait<CT = { N }>;
| ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `i32`
error: aborting due to 1 previous error

View file

@ -0,0 +1,17 @@
//! Check that we correctly handle associated const bindings
//! where the RHS is a normalizable const projection (#151642).
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Trait { type const CT: bool; }
trait Bound { type const N: u32; }
impl Bound for () { type const N: u32 = 0; }
fn f() { let _: dyn Trait<CT = { <() as Bound>::N }>; }
//~^ ERROR the constant `0` is not of type `bool`
fn g(_: impl Trait<CT = { <() as Bound>::N }>) {}
//~^ ERROR the constant `0` is not of type `bool`
fn main() {}

View file

@ -0,0 +1,20 @@
error: the constant `0` is not of type `bool`
--> $DIR/wf-mismatch-3.rs:14:20
|
LL | fn g(_: impl Trait<CT = { <() as Bound>::N }>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `u32`
|
note: required by a const generic parameter in `g`
--> $DIR/wf-mismatch-3.rs:14:20
|
LL | fn g(_: impl Trait<CT = { <() as Bound>::N }>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `g`
error: the constant `0` is not of type `bool`
--> $DIR/wf-mismatch-3.rs:12:17
|
LL | fn f() { let _: dyn Trait<CT = { <() as Bound>::N }>; }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `u32`
error: aborting due to 2 previous errors