Public members should have bigger priority in debugContext
#KT-10634 Fixed
This commit is contained in:
+29
-10
@@ -19,15 +19,13 @@ package org.jetbrains.kotlin.resolve.calls.results
|
|||||||
import gnu.trove.THashSet
|
import gnu.trove.THashSet
|
||||||
import gnu.trove.TObjectHashingStrategy
|
import gnu.trove.TObjectHashingStrategy
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
|
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
@@ -42,7 +40,8 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
fun <D : CallableDescriptor> findMaximallySpecific(
|
fun <D : CallableDescriptor> findMaximallySpecific(
|
||||||
candidates: Set<MutableResolvedCall<D>>,
|
candidates: Set<MutableResolvedCall<D>>,
|
||||||
checkArgumentsMode: CheckArgumentTypesMode,
|
checkArgumentsMode: CheckArgumentTypesMode,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean,
|
||||||
|
isDebuggerContext: Boolean
|
||||||
): MutableResolvedCall<D>? =
|
): MutableResolvedCall<D>? =
|
||||||
if (candidates.size <= 1)
|
if (candidates.size <= 1)
|
||||||
candidates.firstOrNull()
|
candidates.firstOrNull()
|
||||||
@@ -56,7 +55,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
}.singleOrNull()
|
}.singleOrNull()
|
||||||
|
|
||||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
|
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
|
||||||
findMaximallySpecificCall(candidates, discriminateGenerics)
|
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> findMaximallySpecificVariableAsFunctionCalls(candidates: Set<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> {
|
fun <D : CallableDescriptor> findMaximallySpecificVariableAsFunctionCalls(candidates: Set<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> {
|
||||||
@@ -67,7 +66,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
throw AssertionError("Regular call among variable-as-function calls: $it")
|
throw AssertionError("Regular call among variable-as-function calls: $it")
|
||||||
}
|
}
|
||||||
|
|
||||||
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, false) ?: return emptySet()
|
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, false, false) ?: return emptySet()
|
||||||
|
|
||||||
return candidates.filterTo(newResolvedCallSet<MutableResolvedCall<D>>(2)) {
|
return candidates.filterTo(newResolvedCallSet<MutableResolvedCall<D>>(2)) {
|
||||||
it.resultingVariableDescriptor == maxSpecificVariableCall.resultingDescriptor
|
it.resultingVariableDescriptor == maxSpecificVariableCall.resultingDescriptor
|
||||||
@@ -76,7 +75,8 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
|
|
||||||
private fun <D : CallableDescriptor> findMaximallySpecificCall(
|
private fun <D : CallableDescriptor> findMaximallySpecificCall(
|
||||||
candidates: Set<MutableResolvedCall<D>>,
|
candidates: Set<MutableResolvedCall<D>>,
|
||||||
discriminateGenerics: Boolean
|
discriminateGenerics: Boolean,
|
||||||
|
isDebuggerContext: Boolean
|
||||||
): MutableResolvedCall<D>? {
|
): MutableResolvedCall<D>? {
|
||||||
val filteredCandidates = uniquifyCandidatesSet(candidates)
|
val filteredCandidates = uniquifyCandidatesSet(candidates)
|
||||||
|
|
||||||
@@ -97,7 +97,10 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 -> isOfNotLessSpecificShape(call1, call2) }?.resolvedCall
|
return bestCandidatesByParameterTypes.exactMaxWith {
|
||||||
|
call1, call2 ->
|
||||||
|
isOfNotLessSpecificShape(call1, call2) && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext)
|
||||||
|
}?.resolvedCall
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <C : Any> Collection<C>.exactMaxWith(isNotWorse: (C, C) -> Boolean): C? {
|
private inline fun <C : Any> Collection<C>.exactMaxWith(isNotWorse: (C, C) -> Boolean): C? {
|
||||||
@@ -231,6 +234,22 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <D: CallableDescriptor, K> isOfNotLessSpecificVisibilityForDebugger(
|
||||||
|
call1: CandidateCallWithArgumentMapping<D, K>,
|
||||||
|
call2: CandidateCallWithArgumentMapping<D, K>,
|
||||||
|
isDebuggerContext: Boolean
|
||||||
|
): Boolean {
|
||||||
|
if (isDebuggerContext) {
|
||||||
|
val isMoreVisible1 = Visibilities.compare(
|
||||||
|
call1.resolvedCall.resultingDescriptor.visibility,
|
||||||
|
call2.resolvedCall.resultingDescriptor.visibility
|
||||||
|
)
|
||||||
|
if (isMoreVisible1 != null && isMoreVisible1 < 0) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `true` if `d1` is definitely not less specific than `d2`,
|
* Returns `true` if `d1` is definitely not less specific than `d2`,
|
||||||
* `false` if `d1` is definitely less specific than `d2`,
|
* `false` if `d1` is definitely less specific than `d2`,
|
||||||
|
|||||||
+6
-4
@@ -96,7 +96,8 @@ public class ResolutionResultsHandler {
|
|||||||
Set<MutableResolvedCall<D>> successfulAndIncomplete = Sets.newLinkedHashSet();
|
Set<MutableResolvedCall<D>> successfulAndIncomplete = Sets.newLinkedHashSet();
|
||||||
successfulAndIncomplete.addAll(successfulCandidates);
|
successfulAndIncomplete.addAll(successfulCandidates);
|
||||||
successfulAndIncomplete.addAll(incompleteCandidates);
|
successfulAndIncomplete.addAll(incompleteCandidates);
|
||||||
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(successfulAndIncomplete, true, checkArgumentsMode);
|
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(
|
||||||
|
successfulAndIncomplete, true, context.isDebuggerContext, checkArgumentsMode);
|
||||||
if (results.isSingleResult()) {
|
if (results.isSingleResult()) {
|
||||||
MutableResolvedCall<D> resultingCall = results.getResultingCall();
|
MutableResolvedCall<D> resultingCall = results.getResultingCall();
|
||||||
resultingCall.getTrace().moveAllMyDataTo(context.trace);
|
resultingCall.getTrace().moveAllMyDataTo(context.trace);
|
||||||
@@ -147,7 +148,7 @@ public class ResolutionResultsHandler {
|
|||||||
if (severityLevel.contains(ARGUMENTS_MAPPING_ERROR)) {
|
if (severityLevel.contains(ARGUMENTS_MAPPING_ERROR)) {
|
||||||
return recordFailedInfo(tracing, trace, thisLevel);
|
return recordFailedInfo(tracing, trace, thisLevel);
|
||||||
}
|
}
|
||||||
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false, checkArgumentsMode);
|
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false, false, checkArgumentsMode);
|
||||||
return recordFailedInfo(tracing, trace, results.getResultingCalls());
|
return recordFailedInfo(tracing, trace, results.getResultingCalls());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,6 +189,7 @@ public class ResolutionResultsHandler {
|
|||||||
public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
|
public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
|
||||||
@NotNull Set<MutableResolvedCall<D>> candidates,
|
@NotNull Set<MutableResolvedCall<D>> candidates,
|
||||||
boolean discriminateGenerics,
|
boolean discriminateGenerics,
|
||||||
|
boolean isDebuggerContext,
|
||||||
@NotNull CheckArgumentTypesMode checkArgumentsMode
|
@NotNull CheckArgumentTypesMode checkArgumentsMode
|
||||||
) {
|
) {
|
||||||
if (candidates.size() == 1) {
|
if (candidates.size() == 1) {
|
||||||
@@ -203,14 +205,14 @@ public class ResolutionResultsHandler {
|
|||||||
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
|
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, checkArgumentsMode, false);
|
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, checkArgumentsMode, false, isDebuggerContext);
|
||||||
if (maximallySpecific != null) {
|
if (maximallySpecific != null) {
|
||||||
return OverloadResolutionResultsImpl.success(maximallySpecific);
|
return OverloadResolutionResultsImpl.success(maximallySpecific);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (discriminateGenerics) {
|
if (discriminateGenerics) {
|
||||||
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(
|
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(
|
||||||
noOverrides, checkArgumentsMode, true);
|
noOverrides, checkArgumentsMode, true, isDebuggerContext);
|
||||||
if (maximallySpecificGenericsDiscriminated != null) {
|
if (maximallySpecificGenericsDiscriminated != null) {
|
||||||
return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated);
|
return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
LineBreakpoint created at privateMembersPriority.kt:22
|
||||||
|
LineBreakpoint created at privateMembersPriority.kt:34
|
||||||
|
LineBreakpoint created at privateMembersPriority.kt:41
|
||||||
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! privateMembersPriority.PrivateMembersPriorityKt
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
privateMembersPriority.kt:22
|
||||||
|
Compile bytecode for privateFun()
|
||||||
|
privateMembersPriority.kt:34
|
||||||
|
Compile bytecode for javaClass.size
|
||||||
|
privateMembersPriority.kt:41
|
||||||
|
Compile bytecode for TwoPrivateFun().foo(1)
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
package privateMembersPriority
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
Receiver2().test1()
|
||||||
|
test2()
|
||||||
|
test3()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Receiver1 {
|
||||||
|
private fun privateFun() = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
class Receiver2 {
|
||||||
|
fun privateFun() = 2
|
||||||
|
|
||||||
|
// In IDE -> privateFun() will return 2, because privateFun from Receiver is invisible in current scope
|
||||||
|
fun test1() {
|
||||||
|
with(Receiver1()) {
|
||||||
|
// EXPRESSION: privateFun()
|
||||||
|
// RESULT: 1: I
|
||||||
|
//Breakpoint!
|
||||||
|
privateFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In debuggerContext there are two properties size in ArrayList (java field + kotlin property)
|
||||||
|
fun test2() {
|
||||||
|
val javaClass = arrayListOf(1)
|
||||||
|
|
||||||
|
// EXPRESSION: javaClass.size
|
||||||
|
// RESULT: 1: I
|
||||||
|
//Breakpoint!
|
||||||
|
javaClass.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3() {
|
||||||
|
// EXPRESSION: TwoPrivateFun().foo(1)
|
||||||
|
// RESULT: 1: I
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
class TwoPrivateFun {
|
||||||
|
private fun foo(i: Int) = 1
|
||||||
|
private fun foo(i: Double) = 2
|
||||||
|
}
|
||||||
+6
@@ -778,6 +778,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doMultipleBreakpointsTest(fileName);
|
doMultipleBreakpointsTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("privateMembersPriority.kt")
|
||||||
|
public void testPrivateMembersPriority() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/privateMembersPriority.kt");
|
||||||
|
doMultipleBreakpointsTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("whenEntry.kt")
|
@TestMetadata("whenEntry.kt")
|
||||||
public void testWhenEntry() throws Exception {
|
public void testWhenEntry() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/whenEntry.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/whenEntry.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user