Debugger: Remove debugger-related hacks in resolution

Candidate ordering should be the same in ordinary Kotlin code and in evaluated expressions.
With the invention of 'foo_field' syntax, there is no need to do these nasty things any more.
This commit is contained in:
Yan Zhulanow
2019-05-22 19:25:22 +09:00
parent b4f515a436
commit 54f78a2920
9 changed files with 30 additions and 46 deletions
@@ -105,7 +105,7 @@ public class ResolutionResultsHandler {
successfulAndIncomplete.addAll(successfulCandidates); successfulAndIncomplete.addAll(successfulCandidates);
successfulAndIncomplete.addAll(incompleteCandidates); successfulAndIncomplete.addAll(incompleteCandidates);
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific( OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(
successfulAndIncomplete, true, context.isDebuggerContext, checkArgumentsMode, languageVersionSettings); successfulAndIncomplete, true, checkArgumentsMode, languageVersionSettings);
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);
@@ -160,7 +160,7 @@ public class ResolutionResultsHandler {
return recordFailedInfo(tracing, trace, myResolver.filterOutEquivalentCalls(new LinkedHashSet<>(thisLevel))); return recordFailedInfo(tracing, trace, myResolver.filterOutEquivalentCalls(new LinkedHashSet<>(thisLevel)));
} }
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific( OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(
thisLevel, false, false, checkArgumentsMode, languageVersionSettings); thisLevel, false, checkArgumentsMode, languageVersionSettings);
return recordFailedInfo(tracing, trace, results.getResultingCalls()); return recordFailedInfo(tracing, trace, results.getResultingCalls());
} }
} }
@@ -196,7 +196,6 @@ public class ResolutionResultsHandler {
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific( private <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,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings
) { ) {
@@ -217,7 +216,7 @@ public class ResolutionResultsHandler {
} }
Set<MutableResolvedCall<D>> specificCalls = Set<MutableResolvedCall<D>> specificCalls =
myResolver.chooseMaximallySpecificCandidates(refinedCandidates, checkArgumentsMode, discriminateGenerics, isDebuggerContext); myResolver.chooseMaximallySpecificCandidates(refinedCandidates, checkArgumentsMode, discriminateGenerics);
if (specificCalls.size() == 1) { if (specificCalls.size() == 1) {
return OverloadResolutionResultsImpl.success(specificCalls.iterator().next()); return OverloadResolutionResultsImpl.success(specificCalls.iterator().next());
@@ -129,8 +129,6 @@ class KotlinCallResolver(
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
candidates: Collection<KotlinResolutionCandidate> candidates: Collection<KotlinResolutionCandidate>
): CallResolutionResult { ): CallResolutionResult {
val isDebuggerContext = candidateFactory.scopeTower.isDebuggerContext
var refinedCandidates = candidates var refinedCandidates = candidates
if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.RefinedSamAdaptersPriority)) { if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.RefinedSamAdaptersPriority)) {
val nonSynthesized = candidates.filter { !it.resolvedCall.candidateDescriptor.isSynthesized } val nonSynthesized = candidates.filter { !it.resolvedCall.candidateDescriptor.isSynthesized }
@@ -142,8 +140,7 @@ class KotlinCallResolver(
val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates( val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
refinedCandidates, refinedCandidates,
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
discriminateGenerics = true, // todo discriminateGenerics = true // todo
isDebuggerContext = isDebuggerContext
) )
return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks) return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
@@ -130,8 +130,7 @@ class CallableReferenceResolver(
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates( return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(
candidates, candidates,
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
discriminateGenerics = false, // we can't specify generics explicitly for callable references discriminateGenerics = false // we can't specify generics explicitly for callable references
isDebuggerContext = scopeTower.isDebuggerContext
) )
} }
} }
@@ -49,8 +49,6 @@ internal object CheckVisibility : ResolutionPart() {
val containingDescriptor = scopeTower.lexicalScope.ownerDescriptor val containingDescriptor = scopeTower.lexicalScope.ownerDescriptor
val dispatchReceiverArgument = resolvedCall.dispatchReceiverArgument val dispatchReceiverArgument = resolvedCall.dispatchReceiverArgument
if (scopeTower.isDebuggerContext) return
val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER
val invisibleMember = val invisibleMember =
Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return
@@ -61,13 +61,12 @@ open class OverloadingConflictResolver<C : Any>(
fun chooseMaximallySpecificCandidates( fun chooseMaximallySpecificCandidates(
candidates: Collection<C>, candidates: Collection<C>,
checkArgumentsMode: CheckArgumentTypesMode, checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean, discriminateGenerics: Boolean
isDebuggerContext: Boolean
): Set<C> { ): Set<C> {
candidates.setIfOneOrEmpty()?.let { return it } candidates.setIfOneOrEmpty()?.let { return it }
val fixedCandidates = if (getVariableCandidates(candidates.first()) != null) { val fixedCandidates = if (getVariableCandidates(candidates.first()) != null) {
findMaximallySpecificVariableAsFunctionCalls(candidates, isDebuggerContext) ?: return LinkedHashSet(candidates) findMaximallySpecificVariableAsFunctionCalls(candidates) ?: return LinkedHashSet(candidates)
} else { } else {
candidates candidates
} }
@@ -93,13 +92,13 @@ open class OverloadingConflictResolver<C : Any>(
return noOverrides return noOverrides
} }
val maximallySpecific = findMaximallySpecific(noOverrides, checkArgumentsMode, false, isDebuggerContext) val maximallySpecific = findMaximallySpecific(noOverrides, checkArgumentsMode, false)
if (maximallySpecific != null) { if (maximallySpecific != null) {
return setOf(maximallySpecific) return setOf(maximallySpecific)
} }
if (discriminateGenerics) { if (discriminateGenerics) {
val maximallySpecificGenericsDiscriminated = findMaximallySpecific(noOverrides, checkArgumentsMode, true, isDebuggerContext) val maximallySpecificGenericsDiscriminated = findMaximallySpecific(noOverrides, checkArgumentsMode, true)
if (maximallySpecificGenericsDiscriminated != null) { if (maximallySpecificGenericsDiscriminated != null) {
return setOf(maximallySpecificGenericsDiscriminated) return setOf(maximallySpecificGenericsDiscriminated)
} }
@@ -141,8 +140,7 @@ open class OverloadingConflictResolver<C : Any>(
private fun findMaximallySpecific( private fun findMaximallySpecific(
candidates: Set<C>, candidates: Set<C>,
checkArgumentsMode: CheckArgumentTypesMode, checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean, discriminateGenerics: Boolean
isDebuggerContext: Boolean
): C? = ): C? =
if (candidates.size <= 1) if (candidates.size <= 1)
candidates.firstOrNull() candidates.firstOrNull()
@@ -155,29 +153,29 @@ open class OverloadingConflictResolver<C : Any>(
} }
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS -> CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext) findMaximallySpecificCall(candidates, discriminateGenerics)
?: hasSAMConversion?.let { hasConversion -> ?: hasSAMConversion?.let { hasConversion ->
findMaximallySpecificCall( findMaximallySpecificCall(
candidates.filterNotTo(mutableSetOf()) { hasConversion(it) }, candidates.filterNotTo(mutableSetOf()) { hasConversion(it) },
discriminateGenerics, isDebuggerContext discriminateGenerics
) )
} }
?: findMaximallySpecificCall( ?: findMaximallySpecificCall(
candidates.filterNotTo(mutableSetOf()) { createFlatSignature(it).isSyntheticMember }, candidates.filterNotTo(mutableSetOf()) { createFlatSignature(it).isSyntheticMember },
discriminateGenerics, isDebuggerContext discriminateGenerics
) )
} }
// null means ambiguity between variables // null means ambiguity between variables
private fun findMaximallySpecificVariableAsFunctionCalls(candidates: Collection<C>, isDebuggerContext: Boolean): Set<C>? { private fun findMaximallySpecificVariableAsFunctionCalls(candidates: Collection<C>): Set<C>? {
val variableCalls = candidates.mapTo(newResolvedCallSet(candidates.size)) { val variableCalls = candidates.mapTo(newResolvedCallSet(candidates.size)) {
getVariableCandidates(it) ?: throw AssertionError("Regular call among variable-as-function calls: $it") getVariableCandidates(it) ?: throw AssertionError("Regular call among variable-as-function calls: $it")
} }
val maxSpecificVariableCalls = chooseMaximallySpecificCandidates( val maxSpecificVariableCalls = chooseMaximallySpecificCandidates(
variableCalls, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, variableCalls, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
isDebuggerContext = isDebuggerContext, discriminateGenerics = false discriminateGenerics = false
) )
val maxSpecificVariableCall = maxSpecificVariableCalls.singleOrNull() ?: return null val maxSpecificVariableCall = maxSpecificVariableCalls.singleOrNull() ?: return null
@@ -186,11 +184,7 @@ open class OverloadingConflictResolver<C : Any>(
} }
} }
private fun findMaximallySpecificCall( private fun findMaximallySpecificCall(candidates: Set<C>, discriminateGenerics: Boolean): C? {
candidates: Set<C>,
discriminateGenerics: Boolean,
isDebuggerContext: Boolean
): C? {
val filteredCandidates = uniquifyCandidatesSet(candidates) val filteredCandidates = uniquifyCandidatesSet(candidates)
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull() if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
@@ -205,9 +199,7 @@ open class OverloadingConflictResolver<C : Any>(
} }
} }
return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 -> return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 -> isOfNotLessSpecificShape(call1, call2) }?.origin
isOfNotLessSpecificShape(call1, call2) && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext)
}?.origin
} }
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? {
@@ -361,19 +353,6 @@ open class OverloadingConflictResolver<C : Any>(
return true return true
} }
private fun isOfNotLessSpecificVisibilityForDebugger(
call1: FlatSignature<C>,
call2: FlatSignature<C>,
isDebuggerContext: Boolean
): Boolean {
if (isDebuggerContext) {
val isMoreVisible1 = Visibilities.compare(call1.descriptorVisibility(), call2.descriptorVisibility())
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`,
@@ -60,7 +60,7 @@ internal abstract class AbstractScopeTowerLevel(
} }
if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType)) if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType))
val shouldSkipVisibilityCheck = scopeTower.isDebuggerContext || scopeTower.isNewInferenceEnabled val shouldSkipVisibilityCheck = scopeTower.isNewInferenceEnabled
if (!shouldSkipVisibilityCheck) { if (!shouldSkipVisibilityCheck) {
Visibilities.findInvisibleMember( Visibilities.findInvisibleMember(
getReceiverValueWithSmartCast(dispatchReceiver?.receiverValue, dispatchReceiverSmartCastType), getReceiverValueWithSmartCast(dispatchReceiver?.receiverValue, dispatchReceiverSmartCastType),
+6
View File
@@ -0,0 +1,6 @@
import java.util.ArrayList
fun foo() {
val a = ArrayList<String>()
<caret>val x = 5
}
@@ -0,0 +1 @@
a.<error descr="[INVISIBLE_MEMBER] Cannot access 'ensureCapacityInternal': it is private in 'ArrayList'">ensureCapacityInternal</error>(0)
@@ -111,6 +111,11 @@ public class CodeFragmentHighlightingTestGenerated extends AbstractCodeFragmentH
runTest("idea/testData/checker/codeFragments/privateMember.kt"); runTest("idea/testData/checker/codeFragments/privateMember.kt");
} }
@TestMetadata("privateMembers.kt")
public void testPrivateMembers() throws Exception {
runTest("idea/testData/checker/codeFragments/privateMembers.kt");
}
@TestMetadata("protectedMember.kt") @TestMetadata("protectedMember.kt")
public void testProtectedMember() throws Exception { public void testProtectedMember() throws Exception {
runTest("idea/testData/checker/codeFragments/protectedMember.kt"); runTest("idea/testData/checker/codeFragments/protectedMember.kt");