diff --git a/packages/pyright-internal/src/analyzer/operations.ts b/packages/pyright-internal/src/analyzer/operations.ts index ca2672395fed..c15889d3bccd 100644 --- a/packages/pyright-internal/src/analyzer/operations.ts +++ b/packages/pyright-internal/src/analyzer/operations.ts @@ -1036,18 +1036,19 @@ function calcLiteralForBinaryOp(operator: OperatorType, leftType: Type, rightTyp // BigInt rounds to zero, but floor divide rounds to negative // infinity, so we need to adjust the result if the signs // of the operands are different. - if (leftLiteralValue !== rightLiteralValue && leftLiteralValue !== BigInt(0)) { - if ( - leftLiteralValue < BigInt(0) !== rightLiteralValue < BigInt(0) && - leftLiteralValue !== rightLiteralValue * BigInt(-1) - ) { - newValue -= BigInt(1); - } + if ( + newValue * rightLiteralValue !== leftLiteralValue && + leftLiteralValue < BigInt(0) !== rightLiteralValue < BigInt(0) + ) { + newValue -= BigInt(1); } } } else if (operator === OperatorType.Mod) { if (rightLiteralValue !== BigInt(0)) { - newValue = leftLiteralValue % rightLiteralValue; + // BigInt always produces a remainder, but Python produces + // a modulo result whose sign is always the same as the + // right operand. + newValue = ((leftLiteralValue % rightLiteralValue) + rightLiteralValue) % rightLiteralValue; } } else if (operator === OperatorType.Power) { if (rightLiteralValue >= BigInt(0)) { diff --git a/packages/pyright-internal/src/tests/samples/operator8.py b/packages/pyright-internal/src/tests/samples/operator8.py index 654658819ab6..6e62855045d8 100644 --- a/packages/pyright-internal/src/tests/samples/operator8.py +++ b/packages/pyright-internal/src/tests/samples/operator8.py @@ -77,11 +77,47 @@ def func1(a: Literal[1, 2], b: Literal[0, 4], c: Literal[3, 4]): c12 = 6 // -6 reveal_type(c12, expected_text="Literal[-1]") - c13 = 1 << -1 - reveal_type(c13, expected_text="int") + c13 = 6 // -3 + reveal_type(c13, expected_text="Literal[-2]") - c14 = 1 >> -1 - reveal_type(c14, expected_text="int") + c14 = 256 // -16 + reveal_type(c14, expected_text="Literal[-16]") + + c20 = 1 << -1 + reveal_type(c20, expected_text="int") + + c21 = 1 >> -1 + reveal_type(c21, expected_text="int") + + c30 = -129 % 16 + reveal_type(c30, expected_text="Literal[15]") + + c31 = -129 % 32 + reveal_type(c31, expected_text="Literal[31]") + + c32 = -129 % 100 + reveal_type(c32, expected_text="Literal[71]") + + c33 = 256 % -32678 + reveal_type(c33, expected_text="Literal[-32422]") + + c34 = 256 % -129 + reveal_type(c34, expected_text="Literal[-2]") + + c35 = 0 % -1 + reveal_type(c35, expected_text="Literal[0]") + + c36 = -1 % -1 + reveal_type(c36, expected_text="Literal[0]") + + c37 = 1 % 1 + reveal_type(c37, expected_text="Literal[0]") + + c38 = -2 % 1 + reveal_type(c38, expected_text="Literal[0]") + + c39 = 4 % -2 + reveal_type(c39, expected_text="Literal[0]") def func2(cond: bool):