Skip to content

ModelingToolkitBase QA lane red since #4832: JET typo mode reports 263 errors, 234 of them from Moshi @match codegen #5063

Description

@ChrisRackauckas-Claude

Summary

The lib/ModelingToolkitBase [QA] / Julia 1 lane of Sublibrary CI has been red on every master run since #4832 (92c27bb9fd, 2026-08-11) introduced SciMLTesting.run_qa(ModelingToolkitBase; jet = true), i.e. JET.test_package(ModelingToolkitBase; target_modules = (ModelingToolkitBase,), mode = :typo). The check reports 263 possible errors and fails; before that commit the QA lane ran only test/qa/jet.jl (54 @test_calls) and the report_package check did not exist, so there is no MTK commit to bisect to.

Latest master run: https://github.com/SciML/ModelingToolkit.jl/actions/runs/33444273161/job/99660311927 (e91f13e4, JET 0.12.1, Julia 1.12.7: JET-test failed ... 263 possible errors found). Every earlier run that executed the job is red as well, e.g. https://github.com/SciML/ModelingToolkit.jl/actions/runs/31478008118 (the #4832 PR itself, merged red), https://github.com/SciML/ModelingToolkit.jl/actions/runs/32557851438/job/96996767096, https://github.com/SciML/ModelingToolkit.jl/actions/runs/33305672292/job/99250653964.

The root tests / QA (julia 1) lane is green because test/qa/Project.toml pins JET = "0.9,0.10,0.11" and analyses only the ModelingToolkit facade; lib/ModelingToolkitBase/test/qa/Project.toml has no JET compat, but the JET version is not the cause (see below).

Local reproduction (clean master worktree, 22cb5b0a21)

export JULIA_DEPOT_PATH="$HOME/sandbox/initwrap/depot:$HOME/.julia"
cd lib/ModelingToolkitBase/test/qa
julia +1.12 --startup-file=no --project=. -e 'using Pkg; Pkg.instantiate(); include("aqua.jl")'
Quality Assurance: JET-test failed at ~/.julia/packages/JET/vOTu0/src/JETBase.jl:1312
  Expression: (JET.report_package)(ModelingToolkitBase; toplevel_logger = nothing, target_modules = (ModelingToolkitBase,), mode = typo)
  ═════ 263 possible errors found ═════
  ┌ default_toterm(x::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymbolicUtils.SymReal}) @ ModelingToolkitBase .../src/variables.jl:268
  │ local variable `##And#280#f#1` may be undefined: ##And#280#f#1::Any
  ...
Test Summary:                                | Pass  Fail  Total      Time
Quality Assurance                            |   20     1     21  29m27.9s

Running only the JET call (JET.report_package(ModelingToolkitBase; toplevel_logger = nothing, target_modules = (ModelingToolkitBase,), mode = :typo)) on Julia 1.12.7:

JET Moshi reports JET time
0.12.1 0.3.12 263 1036 s
0.11.6 0.3.12 263 (identical set) 1041 s

So this is not a JET 0.12 regression. Of the 263 reports, 234 are local variable ``##And#N#x#1`` / ``##Call#N#x#1`` may be undefined at Moshi.Match.@match sites (utils.jl, systems/abstractsystem.jl, systems/problem_utils.jl, systems/callbacks.jl, variables.jl, systems/system.jl, ...); the remaining 29 are in hand-written code (see the PR below).

Root cause of the 234 @match reports: Moshi's @match codegen

For Pattern(; f, args) && if f isa Int end => body, Moshi 0.3.12 expands the condition to

if begin
        v = x
        begin
            v isa A && begin
                begin ff = v.f; true end && begin gg = v.g; true end
            end
        end
    end && ff isa Int

A begin ... end whose value is a && makes Julia lower ff through a phi node with an #undef edge, so every later use of ff (the guard, the body's let) gets a throw_undef_if_not and JET's typo mode reports it. The runtime behaviour is correct. This is the pattern already reduced in aviatesk/JET.jl#858 and JuliaLang/julia#62745, and discussed for the root QA lane in #4958. Shapes tested with JET.report_call(f, (Any,); mode = :typo) on Julia 1.12.7 / JET 0.12.1:

shape reports throw_undef_if_not in code_typed
Moshi 0.3.12 output (blocks around each conjunction) 3 yes
same, but no block around the conjunctions 3 yes
holder assignment hoisted, blocks kept 3 yes
flat && chain, (begin v = x; true end) && v isa A && (begin ff = v.f; true end) && ... && ff isa Int 0 no
flat chain, left-nested ((a && b) && c) 0 no

Fix candidate (upstream, Moshi.jl)

Emitting the match condition as one flat && chain fixes it: https://github.com/ChrisRackauckas-Claude/Moshi.jl/tree/flat-match-conditions (commit ef79026, 3 small changes in src/match/emit/{ctx,logic,call}.jl plus a regression test asserting no throw_undef_if_not in the typed IR of guarded matches). With it:

  • the regression test fails on v0.3.12 and passes on the branch, on Julia 1.10.11 and 1.12.7; Moshi's full test suite passes on both;
  • JET.report_call on real @match functions goes from 3/2/5/7 reports to 0/0/0/0;
  • JET.report_package(ModelingToolkitBase; ...) on master goes from 263 to 29 reports and from 1036 s to 332 s.

Roger-luo/Moshi.jl is not a SciML repository, so no PR was opened there; the branch is ready to open if you want it.

The other 29 reports are real

They are fixed in the PR linked in the first comment below: Shift(steps) calling new from an outer constructor, s/sz/expr/v typos, an undefined ModelingtoolkitizeParametersNotSupportedError, extend calling the removed convert_system, the Substituter method for AffectSystem using removed System fields, optext/coeff undefined on some paths, and a handful of locals that are only bound on some branches or captured by closures after reassignment. With that PR and the Moshi branch together, report_package reports 0 (JET run time 330 s instead of 1036 s).

Also noticed

  • With Julia 1.10.11 the same env resolves JET 0.9.18 and report_package produces 38 unrelated toplevel reports (UndefVarError: MassActionJump not defined, ConstantRateJump, BlockedArray, BandedMatrix, ...), i.e. JET 0.9's virtual processing of using X: name imports. test_groups.toml lists versions = ["lts", "1"] for QA but Sublibrary CI only ran a Julia 1 QA job, so this is not currently exercised.
  • Moshi's plain-struct keyword pattern A(; f) expands to Core.getfield(v, f) with f unquoted (QuoteNode missing in src/match/emit/call.jl), so it throws UndefVarError: f. MTK only uses keyword patterns on @data variants, which are handled correctly.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions