From 0da70ef8be22d162c4d0cea350288c47b3492cf1 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 30 Sep 2021 13:50:18 +0100 Subject: [PATCH] add Value.considered_bool() function testing len(Value) == 1 is one of the rare places that makes an assumption between Type 1 (Ast) low-level nmigen language constructs and between Type 2 (dsl.Module) high-level nmigen language constructs. a "Value.considered_bool()" function de-couples that assumption and allows for a proper separation between Type 1 and Type 2 nmigen language constructs, providing a clean design where Liskov Substitution Principle may successfully be applied at the Type I (ast) level --- nmigen/compat/fhdl/structure.py | 4 ++-- nmigen/hdl/ast.py | 3 +++ nmigen/hdl/dsl.py | 10 +++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/nmigen/compat/fhdl/structure.py b/nmigen/compat/fhdl/structure.py index 68ddc49..5a29b00 100644 --- a/nmigen/compat/fhdl/structure.py +++ b/nmigen/compat/fhdl/structure.py @@ -123,14 +123,14 @@ class If(ast._InternalSwitch): @deprecated("instead of `If(cond, ...)`, use `with m.If(cond): ...`") def __init__(self, cond, *stmts): cond = Value.cast(cond) - if len(cond) != 1: + if not cond.considered_bool(): cond = cond.bool() super().__init__(cond, {("1",): ast.Statement.cast(stmts)}) @deprecated("instead of `.Elif(cond, ...)`, use `with m.Elif(cond): ...`") def Elif(self, cond, *stmts): cond = Value.cast(cond) - if len(cond) != 1: + if not cond.considered_bool(): cond = cond.bool() self.cases = OrderedDict((("-" + k,), v) for (k,), v in self.cases.items()) self.cases[("1" + "-" * len(self.test),)] = ast.Statement.cast(stmts) diff --git a/nmigen/hdl/ast.py b/nmigen/hdl/ast.py index 1df331e..ef90f46 100644 --- a/nmigen/hdl/ast.py +++ b/nmigen/hdl/ast.py @@ -175,6 +175,9 @@ class Value(metaclass=ABCMeta): def __Assign__(self, rhs, *, src_loc_at=0): return _InternalAssign(self, rhs, src_loc_at=src_loc_at) + def considered_bool(self): + return len(self) == 1 + def __bool__(self): raise TypeError("Attempted to convert nMigen value to Python boolean") diff --git a/nmigen/hdl/dsl.py b/nmigen/hdl/dsl.py index c447369..337e176 100644 --- a/nmigen/hdl/dsl.py +++ b/nmigen/hdl/dsl.py @@ -433,9 +433,13 @@ class Module(_ModuleBuilderRoot, Elaboratable): tests, cases = [], OrderedDict() for if_test, if_case in zip(if_tests + [None], if_bodies): if if_test is not None: - if_test = Value.cast(if_test) - if len(if_test) != 1: - if_test = if_test.bool() + # check if the if_test is not considered boolean, and only + # append a converted version if it is not. this defers the + # Value.cast (which would lose type if done mandatorially). + # ast._InternalSwitch does a (second) Value.cast anyway + _if_test = Value.cast(if_test) + if not _if_test.considered_bool(): + if_test = _if_test.bool() tests.append(if_test) if if_test is not None: -- 2.30.2