22from collections .abc import Mapping , Sequence
33import warnings
44import operator
5+ try :
6+ import annotationlib # py3.14+
7+ except ImportError :
8+ annotationlib = None # py3.13-
59
610from amaranth ._utils import final
711from amaranth .hdl import *
@@ -1208,7 +1212,19 @@ def __repr__(self):
12081212
12091213class _AggregateMeta (ShapeCastable , type ):
12101214 def __new__ (metacls , name , bases , namespace ):
1211- if "__annotations__" not in namespace :
1215+ annotations = None
1216+ skipped_annotations = set ()
1217+ wrapped_annotate = None
1218+ if annotationlib is not None :
1219+ if annotate := annotationlib .get_annotate_from_class_namespace (namespace ):
1220+ annotations = annotationlib .call_annotate_function (
1221+ annotate , format = annotationlib .Format .VALUE )
1222+ def wrapped_annotate (format ):
1223+ annos = annotationlib .call_annotate_function (annotate , format , owner = cls )
1224+ return {k : v for k , v in annos .items () if k not in skipped_annotations }
1225+ else :
1226+ annotations = namespace .get ("__annotations__" )
1227+ if annotations is None :
12121228 # This is a base class without its own layout. It is not shape-castable, and cannot
12131229 # be instantiated. It can be used to share behavior.
12141230 return type .__new__ (metacls , name , bases , namespace )
@@ -1217,13 +1233,14 @@ def __new__(metacls, name, bases, namespace):
12171233 # be instantiated. It can also be subclassed, and used to share layout and behavior.
12181234 layout = dict ()
12191235 default = dict ()
1220- for field_name in {** namespace [ "__annotations__" ] }:
1236+ for field_name in {** annotations }:
12211237 try :
1222- Shape .cast (namespace [ "__annotations__" ] [field_name ])
1238+ Shape .cast (annotations [field_name ])
12231239 except TypeError :
12241240 # Not a shape-castable annotation; leave as-is.
12251241 continue
1226- layout [field_name ] = namespace ["__annotations__" ].pop (field_name )
1242+ skipped_annotations .add (field_name )
1243+ layout [field_name ] = annotations .pop (field_name )
12271244 if field_name in namespace :
12281245 default [field_name ] = namespace .pop (field_name )
12291246 cls = type .__new__ (metacls , name , bases , namespace )
@@ -1234,6 +1251,8 @@ def __new__(metacls, name, bases, namespace):
12341251 .format (", " .join (default .keys ())))
12351252 cls .__layout = cls .__layout_cls (layout )
12361253 cls .__default = default
1254+ if wrapped_annotate is not None :
1255+ cls .__annotate__ = wrapped_annotate
12371256 return cls
12381257 else :
12391258 # This is a class that has a base class with a layout and annotations. Such a class
0 commit comments