NI: introduce simple calls storage (which aren't gone through type inference) in coroutine inference session to further substitute postponed variable

^KT-40151 Fixed
This commit is contained in:
Victor Petukhov
2020-07-09 15:17:07 +03:00
parent 3acb4e54d5
commit 514ac7dc8f
10 changed files with 124 additions and 37 deletions
@@ -1708,6 +1708,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");
@@ -5,22 +5,15 @@
package org.jetbrains.kotlin.resolve.calls.inference
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtDoubleColonExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.MissingSupertypesResolver
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.components.CompletedCallInfo
import org.jetbrains.kotlin.resolve.calls.components.NewConstraintSystemImpl
@@ -34,10 +27,7 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.typeUtil.contains
@@ -64,6 +54,10 @@ class CoroutineInferenceSession(
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns
) {
private val commonCalls = arrayListOf<PSICompletedCallInfo>()
// Simple calls are calls which might not have gone through type inference, but may contain unsubstituted postponed variables inside their types.
private val simpleCommonCalls = arrayListOf<KtExpression>()
private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
private var hasInapplicableCall = false
@@ -85,6 +79,10 @@ class CoroutineInferenceSession(
} || candidate.getSubResolvedAtoms().any { it.hasPostponed() }
}
fun addSimpleCall(callExpression: KtExpression) {
simpleCommonCalls.add(callExpression)
}
override fun addCompletedCallInfo(callInfo: CompletedCallInfo) {
require(callInfo is PSICompletedCallInfo) { "Wrong instance of callInfo: $callInfo" }
@@ -260,38 +258,43 @@ class CoroutineInferenceSession(
return commonSystem to effectivelyEmptyCommonSystem
}
private fun reportDiagnostics(completedCall: CallInfo, resolvedCall: ResolvedCall<*>, diagnostics: List<KotlinCallDiagnostic>) {
kotlinToResolvedCallTransformer.reportCallDiagnostic(
completedCall.context,
trace,
completedCall.callResolutionResult.resultCallAtom,
resolvedCall.resultingDescriptor,
diagnostics
)
}
private fun updateCalls(lambda: ResolvedLambdaAtom, commonSystem: NewConstraintSystemImpl) {
val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor()
val commonSystemSubstitutor = commonSystem.buildCurrentSubstitutor() as NewTypeSubstitutor
val nonFixedTypesToResult = nonFixedToVariablesSubstitutor.map.mapValues { commonSystemSubstitutor.safeSubstitute(it.value) }
val nonFixedTypesToResultSubstitutor = ComposedSubstitutor(commonSystemSubstitutor, nonFixedToVariablesSubstitutor)
val atomCompleter = createResolvedAtomCompleter(nonFixedTypesToResultSubstitutor, topLevelCallContext)
for (completedCall in commonCalls) {
updateCall(completedCall, nonFixedTypesToResultSubstitutor, nonFixedTypesToResult)
kotlinToResolvedCallTransformer.reportCallDiagnostic(
completedCall.context,
trace,
completedCall.callResolutionResult.resultCallAtom,
completedCall.resolvedCall.resultingDescriptor,
commonSystem.diagnostics
)
reportDiagnostics(completedCall, completedCall.resolvedCall, commonSystem.diagnostics)
}
val lambdaAtomCompleter = createResolvedAtomCompleter(nonFixedTypesToResultSubstitutor, topLevelCallContext)
for (callInfo in partiallyResolvedCallsInfo) {
val resolvedCall = completeCall(callInfo, lambdaAtomCompleter) ?: continue
kotlinToResolvedCallTransformer.reportCallDiagnostic(
callInfo.context,
trace,
callInfo.callResolutionResult.resultCallAtom,
resolvedCall.resultingDescriptor,
commonSystem.diagnostics
)
val resolvedCall = completeCall(callInfo, atomCompleter) ?: continue
reportDiagnostics(callInfo, resolvedCall, commonSystem.diagnostics)
}
lambdaAtomCompleter.completeAll(lambda)
for (simpleCall in simpleCommonCalls) {
when (simpleCall) {
is KtCallableReferenceExpression -> updateCallableReferenceType(simpleCall, nonFixedTypesToResultSubstitutor)
else -> throw Exception("Unsupported call expression type")
}
}
atomCompleter.completeAll(lambda)
}
private fun updateCall(
@@ -313,6 +316,28 @@ class CoroutineInferenceSession(
completeCall(completedCall, atomCompleter)
}
private fun updateCallableReferenceType(expression: KtCallableReferenceExpression, substitutor: NewTypeSubstitutor) {
val functionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression) as? SimpleFunctionDescriptorImpl ?: return
val returnType = functionDescriptor.returnType
fun KotlinType.substituteAndApproximate() = typeApproximator.approximateDeclarationType(
substitutor.safeSubstitute(this.unwrap()),
local = true,
languageVersionSettings = topLevelCallContext.languageVersionSettings
)
if (returnType != null && returnType.contains { it is StubType }) {
functionDescriptor.setReturnType(returnType.substituteAndApproximate())
}
for (valueParameter in functionDescriptor.valueParameters) {
if (valueParameter !is ValueParameterDescriptorImpl || valueParameter.type !is StubType)
continue
valueParameter.setOutType(valueParameter.type.substituteAndApproximate())
}
}
private fun completeCall(
callInfo: CallInfo,
atomCompleter: ResolvedAtomCompleter
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.checkers.isBuiltInCoroutineContext
import org.jetbrains.kotlin.resolve.calls.context.*
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSession
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
@@ -49,10 +50,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.types.expressions.FunctionWithBigAritySupport.LanguageVersionDependent
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.yieldIfNotNull
import java.util.*
import javax.inject.Inject
@@ -558,6 +556,11 @@ class DoubleColonExpressionResolver(
val (lhs, resolutionResults) = resolveCallableReference(expression, c, ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS)
val result = getCallableReferenceType(expression, lhs, resolutionResults, c)
val dataFlowInfo = (lhs as? DoubleColonLHS.Expression)?.dataFlowInfo ?: c.dataFlowInfo
if (c.inferenceSession is CoroutineInferenceSession && result?.contains { it is StubType } == true) {
c.inferenceSession.addSimpleCall(expression)
}
return dataFlowAnalyzer.checkType(createTypeInfo(result, dataFlowInfo), expression, c)
}
@@ -0,0 +1,24 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.*
suspend fun foo() {
val x = sequence {
yield(1)
::`yield`
}
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
builder { foo() }
return "OK"
}
@@ -1728,6 +1728,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");
@@ -1728,6 +1728,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");
@@ -1708,6 +1708,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");
@@ -1323,6 +1323,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");
@@ -1333,6 +1333,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");
@@ -1333,6 +1333,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/builderInference/lackOfNullCheckOnNullableInsideBuild.kt");
}
@TestMetadata("substituteStubTypeIntoCR.kt")
public void testSubstituteStubTypeIntoCR() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntoCR.kt");
}
@TestMetadata("substituteStubTypeIntolambdaParameterDescriptor.kt")
public void testSubstituteStubTypeIntolambdaParameterDescriptor() throws Exception {
runTest("compiler/testData/codegen/box/builderInference/substituteStubTypeIntolambdaParameterDescriptor.kt");