Skip to content

Commit

Permalink
fix the algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper committed Jun 2, 2024
1 parent 6a1c95f commit 9740de3
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 34 deletions.
26 changes: 25 additions & 1 deletion vyper/semantics/analysis/global_.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from vyper.exceptions import ExceptionList, InitializerException
from vyper.semantics.analysis.base import InitializesInfo, UsesInfo
from vyper.semantics.types.module import ModuleT
from vyper.utils import OrderedSet


def validate_compilation_target(module_t: ModuleT):
Expand Down Expand Up @@ -54,14 +55,37 @@ def _validate_global_initializes_constraint(module_t: ModuleT):
all_used_modules = _collect_used_modules_r(module_t)
all_initialized_modules = _collect_initialized_modules_r(module_t)

hint = None

init_calls = []
if module_t.init_function is not None:
init_calls = list(module_t.init_function.reachable_internal_functions)
seen: OrderedSet = OrderedSet()

for init_t in init_calls:
seen.add(init_t)
init_m = init_t.decl_node.module_node._metadata["type"]
init_info = all_initialized_modules[init_m]

Check warning on line 68 in vyper/semantics/analysis/global_.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/analysis/global_.py#L66-L68

Added lines #L66 - L68 were not covered by tests
for dep in init_info.dependencies:
m = dep.module_t

Check warning on line 70 in vyper/semantics/analysis/global_.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/analysis/global_.py#L70

Added line #L70 was not covered by tests
if m.init_function is None:
continue

Check warning on line 72 in vyper/semantics/analysis/global_.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/analysis/global_.py#L72

Added line #L72 was not covered by tests
if m.init_function not in seen:
# TODO: recover source info
msg = f"Tried to initialize `{init_info.module_info.alias}`, "
msg += f"but it depends on `{dep.alias}`, which has not been "
msg += "initialized yet."
hint = f"call `{dep.alias}.__init__()` before "
hint += f"`{init_info.module_info.alias}.__init__()`."
raise InitializerException(msg, hint=hint)

Check warning on line 80 in vyper/semantics/analysis/global_.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/analysis/global_.py#L75-L80

Added lines #L75 - L80 were not covered by tests

err_list = ExceptionList()

for u, uses in all_used_modules.items():
if u not in all_initialized_modules:
msg = f"module `{u}` is used but never initialized!"

# construct a hint if the module is in scope
hint = None
found_module = module_t.find_module_info(u)
if found_module is not None:
# TODO: do something about these constants
Expand Down
23 changes: 0 additions & 23 deletions vyper/semantics/analysis/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,6 @@ def validate_initialized_modules(self):
# map of seen __init__() function calls
seen_initializers = {}

# modules which were already initialized in another module
already_initialized = OrderedSet()

for call_node in init_calls:
expr_info = call_node.func._expr_info
if expr_info is None:
Expand Down Expand Up @@ -373,29 +370,9 @@ def validate_initialized_modules(self):
hint += "as a top-level statement to your contract"
raise InitializerException(msg, call_node.func, hint=hint)

initializer_info = should_initialize[initialized_module.module_t]
for dep_info in initializer_info.dependencies: # type: ModuleInfo
dep_t = dep_info.module_t

if dep_t in already_initialized or dep_t.init_function is None:
continue

if dep_t not in seen_initializers:
msg = f"Tried to initialize `{initialized_module.alias}`, "
msg += f"but it depends on `{dep_info.alias}`, which has "
msg += "not been initialized yet."
hint = f"call `{dep_info.alias}.__init__()` before "
hint += f"`{initialized_module.alias}.__init__()`."
raise InitializerException(msg, call_node.func, hint=hint)

del should_initialize[initialized_module.module_t]
seen_initializers[initialized_module.module_t] = call_node.func

# add the modules that the module initialized, these are already
# checked in the recursion.
initialized = initialized_module.module_t
already_initialized.update(initialized.initialized_modules_recursed)

if len(should_initialize) > 0:
err_list = ExceptionList()
for s in should_initialize.values():
Expand Down
10 changes: 0 additions & 10 deletions vyper/semantics/types/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,16 +486,6 @@ def initialized_modules(self):
ret.append(info)
return ret

@cached_property
def initialized_modules_recursed(self) -> OrderedSet["ModuleT"]:
# modules which are initialized, taking into account recursion
ret: OrderedSet = OrderedSet()
for info in self.initialized_modules:
module_t = info.module_info.module_t
ret |= module_t.initialized_modules_recursed
ret.add(module_t)
return ret

@cached_property
def exposed_functions(self):
# return external functions that are exposed in the runtime
Expand Down

0 comments on commit 9740de3

Please sign in to comment.