Cleanup CanBeSubscriptedConstraint

It was using an AST argument, and I'd rather not have those
in the typing system (except the generator).
This commit is contained in:
Johan B.W. de Vries 2025-05-12 19:20:50 +02:00
parent df5c1911bf
commit 67af569448
3 changed files with 28 additions and 33 deletions

View File

@ -50,7 +50,7 @@ NewConstraintList = List['ConstraintBase']
CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes] CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes]
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, Type3, PlaceholderForType]]] HumanReadableRet = Tuple[str, Dict[str, Union[None, int, str, ourlang.Expression, Type3, PlaceholderForType]]]
class Context: class Context:
""" """
@ -500,45 +500,42 @@ class CanBeSubscriptedConstraint(ConstraintBase):
""" """
A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array) A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array)
""" """
__slots__ = ('ret_type3', 'type3', 'index', 'index_phft', ) __slots__ = ('ret_type3', 'type3', 'index_type3', 'index_const', )
ret_type3: Type3OrPlaceholder ret_type3: PlaceholderForType
type3: Type3OrPlaceholder type3: PlaceholderForType
index: ourlang.Expression index_type3: PlaceholderForType
index_phft: Type3OrPlaceholder index_const: int | None
def __init__( def __init__(
self, self,
ret_type3: PlaceholderForType, ret_type3: PlaceholderForType,
type3: PlaceholderForType, type3: PlaceholderForType,
index: ourlang.Expression, index_type3: PlaceholderForType,
index_phft: PlaceholderForType, index_const: int | None,
comment: Optional[str] = None, comment: Optional[str] = None,
) -> None: ) -> None:
super().__init__(comment=comment) super().__init__(comment=comment)
self.ret_type3 = ret_type3 self.ret_type3 = ret_type3
self.type3 = type3 self.type3 = type3
self.index = index self.index_type3 = index_type3
self.index_phft = index_phft self.index_const = index_const
def _generate_bytes(self) -> CheckResult: def _generate_bytes(self) -> CheckResult:
return [ return [
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: bytes -> u32 -> u8'), SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: bytes -> u32 -> u8'),
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'), SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
] ]
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult: def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
sa_type, sa_len = sa_args sa_type, sa_len = sa_args
if isinstance(self.index, ourlang.ConstantPrimitive): if self.index_const is not None and (self.index_const < 0 or sa_len.value <= self.index_const):
assert isinstance(self.index.value, int) return Error('Tuple index out of range')
if self.index.value < 0 or sa_len.value <= self.index.value:
return Error('Tuple index out of range')
return [ return [
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: Subscriptable a => a b -> u32 -> b'), SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'), SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
] ]
@ -547,18 +544,15 @@ class CanBeSubscriptedConstraint(ConstraintBase):
# e.g. rather than having to do `fst a` and `snd a` and only have to-sized tuples # e.g. rather than having to do `fst a` and `snd a` and only have to-sized tuples
# we use a[0] and a[1] and allow for a[2] and on. # we use a[0] and a[1] and allow for a[2] and on.
if not isinstance(self.index, ourlang.ConstantPrimitive): if self.index_const is None:
return Error('Must index with literal')
if not isinstance(self.index.value, int):
return Error('Must index with integer literal') return Error('Must index with integer literal')
if self.index.value < 0 or len(tp_args) <= self.index.value: if self.index_const < 0 or len(tp_args) <= self.index_const:
return Error('Tuple index out of range') return Error('Tuple index out of range')
return [ return [
SameTypeConstraint(prelude.u32, self.index_phft, comment=f'Tuple subscript index {self.index.value}'), SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'), SameTypeConstraint(tp_args[self.index_const], self.ret_type3, comment=f'Tuple subscript index {self.index_const}'),
] ]
GENERATE_ROUTER = TypeApplicationRouter['CanBeSubscriptedConstraint', CheckResult]() GENERATE_ROUTER = TypeApplicationRouter['CanBeSubscriptedConstraint', CheckResult]()
@ -567,12 +561,10 @@ class CanBeSubscriptedConstraint(ConstraintBase):
GENERATE_ROUTER.add(prelude.tuple_, _generate_tuple) GENERATE_ROUTER.add(prelude.tuple_, _generate_tuple)
def check(self) -> CheckResult: def check(self) -> CheckResult:
exp_type = self.type3 if self.type3.resolve_as is None:
if isinstance(exp_type, PlaceholderForType): return RequireTypeSubstitutes()
if exp_type.resolve_as is None:
return RequireTypeSubstitutes()
exp_type = exp_type.resolve_as exp_type = self.type3.resolve_as
try: try:
return self.__class__.GENERATE_ROUTER(self, exp_type) return self.__class__.GENERATE_ROUTER(self, exp_type)
@ -584,9 +576,9 @@ class CanBeSubscriptedConstraint(ConstraintBase):
'{type3}[{index}]', '{type3}[{index}]',
{ {
'type3': self.type3, 'type3': self.type3,
'index': self.index, 'index': self.index_type3 if self.index_const is None else self.index_const,
}, },
) )
def __repr__(self) -> str: def __repr__(self) -> str:
return f'CanBeSubscriptedConstraint({repr(self.type3)}, {repr(self.index)}, comment={repr(self.comment)})' return f'CanBeSubscriptedConstraint({self.ret_type3!r}, {self.type3!r}, {self.index_type3!r}, {self.index_const!r}, comment={repr(self.comment)})'

View File

@ -193,7 +193,10 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: PlaceholderForType)
yield from expression(ctx, inp.varref, varref_phft) yield from expression(ctx, inp.varref, varref_phft)
yield from expression(ctx, inp.index, index_phft) yield from expression(ctx, inp.index, index_phft)
yield CanBeSubscriptedConstraint(phft, varref_phft, inp.index, index_phft) if isinstance(inp.index, ourlang.ConstantPrimitive) and isinstance(inp.index.value, int):
yield CanBeSubscriptedConstraint(phft, varref_phft, index_phft, inp.index.value)
else:
yield CanBeSubscriptedConstraint(phft, varref_phft, index_phft, None)
return return
if isinstance(inp, ourlang.AccessStructMember): if isinstance(inp, ourlang.AccessStructMember):

View File

@ -64,7 +64,7 @@ def testEntry(x: (u8, u32, u64), y: u8) -> u64:
return x[y] return x[y]
""" """
with pytest.raises(Type3Exception, match='Must index with literal'): with pytest.raises(Type3Exception, match='Must index with integer literal'):
Suite(code_py).run_code() Suite(code_py).run_code()
@pytest.mark.integration_test @pytest.mark.integration_test