From 0db04d7bb0783811d8cead19568e4a9b154b50e6 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Thu, 20 Aug 2026 16:16:58 +0200 Subject: [PATCH 1/3] Remove unused _NodeMetadataJournal --- tests/unit/ast/test_metadata_journal.py | 82 ------------------------ vyper/ast/metadata.py | 83 ------------------------- vyper/ast/nodes.py | 3 +- 3 files changed, 1 insertion(+), 167 deletions(-) delete mode 100644 tests/unit/ast/test_metadata_journal.py delete mode 100644 vyper/ast/metadata.py diff --git a/tests/unit/ast/test_metadata_journal.py b/tests/unit/ast/test_metadata_journal.py deleted file mode 100644 index 34830409fc..0000000000 --- a/tests/unit/ast/test_metadata_journal.py +++ /dev/null @@ -1,82 +0,0 @@ -from vyper.ast.metadata import NodeMetadata -from vyper.exceptions import VyperException - - -def test_metadata_journal_basic(): - m = NodeMetadata() - - m["x"] = 1 - assert m["x"] == 1 - - -def test_metadata_journal_commit(): - m = NodeMetadata() - - with m.enter_typechecker_speculation(): - m["x"] = 1 - - assert m["x"] == 1 - - -def test_metadata_journal_exception(): - m = NodeMetadata() - - m["x"] = 1 - try: - with m.enter_typechecker_speculation(): - m["x"] = 2 - m["x"] = 3 - - assert m["x"] == 3 - raise VyperException("dummy exception") - - except VyperException: - pass - - # rollback upon exception - assert m["x"] == 1 - - -def test_metadata_journal_rollback_inner(): - m = NodeMetadata() - - m["x"] = 1 - with m.enter_typechecker_speculation(): - m["x"] = 2 - - try: - with m.enter_typechecker_speculation(): - m["x"] = 3 - m["x"] = 4 # test multiple writes - - assert m["x"] == 4 - raise VyperException("dummy exception") - - except VyperException: - pass - - assert m["x"] == 2 - - -def test_metadata_journal_rollback_outer(): - m = NodeMetadata() - - m["x"] = 1 - try: - with m.enter_typechecker_speculation(): - m["x"] = 2 - - with m.enter_typechecker_speculation(): - m["x"] = 3 - m["x"] = 4 # test multiple writes - - assert m["x"] == 4 - - m["x"] = 5 - - raise VyperException("dummy exception") - - except VyperException: - pass - - assert m["x"] == 1 diff --git a/vyper/ast/metadata.py b/vyper/ast/metadata.py deleted file mode 100644 index b4bf6a53bd..0000000000 --- a/vyper/ast/metadata.py +++ /dev/null @@ -1,83 +0,0 @@ -import contextlib -from typing import Any - -from vyper.exceptions import VyperException - - -# a commit/rollback scheme for metadata caching. in the case that an -# exception is thrown and caught during type checking (currently, only -# during for loop iterator variable type inference), we can roll back -# any state updates due to type checking. -# this is implemented as a stack of changesets, because we need to -# handle nested rollbacks in the case of nested for loops -class _NodeMetadataJournal: - _NOT_FOUND = object() - - def __init__(self): - self._node_updates: list[dict[tuple[int, str, Any], NodeMetadata]] = [] - - def register_update(self, metadata, k): - KEY = (id(metadata), k) - if KEY in self._node_updates[-1]: - return - prev = metadata.get(k, self._NOT_FOUND) - self._node_updates[-1][KEY] = (metadata, prev) - - @contextlib.contextmanager - def enter(self): - self._node_updates.append({}) - try: - yield - except VyperException as e: - # note: would be better to only catch typechecker exceptions here. - self._rollback_inner() - raise e from e - else: - self._commit_inner() - - def _rollback_inner(self): - for (_, k), (metadata, prev) in self._node_updates[-1].items(): - if prev is self._NOT_FOUND: - metadata.pop(k, None) - else: - metadata[k] = prev - self._pop_inner() - - def _commit_inner(self): - inner = self._pop_inner() - - if len(self._node_updates) == 0: - return - - outer = self._node_updates[-1] - - # register with previous frame in case inner gets committed - # but outer needs to be rolled back - for (_, k), (metadata, prev) in inner.items(): - if (id(metadata), k) not in outer: - outer[(id(metadata), k)] = (metadata, prev) - - def _pop_inner(self): - return self._node_updates.pop() - - -class NodeMetadata(dict): - """ - A data structure which allows for journaling. - """ - - _JOURNAL: _NodeMetadataJournal = _NodeMetadataJournal() - - def __setitem__(self, k, v): - # if we are in a context where we need to journal, add - # this to the changeset. - if len(self._JOURNAL._node_updates) != 0: - self._JOURNAL.register_update(self, k) - - super().__setitem__(k, v) - - @classmethod - @contextlib.contextmanager - def enter_typechecker_speculation(cls): - with cls._JOURNAL.enter(): - yield diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index 1b612d836a..438aa7fcd5 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -9,7 +9,6 @@ import sys from typing import Any, Optional, Union -from vyper.ast.metadata import NodeMetadata from vyper.compiler.settings import VYPER_ERROR_CONTEXT_LINES, VYPER_ERROR_LINE_NUMBERS, Settings from vyper.exceptions import ( ArgumentException, @@ -248,7 +247,7 @@ def __init__(self, parent: Optional["VyperNode"] = None, **kwargs: dict): """ self.set_parent(parent) self._children: list = [] - self._metadata: NodeMetadata = NodeMetadata() + self._metadata: dict = {} self._original_node = None self._cache_descendants = None From f43f0839f7f229b45e6ea155b43a6f0e87152c6f Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Mon, 31 Aug 2026 12:46:37 +0200 Subject: [PATCH 2/3] Add NodeMetadata back --- vyper/ast/metadata.py | 11 +++++++++++ vyper/ast/nodes.py | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 vyper/ast/metadata.py diff --git a/vyper/ast/metadata.py b/vyper/ast/metadata.py new file mode 100644 index 0000000000..262acd8f07 --- /dev/null +++ b/vyper/ast/metadata.py @@ -0,0 +1,11 @@ +import contextlib + +class NodeMetadata(dict): + """ + The data structure which represents a Node's metadata + """ + + def __setitem__(self, k, v): + + super().__setitem__(k, v) + diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index 438aa7fcd5..1b612d836a 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -9,6 +9,7 @@ import sys from typing import Any, Optional, Union +from vyper.ast.metadata import NodeMetadata from vyper.compiler.settings import VYPER_ERROR_CONTEXT_LINES, VYPER_ERROR_LINE_NUMBERS, Settings from vyper.exceptions import ( ArgumentException, @@ -247,7 +248,7 @@ def __init__(self, parent: Optional["VyperNode"] = None, **kwargs: dict): """ self.set_parent(parent) self._children: list = [] - self._metadata: dict = {} + self._metadata: NodeMetadata = NodeMetadata() self._original_node = None self._cache_descendants = None From 336f63072f300a08a6ec18189653db6db69a3dc5 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Mon, 31 Aug 2026 12:52:00 +0200 Subject: [PATCH 3/3] Make lint --- vyper/ast/metadata.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/vyper/ast/metadata.py b/vyper/ast/metadata.py index 262acd8f07..2c7c629c94 100644 --- a/vyper/ast/metadata.py +++ b/vyper/ast/metadata.py @@ -1,5 +1,3 @@ -import contextlib - class NodeMetadata(dict): """ The data structure which represents a Node's metadata @@ -8,4 +6,3 @@ class NodeMetadata(dict): def __setitem__(self, k, v): super().__setitem__(k, v) -