hdl._ast: enforce the ShapeCastable.const
contract in Const()
.
This commit is contained in:
parent
5577f4e703
commit
c4bbcc6f8a
|
@ -1503,7 +1503,13 @@ class ValueLike(metaclass=_ValueLikeMeta):
|
||||||
class _ConstMeta(ABCMeta):
|
class _ConstMeta(ABCMeta):
|
||||||
def __call__(cls, value, shape=None, src_loc_at=0, **kwargs):
|
def __call__(cls, value, shape=None, src_loc_at=0, **kwargs):
|
||||||
if isinstance(shape, ShapeCastable):
|
if isinstance(shape, ShapeCastable):
|
||||||
return shape.const(value)
|
value = shape.const(value)
|
||||||
|
cast_shape = Shape.cast(shape)
|
||||||
|
cast_value = Const.cast(value)
|
||||||
|
if cast_value.shape() != cast_shape:
|
||||||
|
raise ValueError(f"Constant returned by {shape!r}.const() must have the shape that "
|
||||||
|
f"it casts to, {cast_shape!r}, and not {cast_value.shape()!r}")
|
||||||
|
return value
|
||||||
return super().__call__(value, shape, **kwargs, src_loc_at=src_loc_at + 1)
|
return super().__call__(value, shape, **kwargs, src_loc_at=src_loc_at + 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -223,12 +223,7 @@ class Layout(ShapeCastable, metaclass=ABCMeta):
|
||||||
field = self[key]
|
field = self[key]
|
||||||
cast_field_shape = Shape.cast(field.shape)
|
cast_field_shape = Shape.cast(field.shape)
|
||||||
if isinstance(field.shape, ShapeCastable):
|
if isinstance(field.shape, ShapeCastable):
|
||||||
key_value = hdl.Const.cast(field.shape.const(key_value))
|
key_value = hdl.Const.cast(hdl.Const(key_value, field.shape))
|
||||||
if key_value.shape() != cast_field_shape:
|
|
||||||
raise ValueError("Constant returned by {!r}.const() must have the shape that "
|
|
||||||
"it casts to, {!r}, and not {!r}"
|
|
||||||
.format(field.shape, cast_field_shape,
|
|
||||||
key_value.shape()))
|
|
||||||
elif not isinstance(key_value, hdl.Const):
|
elif not isinstance(key_value, hdl.Const):
|
||||||
key_value = hdl.Const(key_value, cast_field_shape)
|
key_value = hdl.Const(key_value, cast_field_shape)
|
||||||
mask = ((1 << cast_field_shape.width) - 1) << field.offset
|
mask = ((1 << cast_field_shape.width) - 1) << field.offset
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Memory(wiring.Component):
|
||||||
|
|
||||||
if isinstance(shape, ShapeCastable):
|
if isinstance(shape, ShapeCastable):
|
||||||
self._elems = [None] * depth
|
self._elems = [None] * depth
|
||||||
self._raw = [Const.cast(shape.const(None)).value] * depth
|
self._raw = [Const.cast(Const(None, shape)).value] * depth
|
||||||
else:
|
else:
|
||||||
self._elems = [0] * depth
|
self._elems = [0] * depth
|
||||||
self._raw = self._elems # intentionally mutably aliased
|
self._raw = self._elems # intentionally mutably aliased
|
||||||
|
@ -113,7 +113,7 @@ class Memory(wiring.Component):
|
||||||
self[actual_index] = actual_value
|
self[actual_index] = actual_value
|
||||||
else:
|
else:
|
||||||
if isinstance(self._shape, ShapeCastable):
|
if isinstance(self._shape, ShapeCastable):
|
||||||
self._raw[index] = Const.cast(self._shape.const(value)).value
|
self._raw[index] = Const.cast(Const(value, self._shape)).value
|
||||||
else:
|
else:
|
||||||
value = operator.index(value)
|
value = operator.index(value)
|
||||||
# self._raw[index] assigned by the following line
|
# self._raw[index] assigned by the following line
|
||||||
|
|
|
@ -139,7 +139,7 @@ class Member:
|
||||||
# TODO: We need a simpler way to check for "is this a valid constant initializer"
|
# TODO: We need a simpler way to check for "is this a valid constant initializer"
|
||||||
if issubclass(type(self._description), ShapeCastable):
|
if issubclass(type(self._description), ShapeCastable):
|
||||||
try:
|
try:
|
||||||
self._init_as_const = Const.cast(self._description.const(self._init))
|
self._init_as_const = Const.cast(Const(self._init, self._description))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise TypeError(f"Port member initial value {self._init!r} is not a valid "
|
raise TypeError(f"Port member initial value {self._init!r} is not a valid "
|
||||||
f"constant initializer for {self._description}") from e
|
f"constant initializer for {self._description}") from e
|
||||||
|
|
|
@ -522,10 +522,16 @@ class ConstTestCase(FHDLTestCase):
|
||||||
hash(Const(0))
|
hash(Const(0))
|
||||||
|
|
||||||
def test_shape_castable(self):
|
def test_shape_castable(self):
|
||||||
class MockConstValue:
|
class MockConstValue(ValueCastable):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def shape(self):
|
||||||
|
return MockConstShape()
|
||||||
|
|
||||||
|
def as_value(self):
|
||||||
|
return Const(self.value, 8)
|
||||||
|
|
||||||
class MockConstShape(ShapeCastable):
|
class MockConstShape(ShapeCastable):
|
||||||
def as_shape(self):
|
def as_shape(self):
|
||||||
return unsigned(8)
|
return unsigned(8)
|
||||||
|
|
Loading…
Reference in a new issue