checkModelIs doesn't call pendingResolutions.finish on early-return error paths
Summary
In packages/compiler/src/core/checker.ts, the checkModelIs function calls pendingResolutions.start(modelSymId, ResolutionKind.BaseType) at the beginning but several early-return error paths skip the corresponding pendingResolutions.finish(...) call. This leaves the resolution in a "started" state, causing spurious circular-base-type diagnostics when another model later references the affected model via is or extends.
Repro
model A is { x: int32 };
model B is A;
Expected: Only one diagnostic — is-model error on A (model expression not allowed with is).
Actual: Two diagnostics:
is-model: Model is cannot specify a model expression.
circular-base-type: Type 'A' recursively references itself as a base type. ← spurious
Similarly:
model A is "hello";
model B is A;
Produces a spurious circular-base-type for A.
Root Cause
In checkModelIs (~line 6397), pendingResolutions.start is called unconditionally, but three early-return branches don't call finish:
- Model expression (line ~6415):
return undefined after reporting is-model with modelExpression message
- Circular reference detected (line ~6430):
return undefined after reporting circular-base-type
- Other invalid expression (line ~6435):
return undefined after reporting is-model
The finish call only exists after the if/else block (line ~6438), which is unreachable on these paths.
Fix
Add pendingResolutions.finish(modelSymId, ResolutionKind.BaseType) before each early return undefined in checkModelIs.
Test coverage
Regression tests have been added in packages/compiler/test/checker/model.test.ts under "pending resolution is finished on error paths" (currently marked with it.fails). Once fixed, flip them to regular it(...).
checkModelIsdoesn't callpendingResolutions.finishon early-return error pathsSummary
In
packages/compiler/src/core/checker.ts, thecheckModelIsfunction callspendingResolutions.start(modelSymId, ResolutionKind.BaseType)at the beginning but several early-return error paths skip the correspondingpendingResolutions.finish(...)call. This leaves the resolution in a "started" state, causing spuriouscircular-base-typediagnostics when another model later references the affected model viaisorextends.Repro
Expected: Only one diagnostic —
is-modelerror onA(model expression not allowed withis).Actual: Two diagnostics:
is-model: Modeliscannot specify a model expression.circular-base-type: Type 'A' recursively references itself as a base type. ← spuriousSimilarly:
Produces a spurious
circular-base-typeforA.Root Cause
In
checkModelIs(~line 6397),pendingResolutions.startis called unconditionally, but three early-return branches don't callfinish:return undefinedafter reportingis-modelwithmodelExpressionmessagereturn undefinedafter reportingcircular-base-typereturn undefinedafter reportingis-modelThe
finishcall only exists after the if/else block (line ~6438), which is unreachable on these paths.Fix
Add
pendingResolutions.finish(modelSymId, ResolutionKind.BaseType)before each earlyreturn undefinedincheckModelIs.Test coverage
Regression tests have been added in
packages/compiler/test/checker/model.test.tsunder"pending resolution is finished on error paths"(currently marked withit.fails). Once fixed, flip them to regularit(...).