Skip to content

Fix constraint solver non-determinism and test isolation#28

Merged
wolfy-j merged 4 commits intomainfrom
fix/type-system-gaps
Apr 4, 2026
Merged

Fix constraint solver non-determinism and test isolation#28
wolfy-j merged 4 commits intomainfrom
fix/type-system-gaps

Conversation

@wolfy-j
Copy link
Copy Markdown
Contributor

@wolfy-j wolfy-j commented Apr 4, 2026

Summary

  • Fix non-deterministic constraint narrowing that caused flaky test failures
  • Fix LState pool test isolation for TestUninitializedVarAccess
  • Export types as table values in all realworld fixtures

Root cause

applyIsNil in the constraint solver's type domain unconditionally set the narrowed type to nil without checking if the base type could actually be nil. When a contradictory isNil constraint was applied to a non-optional type (e.g., after truthiness narrowing), it corrupted the domain state instead of marking it unsatisfiable. This caused non-deterministic narrowing results depending on constraint evaluation order.

Changes

  • types/flow/domain/type_domain.go: applyIsNil now filters base type by kind.Nil and marks domain unsatisfiable when narrowing produces Never
  • types/constraint/solver.go: Propagate unsat from domain application
  • state_test.go: Drain pool + GC flush for registry-capacity-sensitive test
  • testdata/fixtures/realworld/: Export cross-file types as M.Type = Type

Test plan

  • 0 failures in 50 consecutive runs of go test -count=1 .
  • go test -count=1 ./... — all packages pass
  • TestFixtureOrder_GenericRegistryThenMultiReturn regression test
  • New unit tests in type_domain_test.go and solver_test.go

wolfy-j added 4 commits April 3, 2026 17:13
…elds

Add missing grammar rule for (params) -> () in function type expressions.
The parser handled () -> () but not (self: T) -> () or (a: number) -> (),
causing parse errors in record field type annotations with void-returning
methods.

One new rule in parser.go.y:
  '(' funcparamlist ')' TArrow '(' ')' → FunctionTypeExpr with empty Returns

Impact on real-world fixture scorecard (117 → 72 tracked errors):
- factory-constructor:    6 → 0 (fixed)
- iterator-pipeline:     11 → 0 (fixed)
- module-with-generics:   5 → 0 (fixed)
- service-locator:       14 → 0 (fixed)
- generic-registry:      12 → 4
- metatable-oop:          5 → 4
Two independent bugs causing test non-determinism:

1. types/flow/domain/type_domain.go: applyIsNil was unconditionally
   setting narrowed type to nil without checking if the base type
   could actually be nil. When a contradictory isNil constraint applied
   to a non-optional type, it corrupted the domain state instead of
   marking it unsatisfiable. Now filters by kind.Nil and marks Unsat
   when narrowing produces Never.

2. state_test.go: TestUninitializedVarAccess requires an exact 128-slot
   registry to trigger the resize at the right point. Previous drain of
   statePool was insufficient — per-P caches in sync.Pool could return
   states after the drain. Added runtime.GC() between drain passes to
   flush per-P caches.

Verified: 0 failures in 50 consecutive runs of go test -count=1 .
Add M.TypeName = TypeName exports for all cross-file type declarations.
While the checker resolves types through manifests (not runtime values),
exporting types is idiomatic and enables runtime validation via :is().
When an identifier resolves to unknown through normal flow analysis but
matches a declared type name in scope, produce a Meta type wrapping
the declared type. This enables type values to flow through module
exports as first-class values.

Example: type Config = {host: string}; return {Config = Config}
Previously the Config field was unknown. Now it's typeof(Config),
enabling cross-module patterns like mylib.Config:is(data).

This matches the pattern used in wippy production code where type
declarations are exported as table fields for runtime validation.
@wolfy-j wolfy-j merged commit a58b4bb into main Apr 4, 2026
@wolfy-j wolfy-j deleted the fix/type-system-gaps branch April 9, 2026 03:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant