Skip to content

Three generated-primitive guards pass when their premise breaks #704

Description

@mparrett

#656 was a shadowed registration. reduce was registered both by hand in installLangNS and by the generated //lg:native registrar; the generated body won, the closure's ArrayVector and Range fast paths were lost, and reduce ran 1.75x slower with the suite green — including TestReduceRangeFastPath, which asserts results rather than which path produced them. #686 fixed it and added TestNoNewShadowedHandRegistrations to ratchet the duplicate-registration set.

Three other guards in the same area fail the same way: they pass when the property they exist to protect stops holding. Each was raised as a non-blocking follow-up during review of #639/#640 and never filed.

Checked against main @ 8a8222d0.

1. Nothing enforces the builtins-override-primitives ordering

pkg/rt/zz_run_installers.go documents a precedence guarantee: builtins register after the installer drain, so builtin versions override the generated primitives for overlapping names (vector, cons, contains?, array-map, nth).

Swapping the two calls in that init() inverts the precedence, and go test ./pkg/rt/ still passes.

#686's new test covers a neighbouring hazard: it ratchets which names are registered twice, not which registration wins.

Either the precedence needs a test that fails when the order is wrong, or another mechanism already guarantees it and the comment should name that mechanism instead.

2. The generated-primitive audit skips source-only siblings

AuditGeneratedPrimitives (pkg/rt/generated_prim_audit_test.go) walks genPrimBindings and asserts that each generated primitive resolves in its canonical namespace. They all do. What breaks is the namespace's source-defined siblings: clojure.string/upper-case is generated and guarded, clojure.string/join comes from string.lg, and nothing in the audit looks at it.

Asserting that one known source-only name still resolves after a require would close the gap.

3. TestGeneratePreservesSourcePackageName passes on zero specs

The test (internal/primgen/prims_test.go) asserts that the generated output contains package primitives and does not contain package v2. Reverting its fixture to the pre-fix //lg:native clojure.core noop spelling still passes:

lgprimgen: no //lg:native directives found in <tmpdir>; generating empty stub
lgprimgen: generated primitives → <tmpdir>/zz_primitives_generated.go (0 specs)
--- PASS: TestGeneratePreservesSourcePackageName (0.00s)

The empty-stub branch reaches the same package clause by a different route, so the assertion holds for the wrong reason. An assertion on the spec count, or on the emitted noop binding, pins the premise.

Adjacent open work: #696 and #697, retiring and draining the hand registrations the generated registrar shadows.

Parented under #528.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions