hdl._ast: deprecate ValueCastable.lowermethod.

This commit is contained in:
Wanda 2024-02-13 05:21:39 +01:00 committed by Catherine
parent e2fd819742
commit 0da439cce1
7 changed files with 10 additions and 39 deletions

View file

@ -1262,9 +1262,6 @@ class ValueCastable:
if cls.shape is ValueCastable.shape: if cls.shape is ValueCastable.shape:
raise TypeError(f"Class '{cls.__name__}' deriving from 'ValueCastable' must override " raise TypeError(f"Class '{cls.__name__}' deriving from 'ValueCastable' must override "
"the 'shape' method") "the 'shape' method")
if not hasattr(cls.as_value, "_ValueCastable__memoized"):
raise TypeError(f"Class '{cls.__name__}' deriving from 'ValueCastable' must decorate "
"the 'as_value' method with the 'ValueCastable.lowermethod' decorator")
# The signatures and definitions of these methods are weird because they are present here for # The signatures and definitions of these methods are weird because they are present here for
# documentation (and error checking above) purpose only and should not affect control flow. # documentation (and error checking above) purpose only and should not affect control flow.
@ -1333,17 +1330,10 @@ class ValueCastable:
""" """
return super().shape(*args, **kwargs) # :nocov: return super().shape(*args, **kwargs) # :nocov:
# TODO(amaranth-0.6): remove
@staticmethod @staticmethod
@deprecated("`ValueCastable.lowermethod` is no longer required and will be removed in Amaranth 0.6")
def lowermethod(func): def lowermethod(func):
"""Decorator to memoize lowering methods.
Ensures the decorated method is called only once, with subsequent method calls returning
the object returned by the first first method call.
This decorator is required to decorate the :pc:`as_value` method of :pc:`ValueCastable`
subclasses. This is to ensure that Amaranth's view of representation of all values stays
internally consistent.
"""
@functools.wraps(func) @functools.wraps(func)
def wrapper_memoized(self, *args, **kwargs): def wrapper_memoized(self, *args, **kwargs):
# Use `in self.__dict__` instead of `hasattr` to avoid interfering with custom # Use `in self.__dict__` instead of `hasattr` to avoid interfering with custom

View file

@ -178,7 +178,6 @@ class Record(ValueCastable):
raise AttributeError("{} does not have a field '{}'. Did you mean one of: {}?" raise AttributeError("{} does not have a field '{}'. Did you mean one of: {}?"
.format(reference, item, ", ".join(self.fields))) from None .format(reference, item, ", ".join(self.fields))) from None
@ValueCastable.lowermethod
def as_value(self): def as_value(self):
return Cat(self.fields.values()) return Cat(self.fields.values())

View file

@ -638,7 +638,6 @@ class View(ValueCastable):
""" """
return self.__orig_layout return self.__orig_layout
@ValueCastable.lowermethod
def as_value(self): def as_value(self):
"""Get underlying value. """Get underlying value.

View file

@ -232,7 +232,6 @@ class EnumView(ValueCastable):
"""Returns the underlying enum type.""" """Returns the underlying enum type."""
return self.enum return self.enum
@ValueCastable.lowermethod
def as_value(self): def as_value(self):
"""Returns the underlying value.""" """Returns the underlying value."""
return self.target return self.target

View file

@ -1040,7 +1040,6 @@ class ArrayTestCase(FHDLTestCase):
def test_index_value_castable(self): def test_index_value_castable(self):
class MyValue(ValueCastable): class MyValue(ValueCastable):
@ValueCastable.lowermethod
def as_value(self): def as_value(self):
return Signal() return Signal()
@ -1328,7 +1327,6 @@ class MockValueCastable(ValueCastable):
def shape(self): def shape(self):
return Value.cast(self.dest).shape() return Value.cast(self.dest).shape()
@ValueCastable.lowermethod
def as_value(self): def as_value(self):
return self.dest return self.dest
@ -1340,9 +1338,10 @@ class MockValueCastableChanges(ValueCastable):
def shape(self): def shape(self):
return unsigned(self.width) return unsigned(self.width)
@ValueCastable.lowermethod with _ignore_deprecated():
def as_value(self): @ValueCastable.lowermethod
return Signal(self.width) def as_value(self):
return Signal(self.width)
class MockValueCastableCustomGetattr(ValueCastable): class MockValueCastableCustomGetattr(ValueCastable):
@ -1352,29 +1351,16 @@ class MockValueCastableCustomGetattr(ValueCastable):
def shape(self): def shape(self):
assert False assert False
@ValueCastable.lowermethod with _ignore_deprecated():
def as_value(self): @ValueCastable.lowermethod
return Const(0) def as_value(self):
return Const(0)
def __getattr__(self, attr): def __getattr__(self, attr):
assert False assert False
class ValueCastableTestCase(FHDLTestCase): class ValueCastableTestCase(FHDLTestCase):
def test_not_decorated(self):
with self.assertRaisesRegex(TypeError,
r"^Class 'MockValueCastableNotDecorated' deriving from 'ValueCastable' must "
r"decorate the 'as_value' method with the 'ValueCastable.lowermethod' decorator$"):
class MockValueCastableNotDecorated(ValueCastable):
def __init__(self):
pass
def shape(self):
pass
def as_value(self):
return Signal()
def test_no_override(self): def test_no_override(self):
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Class 'MockValueCastableNoOverrideAsValue' deriving from 'ValueCastable' must " r"^Class 'MockValueCastableNoOverrideAsValue' deriving from 'ValueCastable' must "

View file

@ -4,7 +4,6 @@ import unittest
from types import SimpleNamespace as NS from types import SimpleNamespace as NS
from amaranth import * from amaranth import *
from amaranth.hdl._ast import ValueCastable
from amaranth.lib import data, enum from amaranth.lib import data, enum
from amaranth.lib.wiring import Flow, In, Out, Member from amaranth.lib.wiring import Flow, In, Out, Member
from amaranth.lib.wiring import SignatureError, SignatureMembers, FlippedSignatureMembers from amaranth.lib.wiring import SignatureError, SignatureMembers, FlippedSignatureMembers

View file

@ -728,7 +728,6 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
def test_value_castable(self): def test_value_castable(self):
class MyValue(ValueCastable): class MyValue(ValueCastable):
@ValueCastable.lowermethod
def as_value(self): def as_value(self):
return Signal() return Signal()