Skip to content

final fn references program-interior mappings/storage without qualification #29499

Description

@mohammadfawaz

Summary

The program { ... } block is the externally-accessible surface (the on-chain ABI): entry fn, view fn, records, mappings, and storage all live inside it because they are externally callable/queryable/readable. helper fn and final fn are inlined and never independently callable, so they are declared outside the block.

A top-level final fn, though it sits outside the block, can still name program-interior mappings and storage variables directly, unqualified.

final fn update_balance(receiver: address, amount: u64) {
    let current: u64 = balances.get_or_use(receiver, 0u64);  // `balances` is declared inside program { ... }
    balances.set(receiver, current + amount);
}

program cheatsheet.aleo {
    mapping balances: address => u64;
    // ...
}

So the braces gate external access but do not gate name visibility — two different meanings layered on one set of braces.

Proposed fix

A final fn is really a helper function that happens to permit on-chain code. Treat it like one: require it to qualify mapping/storage references with the program name, e.g.

final fn update_balance(receiver: address, amount: u64) {
    let current: u64 = cheatsheet.aleo::balances.get_or_use(receiver, 0u64);
    cheatsheet.aleo::balances.set(receiver, current + amount);
}

This makes the dependency on program-interior state explicit at the point of use and keeps the program { ... } braces meaning exactly one thing.

Metadata

Metadata

Assignees

Labels

🐛 bugSomething isn't working🧱 Core CompilerAnything related to the core compiler including parsing, analysis, transforms, codegen, etc.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions