Conversation
TomAFrench
force-pushed
the
cb/ninv-trait-generic-kinds
branch
from
September 16, 2026 15:06
542c4af to
5f60f5b
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When an impl method declares a generic with a different kind from the trait method's generic at the same position (a type parameter on one side, a numeric generic on the other),
check_trait_impl_method_matches_declarationrecorded a trait-to-impl binding whose recorded kind contradicted its replacement. If the trait method bounds that generic, the bound is substituted through the binding and the kindassert!inType::substitute_helperaborts the compiler (nargo checkexits 101 with a Rust panic).This PR compares the two kinds before recording the binding:
TypeCheckError::GenericKindMismatch, located at the impl method's generic: "fdeclares its genericQas a numeric generic of typeu32but the trait declares a type parameter".u32vsu64) are already reported by generic resolution ("The numeric generic is not of typeu64"). They are also left unbound, but not reported a second time.Invariant
This enforces two entries in the Noir audit's invariant register:
ninv:trait-impls-conform-to-declarations: an impl is accepted only if every method matches its trait's declaration in generic count, generic kind, parameter types and bounds, and any mismatch is a diagnostic.ninv:no-panic-on-user-input: no source program makes the compiler panic.Refs noir-lang/noir-claude#1711. That finding also suggests renaming
derive_hash's hasher parameter fromHtoH_innoir_stdlib/src/hash/mod.nr, so that#[derive(Hash)]on a struct with a generic namedHcompiles. That rename is not in this PR, and the issue stays open for it. With this PR that case produces diagnostics instead of a panic.Changes
compiler/noirc_frontend/src/elaborator/traits.rs: kind comparison in the trait-method/impl-method generic pairing loop.compiler/noirc_frontend/src/hir/type_check/errors.rs:TypeCheckError::GenericKindMismatchand its diagnostic.compiler/noirc_frontend/src/tests/traits/trait_impl_validation.rs: four tests.trait_impl_method_numeric_generic_for_bounded_type_parameter: the reproducer from the finding; it panics without the fix (see below).trait_impl_method_type_parameter_for_numeric_generic: the reverse direction.trait_impl_method_numeric_generic_of_different_type:u32vsu64is still an error and is not reported twice.trait_impl_method_generic_kinds_that_match_are_accepted: matching kinds under different names compile.Testing
cargo test -p noirc_frontend -- tests::traits: 351 passed.traits.rschange stashed,trait_impl_method_numeric_generic_for_bounded_type_parameterfails withpanicked at compiler/noirc_frontend/src/hir_def/types.rs:2963:29: while substituting (unbound): expected kind of unbound TypeVariable (Normal) to match the kind of its binding (Numeric(u32)).nargo checkwith this branch, on both reproducers from the finding: the plain-Noir trait impl, and#[derive(std::hash::Hash)] struct B<let H: u32> { x: [Field; H] }. Both now exit with diagnostics instead of a panic.cargo fmt --all -- --checkandcargo clippy -p noirc_frontend --testsare clean.Created by claudebox · group:
slackbot· requested by Tom (@TomAFrench) · Slack thread