From b6b6dc0b8260bacc01304c230e53b4328ae4ce23 Mon Sep 17 00:00:00 2001 From: zedddie Date: Thu, 5 Feb 2026 18:54:59 +0100 Subject: [PATCH 1/3] mGCA: add associated const type check in dyn arm --- .../rustc_trait_selection/src/traits/wf.rs | 28 +++++++++++++++++++ .../wf-mismatch-1.rs | 12 ++++++++ .../wf-mismatch-2.rs | 12 ++++++++ .../wf-mismatch-3.rs | 15 ++++++++++ 4 files changed, 67 insertions(+) create mode 100644 tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d383cb9d91dd4..358f14221a0dc 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -951,6 +951,34 @@ impl<'a, 'tcx> TypeVisitor> 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 diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs new file mode 100644 index 0000000000000..319e3421a4cd1 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs @@ -0,0 +1,12 @@ +//@ known-bug: unknown +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { #[type_const] const CT: bool; } + +// FIXME: this should yield a type mismatch (`bool` v `i32`) +fn f(_: impl Trait) {} + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs new file mode 100644 index 0000000000000..2adaaa3dd0504 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs @@ -0,0 +1,12 @@ +//@ known-bug: unknown +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { #[type_const] const CT: bool; } + +fn f() { + let _: dyn Trait; // FIXME: this should yield a type mismatch (`bool` v `i32`) +} +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs new file mode 100644 index 0000000000000..29d089bf9d2b6 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs @@ -0,0 +1,15 @@ +//@ known-bug: unknown +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { #[type_const] const CT: bool; } + +trait Bound { #[type_const] const N: u32; } +impl Bound for () { #[type_const] const N: u32 = 0; } + +fn f() { let _: dyn Trait::N }>; } // FIXME +fn g(_: impl Trait::N }>) {} // FIXME + +fn main() {} From 963f82d3224ea0b1f7b1ca182b67af3e9293e89f Mon Sep 17 00:00:00 2001 From: zedddie Date: Sat, 7 Feb 2026 07:15:24 +0100 Subject: [PATCH 2/3] mGCA: add associated const obligations in wfck --- .../rustc_hir_analysis/src/check/wfcheck.rs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index ceb0e138a0dae..32af13b88a1ab 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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); } From ec03e39afd210cff8516b14b92dc259f61d303c5 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 9 Feb 2026 10:40:42 +0100 Subject: [PATCH 3/3] bless tests --- ...ection-behind-trait-alias-mentions-self.rs | 1 + ...on-behind-trait-alias-mentions-self.stderr | 16 +++++++++++++-- ...yn-const-projection-escaping-bound-vars.rs | 11 ++++++++++ .../wf-mismatch-1.rs | 9 ++++----- .../wf-mismatch-1.stderr | 14 +++++++++++++ .../wf-mismatch-2.rs | 9 +++++---- .../wf-mismatch-2.stderr | 8 ++++++++ .../wf-mismatch-3.rs | 16 ++++++++------- .../wf-mismatch-3.stderr | 20 +++++++++++++++++++ 9 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 tests/ui/const-generics/associated-const-bindings/dyn-const-projection-escaping-bound-vars.rs create mode 100644 tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.stderr create mode 100644 tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.stderr create mode 100644 tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.stderr diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs index 415d7bda347b3..9564903dce5b7 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs @@ -15,6 +15,7 @@ trait Trait { struct Hold(T); trait Bound = Trait }>; +//~^ ERROR the constant `Hold::` is not of type `i32` fn main() { let _: dyn Bound; //~ ERROR associated constant binding in trait object type mentions `Self` diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.stderr index 576d4c3230eeb..699b9192cf937 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.stderr +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-projection-behind-trait-alias-mentions-self.stderr @@ -1,5 +1,17 @@ +error: the constant `Hold::` is not of type `i32` + --> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:17:21 + | +LL | trait Bound = Trait }>; + | ^^^^^^^^^^^^^^^^^^^^ 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 }>; + | ^^^^^^^^^^^^^^^^^^^^ 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 }>; | -------------------- this binding mentions `Self` @@ -7,5 +19,5 @@ LL | trait Bound = Trait }>; LL | let _: dyn Bound; | ^^^^^^^^^ contains a mention of `Self` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-const-projection-escaping-bound-vars.rs b/tests/ui/const-generics/associated-const-bindings/dyn-const-projection-escaping-bound-vars.rs new file mode 100644 index 0000000000000..c2ae86232a02b --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-const-projection-escaping-bound-vars.rs @@ -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>)) {} + +fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs index 319e3421a4cd1..1beeb07e995a0 100644 --- a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.rs @@ -1,12 +1,11 @@ -//@ known-bug: unknown -//@ check-pass +//! 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] const CT: bool; } +trait Trait { type const CT: bool; } -// FIXME: this should yield a type mismatch (`bool` v `i32`) fn f(_: impl Trait) {} - +//~^ ERROR the constant `N` is not of type `bool` fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.stderr b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.stderr new file mode 100644 index 0000000000000..56e01e6400783 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-1.stderr @@ -0,0 +1,14 @@ +error: the constant `N` is not of type `bool` + --> $DIR/wf-mismatch-1.rs:9:34 + | +LL | fn f(_: impl Trait) {} + | ^^^^^^^^^^ expected `bool`, found `i32` + | +note: required by a const generic parameter in `f` + --> $DIR/wf-mismatch-1.rs:9:34 + | +LL | fn f(_: impl Trait) {} + | ^^^^^^^^^^ required by this const generic parameter in `f` + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs index 2adaaa3dd0504..7a75b6da78c5c 100644 --- a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.rs @@ -1,12 +1,13 @@ -//@ known-bug: unknown -//@ check-pass +//! 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] const CT: bool; } +trait Trait { type const CT: bool; } fn f() { - let _: dyn Trait; // FIXME: this should yield a type mismatch (`bool` v `i32`) + let _: dyn Trait; + //~^ ERROR the constant `N` is not of type `bool` } fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.stderr b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.stderr new file mode 100644 index 0000000000000..8169cc07fc5f5 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-2.stderr @@ -0,0 +1,8 @@ +error: the constant `N` is not of type `bool` + --> $DIR/wf-mismatch-2.rs:10:12 + | +LL | let _: dyn Trait; + | ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `i32` + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs index 29d089bf9d2b6..3eeb7703aa2b0 100644 --- a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.rs @@ -1,15 +1,17 @@ -//@ known-bug: unknown -//@ check-pass +//! 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] const CT: bool; } +trait Trait { type const CT: bool; } -trait Bound { #[type_const] const N: u32; } -impl Bound for () { #[type_const] const N: u32 = 0; } +trait Bound { type const N: u32; } +impl Bound for () { type const N: u32 = 0; } -fn f() { let _: dyn Trait::N }>; } // FIXME -fn g(_: impl Trait::N }>) {} // FIXME +fn f() { let _: dyn Trait::N }>; } +//~^ ERROR the constant `0` is not of type `bool` +fn g(_: impl Trait::N }>) {} +//~^ ERROR the constant `0` is not of type `bool` fn main() {} diff --git a/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.stderr b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.stderr new file mode 100644 index 0000000000000..ac21527e04edd --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/wf-mismatch-3.stderr @@ -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::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::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::N }>; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `u32` + +error: aborting due to 2 previous errors +