Skip to content

fix(aiken-lang): include same-module function dependencies in UPLC export (#1333)#1

Open
knoal wants to merge 3 commits into
mainfrom
fix/same-module-function-dependency-1333-v2
Open

fix(aiken-lang): include same-module function dependencies in UPLC export (#1333)#1
knoal wants to merge 3 commits into
mainfrom
fix/same-module-function-dependency-1333-v2

Conversation

@knoal

@knoal knoal commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Problem

When exporting a function that calls a same-module private helper function, aiken export produces UPLC where the helper appears as a free variable reference rather than including its definition.

Repro from aiken-lang#1333:

pub fn helper(x: Int) -> Bool { x > 0 }
pub fn main(y: Int) -> Bool { helper(y) }

Running aiken export and evaluating the exported main with amaru-uplc gives:

OpenTermEvaluated(Var(DeBruijn(N)))

Root Cause

In hoist_function, when a same-module function dependency is hoisted onto the validator tree:

  1. An Air::DefineFunc node is created with the function body embedded
  2. The code generator produces the correct UPLC structure (lambda(func_name).apply(func_body) wrapping)
  3. But: the function was never registered in key_to_func via insert_new_function

Without registration in key_to_func, the DefineFunc-generated UPLC creates a local variable binding that nothing resolves — leaving a free variable at the call site.

Fix

After hoisting a user-defined function (identified by being present in self.functions), register it in key_to_func via insert_new_function. This ensures the DefineFunc processing can look up the function and generate the correct Var reference.

The fix is guarded with self.functions.contains_key(key) to skip compiler-builtin functions (which use a different registration path).

Testing

  • All 178 existing aiken-project --lib tests pass
  • All 5 export tests pass
  • Added regression test export_same_module_dependency in crates/aiken-project/src/export.rs

Fixes aiken-lang#1333

Sophia (Hermes Agent) added 3 commits July 5, 2026 23:14
…port

When a public function calls a same-module private helper function,
aiken export was producing UPLC where the helper appeared as a free
variable reference rather than including its definition.

Root cause: hoist_function creates Air::DefineFunc nodes with the
function body embedded, and the code generator produces the correct
UPLC structure (lambda/apply wrapping), but the helper function was
never registered in key_to_func. This meant the function call site
couldn't be resolved at runtime.

Fix: after hoisting a function that exists in self.functions (i.e.,
a user-defined function, not a compiler-builtin), register it in
key_to_func via insert_new_function so DefineFunc processing can
find it.

Regression test added in aiken-project.

Fixes aiken-lang#1333
- Collapse 6-line comment block to 2 lines
- Destructure body directly in the HoistableFunction::Function match arm
- Drop intermediate func_body_vec and func_def bindings
- Separate borrow scopes to satisfy the borrow checker cleanly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aiken export does not bundle dependencies

1 participant