[NI] Make CallResolutionResult more typed

This commit is contained in:
Mikhail Zarechenskiy
2018-03-15 13:01:57 +03:00
parent c8ef785010
commit ff10e97c28
9 changed files with 92 additions and 128 deletions
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve;
@@ -33,7 +22,7 @@ import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
import org.jetbrains.kotlin.resolve.calls.model.CallResolutionResult;
import org.jetbrains.kotlin.resolve.calls.model.PartialCallResolutionResult;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
@@ -128,7 +117,7 @@ public interface BindingContext {
new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, CallResolutionResult> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, PartialCallResolutionResult> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtExpression, Call> DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
@@ -73,9 +73,10 @@ class KotlinToResolvedCallTransformer(
baseResolvedCall: CallResolutionResult,
context: BasicCallResolutionContext
): ResolvedCall<D> {
val candidate = baseResolvedCall.resultCallAtom!!
when (baseResolvedCall.type) {
CallResolutionResult.Type.PARTIAL -> {
return when (baseResolvedCall) {
is PartialCallResolutionResult -> {
val candidate = baseResolvedCall.resultCallAtom
val psiKotlinCall = candidate.atom.psiKotlinCall
val psiCall = if (psiKotlinCall is PSIKotlinCallForInvoke)
psiKotlinCall.baseCall.psiCall
@@ -85,9 +86,12 @@ class KotlinToResolvedCallTransformer(
context.trace.record(BindingContext.ONLY_RESOLVED_CALL, psiCall, baseResolvedCall)
context.inferenceSession.addPartiallyResolvedCall(baseResolvedCall)
return createStubResolvedCallAndWriteItToTrace(candidate, context.trace, baseResolvedCall.diagnostics)
createStubResolvedCallAndWriteItToTrace(candidate, context.trace, baseResolvedCall.diagnostics)
}
CallResolutionResult.Type.ERROR, CallResolutionResult.Type.COMPLETED -> {
is CompletedCallResolutionResult, is ErrorCallResolutionResult -> {
val candidate = (baseResolvedCall as SingleCallResolutionResult).resultCallAtom
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
val ktPrimitiveCompleter = ResolvedAtomCompleter(
resultSubstitutor, context.trace, context, this, expressionTypingServices, argumentTypeResolver,
@@ -98,9 +102,11 @@ class KotlinToResolvedCallTransformer(
ktPrimitiveCompleter.completeAll(subKtPrimitive)
}
return ktPrimitiveCompleter.completeResolvedCall(candidate, baseResolvedCall.diagnostics) as ResolvedCall<D>
ktPrimitiveCompleter.completeResolvedCall(candidate, baseResolvedCall.diagnostics) as ResolvedCall<D>
}
CallResolutionResult.Type.ALL_CANDIDATES -> error("Cannot transform result for ALL_CANDIDATES mode")
is SingleCallResolutionResult -> error("Call resolution result for one candidate didn't transformed: $baseResolvedCall")
is AllCandidatesResolutionResult -> error("Cannot transform result for ALL_CANDIDATES mode")
}
}
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.tower
@@ -157,7 +146,7 @@ class SubKotlinCallArgumentImpl(
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
override val receiver: ReceiverValueWithSmartCastInfo,
override val callResult: CallResolutionResult
override val callResult: PartialCallResolutionResult
) : SimplePSIKotlinCallArgument(), SubKotlinCallArgument {
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName
@@ -174,13 +174,13 @@ class PSICallResolver(
result: CallResolutionResult,
tracingStrategy: TracingStrategy
): OverloadResolutionResults<D> {
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
val resolvedCalls = result.allCandidates?.map {
if (result is AllCandidatesResolutionResult) {
val resolvedCalls = result.allCandidates.map {
val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor()
kotlinToResolvedCallTransformer.transformToResolvedCall<D>(it.resolvedCall, null, resultingSubstitutor, result.diagnostics)
}
return AllCandidates(resolvedCalls ?: emptyList())
return AllCandidates(resolvedCalls)
}
val trace = context.trace
@@ -198,7 +198,7 @@ class PSICallResolver(
getResultApplicability(result.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
val resolvedCall = if (isInapplicableReceiver) {
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
val singleCandidate = result.resultCallAtom() ?: error("Should be not null for result: $result")
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also {
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
}
@@ -398,12 +398,8 @@ class PSICallResolver(
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
val variableResult = CallResolutionResult(
CallResolutionResult.Type.PARTIAL,
variable.resolvedCall,
listOf(),
variable.getSystem().asReadOnlyStorage()
)
val variableResult = PartialCallResolutionResult(variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage())
return SubKotlinCallArgumentImpl(
CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
@@ -56,11 +56,7 @@ class ResolvedAtomCompleter(
is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom)
is ResolvedLambdaAtom -> completeLambda(resolvedAtom)
is ResolvedCallAtom -> completeResolvedCall(resolvedAtom, emptyList())
is CallResolutionResult -> {
if (resolvedAtom.type == CallResolutionResult.Type.PARTIAL) {
resolvedAtom.resultCallAtom?.let { completeResolvedCall(it, resolvedAtom.diagnostics) }
}
}
is PartialCallResolutionResult -> completeResolvedCall(resolvedAtom.resultCallAtom, resolvedAtom.diagnostics)
}
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
@@ -41,7 +40,7 @@ class KotlinCallCompleter(
return if (resolutionCallbacks.inferenceSession.shouldFixTypeVariables())
candidate.runCompletion(completionType, diagnosticHolder, resolutionCallbacks)
else
candidate.asCallResolutionResult(CallResolutionResult.Type.PARTIAL, diagnosticHolder)
candidate.asCallResolutionResult(ConstraintSystemCompletionMode.PARTIAL, diagnosticHolder)
}
fun createAllCandidatesResult(
@@ -61,7 +60,7 @@ class KotlinCallCompleter(
collectAllCandidatesMode = true
)
}
return CallResolutionResult(CallResolutionResult.Type.ALL_CANDIDATES, null, emptyList(), ConstraintStorage.Empty, candidates)
return AllCandidatesResolutionResult(candidates)
}
private fun KotlinResolutionCandidate.runCompletion(
@@ -71,17 +70,12 @@ class KotlinCallCompleter(
): CallResolutionResult {
if (ErrorUtils.isError(resolvedCall.candidateDescriptor) || csBuilder.hasContradiction) {
runCompletion(resolvedCall, ConstraintSystemCompletionMode.FULL, diagnosticHolder, getSystem(), resolutionCallbacks)
return asCallResolutionResult(CallResolutionResult.Type.ERROR, diagnosticHolder)
return asCallResolutionResult(completionType, diagnosticHolder, isError = true)
}
runCompletion(resolvedCall, completionType, diagnosticHolder, getSystem(), resolutionCallbacks)
val callResolutionType = if (completionType == ConstraintSystemCompletionMode.FULL)
CallResolutionResult.Type.COMPLETED
else
CallResolutionResult.Type.PARTIAL
return asCallResolutionResult(callResolutionType, diagnosticHolder)
return asCallResolutionResult(completionType, diagnosticHolder)
}
private fun runCompletion(
@@ -161,18 +155,22 @@ class KotlinCallCompleter(
return resolutionCallbacks.createReceiverWithSmartCastInfo(resolvedCall)?.stableType ?: returnType
}
private fun KotlinResolutionCandidate?.asCallResolutionResult(
type: CallResolutionResult.Type,
diagnosticsHolder: KotlinDiagnosticsHolder.SimpleHolder
private fun KotlinResolutionCandidate.asCallResolutionResult(
type: ConstraintSystemCompletionMode,
diagnosticsHolder: KotlinDiagnosticsHolder.SimpleHolder,
isError: Boolean = false
): CallResolutionResult {
val diagnosticsFromResolutionParts = this?.diagnosticsFromResolutionParts ?: emptyList<KotlinCallDiagnostic>()
val systemStorage = this?.getSystem()?.asReadOnlyStorage() ?: ConstraintStorage.Empty
val systemStorage = getSystem().asReadOnlyStorage()
val allDiagnostics = diagnosticsHolder.getDiagnostics() + this.diagnosticsFromResolutionParts
return CallResolutionResult(
type,
this?.resolvedCall,
diagnosticsHolder.getDiagnostics() + diagnosticsFromResolutionParts,
systemStorage
)
if (isError) {
return ErrorCallResolutionResult(resolvedCall, allDiagnostics, systemStorage)
}
return if (type == ConstraintSystemCompletionMode.FULL) {
CompletedCallResolutionResult(resolvedCall, allDiagnostics, systemStorage)
} else {
PartialCallResolutionResult(resolvedCall, allDiagnostics, systemStorage)
}
}
}
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.model
@@ -44,18 +33,6 @@ private fun SimpleKotlinCallArgument.checkReceiverInvariants() {
assert(argumentName == null) {
"Argument name should be null for receiver: $this, but it is $argumentName"
}
checkArgumentInvariants()
}
private fun KotlinCallArgument.checkArgumentInvariants() {
if (this is SubKotlinCallArgument) {
assert(callResult.type == CallResolutionResult.Type.PARTIAL) {
"SubCall should has type PARTIAL: $callResult"
}
assert(callResult.resultCallAtom != null) {
"SubCall should has resultCallAtom: $callResult"
}
}
}
fun KotlinCall.checkCallInvariants() {
@@ -65,8 +42,6 @@ fun KotlinCall.checkCallInvariants() {
explicitReceiver.safeAs<SimpleKotlinCallArgument>()?.checkReceiverInvariants()
dispatchReceiverForInvokeExtension.safeAs<SimpleKotlinCallArgument>()?.checkReceiverInvariants()
argumentsInParenthesis.forEach(KotlinCallArgument::checkArgumentInvariants)
externalArgument?.checkArgumentInvariants()
if (callKind != KotlinCallKind.FUNCTION) {
assert(externalArgument == null) {
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.model
@@ -55,7 +44,7 @@ interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgum
interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument, ResolutionAtom
interface SubKotlinCallArgument : SimpleKotlinCallArgument {
val callResult: CallResolutionResult
val callResult: PartialCallResolutionResult
}
interface LambdaKotlinCallArgument : PostponableKotlinCallArgument {
@@ -148,29 +148,55 @@ class ResolvedCollectionLiteralAtom(
}
}
class CallResolutionResult(
val type: Type,
val resultCallAtom: ResolvedCallAtom?,
sealed class CallResolutionResult(
resultCallAtom: ResolvedCallAtom?,
val diagnostics: List<KotlinCallDiagnostic>,
val constraintSystem: ConstraintStorage,
val allCandidates: Collection<KotlinResolutionCandidate>? = null
val constraintSystem: ConstraintStorage
) : ResolvedAtom() {
override val atom: ResolutionAtom? get() = null
enum class Type {
COMPLETED, // resultSubstitutor possible create use constraintSystem
PARTIAL,
ERROR, // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates
ALL_CANDIDATES // allCandidates != null
}
init {
setAnalyzedResults(listOfNotNull(resultCallAtom))
}
override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})"
final override fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>) {
super.setAnalyzedResults(subResolvedAtoms)
}
override val atom: ResolutionAtom? get() = null
override fun toString() = "diagnostics: (${diagnostics.joinToString()})"
}
open class SingleCallResolutionResult(
val resultCallAtom: ResolvedCallAtom,
diagnostics: List<KotlinCallDiagnostic>,
constraintSystem: ConstraintStorage
) : CallResolutionResult(resultCallAtom, diagnostics, constraintSystem)
class PartialCallResolutionResult(
resultCallAtom: ResolvedCallAtom,
diagnostics: List<KotlinCallDiagnostic>,
constraintSystem: ConstraintStorage
) : SingleCallResolutionResult(resultCallAtom, diagnostics, constraintSystem)
class CompletedCallResolutionResult(
resultCallAtom: ResolvedCallAtom,
diagnostics: List<KotlinCallDiagnostic>,
constraintSystem: ConstraintStorage
) : SingleCallResolutionResult(resultCallAtom, diagnostics, constraintSystem)
class ErrorCallResolutionResult(
resultCallAtom: ResolvedCallAtom,
diagnostics: List<KotlinCallDiagnostic>,
constraintSystem: ConstraintStorage
) : SingleCallResolutionResult(resultCallAtom, diagnostics, constraintSystem)
class AllCandidatesResolutionResult(
val allCandidates: Collection<KotlinResolutionCandidate>
) : CallResolutionResult(null, emptyList(), ConstraintStorage.Empty)
fun CallResolutionResult.resultCallAtom(): ResolvedCallAtom? =
if (this is SingleCallResolutionResult) resultCallAtom else null
val ResolvedCallAtom.freshReturnType: UnwrappedType?
get() {
val returnType = candidateDescriptor.returnType ?: return null