Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()?;
Copy link
Contributor Author

@zedddie zedddie Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in previous variant I didn't really use sp, just passed to the next filter_map, so can be simplified to this

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);
}

Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
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`
...
LL | let _: dyn Bound;
| ^^^^^^^^^ contains a mention of `Self`

error: aborting due to 1 previous error
error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Check associated const binding with escaping bound vars doesn't cause ICE
Copy link
Contributor Author

@zedddie zedddie Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was not sure on adding this, but i guess this works as regression test for the check logic :"

//! (#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() {}
11 changes: 11 additions & 0 deletions tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

13 changes: 13 additions & 0 deletions tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

17 changes: 17 additions & 0 deletions tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

Loading