Skip to content

feat(guppylang_internals)!: Implement error handling for modified variables outside modifiers#1712

Draft
nicolaassolini-qntm wants to merge 3 commits intomainfrom
na/1700-raise-an-error-when-variables-are-used-outside-a-modifier-block
Draft

feat(guppylang_internals)!: Implement error handling for modified variables outside modifiers#1712
nicolaassolini-qntm wants to merge 3 commits intomainfrom
na/1700-raise-an-error-when-variables-are-used-outside-a-modifier-block

Conversation

@nicolaassolini-qntm
Copy link
Copy Markdown
Contributor

@nicolaassolini-qntm nicolaassolini-qntm commented May 1, 2026

closes #1700

  • Captured variables assigned inside a modifier block are now tracked on CheckedModifiedBlock.
  • Copyable/classical captured variables modified in the block are marked as consumed for the outer scope.
  • Later use now raises a Variable modified in the modifier block, including a note pointing to the assignment inside the modifier.
  • Added tests

BREAKING CHANGE: The class constructor of CheckedModifiedBlock in guppylang_internals/nodes.py now takes an extra argument (modified_captured: Mapping[str, AstNode])

@hugrbot
Copy link
Copy Markdown
Collaborator

hugrbot commented May 1, 2026

This PR contains breaking changes to the public Python API.

Breaking changes summary
guppylang-internals/src/guppylang_internals/nodes.py:893: CheckedModifiedBlock.__init__(modifiers):
Positional parameter was moved
Details: position: from 5 to 6 (+1)

guppylang-internals/src/guppylang_internals/nodes.py:893: CheckedModifiedBlock.__init__(modified_captured):
Parameter was added as required


@nicolaassolini-qntm nicolaassolini-qntm changed the title Implement error handling for modified variables outside modifiers feat: Implement error handling for modified variables outside modifiers May 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

🐰 Bencher Report

Branchna/1700-raise-an-error-when-variables-are-used-outside-a-modifier-block
TestbedLinux
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
microseconds (µs)
(Result Δ%)
Upper Boundary
microseconds (µs)
(Limit %)
tests/benchmarks/test_big_array.py::test_big_array_check📈 view plot
🚷 view threshold
870,780.05 µs
(-14.09%)Baseline: 1,013,581.58 µs
1,064,260.65 µs
(81.82%)
tests/benchmarks/test_big_array.py::test_big_array_compile📈 view plot
🚷 view threshold
2,121,526.13 µs
(-0.18%)Baseline: 2,125,295.27 µs
2,231,560.03 µs
(95.07%)
tests/benchmarks/test_big_array.py::test_big_array_executable📈 view plot
🚷 view threshold
8,777,533.78 µs
(+1.93%)Baseline: 8,611,724.33 µs
9,042,310.55 µs
(97.07%)
tests/benchmarks/test_ctrl_flow.py::test_many_ctrl_flow_check📈 view plot
🚷 view threshold
109,183.00 µs
(-4.36%)Baseline: 114,159.33 µs
119,867.30 µs
(91.09%)
tests/benchmarks/test_ctrl_flow.py::test_many_ctrl_flow_compile📈 view plot
🚷 view threshold
232,023.20 µs
(-2.35%)Baseline: 237,598.15 µs
249,478.06 µs
(93.00%)
tests/benchmarks/test_ctrl_flow.py::test_many_ctrl_flow_executable📈 view plot
🚷 view threshold
952,387.91 µs
(-27.05%)Baseline: 1,305,526.15 µs
1,370,802.46 µs
(69.48%)
tests/benchmarks/test_prelude.py::test_import_guppy📈 view plot
🚷 view threshold
51.21 µs
(-5.92%)Baseline: 54.44 µs
57.16 µs
(89.60%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_benchmark📈 view plot
🚷 view threshold
463,308.71 µs
(-2.51%)Baseline: 475,216.79 µs
498,977.63 µs
(92.85%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_pop_benchmark📈 view plot
🚷 view threshold
619,643.00 µs
(-1.36%)Baseline: 628,161.81 µs
659,569.90 µs
(93.95%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

🐰 Bencher Report

Branchna/1700-raise-an-error-when-variables-are-used-outside-a-modifier-block
TestbedLinux
Click to view all benchmark results
Benchmarkhugr_bytesBenchmark Result
bytes x 1e3
(Result Δ%)
Upper Boundary
bytes x 1e3
(Limit %)
hugr_nodesBenchmark Result
nodes
(Result Δ%)
Upper Boundary
nodes
(Limit %)
tests/benchmarks/test_big_array.py::test_big_array_compile📈 view plot
🚷 view threshold
158.77 x 1e3
(0.00%)Baseline: 158.77 x 1e3
160.36 x 1e3
(99.01%)
📈 view plot
🚷 view threshold
6,641.00
(0.00%)Baseline: 6,641.00
6,707.41
(99.01%)
tests/benchmarks/test_ctrl_flow.py::test_many_ctrl_flow_compile📈 view plot
🚷 view threshold
27.53 x 1e3
(0.00%)Baseline: 27.53 x 1e3
27.81 x 1e3
(99.01%)
📈 view plot
🚷 view threshold
1,074.00
(0.00%)Baseline: 1,074.00
1,084.74
(99.01%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_benchmark_compile📈 view plot
🚷 view threshold
10.91 x 1e3
(0.00%)Baseline: 10.91 x 1e3
11.02 x 1e3
(99.01%)
📈 view plot
🚷 view threshold
308.00
(0.00%)Baseline: 308.00
311.08
(99.01%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_pop_benchmark_compile📈 view plot
🚷 view threshold
14.84 x 1e3
(0.00%)Baseline: 14.84 x 1e3
14.99 x 1e3
(99.01%)
📈 view plot
🚷 view threshold
435.00
(0.00%)Baseline: 435.00
439.35
(99.01%)
🐰 View full continuous benchmarking report in Bencher

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 1, 2026

Codecov Report

❌ Patch coverage is 96.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.48%. Comparing base (561882f) to head (8f4de34).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...c/guppylang_internals/checker/linearity_checker.py 93.47% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1712      +/-   ##
==========================================
+ Coverage   93.47%   93.48%   +0.01%     
==========================================
  Files         133      133              
  Lines       12697    12748      +51     
==========================================
+ Hits        11868    11918      +50     
- Misses        829      830       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

This PR addresses #1700 by detecting when classical/copyable variables captured by a modifier block are assigned within that block, and raising an error if the stale outer binding is used afterward.

Changes:

  • Track captured variables that are assigned inside modifier blocks (CheckedModifiedBlock.modified_captured), including nested modifier bodies.
  • Extend linearity checking to mark such variables as unusable after the modifier and emit a dedicated diagnostic with a note pointing to the in-modifier assignment.
  • Add new error fixtures covering basic, sequential, nested, multiple-variable, and branching scenarios.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/error/modifier_errors/captured_classical_modified.py New error fixture: modified captured variable used after a modifier block.
tests/error/modifier_errors/captured_classical_modified.err Expected diagnostic output for the above scenario.
tests/error/modifier_errors/captured_classical_modified_sequential.py New error fixture: sequential modifier blocks reusing a modified captured variable.
tests/error/modifier_errors/captured_classical_modified_sequential.err Expected diagnostic output for sequential modifier case.
tests/error/modifier_errors/captured_classical_modified_nested.py New error fixture: modification occurs inside nested modifiers.
tests/error/modifier_errors/captured_classical_modified_nested.err Expected diagnostic output for nested modifier case.
tests/error/modifier_errors/captured_classical_modified_multiple.py New error fixture: multiple captured variables modified; verifies first reported.
tests/error/modifier_errors/captured_classical_modified_multiple.err Expected diagnostic output for multiple modified captures.
tests/error/modifier_errors/captured_classical_modified_branch.py New error fixture: usage in a branch after a modifier.
tests/error/modifier_errors/captured_classical_modified_branch.err Expected diagnostic output for branch usage case.
tests/error/errors_on_usage/branch_in_modifier.py New error fixture ensuring “not defined” behavior remains for vars only defined inside modifier branches.
tests/error/errors_on_usage/branch_in_modifier.err Expected output for “Variable not defined” regression case.
guppylang-internals/src/guppylang_internals/nodes.py Add modified_captured field to CheckedModifiedBlock for later diagnostics/linearity.
guppylang-internals/src/guppylang_internals/checker/stmt_checker.py Minor rename cleanup: return the checked modified block variable consistently.
guppylang-internals/src/guppylang_internals/checker/modifier_checker.py Compute modified_captured by scanning CFG BB assignments, recursing into nested modifier blocks.
guppylang-internals/src/guppylang_internals/checker/linearity_checker.py Introduce UseKind.DEFINED_IN_MODIFIER and raise ModifiedVariableUsedError on later uses; mark modified copyable captures as stale.
guppylang-internals/src/guppylang_internals/checker/errors/linearity.py Add new ModifiedVariableUsedError diagnostic with note/help.
guppylang-internals/src/guppylang_internals/checker/cfg_checker.py Adds commented-out debug print (should be removed).
guppylang-internals/src/guppylang_internals/cfg/cfg.py Adds cfg_as_string() helper (currently unused except for commented debug line).
.gitignore Ignore AGENTS.md.

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

Comment thread guppylang-internals/src/guppylang_internals/checker/cfg_checker.py Outdated
Comment thread guppylang-internals/src/guppylang_internals/cfg/cfg.py Outdated
@nicolaassolini-qntm nicolaassolini-qntm changed the title feat: Implement error handling for modified variables outside modifiers feat(guppylang_internals)!: Implement error handling for modified variables outside modifiers May 1, 2026
@nicolaassolini-qntm nicolaassolini-qntm marked this pull request as draft May 1, 2026 16:05
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 1, 2026

Congrats! CodSpeed is installed 🎉

🆕 9 new benchmarks were detected.

You will start to see performance impacts in the reports once the benchmarks are run from your default branch.

Detected benchmarks


Open in CodSpeed

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.

[Feature]: Raise an error when variables are used outside a modifier block

4 participants