-
-
Notifications
You must be signed in to change notification settings - Fork 804
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: allow constant interfaces #3718
Conversation
Codecov ReportAttention:
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #3718 +/- ##
==========================================
- Coverage 84.16% 84.11% -0.06%
==========================================
Files 92 92
Lines 13133 13141 +8
Branches 2926 2927 +1
==========================================
- Hits 11054 11053 -1
- Misses 1659 1667 +8
- Partials 420 421 +1 ☔ View full report in Codecov by Sentry. |
FOO: constant(Foo) = Foo(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF) | ||
|
||
@external | ||
def bar(a: uint256, b: Foo = Foo(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF)) -> Foo: |
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.
it would be good for the tests if bar()
and faz()
returned something different
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.
do you mean like any constant interface?
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.
yea, like 0xaaaa vs 0xbbbbb
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.
per https://github.com/vyperlang/vyper/pull/3718/files#r1440581290, i think it's going to be cleaner if we can get more annotation into the constant folding pass. i think this can be best accomplished if we interleave constant folding into the dependency resolving loop in the module analyzer. we can also probably clean up the constant folding pass further by implementing it as a separate Visitor implementation. this will separate it from the concerns of VyperNode definitions (which should be more pure and not really "know" how to fold themselves) and also be able to incorporate other information that should belong to later passes (mainly, constants structs and interfaces which only get populated during module analysis).
alright, i performed this refactor in tserg#1. but i think actually a simpler fix to the problem at hand is to just introduce a |
from vyper.semantics.analysis.utils import ( | ||
check_modifiability, | ||
validate_expected_type, | ||
validate_unique_method_ids, | ||
) |
Check notice
Code scanning / CodeQL
Cyclic import Note
vyper.semantics.analysis.utils
from vyper.semantics.analysis.levenshtein_utils import get_levenshtein_error_suggestions | ||
from vyper.semantics.analysis.utils import validate_expected_type | ||
from vyper.semantics.analysis.utils import check_modifiability, validate_expected_type |
Check notice
Code scanning / CodeQL
Cyclic import Note
vyper.semantics.analysis.utils
can you merge in the latest changes from master? and then i think this should be more or less good to go |
vyper/semantics/analysis/utils.py
Outdated
call_type_modifiability = getattr(call_type, "_modifiability", Modifiability.MODIFIABLE) | ||
return call_type_modifiability >= modifiability | ||
# structs and interfaces | ||
if isinstance(call_type, TYPE_T): |
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.
it's more complicated but i think this actually should use TYPE_T.check_modifiability_for_call
(which can dispatch to something like StructT.ctor_modifiability_for_call
). the way you have it written, a struct instance can pass the modifiability check.
call_type_modifiability = getattr(call_type, "_modifiability", Modifiability.MODIFIABLE) | ||
return call_type_modifiability >= modifiability | ||
# structs and interfaces | ||
if hasattr(call_type, "check_modifiability_for_call"): |
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.
as a general comment, i'd like to move these hasattr checks to be more like
if call_type._is_callable:
call_type.check_modifiability_for_call(...)
that way we impose more structure on the APIs of callable types. but i think that can be pushed to "future work"
@@ -334,6 +334,11 @@ def __init__(self, typedef): | |||
def __repr__(self): | |||
return f"type({self.typedef})" | |||
|
|||
def check_modifiability_for_call(self, node, modifiability): | |||
if hasattr(self.typedef, "_ctor_modifiability_for_call"): |
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.
ditto here -- all these hasattr(self.typedef, "_ctor_...")
could be more like
if self._is_callable:
self.typedef._ctor_modifiability_for_call(...)
@@ -81,6 +85,9 @@ def _ctor_arg_types(self, node): | |||
def _ctor_kwarg_types(self, node): | |||
return {} | |||
|
|||
def _ctor_modifiability_for_call(self, node: vy_ast.Call, modifiability: Modifiability) -> bool: | |||
return check_modifiability(node.args[0], modifiability) |
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 will panic if len(node.args) < 1
(because in some cases, check_modifiability runs before validate_call_args).
@@ -419,3 +420,6 @@ def _ctor_call_return(self, node: vy_ast.Call) -> "StructT": | |||
) | |||
|
|||
return self | |||
|
|||
def _ctor_modifiability_for_call(self, node: vy_ast.Call, modifiability: Modifiability) -> bool: | |||
return all(check_modifiability(v, modifiability) for v in node.args[0].values) |
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.
same -- will panic if len(node.args) < 1
vyper/semantics/types/function.py
Outdated
validate_expected_type, | ||
) | ||
from vyper.semantics.analysis.base import FunctionVisibility, StateMutability, StorageSlot | ||
from vyper.semantics.analysis.utils import get_exact_type_from_node, validate_expected_type |
Check notice
Code scanning / CodeQL
Cyclic import
bf7b346
to
4924a85
Compare
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.
looks good. i worked a bit on the panic issue in bf7b346 but i think we can punt on it to a future PR since it's a fairly minor UX thing. (and it's not really a regression since that ordering of check_modifiability before the call to validate_call_args was already latent in the codebase).
What I did
Fix #3407
How I did it
Handle interfaces for
check_modifiability
and in codegen.How to verify it
See tests.
Commit message
Description for the changelog
Allow interfaces as constants.
Cute Animal Picture