Skip to content
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[ux]: support constants from imported interface #4253

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions vyper/semantics/analysis/constant_folding.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from vyper.exceptions import InvalidLiteral, UnfoldableNode, VyperException
from vyper.semantics.analysis.base import VarInfo
from vyper.semantics.analysis.common import VyperNodeVisitorBase
from vyper.semantics.types.module import InterfaceT
from vyper.semantics.namespace import get_namespace


Expand Down Expand Up @@ -105,12 +106,11 @@ def visit_Attribute(self, node) -> vy_ast.ExprNode:
# not super type-safe but we don't care. just catch AttributeErrors
# and move on
try:
module_t = namespace[value.id].module_t

ns_member = namespace[value.id]
module_t = ns_member if isinstance(ns_member, InterfaceT) else ns_member.module_t
for module_name in path:
module_t = module_t.members[module_name].module_t

varinfo = module_t.get_member(node.attr, node)
varinfo = module_t.get_type_member(node.attr, node) if isinstance(module_t, InterfaceT) else module_t.get_member(node.attr, node)

return varinfo.decl_node.value.get_folded_value()
except (VyperException, AttributeError, KeyError):
Expand Down
29 changes: 20 additions & 9 deletions vyper/semantics/types/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
StructureException,
UnfoldableNode,
)
from vyper.semantics.analysis.base import Modifiability
from vyper.semantics.analysis.base import Modifiability, VarInfo

Check notice

Code scanning / CodeQL

Cyclic import Note

Import of module
vyper.semantics.analysis.base
begins an import cycle.
from vyper.semantics.analysis.utils import (
check_modifiability,
get_exact_type_from_node,
Expand Down Expand Up @@ -45,28 +45,33 @@
functions: dict,
events: dict,
structs: dict,
constants: dict,
) -> None:
validate_unique_method_ids(list(functions.values()))

members = functions | events | structs
members = functions | events | structs | constants

# sanity check: by construction, there should be no duplicates.
assert len(members) == len(functions) + len(events) + len(structs)
assert len(members) == len(functions) + len(events) + len(structs) + len(constants)

super().__init__(functions)

self._helper = VyperType(events | structs)
self._helper = VyperType(events | structs | constants)
self._id = _id
self._helper._id = _id
self.functions = functions
self.events = events
self.structs = structs
self.constants = constants

self.decl_node = decl_node

def get_type_member(self, attr, node):
# get an event or struct from this interface
return TYPE_T(self._helper.get_member(attr, node))
# get an event, struct or constant from this interface
type_member = self._helper.get_member(attr, node)
if isinstance(type_member, (EventT, StructT)):
return TYPE_T(type_member)
return type_member

@property
def getter_signature(self):
Expand Down Expand Up @@ -161,10 +166,12 @@
function_list: list[tuple[str, ContractFunctionT]],
event_list: list[tuple[str, EventT]],
struct_list: list[tuple[str, StructT]],
constant_list: list[tuple[str, VarInfo]],
) -> "InterfaceT":
functions = {}
events = {}
structs = {}
constants = {}

seen_items: dict = {}

Expand All @@ -187,7 +194,11 @@
_mark_seen(name, struct)
structs[name] = struct

return cls(interface_name, decl_node, functions, events, structs)
for name, constant in constant_list:
_mark_seen(name, constant)
constants[name] = constant

return cls(interface_name, decl_node, functions, events, structs, constants)

@classmethod
def from_json_abi(cls, name: str, abi: dict) -> "InterfaceT":
Expand Down Expand Up @@ -247,8 +258,8 @@
# these are accessible via import, but they do not show up
# in the ABI json
structs = [(node.name, node._metadata["struct_type"]) for node in module_t.struct_defs]

return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs)
constants = [(node.target.id, node.target._metadata["varinfo"]) for node in module_t.variable_decls if node.target._metadata["varinfo"].modifiability is Modifiability.CONSTANT]
return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, constants)

@classmethod
def from_InterfaceDef(cls, node: vy_ast.InterfaceDef) -> "InterfaceT":
Expand Down
Loading