Skip to content

feat: full arc56 source info#665

Draft
joe-p wants to merge 2 commits intomainfrom
feat/arc56_source_info
Draft

feat: full arc56 source info#665
joe-p wants to merge 2 commits intomainfrom
feat/arc56_source_info

Conversation

@joe-p
Copy link
Copy Markdown
Contributor

@joe-p joe-p commented Feb 27, 2026

Adds full source information to the generated ARC56. This is generally useful for developers who need to debug unexpected errors, especially when it needs to be done by hand.

One thing to note here is that Puya doesn't seem to have a full mapping of every PC to the high-level source. Presumably this is because of the optimization pipeline. I think this is acceptable because it still gives you the TEAL, which will be still be very helpful compared to just the PC

Note: This was one-shotted by 5.3 codex. I haven't carefully reviewed the code yet

@engineering-ci
Copy link
Copy Markdown

engineering-ci bot commented Feb 27, 2026

⚠️ No changelog fragment detected

@engineering-ci
Copy link
Copy Markdown

engineering-ci bot commented Feb 27, 2026

Checking stubs for changes and corresponding version bump in origin/feat/arc56_source_info

Last puyapy release: v5.7.1
This branch stubs version: 3.5.0
Last released stubs version: 3.4.0
Main stubs version: 3.5.0

💡 Stub version change: 3.4.0 -> 3.5.0
✅ Stub files unchanged
✅ Stub check passed!

@engineering-ci
Copy link
Copy Markdown

Name Status O0 bytes O1 bytes O2 bytes O0 ops O1 ops O2 ops

@joe-p joe-p force-pushed the feat/arc56_source_info branch 3 times, most recently from 113a2fa to 5f1d58a Compare March 6, 2026 18:40
@engineering-ci
Copy link
Copy Markdown

engineering-ci bot commented Mar 6, 2026

Coverage

Tests Skipped Failures Errors Time
1493 3 💤 0 ❌ 0 🔥 14m 1s ⏱️

@joe-p joe-p force-pushed the feat/arc56_source_info branch 2 times, most recently from 9bd17e5 to c9d370a Compare March 6, 2026 19:36
@joe-p joe-p force-pushed the feat/arc56_source_info branch from c9d370a to fcdb532 Compare March 6, 2026 19:49
@joe-p joe-p requested a review from Copilot March 6, 2026 19:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds richer ARC-56 source mappings to help developers debug runtime errors by including TEAL line numbers and high-level source references where available.

Changes:

  • Threads a new full_source_info option from CLI/options through compilation and ARC-56 generation.
  • Extends ARC-56 SourceInfo with optional teal and source fields and generates these mappings.
  • Updates ARC-56 action-combining logic to validate/filter OnComplete actions.

Reviewed changes

Copilot reviewed 7 out of 441 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/puyapy/compile.py Forces full_source_info off for ARC4 client generation path.
src/puyapy/main.py Adds CLI flag/default for full_source_info and documents it.
src/puya/service.py Passes full_source_info through service compilation into ARC-56 generation.
src/puya/options.py Adds full_source_info option (default enabled).
src/puya/compile.py Passes full_source_info through artifact writing into ARC-56 generation.
src/puya/arc56_models.py Extends ARC-56 source info model to include TEAL/source references.
src/puya/arc56.py Implements decoding/mapping logic and plumbs full_source_info through ARC-56 output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +241 to +263
for line_num, line in enumerate(teal_src.splitlines(), start=1):
stripped = line.strip()
if not stripped or stripped.startswith(("//", "#pragma")) or stripped.endswith(":"):
continue
op_line_numbers.append((line_num, stripped))

if not op_line_numbers:
return {}

line_idx = 0
result = dict[int, int]()
for pc in sorted(pc_events):
event = pc_events[pc]
op = event.get("op") if event else None
if not op:
continue
while line_idx < len(op_line_numbers):
line_num, line_op = op_line_numbers[line_idx]
line_idx += 1
if line_op == op:
result[pc] = line_num
break
return result
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TEAL line-to-op matching is comparing the full stripped TEAL line (which often includes operands and inline comments, e.g. int 1, bnz label, int 1 // comment) to event['op'] (likely just the opcode mnemonic, e.g. int, bnz). This will fail to match for most ops and produce incorrect/missing teal mappings. Parse the first token as the opcode (and strip inline comments, and treat # comment lines similarly to //) before comparing to op.

Copilot uses AI. Check for mistakes.
Comment on lines +295 to +313
def _base64vlq_decode(value: str) -> tuple[int, int, int, int]:
decoded = []
current = 0
shift = 0
for char in value:
digit = _decode_base64_char(char)
continuation = digit & 0b100000
payload = digit & 0b011111
current |= payload << shift
shift += 5
if continuation:
continue
sign = -1 if current & 1 else 1
decoded.append(sign * (current >> 1))
current = 0
shift = 0
if len(decoded) != 4:
raise ValueError(f"Invalid source map segment: {value!r}")
return typing.cast(tuple[int, int, int, int], tuple(decoded))
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-failing when a VLQ segment doesn't decode to exactly 4 values can break ARC-56 generation if the mapping format varies (segments can be variable-length in common sourcemap/VLQ encodings). Consider decoding more defensively (e.g., accept 4+ values and ignore extras, or skip segments that don't match expectations) and ensure _decode_source_mappings does not propagate a ValueError that prevents emitting ARC-56.

Copilot uses AI. Check for mistakes.
optimization_level: Set optimization level of output TEAL / AVM bytecode
full_source_info: Include detailed source mappings (TEAL line numbers and
source file references) in ARC-56 output
optimization_level: Set optimization level of output TEAL / AVM bytecode
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring lists optimization_level twice (lines 131 and 134). Removing the duplicate entry will prevent confusion and keep the CLI docs consistent.

Suggested change
optimization_level: Set optimization level of output TEAL / AVM bytecode

Copilot uses AI. Check for mistakes.
clear_program=artifact.clear_program,
metadata=artifact.metadata,
template_prefix=template_prefix,
full_source_info=False,
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hard-codes full_source_info=False on the ARC-56 generation path used by write_arc4_clients, which conflicts with the new default of enabling full source info elsewhere (CLI/options default True). Consider threading the user-configured value through here (or leaving it to the ARC-56 default) so the feature behaves consistently across entry points.

Suggested change
full_source_info=False,

Copilot uses AI. Check for mistakes.
Comment on lines +447 to 464
create = sorted(
{oca for action in actions for oca in action.create if allowed_create_oca(oca)}
)
call = sorted({oca for action in actions for oca in action.call if allowed_call_oca(oca)})
return models.MethodActions(
create=sorted(set(itertools.chain.from_iterable(a.create for a in actions))),
call=sorted(set(itertools.chain.from_iterable(a.call for a in actions))),
create=typing.cast(
Sequence[typing.Literal["NoOp", "OptIn", "DeleteApplication"]],
create,
),
call=typing.cast(
Sequence[
typing.Literal[
"NoOp", "OptIn", "CloseOut", "UpdateApplication", "DeleteApplication"
]
],
call,
),
)
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid/unknown OnComplete action values are silently dropped by the allowed_*_oca filters. If an invalid value appears upstream, silently omitting it can make ARC-56 output inaccurate and harder to debug. Consider raising an error (or at least logging) when an unexpected OCA is encountered, instead of filtering it out without notification.

Copilot uses AI. Check for mistakes.
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.

2 participants