Skip to content

fix[lang]: forbid assignment to values#5181

Open
Sporarum wants to merge 6 commits into
vyperlang:masterfrom
Sporarum:l-values
Open

fix[lang]: forbid assignment to values#5181
Sporarum wants to merge 6 commits into
vyperlang:masterfrom
Sporarum:l-values

Conversation

@Sporarum

@Sporarum Sporarum commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

What I did

Fix #5138
Fix #5151

In short: we didn't check what was on the lhs of assignments enough, so things like self.g()[0] = 5 were allowed => failed asserts

How I did it

Check that the lhs of assignments has a location (memory/transient/storage), and if not, raise an exception.
This catches even tricky cases, like the long-standing self.nostedArray.pop().append() which otherwise have correct type and mutability

How to verify it

pytest

Commit message

the left hand-side of assignments used to only be checked to have
correct mutability and location. however some expressions fulfilled
these criterion without representing a concrete offset in
memory/transient/storage, for example 'self.g()[0] = 5'. this commit
addresses that by directly checking that the lhs has a location.

Description for the changelog

Compiler no longer panics when trying to assign to expressions

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Gas Changes

No changes detected.

Summary

  • Total tests measured: 815
  • Changed: 0
  • Regressions (gas up): 0
  • Improvements (gas down): 0
  • New tests: 0
  • Deleted tests: 0
  • Newly failing: 0
  • Newly passing: 0

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

📊 Bytecode Size Changes (venom)

No changes detected.

Full bytecode sizes

Contract legacy-O2 legacy-Os -O2 -O3 -Os
curvefi/amm/stableswap/meta_implementation/meta_implementation_v_700.vy 23610 22805 20786 19755 19315
curvefi/legacy/CurveStableSwapMetaNG.vy 24952 23578 20490 19871 19175
curvefi/amm/stableswap/implementation/implementation_v_700.vy 24962 23769 20264 19393 18845
curvefi/legacy/CurveStableSwapNG.vy 24473 23298 19677 18844 18314
curvefi/amm/tricryptoswap/implementation/implementation_v_200.vy 20724 19959 18020 17518 16961
yearnfi/VaultV3.vy 19972 19063 17017 15131 14477
curvefi/amm/twocryptoswap/implementation/implementation_v_210.vy 17634 16894 15685 15132 14648
curvefi/legacy/CurveCryptoSwap2.vy 18947 18382 15634 15092 14711
yearnfi/VaultV2.vy 16676 15763 13863 13405 12574
curvefi/amm/stableswap/factory/factory_v_100.vy 14558 13978 13317 11825 11788
curvefi/gauge/child_gauge/implementation/implementation_v_110.vy 12338 11561 10270 9775 9182
curvefi/gauge/child_gauge/implementation/implementation_v_100.vy 12017 11249 9998 9502 8920
curvefi/amm/stableswap/views/views_v_120.vy 12784 12368 9970 9413 9532
curvefi/amm/tricryptoswap/math/math_v_200.vy 11189 11126 9520 8162 8424
curvefi/legacy/CurveCryptoMathOptimized3.vy 11188 11125 9519 8162 8424
curvefi/gauge/child_gauge/implementation/implementation_v_020.vy 10665 9947 9013 8565 8028
curvefi/helpers/router/router_v_110.vy 6717 6717 7003 6376 6607
curvefi/amm/tricryptoswap/views/views_v_200.vy 7821 7776 6697 6445 6514
curvefi/registries/metaregistry/metaregistry_v_110.vy 7590 6732 6651 5888 5727
curvefi/helpers/stable_swap_meta_zap/stable_swap_meta_zap_v_100.vy 7302 7067 6379 6012 6114
curvefi/amm/twocryptoswap/views/views_v_200.vy 6991 6946 6272 6026 6089
curvefi/amm/twocryptoswap/factory/factory_v_200.vy 5540 5252 5994 4697 4845
curvefi/amm/tricryptoswap/factory/factory_v_200.vy 5246 5021 5923 4926 5039
curvefi/registries/metaregistry/registry_handlers/stableswap/handler_v_110.vy 6633 6259 5859 5094 5562
curvefi/amm/twocryptoswap/math/math_v_210.vy 6800 6800 5581 5107 5112
curvefi/gauge/child_gauge/factory/factory_v_201.vy 4844 4547 4266 4014 3780
yearnfi/VaultFactory.vy 3765 3617 3985 2505 2965
curvefi/registries/metaregistry/registry_handlers/tricryptoswap/handler_v_110.vy 4241 3939 3838 3547 3547
curvefi/registries/metaregistry/registry_handlers/twocryptoswap/handler_v_110.vy 4186 3884 3777 3417 3433
curvefi/gauge/child_gauge/factory/factory_v_100.vy 4183 3914 3694 3428 3213
curvefi/helpers/rate_provider/rate_provider_v_101.vy 3260 3260 2779 2437 2450
curvefi/registries/address_provider/address_provider_v_201.vy 2973 2782 2713 2569 2424
curvefi/amm/stableswap/math/math_v_100.vy 3067 3046 2598 2403 2423
curvefi/helpers/rate_provider/rate_provider_v_100.vy 2847 2841 2357 2050 2058
curvefi/helpers/deposit_and_stake_zap/deposit_and_stake_zap_v_100.vy 2322 2316 2123 1889 1921
curvefi/governance/relayer/taiko/relayer_v_001.vy 2068 2064 1784 1579 1612
curvefi/governance/relayer/polygon_cdk/relayer_v_101.vy 1556 1523 1587 1405 1406
curvefi/governance/relayer/arb_orbit/relayer_v_101.vy 1266 1262 1280 1124 1155
curvefi/governance/relayer/op_stack/relayer_v_101.vy 1186 1182 1219 1066 1094
curvefi/governance/relayer/not_rollup/relayer_v_100.vy 1168 1153 1208 1061 1073
curvefi/governance/vault/vault_v_100.vy 964 941 885 866 864
curvefi/governance/relayer/relayer_v_100.vy 496 496 600 505 510
curvefi/governance/agent/agent_v_100.vy 541 541 443 415 419
curvefi/governance/agent/agent_v_101.vy 541 541 443 415 419

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22610a6845

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread vyper/codegen/expr.py
if not o.location:
raise StructureException("Looking for a variable location, instead got a value", expr)
# Looking for a variable location, instead got a value
assert o.location

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep non-pointer address members from reaching this assert

This assert is still reachable when the lvalue is an address member rooted in a real variable, e.g. addr: address and self.addr.balance = 1 (or a local addr.balance = 1). The new semantic check only rejects DataLocation.UNSET, but get_expr_info for Attribute copies the STORAGE/MEMORY location from the address variable onto .balance, while parse_Attribute lowers .balance to a value IR node with no location. So these invalid assignments now surface as CodegenPanic/assertions instead of the intended user-facing StructureException; either keep the explicit exception here or reject address members during semantic analysis.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The correct fix for this would be to make <address>.balance (and other methods on address) have RUNTIME_CONSTANT mutability

But this is somewhat involved, as currently members cannot have a mutability different than what they are attached to

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed by un-setting the location on "built-in members" of types

A more powerful and correct fix would be to have more granular control over the mutability of attribute accesses, this would allow us to potentially simplify the "not uses/initializes-ed" check (other_module.foo could be set as immutable), and to add private fields to modules (self.counter would be mutable in lib, but lib.counter would be immutable)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

(would also need a new Mutabillity, since addr.balance is neither CONSTANT nor RUNTIME_CONSTANT)

@Sporarum

Sporarum commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

I'm not sure what the wording should be
In other words: How do we call what's allowed on the lhs of an assignment ?
I don't want to use 'l-value' as only C programmers will be familiar with it
But then I don't have good words to describe it "value", "expression", "reference" ?
I considered "variable", but I wouldn't call a.b[10] a variable, since we're indexing into it.

Ideas welcome !

@charles-cooper

Copy link
Copy Markdown
Member

lvalue, assignment target or even 'left hand side of an assignment' are all ok

Comment thread vyper/semantics/analysis/local.py Outdated

if info.location == DataLocation.UNSET:
raise StructureException(
f"Cannot modify `{target.node_source_code}` since it is not a reference", target

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.

Suggested change
f"Cannot modify `{target.node_source_code}` since it is not a reference", target
f"`{target.node_source_code}` is invalid as an assignment target", target

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.

Writing self.balance panics under Venom codegen Assign to call-return index crashes compiler

2 participants