-
-
Notifications
You must be signed in to change notification settings - Fork 810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: immutable variables #2466
Merged
Merged
Changes from all commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
f4f3ea8
chore: replace `is_immutable` -> `is_constant`
skellet0r b06886e
feat: add `immutable` as a reserved keyword
skellet0r d967cf2
feat: handle immutable defs in ModuleNodeVisitor
skellet0r 9a407b6
fix: add `is_immutable` kwarg to get_type_from_annotation
skellet0r ba27726
feat: add `is_immutable` keyword to primitive classes
skellet0r a246ca4
feat: set positions of immutable vars
skellet0r 62d06e3
fix: parse_type of immutable var
skellet0r 859c935
fix: prevent immutable modification outside constructor
skellet0r 2f0e78b
WIP: add branch for immutable vars in expr.py
skellet0r e980523
fix: DataPosition class ImmutableSlot -> CodeOffset
skellet0r 9645b1b
fix: runtime loading of immutables
skellet0r 66c225c
feat: append to init lll storage of immutables
skellet0r a975a6c
fix: update VariableRecord class + add immutables to global ctx
skellet0r 538d31e
fix: modify constructor to return runtime + immutables
skellet0r da098cd
fix: constructor handles data section
skellet0r 12fe4d1
fix: account for immutables at end of runtime code
skellet0r 5b50471
fix: vyper grammar include immutable_def
skellet0r ac55173
test: simple usage of immutable keyword with uint256
skellet0r b9542dc
fix: remove copying of immutables from external_function.py
skellet0r 0f0bc1b
fix: add `is_immutable` kwarg to more Definition classes
skellet0r 7dbe7c3
fix: raise syntax exception if immutable not assigned a value
skellet0r e63cdf1
test: immutable syntax, simple cases
skellet0r cd2cb98
test: accessing stored immutable
skellet0r c0eeeaf
test: verify immutables of dynamic length are disallowed
skellet0r 6a3c946
fix: disallow bytes/string immutables (momentarily)
skellet0r b6c9279
fix: use make_setter for memory cp operation of immutables
skellet0r 02dd076
fix: store memory loc + offset in data section in metadata
skellet0r 2118af0
fix: use data offset + memory loc from metadata section
skellet0r 9f144a0
fix: remove restriction using strings/bytes immutables
skellet0r 11dddb4
fix(test): verify usage of string/bytes immutables
skellet0r 2e32119
fix: only set _metadata on immutable during first pass
skellet0r d05d987
fix: return size of runtime code to account for data section
skellet0r e1a9508
chore: fix test parametrization
skellet0r 15dd832
test: multiple immutable values
skellet0r 86946bf
fix(test): change dummy address used
skellet0r e594099
fix: allocate a new var not internal var
skellet0r 77c4c01
test: user defined struct immutable
skellet0r d358c07
fix: allow immutable sequences (add kwarg to classes)
skellet0r f1b6d6d
test: immutable list usage
skellet0r ec13acf
chore: modify test parametrization
skellet0r b95bef8
docs: add immutable usage docs
skellet0r 14b2edb
fix: allocate memory of immutable in constructor
skellet0r 10c73e4
fix: disallow multiple assignments to immutable
skellet0r 42981ab
test: multiple assignments blocked
skellet0r 3e4de6e
fix: set immutable data location to CODE
skellet0r 48d4691
fix: verify immutable is given a single argument
skellet0r b0fe010
fix: if stmt use bool type as condition
skellet0r b60ae2e
fix: make immutable data size a cached prop on global ctx
skellet0r 9d04be1
fix: swap 'lll' arguments, offset is first code is second
skellet0r 99217d9
fix: remove _metadata dict on LLLnode for immutables
skellet0r 7c01275
fix: mypy typing error
skellet0r b55dfe1
Update vyper/semantics/types/indexable/sequence.py
skellet0r 502bb6a
Update vyper/semantics/types/bases.py
skellet0r 90c8594
fix: use cached property from vyper.utils
skellet0r 713a7bd
chore: leave todo, come back and resolve immutable offsets at compile…
skellet0r 9bd3b45
update a comment about lll macro
charles-cooper File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import pytest | ||
|
||
@pytest.mark.parametrize( | ||
"typ,value", | ||
[ | ||
("uint256", 42), | ||
("int256", -(2 ** 200)), | ||
("int128", -(2 ** 126)), | ||
("address", "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"), | ||
("bytes32", b"deadbeef" * 4), | ||
("bool", True), | ||
("String[10]", "Vyper hiss"), | ||
("Bytes[10]", b"Vyper hiss"), | ||
], | ||
) | ||
def test_value_storage_retrieval(typ, value, get_contract): | ||
code = f""" | ||
VALUE: immutable({typ}) | ||
|
||
@external | ||
def __init__(_value: {typ}): | ||
VALUE = _value | ||
|
||
@view | ||
@external | ||
def get_value() -> {typ}: | ||
return VALUE | ||
""" | ||
|
||
c = get_contract(code, value) | ||
assert c.get_value() == value | ||
|
||
|
||
def test_multiple_immutable_values(get_contract): | ||
code = """ | ||
a: immutable(uint256) | ||
b: immutable(address) | ||
c: immutable(String[64]) | ||
|
||
@external | ||
def __init__(_a: uint256, _b: address, _c: String[64]): | ||
a = _a | ||
b = _b | ||
c = _c | ||
|
||
@view | ||
@external | ||
def get_values() -> (uint256, address, String[64]): | ||
return a, b, c | ||
""" | ||
values = (3, "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "Hello world") | ||
c = get_contract(code, *values) | ||
assert c.get_values() == list(values) | ||
|
||
|
||
def test_struct_immutable(get_contract): | ||
code = """ | ||
struct MyStruct: | ||
a: uint256 | ||
b: uint256 | ||
c: address | ||
d: int256 | ||
|
||
my_struct: immutable(MyStruct) | ||
|
||
@external | ||
def __init__(_a: uint256, _b: uint256, _c: address, _d: int256): | ||
my_struct = MyStruct({ | ||
a: _a, | ||
b: _b, | ||
c: _c, | ||
d: _d | ||
}) | ||
|
||
@view | ||
@external | ||
def get_my_struct() -> MyStruct: | ||
return my_struct | ||
""" | ||
values = (100, 42, "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", -(2 ** 200)) | ||
c = get_contract(code, *values) | ||
assert c.get_my_struct() == values | ||
|
||
|
||
def test_list_immutable(get_contract): | ||
code = """ | ||
my_list: immutable(uint256[3]) | ||
|
||
@external | ||
def __init__(_a: uint256, _b: uint256, _c: uint256): | ||
my_list = [_a, _b, _c] | ||
|
||
@view | ||
@external | ||
def get_my_list() -> uint256[3]: | ||
return my_list | ||
""" | ||
values = (100, 42, 23230) | ||
c = get_contract(code, *values) | ||
assert c.get_my_list() == list(values) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import pytest | ||
|
||
from vyper import compile_code | ||
|
||
fail_list = [ | ||
# VALUE is not set in the constructor | ||
""" | ||
VALUE: immutable(uint256) | ||
|
||
@external | ||
def __init__(): | ||
pass | ||
""", | ||
# no `__init__` function, VALUE not set | ||
""" | ||
VALUE: immutable(uint256) | ||
|
||
@view | ||
@external | ||
def get_value() -> uint256: | ||
return VALUE | ||
""", | ||
# VALUE given an initial value | ||
""" | ||
VALUE: immutable(uint256) = 3 | ||
|
||
@external | ||
def __init__(): | ||
pass | ||
""", | ||
# setting value outside of constructor | ||
""" | ||
VALUE: immutable(uint256) | ||
|
||
@external | ||
def __init__(): | ||
VALUE = 0 | ||
|
||
@external | ||
def set_value(_value: uint256): | ||
VALUE = _value | ||
""", | ||
# modifying immutable multiple times in constructor | ||
""" | ||
VALUE: immutable(uint256) | ||
|
||
@external | ||
def __init__(_value: uint256): | ||
VALUE = _value * 3 | ||
VALUE = VALUE + 1 | ||
""" | ||
|
||
] | ||
|
||
|
||
@pytest.mark.parametrize("bad_code", fail_list) | ||
def test_compilation_fails_with_exception(bad_code): | ||
with pytest.raises(Exception): | ||
compile_code(bad_code) | ||
|
||
|
||
types_list = ( | ||
"uint256", | ||
"int256", | ||
"int128", | ||
"address", | ||
"bytes32", | ||
"decimal", | ||
"bool", | ||
"Bytes[64]", | ||
"String[10]", | ||
) | ||
|
||
|
||
@pytest.mark.parametrize("typ", types_list) | ||
def test_compilation_simple_usage(typ): | ||
code = f""" | ||
VALUE: immutable({typ}) | ||
|
||
@external | ||
def __init__(_value: {typ}): | ||
VALUE = _value | ||
|
||
@view | ||
@external | ||
def get_value() -> {typ}: | ||
return VALUE | ||
""" | ||
|
||
assert compile_code(code) | ||
|
||
|
||
pass_list = [ | ||
# using immutable allowed in constructor | ||
""" | ||
VALUE: immutable(uint256) | ||
|
||
@external | ||
def __init__(_value: uint256): | ||
VALUE = _value * 3 | ||
x: uint256 = VALUE + 1 | ||
""" | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("good_code", pass_list) | ||
def test_compilation_success(good_code): | ||
assert compile_code(good_code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. I wonder if we can get the location of the data section into the runtime code during deploy time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Thinking through the approach, it may not be worth it, but if you have some clever ideas here I am all ears.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an idea: our assembly-to-evm compilation phase has a step which resolves symbols to locations. Since the locations of immutables are statically known (no matter what value they are set to), we can insert symbols into the LLL which directly precede blank space. Basically, _sym_foo doesn't actually take any space in the code. So the runtime data section itself would have something like
Then your code for copying items to LLL would stay the same (it would just overwrite all the jumpdests), but we would know the locations statically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK let's add a TODO here for now:
TODO: resolve code offsets for immutables at compile time