[NI] Update lambda result types.

When completing calls, update return types for functional descriptors
for lambdas using type inference results.

Add toString to some Call subclasses (for debugging purposes).
This commit is contained in:
Dmitry Petrov
2017-04-25 11:57:55 +03:00
committed by Stanislav Erokhin
parent 2bf252afe6
commit 1d6ed4ef8e
9 changed files with 46 additions and 17 deletions
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
import java.util.* import java.util.*
import kotlin.collections.HashMap import kotlin.collections.HashMap
@@ -21,20 +21,20 @@ import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.components.LambdaAnalyzer import org.jetbrains.kotlin.resolve.calls.components.LambdaAnalyzer
import org.jetbrains.kotlin.types.TypeApproximator import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
@@ -94,4 +94,16 @@ class LambdaAnalyzerImpl(
override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) { override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) {
kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace) kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace)
} }
override fun completeLambdaReturnType(lambdaArgument: ResolvedLambdaArgument, returnType: KotlinType) {
val psiCallArgument = lambdaArgument.argument.psiCallArgument
val ktFunction = when (psiCallArgument) {
is LambdaKotlinCallArgumentImpl -> psiCallArgument.ktLambdaExpression.functionLiteral
is FunctionExpressionImpl -> psiCallArgument.ktFunction
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
}
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
throw AssertionError("No function descriptor for resolved lambda argument")
functionDescriptor.setReturnType(returnType)
}
} }
@@ -130,7 +130,9 @@ class PSICallResolver(
val expectedType = context.expectedType.unwrap() val expectedType = context.expectedType.unwrap()
return if (context.contextDependency == ContextDependency.DEPENDENT) { return if (context.contextDependency == ContextDependency.DEPENDENT) {
assert(expectedType == TypeUtils.NO_EXPECTED_TYPE) assert(TypeUtils.noExpectedType(expectedType)) {
"Should have no expected type, got: $expectedType"
}
null null
} }
else { else {
@@ -366,6 +366,11 @@ public class CallMaker {
public CallType getCallType() { public CallType getCallType() {
return CallType.DEFAULT; return CallType.DEFAULT;
} }
@Override
public String toString() {
return DebugTextUtilKt.getDebugText(callElement);
}
}; };
} }
@@ -100,4 +100,9 @@ public class DelegatingCall implements Call {
public CallType getCallType() { public CallType getCallType() {
return delegate.getCallType(); return delegate.getCallType();
} }
@Override
public String toString() {
return "*" + delegate.toString();
}
} }
@@ -220,8 +220,10 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
// This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions
context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType) context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType)
val typeOfBodyExpression = // Type-check the body
components.expressionTypingServices.getBlockReturnedType(functionLiteral.bodyExpression!!, COERCION_TO_UNIT, newContext).type // Type-check the body
val blockReturnedType = components.expressionTypingServices.getBlockReturnedType(functionLiteral.bodyExpression!!, COERCION_TO_UNIT, newContext)
val typeOfBodyExpression = blockReturnedType.type
return computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression) return computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression)
} }
@@ -102,7 +102,7 @@ class KotlinCallResolver(
} }
return maximallySpecificCandidates.map { return maximallySpecificCandidates.map {
kotlinCallCompleter.transformWhenAmbiguity(it) kotlinCallCompleter.transformWhenAmbiguity(it, callContext.lambdaAnalyzer)
} }
} }
} }
@@ -17,10 +17,8 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
interface IsDescriptorFromSourcePredicate: (CallableDescriptor) -> Boolean interface IsDescriptorFromSourcePredicate: (CallableDescriptor) -> Boolean
@@ -39,4 +37,6 @@ interface LambdaAnalyzer {
// todo this is hack for some client which try to read ResolvedCall from trace before all calls completed // todo this is hack for some client which try to read ResolvedCall from trace before all calls completed
fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate)
fun completeLambdaReturnType(lambdaArgument: ResolvedLambdaArgument, returnType: KotlinType)
} }
@@ -63,8 +63,8 @@ class KotlinCallCompleter(
fun getBuilder(): ConstraintSystemBuilder fun getBuilder(): ConstraintSystemBuilder
} }
fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate): ResolvedKotlinCall = fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate, lambdaAnalyzer: LambdaAnalyzer): ResolvedKotlinCall =
toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate) toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate, lambdaAnalyzer)
fun completeCallIfNecessary( fun completeCallIfNecessary(
candidate: KotlinResolutionCandidate, candidate: KotlinResolutionCandidate,
@@ -82,7 +82,7 @@ class KotlinCallCompleter(
val c = candidate.lastCall.constraintSystem.asCallCompleterContext() val c = candidate.lastCall.constraintSystem.asCallCompleterContext()
topLevelCall.competeCall(c, lambdaAnalyzer) topLevelCall.competeCall(c, lambdaAnalyzer)
return toCompletedBaseResolvedCall(c, candidate) return toCompletedBaseResolvedCall(c, candidate, lambdaAnalyzer)
} }
return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate) return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate)
@@ -90,13 +90,17 @@ class KotlinCallCompleter(
private fun toCompletedBaseResolvedCall( private fun toCompletedBaseResolvedCall(
c: Context, c: Context,
candidate: KotlinResolutionCandidate candidate: KotlinResolutionCandidate,
lambdaAnalyzer: LambdaAnalyzer
): ResolvedKotlinCall.CompletedResolvedKotlinCall { ): ResolvedKotlinCall.CompletedResolvedKotlinCall {
val currentSubstitutor = c.buildResultingSubstitutor() val currentSubstitutor = c.buildResultingSubstitutor()
val completedCall = candidate.toCompletedCall(currentSubstitutor) val completedCall = candidate.toCompletedCall(currentSubstitutor)
val competedCalls = c.innerCalls.map { val competedCalls = c.innerCalls.map {
it.candidate.toCompletedCall(currentSubstitutor) it.candidate.toCompletedCall(currentSubstitutor)
} }
c.lambdaArguments.forEach {
lambdaAnalyzer.completeLambdaReturnType(it, currentSubstitutor.safeSubstitute(it.returnType))
}
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls) return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls)
} }