|
2 | 2 | from collections.abc import Mapping, Sequence |
3 | 3 | import warnings |
4 | 4 | import operator |
| 5 | +try: |
| 6 | + import annotationlib # py3.14+ |
| 7 | +except ImportError: |
| 8 | + annotationlib = None # py3.13- |
5 | 9 |
|
6 | 10 | from amaranth._utils import final |
7 | 11 | from amaranth.hdl import * |
@@ -1208,22 +1212,29 @@ def __repr__(self): |
1208 | 1212 |
|
1209 | 1213 | class _AggregateMeta(ShapeCastable, type): |
1210 | 1214 | def __new__(metacls, name, bases, namespace): |
1211 | | - if "__annotations__" not in namespace: |
| 1215 | + if "__annotations__" not in namespace and "__annotate_func__" not in namespace: |
1212 | 1216 | # This is a base class without its own layout. It is not shape-castable, and cannot |
1213 | 1217 | # be instantiated. It can be used to share behavior. |
1214 | 1218 | return type.__new__(metacls, name, bases, namespace) |
1215 | 1219 | elif all(not hasattr(base, "_AggregateMeta__layout") for base in bases): |
| 1220 | + annotations = None |
| 1221 | + if annotationlib is not None: |
| 1222 | + if annotate := annotationlib.get_annotate_from_class_namespace(namespace): |
| 1223 | + annotations = annotationlib.call_annotate_function( |
| 1224 | + annotate, format=annotationlib.Format.VALUE) |
| 1225 | + if annotations is None: |
| 1226 | + annotations = namespace.get("__annotations__", {}) |
1216 | 1227 | # This is a leaf class with its own layout. It is shape-castable and can |
1217 | 1228 | # be instantiated. It can also be subclassed, and used to share layout and behavior. |
1218 | 1229 | layout = dict() |
1219 | 1230 | default = dict() |
1220 | | - for field_name in {**namespace["__annotations__"]}: |
| 1231 | + for field_name in {**annotations}: |
1221 | 1232 | try: |
1222 | | - Shape.cast(namespace["__annotations__"][field_name]) |
| 1233 | + Shape.cast(annotations[field_name]) |
1223 | 1234 | except TypeError: |
1224 | 1235 | # Not a shape-castable annotation; leave as-is. |
1225 | 1236 | continue |
1226 | | - layout[field_name] = namespace["__annotations__"].pop(field_name) |
| 1237 | + layout[field_name] = annotations.pop(field_name) |
1227 | 1238 | if field_name in namespace: |
1228 | 1239 | default[field_name] = namespace.pop(field_name) |
1229 | 1240 | cls = type.__new__(metacls, name, bases, namespace) |
|
0 commit comments