From c1b9c64e10582a1743a1961fb933ce5c17994d7c Mon Sep 17 00:00:00 2001 From: Catherine Date: Fri, 3 Mar 2023 03:45:12 +0000 Subject: [PATCH] lib.data: ignore Python typing annotations in aggregate base class. --- amaranth/lib/data.py | 13 ++++++++++--- tests/test_lib_data.py | 10 ++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/amaranth/lib/data.py b/amaranth/lib/data.py index f58a1a5..3167536 100644 --- a/amaranth/lib/data.py +++ b/amaranth/lib/data.py @@ -407,12 +407,19 @@ class _AggregateMeta(ShapeCastable, type): elif all(not hasattr(base, "_AggregateMeta__layout") for base in bases): # This is a leaf class with its own layout. It is shape-castable and can # be instantiated. It can also be subclassed, and used to share layout and behavior. - reset = dict() - for name in namespace["__annotations__"]: + layout = dict() + reset = dict() + for name in {**namespace["__annotations__"]}: + try: + Shape.cast(namespace["__annotations__"][name]) + except TypeError: + # Not a shape-castable annotation; leave as-is. + continue + layout[name] = namespace["__annotations__"].pop(name) if name in namespace: reset[name] = namespace.pop(name) cls = type.__new__(metacls, name, bases, namespace) - cls.__layout = cls.__layout_cls(namespace["__annotations__"]) + cls.__layout = cls.__layout_cls(layout) cls.__reset = reset return cls else: diff --git a/tests/test_lib_data.py b/tests/test_lib_data.py index 9e32ac2..2ab0092 100644 --- a/tests/test_lib_data.py +++ b/tests/test_lib_data.py @@ -639,6 +639,16 @@ class StructTestCase(FHDLTestCase): class Sd(Sb): b: 1 + def test_typing_annotation_coexistence(self): + class S(Struct): + a: unsigned(1) + b: int + c: str = "x" + + self.assertEqual(Layout.of(S()), StructLayout({"a": unsigned(1)})) + self.assertEqual(S.__annotations__, {"b": int, "c": str}) + self.assertEqual(S.c, "x") + class UnionTestCase(FHDLTestCase): def test_construct(self):