diff --git a/examples/smart_contracts/assert_foo_none.py b/examples/smart_contracts/assert_foo_none.py new file mode 100644 index 00000000..405884fb --- /dev/null +++ b/examples/smart_contracts/assert_foo_none.py @@ -0,0 +1,10 @@ +#!opshin +from opshin.prelude import * + + +def foo() -> None: + return None + + +def validator(datum: int, redeemer: int, context: ScriptContext) -> None: + assert foo(), f"Always fails!" diff --git a/examples/smart_contracts/assert_none.py b/examples/smart_contracts/assert_none.py new file mode 100644 index 00000000..d5e2049f --- /dev/null +++ b/examples/smart_contracts/assert_none.py @@ -0,0 +1,6 @@ +#!opshin +from opshin.prelude import * + + +def validator(datum: int, redeemer: int, context: ScriptContext) -> None: + assert None, f"Always fails!" diff --git a/opshin/type_inference.py b/opshin/type_inference.py index f9b0939b..b1a29348 100644 --- a/opshin/type_inference.py +++ b/opshin/type_inference.py @@ -838,6 +838,22 @@ def visit_Attribute(self, node: Attribute) -> TypedAttribute: def visit_Assert(self, node: Assert) -> TypedAssert: ta = copy(node) ta.test = self.visit(node.test) + try: + warn_assert_msg = f" (see assert with message '{node.msg.values[0].value}')" + except AttributeError: + warn_assert_msg = "" + if isinstance(ta.test.args[0], Constant) and ta.test.args[0].value is None: + OPSHIN_LOGGER.warning( + "Asserting `None'" + + warn_assert_msg + + " is equivalent to asserting False, which always fails." + ) + elif isinstance(ta.test.args[0].typ.typ, UnitType): + OPSHIN_LOGGER.warning( + "Asserting `None'" + + warn_assert_msg + + " is likely to stem from a procedure already doing internal assertions and returning `None'. Asserting this is equivalent to asserting False, which always fails (likely unintended)." + ) assert ( ta.test.typ == BoolInstanceType ), "Assertions must result in a boolean type"