4.7 KiB
Analysis: AST Traversal & Symbol Resolution "Swallow" Bugs
Overview
The Myc compiler utilizes several passes that traverse the Abstract Syntax Tree (AST) at different stages (Untyped, Bound/Typed). A recurring pattern in the codebase was the use of non-exhaustive match arms, specifically _ => Ok(node) or _ => {}.
While convenient, this pattern created "Swallow Traps": when new node types were added to the language (like Again for tail-calls or Pipe for streaming), these passes would silently ignore them. This led to incomplete symbol registration and binder errors.
Identified Issues
1. LambdaCollector (Fixed)
Location: src/ast/compiler/lambda_collector.rs
- Problem: This pass collects all global function definitions (lambdas) for the Specializer (monomorphization). It used
_ => {}, missing nodes with children likeAgain,Pipe, andDestructure. - Impact: Functions defined inside an
againblock or apipelambda were not registered. The Specializer could not find their AST, leading to "Undefined variable" or specialization failures. - Fix: Refactored
visitto use exhaustive matching. EveryBoundKindvariant is now explicitly handled. Nodes with children are traversed recursively; leaf nodes are explicitly ignored.
2. Global Discovery Pass (Current Bottleneck)
Location: src/ast/environment.rs -> discover_globals
- Problem: This pass runs on the Untyped AST before binding. Its job is to find all
defandmacrodeclarations to populate the global symbol table. - Critical Failure: It currently only matches
UntypedKind::Def,UntypedKind::MacroDecl, andUntypedKind::Block. It misses declarations hidden insideAgain,Pipe,If, andLambdabodies. - Impact: Even if the
LambdaCollectoris fixed, theBinderwon't know a symbol is global ifdiscover_globalsdidn't find it first. This explains why tests forAgainandPipestill fail with "Undefined variable".
3. Destructuring Def Bug (Discovered)
Location: src/ast/environment.rs -> discover_globals
- Observation:
discover_globalsonly registers a global if theDeftarget is a singleIdentifier. - Bug:
(def [a b] [1 2])is currently ignored for global registration. These variables are treated as local or remain undefined in the global scope.
4. VM: Evaluation & Pattern Matching
Location: src/ast/vm.rs
eval_core(L309): The main execution loop. It covers most variants but lacks an exhaustive check. NewBoundKindvariants will not be caught at compile-time.unpack(L994): Used for parameter destructuring.Any newmatch &pattern.kind { UntypedKind::Identifier(sym) => { ... } UntypedKind::Tuple { elements } => { ... } _ => Err("Invalid node in parameter pattern".to_string()), }UntypedKind(like Record destructuring) will trigger a runtime error instead of a compile-time exhaustiveness check.after_eval(Observer): Uses_ => {}, meaning new control-flow nodes might lack proper debug/trace logging.
5. Optimizer: Engine & Inlining
Location: src/ast/compiler/optimizer/engine.rs, inliner.rs
flatten_tuple(L693 in engine.rs):Incorrectly assumes that any unknown node is atomic. If a new sequence-like node is added, it won't be flattened, potentially breaking assumptions in the Optimizer's call-site logic.match &node.kind { BoundKind::Tuple { elements } => { ... } BoundKind::Nop => {} _ => into.push(node), }- Inliner Analysis: Uses
_ => falsefor inlinability checks. This prevents new node types from being inlined, leading to sub-optimal code without any warning to the developer.
Regression Testing
A suite of integration tests has been added to src/integration_test.rs to reveal these gaps:
test_lambda_collector_misses_again_arguments: (Currently FAILED)test_lambda_collector_misses_pipe_lambda: (Currently FAILED)test_lambda_collector_misses_destructure_value: (Now PASSED after LambdaCollector fix)test_lambda_collector_misses_get_field_rec: (PASSED, but requires verification against aggressive optimization)
Next Steps
- Refactor
discover_globals: Apply the same exhaustive matching strategy used in theLambdaCollectortosrc/ast/environment.rs. - Implement Pattern Traversal: Update
discover_globalsto extract all identifiers from destructuring patterns (e.g., inDef [a b] ...). - Audit Other Passes: Systematically check
type_checker.rs,optimizer/engine.rs, andvm.rsfor remaining_ =>swallow traps on node kinds.