unlock unlimited code runs for $79, limited time →
NOSSLETTER.techLIVE
back to OSSpedia
rust-lang/rust
senior8/10
type-systemsbackwards-compatibilitycompiler-internals

Allow associated const equality constraints with GCA

Project: rust-lang/rust | Language: Rust | Concepts: type-systems, backwards-compatibility, compiler-internals | Difficulty: senior
Link: https://github.com/rust-lang/rust/pull/159506

The problem

Rust's type system allows traits to have associated constants. However, the ability to specify equality constraints (bindings) on associated constants in generic contexts—especially for non-type associated consts—was limited. The compiler did not consistently allow equality constraints on all associated consts when using the generic_const_args (GCA) feature, and the rules for dyn trait compatibility were not updated to reflect this. This led to unintuitive errors or missing functionality when trying to use equality constraints with associated consts under GCA.

Why it's non-trivial

A naive fix would simply allow all associated consts to be used in equality constraints, but this would break backwards compatibility and could introduce incorrect dyn trait compatibility checks. The compiler needs to distinguish between type-level associated consts, non-type associated consts, and those with their own generics (generic associated consts, or GACs), and only allow equality constraints where the feature is enabled and where it is semantically correct. The rules must also be reflected consistently across multiple compiler components (type lowering, trait selection, diagnostics, etc.) and tested for backwards compatibility.

The approach

Centralize the logic for "can this associated item have an equality constraint?"

A new helper method is added to AssocItem:

+    /// Whether this associated item can be constrained with an equality binding.
+    pub fn can_have_equality_constraint(&self, tcx: TyCtxt<'_>) -> bool {
+        match self.kind {
+            ty::AssocKind::Type { .. } => true,
+            ty::AssocKind::Const { is_type_const: true, .. } => true,
+            ty::AssocKind::Const { is_type_const: false, .. } => {
+                tcx.features().generic_const_args()
+            }
+            ty::AssocKind::Fn { .. } => false,
+        }
+    }

What it does:

  • Returns true for associated types and type-level consts.
  • For non-type consts, only returns true if the generic_const_args feature is enabled.
  • Functions can never be constrained.

This centralizes the logic so all parts of the compiler can consistently check if an associated item is eligible for an equality constraint.

Replace scattered logic with the new helper

Throughout the codebase, replace checks like item.is_type() || item.is_type_const() with the new method:

- .filter(|item| item.is_type() || item.is_type_const())
+ .filter(|item| item.can_have_equality_constraint(tcx))

What it does:

  • Ensures that only those associated items that are eligible (according to the feature flags and type) are considered for equality constraints or trait object compatibility.

This appears in multiple places, such as:

  • When suggesting generic argument bindings in diagnostics.
  • When lowering trait object types.
  • In CFI/typeid calculations.

Update dyn trait compatibility logic

In dyn_compatibility.rs, update the logic for reporting violations for non-type associated consts:

-                } else if !is_type_const {
+                } else if !is_type_const && !tcx.features().generic_const_args() {
                     errors.push(AssocConstViolation::NonType);
                 }

What it does:

  • Only report a dyn compatibility error for non-type associated consts if the feature is not enabled. With GCA enabled, these are now allowed.

Maintain and update error reporting/enums

Reorder and clarify the AssocConstViolation enum so that NonType is only used when appropriate:

-    /// Has own generic parameters (GAC).
-    Generic,
-
-    /// Isn't defined as `type const`.
-    NonType,
+    /// Not defined as a type-level associated const.
+    NonType,
+
+    /// Has own generic parameters (GAC).
+    Generic,

What it does:

  • Keeps error reporting clear and accurate, reflecting the new rules.

Add and update tests

Add new tests to ensure the new behavior is correct and backwards compatibility is maintained:

  • tests/ui/const-generics/gca/dyn-compat-generic-non-type-assoc-const.rs
    Ensures that traits with generic non-type associated consts are still dyn-incompatible, even with GCA enabled.

  • tests/ui/const-generics/gca/dyn-non-type-assoc-const-binding.rs
    Checks that equality constraints on non-type associated consts are accepted with GCA.

  • tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.rs
    Verifies that generic const arguments in GAT constraints are rejected in certain contexts, maintaining soundness.

Also, update comments and error messages in existing tests to clarify when behavior changes under GCA.

From the review thread

BoxyUwU: this change is supposed to be for generic_const_args not min_generic_const_args since mgca doesn't support const items in the type system but full GCA does. once you change that this'll go back to mgca being backwards compatible but with GCA being backwards incompatible (which is OK)


fmease: Note that this change means that stabilizing mGCA will break stable code like tests/ui/type-alias/lack-of-wfcheck.rs.

Takeaways

  • Centralize feature gating and eligibility logic for language features (like associated item equality constraints) in a single helper to avoid inconsistencies across the codebase.
  • When introducing new type system capabilities, ensure that dyn trait compatibility and error reporting are updated to reflect the new rules, and test both new and old behaviors.
  • Backwards-incompatible changes must be carefully feature-gated and tested with both positive and negative cases to avoid breaking existing stable code.