Member and extension functions with 'operator' have now higher priority

This commit is contained in:
Yan Zhulanow
2015-09-22 16:50:22 +03:00
parent 1139a8dd0e
commit 2c7f68ff71
10 changed files with 246 additions and 16 deletions
@@ -18,24 +18,19 @@ package org.jetbrains.kotlin.resolve.calls.callResolverUtil
import com.google.common.collect.Lists
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetSuperExpression
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
import org.jetbrains.kotlin.types.typeUtil.getNestedArguments
import java.util.*
public enum class ResolveArgumentsMode {
RESOLVE_FUNCTION_ARGUMENTS,
@@ -116,6 +111,15 @@ public fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boole
return false
}
fun isConventionCall(call: Call): Boolean {
if (call is CallTransformer.CallForImplicitInvoke) return true
val callElement = call.callElement
if (callElement is JetArrayAccessExpression || callElement is JetMultiDeclarationEntry) return true
val calleeExpression = call.calleeExpression as? JetOperationReferenceExpression ?: return false
return calleeExpression.getNameForConventionalOperation() != null
}
public fun isInvokeCallOnVariable(call: Call): Boolean {
if (call.getCallType() !== Call.CallType.INVOKE) return false
val dispatchReceiver = call.getDispatchReceiver()
@@ -21,10 +21,10 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.doNotAnalyze
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
@@ -135,9 +135,20 @@ public class TaskPrioritizer(
c: TaskPrioritizerContext<D, F>,
isExplicit: Boolean
) {
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) }
addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit, filter = filter)
if (!explicitReceiverTypeIsDynamic) {
addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit, filter)
}
}
addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit)
if (explicitReceiver.value.type.isDynamic()) {
if (explicitReceiverTypeIsDynamic) {
addCandidatesForDynamicReceiver(explicitReceiver, implicitReceivers, c, isExplicit)
}
else {
@@ -149,7 +160,8 @@ public class TaskPrioritizer(
explicitReceiver: ReceiverWithTypes,
implicitReceivers: Collection<ReceiverValue>,
c: TaskPrioritizerContext<D, F>,
isExplicit: Boolean
isExplicit: Boolean,
filter: ((CallableDescriptor) -> Boolean)? = null
) {
for (callableDescriptorCollector in c.callableDescriptorCollectors) {
//member extensions
@@ -164,10 +176,14 @@ public class TaskPrioritizer(
}
//extensions
c.result.addCandidates {
val extensions = callableDescriptorCollector.getExtensionsByName(
c.scope.asJetScope(), c.name, explicitReceiver.types, createLookupLocation(c))
val filteredExtensions = if (filter == null) extensions else extensions.filter(filter)
convertWithImpliedThis(
c.scope,
explicitReceiver.value,
callableDescriptorCollector.getExtensionsByName(c.scope.asJetScope(), c.name, explicitReceiver.types, createLookupLocation(c)),
filteredExtensions,
createKind(EXTENSION_RECEIVER, isExplicit),
c.context.call
)
@@ -179,7 +195,8 @@ public class TaskPrioritizer(
explicitReceiver: ReceiverWithTypes,
c: TaskPrioritizerContext<D, F>,
staticMembers: Boolean,
isExplicit: Boolean
isExplicit: Boolean,
filter: ((CallableDescriptor) -> Boolean)? = null
) {
for (callableDescriptorCollector in c.callableDescriptorCollectors) {
c.result.addCandidates {
@@ -191,8 +208,10 @@ public class TaskPrioritizer(
else {
callableDescriptorCollector.getMembersByName(type, c.name, createLookupLocation(c))
}
val filteredMembers = if (filter == null) membersForThisVariant else membersForThisVariant.filter(filter)
convertWithReceivers(
membersForThisVariant,
filteredMembers,
explicitReceiver.value,
NO_RECEIVER,
members,
@@ -65,7 +65,7 @@ public class OperatorValidator : SymbolUsageValidator {
return
}
if (isVariableAsFunctionCall() || isMultiDeclaration() || isConventionOperator() || isArrayAccessExpression()) {
if (isVariableAsFunctionCall() || isConventionOperator() || isArrayAccessExpression()) {
if (!functionDescriptor.isOperator) {
report(jetElement, functionDescriptor, trace)
}
@@ -0,0 +1,33 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class Example
fun Example.plus(other: Example) = 0
operator fun Example.minus(other: Example) = 0
operator fun Example.times(other: Example) = 0
fun Example.div(other: Example) = 0
fun a() {
with (Example()) {
operator fun Example.plus(other: Example) = ""
fun Example.minus(other: Example) = ""
operator fun Example.times(other: Example) = ""
fun Example.div(other: Example) = ""
with (Example()) {
val a = Example()
val b = Example()
consumeString(a + b)
consumeInt(a - b)
a <!OVERLOAD_RESOLUTION_AMBIGUITY!>*<!> b
a <!OVERLOAD_RESOLUTION_AMBIGUITY!>/<!> b
}
}
}
public fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun consumeInt(i: Int) {}
fun consumeString(s: String) {}
@@ -0,0 +1,17 @@
package
public fun a(): kotlin.Unit
public fun consumeInt(/*0*/ i: kotlin.Int): kotlin.Unit
public fun consumeString(/*0*/ s: kotlin.String): kotlin.Unit
public fun </*0*/ T, /*1*/ R> 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 fun Example.plus(/*0*/ other: Example): kotlin.Int
public operator fun Example.times(/*0*/ other: Example): kotlin.Int
public final class Example {
public constructor 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,36 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class Example {
operator fun plus(other: Example) = 0
fun minus(other: Example) = 0
operator fun times(other: Example) = 0
fun div(other: Example) = 0
}
fun Example.plus(other: Example) = ""
operator fun Example.minus(other: Example) = ""
operator 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 <!OPERATOR_MODIFIER_REQUIRED!>/<!> b
with (Example()) {
consumeInt(this + a)
consumeString(this - b)
consumeInt(this * a)
consumeInt(this <!OPERATOR_MODIFIER_REQUIRED!>/<!> b)
}
}
public fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun consumeInt(i: Int) {}
fun consumeString(s: String) {}
@@ -0,0 +1,21 @@
package
public fun a(): kotlin.Unit
public fun consumeInt(/*0*/ i: kotlin.Int): kotlin.Unit
public fun consumeString(/*0*/ s: kotlin.String): kotlin.Unit
public fun </*0*/ T, /*1*/ R> 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 fun Example.plus(/*0*/ other: Example): kotlin.String
public operator fun Example.times(/*0*/ other: Example): kotlin.String
public final class Example {
public constructor Example()
public final fun div(/*0*/ other: Example): kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,38 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class Example {
fun invoke() = 0
fun get(i: Int) = 0
fun component1() = 0
fun component2() = 0
fun inc() = Example()
}
class Example2 : Example()
operator fun Example.invoke() = ""
operator fun Example.get(i: Int) = ""
operator fun Example.component1() = ""
operator fun Example.component2() = ""
operator fun Example.inc() = Example2()
fun a() {
var a = Example()
consumeString(a())
consumeString(a[1])
val (x, y) = Example()
consumeString(x)
consumeString(y)
consumeExample2(++a)
}
fun consumeInt(i: Int) {}
fun consumeString(s: String) {}
fun consumeExample2(e: Example2) {}
@@ -0,0 +1,35 @@
package
public fun a(): kotlin.Unit
public fun consumeExample2(/*0*/ e: Example2): kotlin.Unit
public fun consumeInt(/*0*/ i: kotlin.Int): kotlin.Unit
public fun consumeString(/*0*/ s: kotlin.String): kotlin.Unit
public operator fun Example.component1(): kotlin.String
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 open class Example {
public constructor Example()
public final fun component1(): kotlin.Int
public final fun component2(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun get(/*0*/ i: kotlin.Int): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun inc(): Example
public final fun invoke(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Example2 : Example {
public constructor Example2()
public final override /*1*/ /*fake_override*/ fun component1(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun component2(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun get(/*0*/ i: kotlin.Int): kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -9188,6 +9188,33 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/modifiers/operator")
@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);
}
@TestMetadata("LocalFunctions.kt")
public void testLocalFunctions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operator/LocalFunctions.kt");
doTest(fileName);
}
@TestMetadata("MemberFunctions.kt")
public void testMemberFunctions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operator/MemberFunctions.kt");
doTest(fileName);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/operator/Simple.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/diagnostics/tests/multimodule")