You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#548 fix is incomplete: <action> of <args> to an include-exposed action is still context-dependently fatal (works in main loop/tests, fatal at top level & in action bodies) #580
This is the same bug as #548, surfacing through a call form that #548's fix did not cover. #548 described a context-dependent fatal Undefined/not defined for include-exposed actions and fixed it for the call <action> with <args> form (now non-fatal everywhere). But the idiomatic<action> of <args> form still shows the original, pre-#548 context-dependent behavior: it resolves fine inside a main loop or a describe/test block, but is fatal at top level and inside an action body.
Because of is the natural WFL call syntax, this keeps multi-file libraries unusable through their natural top-level API even though #548 is marked completed.
Environment
WFL built from source today, .build_meta.json: { "year": 26, "month": 7, "build": 14 } (current main)
Linux, release build (cargo build --release)
The matrix (measured on 26.7.14)
mod.wfl:
define action called greet with parameters s:
return "HI-" with s
end action
call form
top-level stmt
inside define action body
inside main loop
inside describe/test
call greet with "bob"
✅ works
✅ works
✅ works
✅ works
greet of "bob"
❌ fatal
❌ fatal
✅ works
✅ works
The call … with row is exactly #548's fix. The of row is #548's original symptom table (top-level fatal, main loop/test non-fatal) — it was never given the top-level relaxation. The "action body → fatal" cell is an additional context #548's table didn't enumerate.
Repro for the still-fatal cell
main.wfl:
include from "mod.wfl"
display "BEFORE"
store g as greet of "bob"
display "AFTER=" with g
wfl main.wfl →
error[ANALYZE-SEMANTIC]: Variable 'greet' is not defined
BEFORE never prints; exit 3. Swapping only that line to store g as call greet with "bob" prints BEFORE / AFTER=HI-bob on the same build.
Why the two forms diverge (pointers)
greet of "bob" parses to Expression::FunctionCall { function: Variable("greet"), .. }. The analyzer analyzes the callee first via analyze_expression(function) (src/analyzer/mod.rs:2247), which hits the Expression::Variable branch (~mod.rs:2223) and calls report_undefined_name (src/analyzer/mod.rs:482) — fatal unless try_depth > 0, and it does not consult has_includes.
Severity::Error is emitted at src/analyzer/static_analyzer.rs:175; src/main.rs:1109-1119 does process::exit(3) on any error-severity semantic diagnostic. (Inside main loop/test, the same reference is emitted as a non-fatal warning instead — hence the context-dependence.)
Suggested fix
Extend #548's relaxation to the FunctionCall callee path: when a FunctionCall's callee is an unresolved Variable, has_includes is true, and it's not a builtin/param, route it through the same non-fatal-warning path as mod.rs:2533 instead of report_undefined_name's fatal branch — so <name> of <args> behaves like call <name> with <args> under include from.
An included file that references an action from a file it includes is fatal during the included file's own (isolated) analysis:
// base.wfl
define action called base_op with parameters x:
return "base(" with x with ")"
end action
// mid.wfl
include from "base.wfl"
create container Engine:
action run needs x: Text:
return base_op of x
end
end
// app.wfl
include from "mid.wfl"
create new Engine as e:
end
display e.run("hi")
→ error[ERROR]: Semantic error in included file 'mid.wfl': Variable 'base_op' is not defined (fatal). #547 was the stdlib-function instance of "included files analyzed in isolation"; this is the same root for a user action in a sibling include.
Impact / workaround (context: the Scribe templating engine, written in WFL)
To ship on the current build, Scribe had to (1) live in a single file — cross-file of-references are fatal — and (2) expose its API only as container methods (engine.render_string(src, ctx)), because method dispatch is the one call form the analyzer never statically rejects. The natural multi-file, top-level-helper surface (render of tmpl and ctx across an include) is not consumable in a normal wfl program.wfl run. Completing #548 for the of form (and #547 for cross-include user actions) would remove both concessions.
Summary
This is the same bug as #548, surfacing through a call form that #548's fix did not cover. #548 described a context-dependent fatal
Undefined/not definedfor include-exposed actions and fixed it for thecall <action> with <args>form (now non-fatal everywhere). But the idiomatic<action> of <args>form still shows the original, pre-#548 context-dependent behavior: it resolves fine inside amain loopor adescribe/testblock, but is fatal at top level and inside an action body.Because
ofis the natural WFL call syntax, this keeps multi-file libraries unusable through their natural top-level API even though #548 is marked completed.Environment
.build_meta.json:{ "year": 26, "month": 7, "build": 14 }(currentmain)cargo build --release)The matrix (measured on 26.7.14)
mod.wfl:define actionbodymain loopdescribe/testcall greet with "bob"greet of "bob"The
call … withrow is exactly #548's fix. Theofrow is #548's original symptom table (top-level fatal,main loop/test non-fatal) — it was never given the top-level relaxation. The "action body → fatal" cell is an additional context #548's table didn't enumerate.Repro for the still-fatal cell
main.wfl:wfl main.wfl→BEFOREnever prints; exit 3. Swapping only that line tostore g as call greet with "bob"printsBEFORE/AFTER=HI-bobon the same build.Why the two forms diverge (pointers)
greet of "bob"parses toExpression::FunctionCall { function: Variable("greet"), .. }. The analyzer analyzes the callee first viaanalyze_expression(function)(src/analyzer/mod.rs:2247), which hits theExpression::Variablebranch (~mod.rs:2223) and callsreport_undefined_name(src/analyzer/mod.rs:482) — fatal unlesstry_depth > 0, and it does not consulthas_includes.has_includesrelaxation Calling an include-exposed action from top level is a fatal 'Undefined action' (works inside main loop / test blocks) #548 added lives only in the ActionCall path atsrc/analyzer/mod.rs:2533. TheFunctionCall→Variablecallee path (whatofproduces) never reaches it.Severity::Erroris emitted atsrc/analyzer/static_analyzer.rs:175;src/main.rs:1109-1119doesprocess::exit(3)on any error-severity semantic diagnostic. (Insidemain loop/test, the same reference is emitted as a non-fatal warning instead — hence the context-dependence.)Suggested fix
Extend #548's relaxation to the
FunctionCallcallee path: when aFunctionCall's callee is an unresolvedVariable,has_includesis true, and it's not a builtin/param, route it through the same non-fatal-warning path asmod.rs:2533instead ofreport_undefined_name's fatal branch — so<name> of <args>behaves likecall <name> with <args>underinclude from.Related, same class as #547: nested includes
An included file that references an action from a file it includes is fatal during the included file's own (isolated) analysis:
→
error[ERROR]: Semantic error in included file 'mid.wfl': Variable 'base_op' is not defined(fatal). #547 was the stdlib-function instance of "included files analyzed in isolation"; this is the same root for a user action in a sibling include.Impact / workaround (context: the Scribe templating engine, written in WFL)
To ship on the current build, Scribe had to (1) live in a single file — cross-file
of-references are fatal — and (2) expose its API only as container methods (engine.render_string(src, ctx)), because method dispatch is the one call form the analyzer never statically rejects. The natural multi-file, top-level-helper surface (render of tmpl and ctxacross aninclude) is not consumable in a normalwfl program.wflrun. Completing #548 for theofform (and #547 for cross-include user actions) would remove both concessions.