Summary
PR #618 (unit-inference partial results) added an is_macro flag to ModelStage0/ModelStage1 and made units_infer SKIP declared-units constraints for macro bodies. Reason: a Vensim macro annotates its body variables' units with the formal-parameter NAMES (e.g. ~ xfrom, ~ xfrom/tstart inside C-LEARN's RAMP FROM TO) -- a polymorphic-unit idiom, not concrete base units. Treating those names as literal base units leaked them into every instantiation and conflicted with the real argument units (the xfrom/xto storm).
The limitation
The current fix is containment, not a full treatment: inference declines to pin macro-body param-named units, letting them be inferred polymorphically from the equation + cross-module parameter bindings. It does NOT:
- Resolve a param-named unit (
xfrom, xfrom/tstart) to the actual argument's units at each instantiation.
- Check a macro body's internal dimensional consistency against its (polymorphic) signature.
So macro bodies are effectively unit-unchecked (consistent with the existing behavior that skips unit-checking macro models entirely). A fuller treatment would parse a macro-body unit expression, recognize identifiers that are formal parameters, and bind them to the parameters' inferred (metavar) units -- enabling per-instantiation unit resolution AND macro-body unit checking.
Context
Discovered while fixing #614. The containment is correct (no false positives; C-LEARN holds at its documented 14-diagnostic residual) but the polymorphic-unit semantics are not modeled. Relevant code: src/simlin-engine/src/units_infer.rs (the is_macro skip in gen_all_constraints), src/simlin-engine/src/model.rs (ModelStage0/ModelStage1 is_macro).
Lower priority: macro-body unit errors are rare and Vensim is itself lenient here.
Summary
PR #618 (unit-inference partial results) added an
is_macroflag toModelStage0/ModelStage1and madeunits_inferSKIP declared-units constraints for macro bodies. Reason: a Vensim macro annotates its body variables' units with the formal-parameter NAMES (e.g.~ xfrom,~ xfrom/tstartinside C-LEARN'sRAMP FROM TO) -- a polymorphic-unit idiom, not concrete base units. Treating those names as literal base units leaked them into every instantiation and conflicted with the real argument units (thexfrom/xtostorm).The limitation
The current fix is containment, not a full treatment: inference declines to pin macro-body param-named units, letting them be inferred polymorphically from the equation + cross-module parameter bindings. It does NOT:
xfrom,xfrom/tstart) to the actual argument's units at each instantiation.So macro bodies are effectively unit-unchecked (consistent with the existing behavior that skips unit-checking macro models entirely). A fuller treatment would parse a macro-body unit expression, recognize identifiers that are formal parameters, and bind them to the parameters' inferred (metavar) units -- enabling per-instantiation unit resolution AND macro-body unit checking.
Context
Discovered while fixing #614. The containment is correct (no false positives; C-LEARN holds at its documented 14-diagnostic residual) but the polymorphic-unit semantics are not modeled. Relevant code:
src/simlin-engine/src/units_infer.rs(theis_macroskip ingen_all_constraints),src/simlin-engine/src/model.rs(ModelStage0/ModelStage1is_macro).Lower priority: macro-body unit errors are rare and Vensim is itself lenient here.