diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt index 40530931e8b..9b3ffc6d0f8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER import org.jetbrains.kotlin.resolve.scopes.utils.asJetScope import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsFileScope +import org.jetbrains.kotlin.resolve.validation.InfixValidator import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.JetType @@ -138,15 +139,25 @@ public class TaskPrioritizer( ) { val explicitReceiverTypeIsDynamic = explicitReceiver.value.type.isDynamic() - // Members and extensions with 'operator' modifier have higher priority - if (isConventionCall(c.context.call)) { - val filter = { d: CallableDescriptor -> (d is FunctionDescriptor && d.isOperator) || ErrorUtils.isError(d) } + fun addMembersAndExtensionsWithFilter(filter: (CallableDescriptor) -> Boolean) { + // If the explicit receiver is erroneous, an error function is returned by getMembersByName(). + // An error function should not be sorted out by our custom filters to prevent looking for extension functions. + if (explicitReceiver.types.any { it.isError }) return + addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit, filter = filter) if (!explicitReceiverTypeIsDynamic) { addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit, filter) } } + // Members and extensions with 'operator' and 'infix' modifiers have higher priority + if (isConventionCall(c.context.call)) { + addMembersAndExtensionsWithFilter { d: CallableDescriptor -> d is FunctionDescriptor && d.isOperator } + } + if (InfixValidator.isInfixCall(c.context.call.calleeExpression)) { + addMembersAndExtensionsWithFilter { d: CallableDescriptor -> d is FunctionDescriptor && d.isInfix } + } + addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit) if (explicitReceiverTypeIsDynamic) { diff --git a/compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.kt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.kt similarity index 61% rename from compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.kt rename to compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.kt index 36961845e23..84752623c9e 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.kt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.kt @@ -3,26 +3,34 @@ class Example fun Example.plus(other: Example) = 0 -operator fun Example.minus(other: Example) = 0 +operator infix fun Example.minus(other: Example) = 0 -operator fun Example.times(other: Example) = 0 +operator infix fun Example.times(other: Example) = 0 fun Example.div(other: Example) = 0 fun a() { with (Example()) { - operator fun Example.plus(other: Example) = "" + operator infix fun Example.plus(other: Example) = "" fun Example.minus(other: Example) = "" - operator fun Example.times(other: Example) = "" + operator infix fun Example.times(other: Example) = "" fun Example.div(other: Example) = "" with (Example()) { val a = Example() val b = Example() + consumeString(a + b) consumeInt(a - b) + + consumeString(a plus b) + consumeInt(a minus b) + a * b a / b + + a times b + a div b } } } diff --git a/compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.txt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.txt similarity index 81% rename from compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.txt rename to compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.txt index 15d6aef6922..75a995e7e0e 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.txt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.txt @@ -5,9 +5,9 @@ public fun consumeInt(/*0*/ i: kotlin.Int): kotlin.Unit public fun consumeString(/*0*/ s: kotlin.String): kotlin.Unit public fun with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R public fun Example.div(/*0*/ other: Example): kotlin.Int -public operator fun Example.minus(/*0*/ other: Example): kotlin.Int +public operator infix fun Example.minus(/*0*/ other: Example): kotlin.Int public fun Example.plus(/*0*/ other: Example): kotlin.Int -public operator fun Example.times(/*0*/ other: Example): kotlin.Int +public operator infix fun Example.times(/*0*/ other: Example): kotlin.Int public final class Example { public constructor Example() diff --git a/compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.kt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.kt similarity index 58% rename from compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.kt rename to compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.kt index 61736577102..49ae336b5ae 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.kt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.kt @@ -1,32 +1,43 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER class Example { - operator fun plus(other: Example) = 0 + operator infix fun plus(other: Example) = 0 fun minus(other: Example) = 0 - operator fun times(other: Example) = 0 + operator infix fun times(other: Example) = 0 fun div(other: Example) = 0 } fun Example.plus(other: Example) = "" -operator fun Example.minus(other: Example) = "" +operator infix fun Example.minus(other: Example) = "" -operator fun Example.times(other: Example) = "" +operator infix fun Example.times(other: Example) = "" fun Example.div(other: Example) = "" fun a() { val a = Example() val b = Example() + a + b a - b a * b a / b + a plus b + a minus b + a times b + a div b + with (Example()) { consumeInt(this + a) consumeString(this - b) consumeInt(this * a) consumeInt(this / b) + + consumeInt(this plus a) + consumeString(this minus b) + consumeInt(this times a) + consumeInt(this div b) } } diff --git a/compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.txt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.txt similarity index 72% rename from compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.txt rename to compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.txt index 25f82655b67..8debce42588 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.txt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.txt @@ -5,9 +5,9 @@ public fun consumeInt(/*0*/ i: kotlin.Int): kotlin.Unit public fun consumeString(/*0*/ s: kotlin.String): kotlin.Unit public fun with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R public fun Example.div(/*0*/ other: Example): kotlin.String -public operator fun Example.minus(/*0*/ other: Example): kotlin.String +public operator infix fun Example.minus(/*0*/ other: Example): kotlin.String public fun Example.plus(/*0*/ other: Example): kotlin.String -public operator fun Example.times(/*0*/ other: Example): kotlin.String +public operator infix fun Example.times(/*0*/ other: Example): kotlin.String public final class Example { public constructor Example() @@ -15,7 +15,7 @@ public final class Example { 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 fun minus(/*0*/ other: Example): kotlin.Int - public final operator fun plus(/*0*/ other: Example): kotlin.Int - public final operator fun times(/*0*/ other: Example): kotlin.Int + public final operator infix fun plus(/*0*/ other: Example): kotlin.Int + public final operator infix fun times(/*0*/ other: Example): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/modifiers/operator/Simple.kt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.kt similarity index 84% rename from compiler/testData/diagnostics/tests/modifiers/operator/Simple.kt rename to compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.kt index 62f7e6f603d..6b85e26f4da 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operator/Simple.kt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.kt @@ -8,6 +8,8 @@ open class Example { fun component2() = 0 fun inc() = Example() + + fun plus(o: Example) = 0 } class Example2 : Example() @@ -20,8 +22,11 @@ operator fun Example.component2() = "" operator fun Example.inc() = Example2() +infix fun Example.plus(o: Example) = "" + fun a() { var a = Example() + val b = Example() consumeString(a()) consumeString(a[1]) @@ -31,6 +36,8 @@ fun a() { consumeString(y) consumeExample2(++a) + + consumeString(a plus b) } fun consumeInt(i: Int) {} diff --git a/compiler/testData/diagnostics/tests/modifiers/operator/Simple.txt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.txt similarity index 89% rename from compiler/testData/diagnostics/tests/modifiers/operator/Simple.txt rename to compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.txt index e0157555e0e..42af19e26b5 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operator/Simple.txt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.txt @@ -9,6 +9,7 @@ public operator fun Example.component2(): kotlin.String public operator fun Example.get(/*0*/ i: kotlin.Int): kotlin.String public operator fun Example.inc(): Example2 public operator fun Example.invoke(): kotlin.String +public infix fun Example.plus(/*0*/ o: Example): kotlin.String public open class Example { public constructor Example() @@ -19,6 +20,7 @@ public open class Example { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public final fun inc(): Example public final fun invoke(): kotlin.Int + public final fun plus(/*0*/ o: Example): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -31,5 +33,6 @@ public final class Example2 : Example { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public final override /*1*/ /*fake_override*/ fun inc(): Example public final override /*1*/ /*fake_override*/ fun invoke(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun plus(/*0*/ o: Example): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 1184a7e45b9..50ef2711694 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -9261,29 +9261,29 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { } } - @TestMetadata("compiler/testData/diagnostics/tests/modifiers/operator") + @TestMetadata("compiler/testData/diagnostics/tests/modifiers/operatorInfix") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Operator extends AbstractJetDiagnosticsTest { - public void testAllFilesPresentInOperator() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/modifiers/operator"), Pattern.compile("^(.+)\\.kt$"), true); + public static class OperatorInfix extends AbstractJetDiagnosticsTest { + public void testAllFilesPresentInOperatorInfix() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/modifiers/operatorInfix"), Pattern.compile("^(.+)\\.kt$"), true); } @TestMetadata("LocalFunctions.kt") public void testLocalFunctions() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.kt"); + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operatorInfix/LocalFunctions.kt"); doTest(fileName); } @TestMetadata("MemberFunctions.kt") public void testMemberFunctions() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.kt"); + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.kt"); doTest(fileName); } @TestMetadata("Simple.kt") public void testSimple() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operator/Simple.kt"); + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operatorInfix/Simple.kt"); doTest(fileName); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinColorSettingsPage.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinColorSettingsPage.kt index 3d63f0ace0e..153d2311623 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinColorSettingsPage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinColorSettingsPage.kt @@ -95,7 +95,7 @@ var globalCount } override fun getAttributeDescriptors(): Array { - fun String.to(key: TextAttributesKey) = AttributesDescriptor(this, key) + infix fun String.to(key: TextAttributesKey) = AttributesDescriptor(this, key) return arrayOf(OptionsBundle.message("options.java.attribute.descriptor.keyword") to JetHighlightingColors.KEYWORD, JetBundle.message("options.kotlin.attribute.descriptor.builtin.annotation") to JetHighlightingColors.BUILTIN_ANNOTATION,