diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index 2d551911ca5..eb8643a9127 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -510,7 +510,7 @@ private class ConstantExpressionEvaluatorVisitor( } private fun evaluateBinaryAndCheck(receiver: OperationArgument, parameter: OperationArgument, name: String, callExpression: KtExpression): Any? { - val functions = binaryOperations[BinaryOperationKey(receiver.ctcType, parameter.ctcType, name)] ?: return null + val functions = getBinaryOperation(receiver, parameter, name) ?: return null val (function, checker) = functions val actualResult = try { @@ -526,7 +526,14 @@ private class ConstantExpressionEvaluatorVisitor( fun toBigInteger(value: Any?) = BigInteger.valueOf((value as Number).toLong()) - val resultInBigIntegers = checker(toBigInteger(receiver.value), toBigInteger(parameter.value)) + val refinedChecker = if (name == OperatorNameConventions.MOD.asString()) { + getBinaryOperation(receiver, parameter, OperatorNameConventions.REM.asString())?.second ?: return null + } + else { + checker + } + + val resultInBigIntegers = refinedChecker(toBigInteger(receiver.value), toBigInteger(parameter.value)) if (toBigInteger(actualResult) != resultInBigIntegers) { trace.report(Errors.INTEGER_OVERFLOW.on(callExpression.getStrictParentOfType() ?: callExpression)) @@ -534,6 +541,9 @@ private class ConstantExpressionEvaluatorVisitor( return actualResult } + private fun getBinaryOperation(receiver: OperationArgument, parameter: OperationArgument, name: String) = + binaryOperations[BinaryOperationKey(receiver.ctcType, parameter.ctcType, name)] + private fun isDivisionByZero(name: String, parameter: Any?): Boolean { if (name == OperatorConventions.BINARY_OPERATION_NAMES[KtTokens.DIV]!!.asString()) { if (isIntegerType(parameter)) { diff --git a/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt b/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt index 34762a01159..644f89088a6 100644 --- a/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt +++ b/compiler/testData/diagnostics/tests/evaluate/intOverflow.kt @@ -21,6 +21,10 @@ val l20: Int = 30 * 24 * 60 * 60 * 1000 val l21: Int = intMinValue - intMinValue val l22: Int = intMinValue + -intMinValue val l23: Int = intMaxValue + -intMinValue +val l24: Int = (-1).mod(5) +val l25: Int = (-1).rem(5) +val l26: Int = (-1) % 5 + fun foo() { val a3: Int = intMaxValue + 1 - 10 @@ -41,6 +45,9 @@ fun foo() { val l21: Int = intMinValue - intMinValue val l22: Int = intMinValue + -intMinValue val l23: Int = intMaxValue + -intMinValue + val l24: Int = (-1).mod(5) + val l25: Int = (-1).rem(5) + val l26: Int = (-1) % 5 } class A { @@ -63,5 +70,8 @@ class A { val l21: Int = intMinValue - intMinValue val l22: Int = intMinValue + -intMinValue val l23: Int = intMaxValue + -intMinValue + val l24: Int = (-1).mod(5) + val l25: Int = (-1).rem(5) + val l26: Int = (-1) % 5 } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/evaluate/intOverflow.txt b/compiler/testData/diagnostics/tests/evaluate/intOverflow.txt index 518e04d00f8..a239e7c9809 100644 --- a/compiler/testData/diagnostics/tests/evaluate/intOverflow.txt +++ b/compiler/testData/diagnostics/tests/evaluate/intOverflow.txt @@ -20,6 +20,9 @@ public val l20: kotlin.Int = -1702967296 public val l21: kotlin.Int = 0 public val l22: kotlin.Int = 0 public val l23: kotlin.Int = -1 +public val l24: kotlin.Int = -1 +public val l25: kotlin.Int = -1 +public val l26: kotlin.Int = -1 public fun foo(): kotlin.Unit public final class A { diff --git a/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.kt b/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.kt index c100ee377f1..841a80045ed 100644 --- a/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.kt +++ b/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.kt @@ -21,4 +21,8 @@ class Baz { fun local() { operator fun Int.rem(x: Int) {} operator fun String.remAssign(x: Int) {} +} + +fun noOverflow() { + (-1).mod(5) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.txt b/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.txt index 8829fcd6cc8..dd250413129 100644 --- a/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.txt +++ b/compiler/testData/diagnostics/tests/operatorRem/noOperatorRemFeature.txt @@ -1,6 +1,7 @@ package public fun local(): kotlin.Unit +public fun noOverflow(): kotlin.Unit public operator fun Baz.rem(/*0*/ x: kotlin.Int): kotlin.Unit public final class Bar {