Skip to content

Rename duplicate argument variables internally - #355

Open
micpap25 wants to merge 2 commits into
qBraid:mainfrom
micpap25:argument-bug-fix
Open

Rename duplicate argument variables internally#355
micpap25 wants to merge 2 commits into
qBraid:mainfrom
micpap25:argument-bug-fix

Conversation

@micpap25

@micpap25 micpap25 commented Aug 5, 2026

Copy link
Copy Markdown

Summary of changes

Fixes #311

Renames the variables created internally to handle quantum arguments in functions, preventing variable lookup issues caused by redefinition / shadowing.

@micpap25
micpap25 requested a review from TheGupta2012 as a code owner August 5, 2026 17:23
@argus-eye

argus-eye Bot commented Aug 5, 2026

Copy link
Copy Markdown

Argus review

Auto-review is off for this repo. Tick the box below to run a review on this PR.

  • Trigger Argus review

Estimated cost

  • Files changed: 2
  • Diff lines (±): 23
  • Historical avg: ~318.9k tokens · ~$1.35 · across last 6 review(s)

Tip: you can also comment @argus-eye review at any time.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 678ef34c-b2da-4048-9308-3bcb729d5033

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

👋 Hey there! It looks like the changelog might need an update.

Please take a moment to edit the CHANGELOG.md with:

  • A brief, one-to-two sentence summary of your changes.
  • A link back to this PR for reference.
  • (Optional) A small working example if you've added new features.

@micpap25

micpap25 commented Aug 5, 2026

Copy link
Copy Markdown
Author

@ryanhill1 I definitely don't think this is the most elegant way to handle this but the variable's name must be changed before the call to transform_function_qubits since the first thing that function does is use _get_op_bits which will break if it is passed the original register's name. Let me know if you think this is a good approach or if something better could be done.

@ryanhill1 ryanhill1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for taking this on, @micpap25 — and for the root-cause work on #311. Identifying the parameter shadowing was the hard part, and the reported case does now work.

Most of what follows is in the _visit_function_call machinery you mentioned being unfamiliar with. Specifics are inline; two general things:

The suite is red. 10 tests fail here that pass on main — 5 in tests/cli, 5 in tests/qasm3/subroutines. pytest tests reproduces most of the inline findings.

No tests or CHANGELOG entry. A few regression tests would have caught most of this. Worth covering: the #311 repro, an array-typed shadowed parameter (qubit[2] q), reset/barrier bodies, a nested call with differing parameter names, and the q/q_arg collision. tests/qasm3/subroutines/test_subroutines.py is the natural home.

Your diagnosis was right — the gap is between fixing this program and fixing it without disturbing the others, and the four call sites in the last inline comment aren't discoverable without going looking. Happy to pair or split it, and no rush.

Comment thread src/pyqasm/subroutines.py Outdated
# If our actual variable is the same as the function argument,
# give the function argument a temporary name for internal use
if actual_arg_name == formal_reg_name:
formal_reg_name += "_arg"

@ryanhill1 ryanhill1 Aug 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This name reaches the user. It flows into error messages, so a size mismatch reports Expected 3 qubits in variable 'q_arg' when the user wrote q. Breaks the 5 test_subroutines.py tests.

Suggestion: use a separate internal_reg_name for the map keys and leave formal_reg_name alone for messages.

Comment thread src/pyqasm/subroutines.py
formal_reg_name = formal_arg.name.name
# If our actual variable is the same as the function argument,
# give the function argument a temporary name for internal use
if actual_arg_name == formal_reg_name:

@ryanhill1 ryanhill1 Aug 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

_arg can collide with a name already in use:

qubit[2] q;
qubit[2] r;
def f(qubit q, qubit q_arg) { h q; x q_arg; }
f(q[0], r[1]);

main emits h q[0]; x r[1];. Here it's ValueError: Variable 'q_arg' already exists in current scope — and a raw ValueError, not a ValidationError.

Suggestion: use a name that can't appear in user code. INTERNAL_QUBIT_REGISTER in elements.py ("__PYQASM_QUBITS__") is the existing pattern for this.

Comment thread src/pyqasm/visitor.py Outdated
)
except KeyError:
for qubit in operation.qubits:
assert isinstance(qubit.name, str)

@ryanhill1 ryanhill1 Aug 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This fires on real programs — it breaks tests/cli/resources/valid1.qasm and with it all 5 CLI tests:

def create_bell_state(qubit[2] q) { hgate q[0]; cxgate q[0], q[1]; }
create_bell_state(q[0:2]);

A qubit operand has two shapes: for Identifier, .name is a str; for IndexedIdentifier (q[0]), .name is an Identifier and .name.name is the string. The assert only holds for the first.

Also worth knowing: assertions compile out under python -O, where this becomes TypeError: unsupported operand type(s) for +=: 'Identifier' and 'str'. Control flow is better as a real branch handling both shapes.

Comment thread src/pyqasm/visitor.py
operation, transform_map, size_map
)
)
except KeyError:

@ryanhill1 ryanhill1 Aug 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is compensated here, but needed in three places. The rename happens in subroutines.py, so qubit_transform_map is keyed on q_arg while the function body still says q. This try/except patches the mismatch at one use site — but there are three:

visitor.py:754    _visit_reset                    <- not patched
visitor.py:871    _visit_barrier                  <- not patched
visitor.py:1504   _visit_generic_gate_operation

So these still fail, now with a raw KeyError instead of the located ValidationError they gave before:

def f(qubit q) { reset q; }                      // KeyError: ('q', 0)   (barrier too)

def inner(qubit p) { h p; }
def outer(qubit q) { inner(q); }
outer(q[1]);                                     // KeyError: 'q'  — works on main

Suggestion: keep the keys and the body consistent from the start — register the transform map under the name the body uses, or rename the body's references when you rename the parameter. Then no call site needs a retry and all three fix together.

Worth noting too: except KeyError catches it from anywhere inside transform_function_qubits, including genuine bugs.

@micpap25

micpap25 commented Aug 6, 2026

Copy link
Copy Markdown
Author

@ryanhill1 I'm going to start by building tests so that we do not revert back to failing the original #311 case.

@micpap25

micpap25 commented Aug 6, 2026

Copy link
Copy Markdown
Author

Code has been updated so it's not failing any of the (existing) tests except for one which cares about the specific error (ValueError) being raised.

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.

[BUG] Incorrect parsing of qubit in function

2 participants