parent
							
								
									6ad0d21cc9
								
							
						
					
					
						commit
						8e6ae9e6e0
					
				|  | @ -806,43 +806,41 @@ def connect(m, *args, **kwargs): | |||
| 
 | ||||
| 
 | ||||
| class Component(Elaboratable): | ||||
|     def __init__(self): | ||||
|         for name in self.signature.members: | ||||
|             if hasattr(self, name): | ||||
|                 raise NameError(f"Cannot initialize attribute for signature member {name!r} " | ||||
|                                 f"because an attribute with the same name already exists") | ||||
|         self.__dict__.update(self.signature.members.create(path=())) | ||||
| 
 | ||||
|     @property | ||||
|     def signature(self): | ||||
|     def __init__(self, signature=None): | ||||
|         cls = type(self) | ||||
|         members = {} | ||||
|         for base in reversed(cls.mro()[:cls.mro().index(Component)]): | ||||
|             for name, annot in base.__dict__.get("__annotations__", {}).items(): | ||||
|                 if name.startswith("_"): | ||||
|                     continue | ||||
|                 if (annot is Value or annot is Signal or annot is Const or | ||||
|                         (isinstance(annot, type) and issubclass(annot, ValueCastable)) or | ||||
|                         isinstance(annot, Signature)): | ||||
|                     if isinstance(annot, type): | ||||
|                         annot_repr = annot.__name__ | ||||
|                     else: | ||||
|                         annot_repr = repr(annot) | ||||
|                     # To suppress this warning in the rare cases where it is necessary (and naming | ||||
|                     # the field with a leading underscore is infeasible), override the property. | ||||
|                     warnings.warn( | ||||
|                         message=f"Component '{cls.__module__}.{cls.__qualname__}' has " | ||||
|                                 f"an annotation '{name}: {annot_repr}', which is not " | ||||
|                                 f"a signature member; did you mean '{name}: In({annot_repr})' " | ||||
|                                 f"or '{name}: Out({annot_repr})'?", | ||||
|                         category=SyntaxWarning, | ||||
|                         stacklevel=2) | ||||
|                 elif type(annot) is Member: | ||||
|                 if type(annot) is Member: | ||||
|                     if name in members: | ||||
|                         raise SignatureError(f"Member '{name}' is redefined in {base.__module__}.{base.__qualname__}") | ||||
|                     members[name] = annot | ||||
|         if not members: | ||||
|             if signature is None: | ||||
|                 raise NotImplementedError( | ||||
|                 f"Component '{cls.__module__}.{cls.__qualname__}' does not have signature member " | ||||
|                 f"annotations") | ||||
|         return Signature(members) | ||||
|                     f"Component '{cls.__module__}.{cls.__qualname__}' does not have signature " | ||||
|                     f"member annotations") | ||||
|             if isinstance(signature, dict): | ||||
|                 signature = Signature(signature) | ||||
|             elif not isinstance(signature, Signature): | ||||
|                 raise TypeError(f"Object {signature!r} is not a signature nor a dict") | ||||
|         else: | ||||
|             if signature is not None: | ||||
|                 raise TypeError( | ||||
|                     f"Signature was passed as an argument, but component " | ||||
|                     f"'{cls.__module__}.{cls.__qualname__}' already has signature " | ||||
|                     f"member annotations") | ||||
|             signature = Signature(members) | ||||
| 
 | ||||
|         self.__signature = signature | ||||
|         for name in signature.members: | ||||
|             if hasattr(self, name): | ||||
|                 raise NameError(f"Cannot initialize attribute for signature member {name!r} " | ||||
|                                 f"because an attribute with the same name already exists") | ||||
|         self.__dict__.update(signature.members.create(path=())) | ||||
| 
 | ||||
|     @property | ||||
|     def signature(self): | ||||
|         return self.__signature | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ Implemented RFCs | |||
| .. _RFC 34: https://amaranth-lang.org/rfcs/0034-interface-rename.html | ||||
| .. _RFC 35: https://amaranth-lang.org/rfcs/0035-shapelike-valuelike.html | ||||
| .. _RFC 37: https://amaranth-lang.org/rfcs/0037-make-signature-immutable.html | ||||
| .. _RFC 38: https://amaranth-lang.org/rfcs/0038-component-signature-immutability.html | ||||
| 
 | ||||
| 
 | ||||
| * `RFC 1`_: Aggregate data structure library | ||||
|  | @ -85,6 +86,7 @@ Implemented RFCs | |||
| * `RFC 34`_: Rename ``amaranth.lib.wiring.Interface`` to ``PureInterface`` | ||||
| * `RFC 35`_: Add ``ShapeLike``, ``ValueLike`` | ||||
| * `RFC 37`_: Make ``Signature`` immutable | ||||
| * `RFC 38`_: ``Component.signature`` immutability | ||||
| 
 | ||||
| 
 | ||||
| Language changes | ||||
|  |  | |||
|  | @ -711,8 +711,7 @@ class FlippedInterfaceTestCase(unittest.TestCase): | |||
| 
 | ||||
|     def test_propagate_flipped(self): | ||||
|         class InterfaceWithFlippedSub(Component): | ||||
|             signature = Signature({ | ||||
|                 "a": In(Signature({ | ||||
|             a: In(Signature({ | ||||
|                 "b": Out(Signature({ | ||||
|                     "c": Out(1) | ||||
|                 })), | ||||
|  | @ -721,7 +720,6 @@ class FlippedInterfaceTestCase(unittest.TestCase): | |||
|                 })), | ||||
|                 "f": Out(1) | ||||
|             })) | ||||
|             }) | ||||
| 
 | ||||
|             def __init__(self): | ||||
|                 super().__init__() | ||||
|  | @ -984,53 +982,6 @@ class ComponentTestCase(unittest.TestCase): | |||
|                 r"with the same name already exists$"): | ||||
|             C() | ||||
| 
 | ||||
|     def test_missing_in_out_warning(self): | ||||
|         class C1(Component): | ||||
|             prt1 : In(1) | ||||
|             sig2 : Signal | ||||
| 
 | ||||
|         with self.assertWarnsRegex(SyntaxWarning, | ||||
|                 r"^Component '.+\.C1' has an annotation 'sig2: Signal', which is not a signature " | ||||
|                 r"member; did you mean 'sig2: In\(Signal\)' or 'sig2: Out\(Signal\)'\?$"): | ||||
|             C1().signature | ||||
| 
 | ||||
|         class C2(Component): | ||||
|             prt1 : In(1) | ||||
|             sig2 : Signature({}) | ||||
| 
 | ||||
|         with self.assertWarnsRegex(SyntaxWarning, | ||||
|                 r"^Component '.+\.C2' has an annotation 'sig2: Signature\({}\)', which is not " | ||||
|                 r"a signature member; did you mean 'sig2: In\(Signature\({}\)\)' or " | ||||
|                 r"'sig2: Out\(Signature\({}\)\)'\?$"): | ||||
|             C2().signature | ||||
| 
 | ||||
|         class MockValueCastable(ValueCastable): | ||||
|             def shape(self): pass | ||||
|             @ValueCastable.lowermethod | ||||
|             def as_value(self): pass | ||||
| 
 | ||||
|         class C3(Component): | ||||
|             prt1 : In(1) | ||||
|             val2 : MockValueCastable | ||||
| 
 | ||||
|         with self.assertWarnsRegex(SyntaxWarning, | ||||
|                 r"^Component '.+\.C3' has an annotation 'val2: MockValueCastable', which is not " | ||||
|                 r"a signature member; did you mean 'val2: In\(MockValueCastable\)' or " | ||||
|                 r"'val2: Out\(MockValueCastable\)'\?$"): | ||||
|             C3().signature | ||||
| 
 | ||||
|     def test_bug_882(self): | ||||
|         class PageBuffer(Component): | ||||
|             rand: Signature({}).flip() | ||||
|             other: Out(1) | ||||
| 
 | ||||
|         with self.assertWarnsRegex(SyntaxWarning, | ||||
|                 r"^Component '.+\.PageBuffer' has an annotation 'rand: Signature\({}\)\.flip\(\)', " | ||||
|                 r"which is not a signature member; did you mean " | ||||
|                 r"'rand: In\(Signature\({}\)\.flip\(\)\)' or " | ||||
|                 r"'rand: Out\(Signature\({}\)\.flip\(\)\)'\?$"): | ||||
|             PageBuffer() | ||||
| 
 | ||||
|     def test_inherit(self): | ||||
|         class A(Component): | ||||
|             clk: In(1) | ||||
|  | @ -1054,3 +1005,49 @@ class ComponentTestCase(unittest.TestCase): | |||
|         with self.assertRaisesRegex(SignatureError, | ||||
|                 r"^Member 'a' is redefined in .*<locals>.B$"): | ||||
|             B() | ||||
| 
 | ||||
|     def test_create(self): | ||||
|         class C(Component): | ||||
|             def __init__(self, width): | ||||
|                 super().__init__(Signature({ | ||||
|                     "a": In(width) | ||||
|                 })) | ||||
| 
 | ||||
|         c = C(2) | ||||
|         self.assertEqual(c.signature, Signature({"a": In(2)})) | ||||
|         self.assertIsInstance(c.a, Signal) | ||||
|         self.assertEqual(c.a.shape(), unsigned(2)) | ||||
| 
 | ||||
|     def test_create_dict(self): | ||||
|         class C(Component): | ||||
|             def __init__(self, width): | ||||
|                 super().__init__({ | ||||
|                     "a": In(width) | ||||
|                 }) | ||||
| 
 | ||||
|         c = C(2) | ||||
|         self.assertEqual(c.signature, Signature({"a": In(2)})) | ||||
|         self.assertIsInstance(c.a, Signal) | ||||
|         self.assertEqual(c.a.shape(), unsigned(2)) | ||||
| 
 | ||||
|     def test_create_wrong(self): | ||||
|         class C(Component): | ||||
|             a: In(2) | ||||
| 
 | ||||
|             def __init__(self, width): | ||||
|                 super().__init__(Signature({ | ||||
|                     "a": In(width) | ||||
|                 })) | ||||
| 
 | ||||
|         with self.assertRaisesRegex(TypeError, | ||||
|                 r"^Signature was passed as an argument, but component '.*.C' already has signature member annotations$"): | ||||
|             C(2) | ||||
| 
 | ||||
|     def test_create_wrong_type(self): | ||||
|         class C(Component): | ||||
|             def __init__(self, width): | ||||
|                 super().__init__(4) | ||||
| 
 | ||||
|         with self.assertRaisesRegex(TypeError, | ||||
|                 r"^Object 4 is not a signature nor a dict$"): | ||||
|             C(2) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Wanda
						Wanda