From bc4a492f4df415b673b4df39ba079b7b6c3c65f8 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 6 Dec 2016 17:41:22 +0300 Subject: [PATCH] Resolve for rem/modAssign and mod/remAssign rem/remAssign always wins if it is possible --- .../ExpressionTypingVisitorForStatements.java | 24 ++++++++++++++++--- .../tests/operatorRem/modWithRemAssign.kt | 16 +++++++++++++ .../tests/operatorRem/modWithRemAssign.txt | 16 +++++++++++++ .../operatorRem/remAndRemAssignAmbiguity.kt | 12 ++++++++++ .../operatorRem/remAndRemAssignAmbiguity.txt | 12 ++++++++++ .../operatorRem/remWithModAndModAssign.kt | 16 +++++++++++++ .../operatorRem/remWithModAndModAssign.txt | 16 +++++++++++++ .../tests/operatorRem/remWithModAssign.kt | 11 +++++++++ .../tests/operatorRem/remWithModAssign.txt | 12 ++++++++++ .../checkers/DiagnosticsTestGenerated.java | 24 +++++++++++++++++++ 10 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.txt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.kt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.txt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.kt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.txt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.kt create mode 100644 compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index 59fba1693f3..03c336085a2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt; +import org.jetbrains.kotlin.util.OperatorNameConventions; import java.util.Collection; @@ -250,7 +251,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito KotlinType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType; KotlinTypeInfo rightInfo = leftInfo; - if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) { + + boolean hasRemAssignOperation = atLeastOneOperation(assignmentOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM_ASSIGN); + boolean hasRemBinaryOperation = atLeastOneOperation(binaryOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM); + + boolean oneTypeOfModRemOperations = hasRemAssignOperation == hasRemBinaryOperation; + if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess() && oneTypeOfModRemOperations) { // Both 'plus()' and 'plusAssign()' available => ambiguity OverloadResolutionResults ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors); context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls())); @@ -261,7 +267,9 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo())); context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); } - else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) { + else if (assignmentOperationType != null && + (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess()) && + (!hasRemBinaryOperation || !binaryOperationDescriptors.isSuccess())) { // There's 'plusAssign()', so we do a.plusAssign(b) temporaryForAssignmentOperation.commit(); if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) { @@ -289,6 +297,16 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType)); } + private static boolean atLeastOneOperation(Collection> calls, Name operationName) { + for (ResolvedCall call : calls) { + if (call.getCandidateDescriptor().getName().equals(operationName)) { + return true; + } + } + + return false; + } + @Nullable private static KotlinType refineTypeFromPropertySetterIfPossible( @NotNull BindingContext bindingContext, diff --git a/compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt b/compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt new file mode 100644 index 00000000000..5b69f5d996f --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class ModAndRemAssign { + operator fun mod(x: Int) = ModAndRemAssign() + operator fun mod(x: String) = ModAndRemAssign() + operator fun modAssign(x: String) {} + operator fun remAssign(x: Int) {} +} + +operator fun ModAndRemAssign.mod(x: String) = ModAndRemAssign() +operator fun ModAndRemAssign.modAssign(x: String) {} + +fun test() { + val modAndRemAssign = ModAndRemAssign() + modAndRemAssign %= 1 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.txt b/compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.txt new file mode 100644 index 00000000000..01a8648f200 --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.txt @@ -0,0 +1,16 @@ +package + +public fun test(): kotlin.Unit +public operator fun ModAndRemAssign.mod(/*0*/ x: kotlin.String): ModAndRemAssign +public operator fun ModAndRemAssign.modAssign(/*0*/ x: kotlin.String): kotlin.Unit + +public final class ModAndRemAssign { + public constructor ModAndRemAssign() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun mod(/*0*/ x: kotlin.Int): ModAndRemAssign + public final operator fun mod(/*0*/ x: kotlin.String): ModAndRemAssign + public final operator fun modAssign(/*0*/ x: kotlin.String): kotlin.Unit + public final operator fun remAssign(/*0*/ x: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.kt b/compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.kt new file mode 100644 index 00000000000..4ddbf434745 --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +object RemAndRemAssign { + operator fun rem(x: Int) = RemAndRemAssign +} + +operator fun RemAndRemAssign.remAssign(x: Int) {} + +fun test() { + var c = RemAndRemAssign + c %= 1 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.txt b/compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.txt new file mode 100644 index 00000000000..c311160ab3d --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.txt @@ -0,0 +1,12 @@ +package + +public fun test(): kotlin.Unit +public operator fun RemAndRemAssign.remAssign(/*0*/ x: kotlin.Int): kotlin.Unit + +public object RemAndRemAssign { + private constructor RemAndRemAssign() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun rem(/*0*/ x: kotlin.Int): RemAndRemAssign + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.kt b/compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.kt new file mode 100644 index 00000000000..a4550801ae3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class ModAndRemAssign { + operator fun mod(x: Int) = ModAndRemAssign() + operator fun mod(x: String) = ModAndRemAssign() + operator fun modAssign(x: String) {} + operator fun rem(x: Int) = ModAndRemAssign() +} + +operator fun ModAndRemAssign.mod(x: String) = ModAndRemAssign() +operator fun ModAndRemAssign.modAssign(x: String) {} + +fun test() { + var modAndRemAssign = ModAndRemAssign() + modAndRemAssign %= 1 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.txt b/compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.txt new file mode 100644 index 00000000000..7896e119bfe --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.txt @@ -0,0 +1,16 @@ +package + +public fun test(): kotlin.Unit +public operator fun ModAndRemAssign.mod(/*0*/ x: kotlin.String): ModAndRemAssign +public operator fun ModAndRemAssign.modAssign(/*0*/ x: kotlin.String): kotlin.Unit + +public final class ModAndRemAssign { + public constructor ModAndRemAssign() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun mod(/*0*/ x: kotlin.Int): ModAndRemAssign + public final operator fun mod(/*0*/ x: kotlin.String): ModAndRemAssign + public final operator fun modAssign(/*0*/ x: kotlin.String): kotlin.Unit + public final operator fun rem(/*0*/ x: kotlin.Int): ModAndRemAssign + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.kt b/compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.kt new file mode 100644 index 00000000000..54e18151cec --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +object RemAndModAssign { + operator fun modAssign(x: String) {} + operator fun rem(x: Int) = RemAndModAssign +} + +fun test2() { + var c = RemAndModAssign + c %= 123 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.txt b/compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.txt new file mode 100644 index 00000000000..ac9de0dfd59 --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.txt @@ -0,0 +1,12 @@ +package + +public fun test2(): kotlin.Unit + +public object RemAndModAssign { + private constructor RemAndModAssign() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun modAssign(/*0*/ x: kotlin.String): kotlin.Unit + public final operator fun rem(/*0*/ x: kotlin.Int): RemAndModAssign + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index fd046cc7531..e89a120b044 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13348,6 +13348,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("modWithRemAssign.kt") + public void testModWithRemAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt"); + doTest(fileName); + } + @TestMetadata("noDeprecatedModConventionWithoutFeature.kt") public void testNoDeprecatedModConventionWithoutFeature() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/operatorRem/noDeprecatedModConventionWithoutFeature.kt"); @@ -13420,6 +13426,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("remAndRemAssignAmbiguity.kt") + public void testRemAndRemAssignAmbiguity() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/operatorRem/remAndRemAssignAmbiguity.kt"); + doTest(fileName); + } + + @TestMetadata("remWithModAndModAssign.kt") + public void testRemWithModAndModAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/operatorRem/remWithModAndModAssign.kt"); + doTest(fileName); + } + + @TestMetadata("remWithModAssign.kt") + public void testRemWithModAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/operatorRem/remWithModAssign.kt"); + doTest(fileName); + } + @TestMetadata("resolveModIfRemIsHidden.kt") public void testResolveModIfRemIsHidden() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/operatorRem/resolveModIfRemIsHidden.kt");