Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/fpy/semantics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,12 @@ def visit_AstBinaryOp(self, node: AstBinaryOp, state: CompileState):
folded_value = lhs_value / rhs_value
elif node.op == BinaryStackOp.EXPONENT:
folded_value = lhs_value**rhs_value
if isinstance(folded_value, complex):
# float ** float returns a complex number for a negative
# base and a fractional exponent, where the Decimal path
# raises decimal.InvalidOperation
state.err("Domain error", node)
return
elif node.op == BinaryStackOp.FLOOR_DIVIDE:
# Floor toward -inf (Python `//`), matching the runtime backends.
if isinstance(lhs_value, int) and isinstance(rhs_value, int):
Expand Down
18 changes: 18 additions & 0 deletions test/fpy/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ def test_const_complex_pow(self, fprime_test_api):

assert_compile_failure(fprime_test_api, seq)

def test_const_complex_pow_float_operands(self, fprime_test_api):
"""A negative base with a fractional exponent is a domain error even
when an operand has already been folded to a Python float, where
``float ** float`` returns a complex number instead of raising."""
seq = """
x: F64 = F64(-8.0) ** 0.5
"""

assert_compile_failure(fprime_test_api, seq, match="Domain error")

def test_const_complex_pow_float_exponent(self, fprime_test_api):
"""Same when it is the exponent that carries the float type."""
seq = """
y: F64 = (-2.0) ** F64(0.5)
"""

assert_compile_failure(fprime_test_api, seq, match="Domain error")

def test_very_large_const_pow(self, fprime_test_api):
seq = """
10.0 ** 1000
Expand Down
Loading