From 7a66e22bb2f8b7b8e721d16a917e8a0c99ab29ad Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Thu, 18 Mar 2021 14:18:21 +0300 Subject: [PATCH] Implement top-down completion for nested builder inference calls ^KT-42742 Fixed --- .../FirBlackBoxCodegenTestGenerated.java | 12 ++ .../inference/CoroutineInferenceSession.kt | 149 ++++++++------ .../calls/tower/ResolvedAtomCompleter.kt | 183 +++++++++--------- .../DoubleColonExpressionResolver.kt | 2 +- ...pletionWithinThreeBuilderInferenceCalls.kt | 38 ++++ ...ompletionWithinTwoBuilderInferenceCalls.kt | 29 +++ .../diagnostics/tests/AutoCreatedIt.kt | 6 +- .../ExpectedParametersTypesMismatch.kt | 4 +- .../inference/completionOfMultipleLambdas.kt | 2 +- .../diagnostics/tests/regressions/kt30245.kt | 6 +- .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++ .../IrBlackBoxCodegenTestGenerated.java | 12 ++ .../LightAnalysisModeTestGenerated.java | 10 + .../impl/ReceiverParameterDescriptorImpl.java | 2 +- .../impl/VariableDescriptorImpl.java | 2 +- .../org/jetbrains/kotlin/types/TypeUtils.kt | 2 +- .../IrJsCodegenBoxES6TestGenerated.java | 10 + .../IrJsCodegenBoxTestGenerated.java | 10 + .../semantics/JsCodegenBoxTestGenerated.java | 10 + .../IrCodegenBoxWasmTestGenerated.java | 10 + 20 files changed, 339 insertions(+), 172 deletions(-) create mode 100644 compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt create mode 100644 compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index e9d261215c9..550aba3be8f 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -16987,6 +16987,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @Test + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @Test + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt index 5935ff9472b..f6e7eec4819 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt @@ -56,10 +56,18 @@ class CoroutineInferenceSession( ) : ManyCandidatesResolver( psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns ) { + var nestedBuilderInferenceSession: CoroutineInferenceSession? = null + + init { + if (topLevelCallContext.inferenceSession is CoroutineInferenceSession) { + topLevelCallContext.inferenceSession.nestedBuilderInferenceSession = this + } + } + private val commonCalls = arrayListOf() // 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() + private val oldCallableReferenceCalls = arrayListOf() private var hasInapplicableCall = false @@ -105,8 +113,8 @@ class CoroutineInferenceSession( } } - fun addSimpleCall(callExpression: KtExpression) { - simpleCommonCalls.add(callExpression) + fun addOldCallableReferenceCalls(callExpression: KtExpression) { + oldCallableReferenceCalls.add(callExpression) } override fun addCompletedCallInfo(callInfo: CompletedCallInfo) { @@ -139,6 +147,8 @@ class CoroutineInferenceSession( descriptor.extensionReceiverParameter?.type?.contains { it is StubType } == true } + private fun isTopLevelBuilderInferenceCall() = topLevelCallContext.inferenceSession !is CoroutineInferenceSession + fun hasInapplicableCall(): Boolean = hasInapplicableCall override fun writeOnlyStubs(callInfo: SingleCallResolutionResult): Boolean { @@ -178,42 +188,63 @@ class CoroutineInferenceSession( ): Map? { val (commonSystem, effectivelyEmptyConstraintSystem) = buildCommonSystem(initialStorage) val initialStorageSubstitutor = initialStorage.buildResultingSubstitutor(commonSystem, transformTypeVariablesToErrorTypes = false) + if (effectivelyEmptyConstraintSystem) { - updateCalls( - lambda, - initialStorageSubstitutor, - commonSystem.errors - ) + if (isTopLevelBuilderInferenceCall()) { + updateAllCalls(initialStorageSubstitutor, commonSystem, lambda) + } return null } - val context = commonSystem.asConstraintSystemCompleterContext() kotlinConstraintSystemCompleter.completeConstraintSystem( - context, + commonSystem.asConstraintSystemCompleterContext(), builtIns.unitType, partiallyResolvedCallsInfo.map { it.callResolutionResult.resultCallAtom }, completionMode, diagnosticsHolder ) - val resultingSubstitutor = - ComposedSubstitutor(initialStorageSubstitutor, commonSystem.buildCurrentSubstitutor() as NewTypeSubstitutor) - updateCalls(lambda, resultingSubstitutor, commonSystem.errors) + if (isTopLevelBuilderInferenceCall()) { + updateAllCalls(initialStorageSubstitutor, commonSystem, lambda) + } return commonSystem.fixedTypeVariables.cast() // TODO: SUB } + /* + * We update calls in top-down way: + * - updating calls within top-level builder inference call + * - ... + * - updating calls within the deepest builder inference call + */ + private fun updateAllCalls(substitutor: NewTypeSubstitutor, commonSystem: NewConstraintSystemImpl, lambda: ResolvedLambdaAtom) { + val resultingSubstitutor = ComposedSubstitutor(substitutor, commonSystem.buildCurrentSubstitutor() as NewTypeSubstitutor) + + updateCalls(lambda, resultingSubstitutor, commonSystem.errors) + + nestedBuilderInferenceSession?.updateAllCalls(substitutor, commonSystem, lambda) + } + override fun shouldCompleteResolvedSubAtomsOf(resolvedCallAtom: ResolvedCallAtom) = true - private fun createNonFixedTypeToVariableSubstitutor(): NewTypeSubstitutorByConstructorMap { + private fun createNonFixedTypeToVariableMap(): Map { val bindings = hashMapOf() - for ((variable, nonFixedType) in stubsForPostponedVariables) { + + for ((variable, nonFixedType) in stubsForPostponedVariables) { // do it for nested sessions bindings[nonFixedType.constructor] = variable.defaultType } - return NewTypeSubstitutorByConstructorMap(bindings) + val parentBuilderInferenceCallSession = topLevelCallContext.inferenceSession as? CoroutineInferenceSession + + if (parentBuilderInferenceCallSession != null) { + bindings.putAll(parentBuilderInferenceCallSession.createNonFixedTypeToVariableMap()) + } + + return bindings } + private fun createNonFixedTypeToVariableSubstitutor() = NewTypeSubstitutorByConstructorMap(createNonFixedTypeToVariableMap()) + private fun integrateConstraints( commonSystem: NewConstraintSystemImpl, storage: ConstraintStorage, @@ -299,34 +330,6 @@ class CoroutineInferenceSession( ) } - private fun updateCalls(lambda: ResolvedLambdaAtom, substitutor: NewTypeSubstitutor, errors: List) { - val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor() - - val nonFixedTypesToResult = nonFixedToVariablesSubstitutor.map.mapValues { substitutor.safeSubstitute(it.value) } - val nonFixedTypesToResultSubstitutor = ComposedSubstitutor(substitutor, nonFixedToVariablesSubstitutor) - - val atomCompleter = createResolvedAtomCompleter(nonFixedTypesToResultSubstitutor, topLevelCallContext) - - for (completedCall in commonCalls) { - updateCall(completedCall, nonFixedTypesToResultSubstitutor, nonFixedTypesToResult) - reportErrors(completedCall, completedCall.resolvedCall, errors) - } - - for (callInfo in partiallyResolvedCallsInfo) { - val resolvedCall = completeCall(callInfo, atomCompleter) ?: continue - reportErrors(callInfo, resolvedCall, errors) - } - - for (simpleCall in simpleCommonCalls) { - when (simpleCall) { - is KtCallableReferenceExpression -> updateCallableReferenceType(simpleCall, nonFixedTypesToResultSubstitutor) - else -> throw Exception("Unsupported call expression type") - } - } - - atomCompleter.completeAll(lambda) - } - private fun updateCall( completedCall: PSICompletedCallInfo, nonFixedTypesToResultSubstitutor: NewTypeSubstitutor, @@ -346,26 +349,12 @@ 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 + private fun completeCallableReference(expression: KtCallableReferenceExpression, substitutor: NewTypeSubstitutor) { + createResolvedAtomCompleter(substitutor, topLevelCallContext).substituteFunctionLiteralDescriptor( + resolvedAtom = null, + descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression) as? SimpleFunctionDescriptorImpl ?: return, + substitutor ) - - 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( @@ -408,6 +397,40 @@ class CoroutineInferenceSession( containingElement.anyDescendantOfType { it == atom.psiCall.callElement } } } + + companion object { + private fun CoroutineInferenceSession.updateCalls( + lambda: ResolvedLambdaAtom, + substitutor: NewTypeSubstitutor, + errors: List + ) { + val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor() + + val nonFixedTypesToResult = nonFixedToVariablesSubstitutor.map.mapValues { substitutor.safeSubstitute(it.value) } + val nonFixedTypesToResultSubstitutor = ComposedSubstitutor(substitutor, nonFixedToVariablesSubstitutor) + + val atomCompleter = createResolvedAtomCompleter(nonFixedTypesToResultSubstitutor, topLevelCallContext) + + for (completedCall in commonCalls) { + updateCall(completedCall, nonFixedTypesToResultSubstitutor, nonFixedTypesToResult) + reportErrors(completedCall, completedCall.resolvedCall, errors) + } + + for (callInfo in partiallyResolvedCallsInfo) { + val resolvedCall = completeCall(callInfo, atomCompleter) ?: continue + reportErrors(callInfo, resolvedCall, errors) + } + + for (simpleCall in oldCallableReferenceCalls) { + when (simpleCall) { + is KtCallableReferenceExpression -> completeCallableReference(simpleCall, nonFixedTypesToResultSubstitutor) + else -> throw Exception("Unsupported call expression type") + } + } + + atomCompleter.completeAll(lambda) + } + } } class ComposedSubstitutor(val left: NewTypeSubstitutor, val right: NewTypeSubstitutor) : NewTypeSubstitutor { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt index 5a9b75285ff..b3ca43bf765 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt @@ -8,8 +8,8 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce @@ -48,7 +48,7 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.isUnit -import org.jetbrains.kotlin.types.typeUtil.shouldBeSubstituted +import org.jetbrains.kotlin.types.typeUtil.shouldBeUpdated import org.jetbrains.kotlin.utils.addToStdlib.safeAs class ResolvedAtomCompleter( @@ -212,52 +212,93 @@ class ResolvedAtomCompleter( return commonReturnType.isUnit() } - private fun completeLambda(lambda: ResolvedLambdaAtom) { - @Suppress("NAME_SHADOWING") - val lambda = lambda.unwrap() + private fun KotlinType.substituteAndApproximate(substitutor: NewTypeSubstitutor): FunctionLiteralTypes.ProcessedType { + val substitutedType = substitutor.safeSubstitute(this.unwrap()) + + return FunctionLiteralTypes.ProcessedType( + substitutedType, + approximatedType = typeApproximator.approximateDeclarationType( + substitutedType, local = true, languageVersionSettings = topLevelCallContext.languageVersionSettings + ) + ) + } + + fun substituteFunctionLiteralDescriptor( + resolvedAtom: ResolvedLambdaAtom?, // null is for callable references resolved though the old type inference + descriptor: SimpleFunctionDescriptorImpl, + substitutor: NewTypeSubstitutor + ): FunctionLiteralTypes { + val returnType = + (if (resolvedAtom?.isCoercedToUnit == true) builtIns.unitType else resolvedAtom?.returnType) ?: descriptor.returnType + val receiverType = resolvedAtom?.receiver ?: descriptor.extensionReceiverParameter?.type + val valueParameterTypes = resolvedAtom?.parameters ?: descriptor.valueParameters.map { it.type } + + require(returnType != null) + + val substitutedReturnType = returnType.substituteAndApproximate(substitutor).also { + descriptor.setReturnType(it.approximatedType) + } + + val receiverFromDescriptor = descriptor.extensionReceiverParameter + val substitutedReceiverType = receiverType?.substituteAndApproximate(substitutor)?.also { + if (receiverFromDescriptor is ReceiverParameterDescriptorImpl && receiverFromDescriptor.type.shouldBeUpdated()) { + receiverFromDescriptor.setOutType(it.approximatedType) + } + } + + val substitutedValueParameterTypes = descriptor.valueParameters.mapIndexed { i, valueParameter -> + valueParameterTypes[i].substituteAndApproximate(substitutor).also { + if (valueParameter is ValueParameterDescriptorImpl && valueParameter.type.shouldBeUpdated()) { + valueParameter.setOutType(it.approximatedType) + } + } + } + + return FunctionLiteralTypes(substitutedReturnType, substitutedValueParameterTypes, substitutedReceiverType) + } + + private fun completeLambda(resolvedAtom: ResolvedLambdaAtom) { + val lambda = resolvedAtom.unwrap() val resultArgumentsInfo = lambda.resultArgumentsInfo!! - val returnType = if (lambda.isCoercedToUnit) { - builtIns.unitType - } else { - resultSubstitutor.safeSubstitute(lambda.returnType) - } - val receiverType = lambda.receiver - val approximatedValueParameterTypes = lambda.parameters.map { parameterType -> - if (parameterType.shouldBeSubstituted()) { - typeApproximator.approximateDeclarationType( - resultSubstitutor.safeSubstitute(parameterType), - local = true, - languageVersionSettings = topLevelCallContext.languageVersionSettings - ) - } else parameterType + val psiCallArgument = lambda.atom.psiCallArgument + val (ktArgumentExpression, ktFunction) = when (psiCallArgument) { + is LambdaKotlinCallArgumentImpl -> psiCallArgument.ktLambdaExpression to psiCallArgument.ktLambdaExpression.functionLiteral + is FunctionExpressionImpl -> psiCallArgument.ktFunction to psiCallArgument.ktFunction + else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument") } - val approximatedReturnType = - typeApproximator.approximateDeclarationType( - returnType, - local = true, - languageVersionSettings = topLevelCallContext.languageVersionSettings - ) + val descriptor = topLevelTrace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? SimpleFunctionDescriptorImpl + ?: throw AssertionError("No function descriptor for resolved lambda argument") - val approximatedReceiverType = if (receiverType != null) { - typeApproximator.approximateDeclarationType( - resultSubstitutor.safeSubstitute(receiverType), - local = true, - languageVersionSettings = topLevelCallContext.languageVersionSettings - ) - } else null + val substitutedLambdaTypes = substituteFunctionLiteralDescriptor(lambda, descriptor, resultSubstitutor) - updateTraceForLambda(lambda, topLevelTrace, approximatedReturnType, approximatedValueParameterTypes, approximatedReceiverType) + val existingLambdaType = topLevelTrace.getType(ktArgumentExpression) + + if (existingLambdaType == null) { + if (ktFunction is KtNamedFunction && ktFunction.nameIdentifier != null) return // it's a statement + throw AssertionError("No type for resolved lambda argument: ${ktArgumentExpression.text}") + } + + val substitutedFunctionalType = createFunctionType( + builtIns, + existingLambdaType.annotations, + substitutedLambdaTypes.receiverType?.substitutedType, + substitutedLambdaTypes.parameterTypes.map { it.substitutedType }, + null, // parameter names transforms to special annotations, so they are already taken from parameter types + substitutedLambdaTypes.returnType.substitutedType, + lambda.isSuspend + ) + + topLevelTrace.recordType(ktArgumentExpression, substitutedFunctionalType) for (lambdaResult in resultArgumentsInfo.nonErrorArguments) { val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue - val newContext = - topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument) - .replaceExpectedType(approximatedReturnType) - .replaceBindingTrace(topLevelTrace) - + val newContext = topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument) + .replaceExpectedType(substitutedLambdaTypes.returnType.approximatedType) + .replaceBindingTrace(topLevelTrace) val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue + kotlinToResolvedCallTransformer.updateRecordedType( argumentExpression, parameter = null, @@ -268,64 +309,6 @@ class ResolvedAtomCompleter( } } - private fun updateTraceForLambda( - lambda: ResolvedLambdaAtom, - trace: BindingTrace, - returnType: UnwrappedType, - valueParameters: List, - receiverType: UnwrappedType? - ) { - val psiCallArgument = lambda.atom.psiCallArgument - - val ktArgumentExpression: KtExpression - val ktFunction: KtElement - when (psiCallArgument) { - is LambdaKotlinCallArgumentImpl -> { - ktArgumentExpression = psiCallArgument.ktLambdaExpression - ktFunction = ktArgumentExpression.functionLiteral - } - is FunctionExpressionImpl -> { - ktArgumentExpression = psiCallArgument.ktFunction - ktFunction = ktArgumentExpression - } - 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) - - val extensionReceiverParameter = functionDescriptor.extensionReceiverParameter - - if (receiverType != null && extensionReceiverParameter is ReceiverParameterDescriptorImpl && extensionReceiverParameter.type.shouldBeSubstituted()) { - extensionReceiverParameter.setOutType(receiverType) - } - - for ((i, valueParameter) in functionDescriptor.valueParameters.withIndex()) { - if (valueParameter !is ValueParameterDescriptorImpl || !valueParameter.type.shouldBeSubstituted()) continue - valueParameter.setOutType(valueParameters[i]) - } - - val existingLambdaType = trace.getType(ktArgumentExpression) - if (existingLambdaType == null) { - if (ktFunction is KtNamedFunction && ktFunction.nameIdentifier != null) return // it's a statement - - throw AssertionError("No type for resolved lambda argument: ${ktArgumentExpression.text}") - } - val substitutedFunctionalType = createFunctionType( - builtIns, - existingLambdaType.annotations, - lambda.receiver?.let { resultSubstitutor.safeSubstitute(it) }, - lambda.parameters.map { resultSubstitutor.safeSubstitute(it) }, - null, // parameter names transforms to special annotations, so they are already taken from parameter types - returnType, - lambda.isSuspend - ) - - trace.recordType(ktArgumentExpression, substitutedFunctionalType) - } - private fun NewTypeSubstitutor.toOldSubstitution(): TypeSubstitution = object : TypeSubstitution() { override fun get(key: KotlinType): TypeProjection? { return safeSubstitute(key.unwrap()).takeIf { it !== key }?.asTypeProjection() @@ -567,3 +550,11 @@ class ResolvedAtomCompleter( expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext) } } + +class FunctionLiteralTypes( + val returnType: ProcessedType, + val parameterTypes: List, + val receiverType: ProcessedType? +) { + class ProcessedType(val substitutedType: KotlinType, val approximatedType: KotlinType) +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 604a8d18588..7791cb46ad7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -554,7 +554,7 @@ class DoubleColonExpressionResolver( val dataFlowInfo = (lhs as? DoubleColonLHS.Expression)?.dataFlowInfo ?: c.dataFlowInfo if (c.inferenceSession is CoroutineInferenceSession && result?.contains { it is StubType } == true) { - c.inferenceSession.addSimpleCall(expression) + c.inferenceSession.addOldCallableReferenceCalls(expression) } return dataFlowAnalyzer.checkType(createTypeInfo(result, dataFlowInfo), expression, c) diff --git a/compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt b/compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt new file mode 100644 index 00000000000..c29ba629fc9 --- /dev/null +++ b/compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt @@ -0,0 +1,38 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -EXPERIMENTAL_IS_NOT_ENABLED +// WITH_RUNTIME + +import kotlin.experimental.ExperimentalTypeInference + +@OptIn(ExperimentalTypeInference::class) +class A1 { + fun builder1(@BuilderInference configure: A2.() -> Unit) {} +} + +@OptIn(ExperimentalTypeInference::class) +class A2 { + fun builder2(@BuilderInference configure: A3.() -> Unit) {} +} + +@OptIn(ExperimentalTypeInference::class) +class A3 { + fun builder3(@BuilderInference configure: A4.() -> Unit) {} +} + +class A4 { + fun resolver(x: A3_BT3) {} +} + +fun foo(x: A1) { + x.builder1 { + builder2 { + builder3 { + resolver("") + } + } + } +} + +fun box(): String { + foo(A1()) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt b/compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt new file mode 100644 index 00000000000..44920b5d9dc --- /dev/null +++ b/compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt @@ -0,0 +1,29 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -EXPERIMENTAL_IS_NOT_ENABLED +// WITH_RUNTIME + +import kotlin.experimental.ExperimentalTypeInference + +@OptIn(ExperimentalTypeInference::class) +class A1 { + fun builder1(@BuilderInference configure: A2.() -> Unit) {} +} + +@OptIn(ExperimentalTypeInference::class) +class A2 { + fun builder2(@BuilderInference configure: A3.() -> Unit) {} +} + +class A3 { + fun resolver(x: A3_BT2) {} +} + +fun foo(x: A1) { + x.builder1 { + builder2 { resolver("") } + } +} + +fun box(): String { + foo(A1()) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/AutoCreatedIt.kt b/compiler/testData/diagnostics/tests/AutoCreatedIt.kt index 464e073ea33..98887c13f9e 100644 --- a/compiler/testData/diagnostics/tests/AutoCreatedIt.kt +++ b/compiler/testData/diagnostics/tests/AutoCreatedIt.kt @@ -3,8 +3,8 @@ fun text() { "direct:a" to "mock:a" "direct:a" on {it.body == ""} to "mock:a" "direct:a" on {it -> it.body == ""} to "mock:a" - bar {1} - bar {it + 1} + bar {1} + bar {it + 1} bar {it, it1 -> it} bar1 {1} @@ -13,7 +13,7 @@ fun text() { bar2 {} bar2 {1} bar2 {it} - bar2 {it -> it} + bar2 {it -> it} } fun bar(f : (Int, Int) -> Int) {} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt index 1d277074ce7..d86531c5941 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.kt @@ -30,9 +30,9 @@ fun test1() { } - foo2 { + foo2 { "" - } + } foo2 { s: String -> "" } diff --git a/compiler/testData/diagnostics/tests/inference/completionOfMultipleLambdas.kt b/compiler/testData/diagnostics/tests/inference/completionOfMultipleLambdas.kt index 48f29d39ac4..97d310dc5a7 100644 --- a/compiler/testData/diagnostics/tests/inference/completionOfMultipleLambdas.kt +++ b/compiler/testData/diagnostics/tests/inference/completionOfMultipleLambdas.kt @@ -11,7 +11,7 @@ fun test() { kotlin.Unit")!>select3( { a: A, b: A -> Unit }, { b, a -> Unit }, - { it; Unit } + { it; Unit } ) } diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.kt index eca619784db..86615a01a8a 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.kt @@ -46,9 +46,9 @@ fun test1() { // to extension lambda 0 val w11 = W1 { i: Int -> i } // oi- ni- val i11: E0 = id { i: Int -> i } // o1+ ni+ - val w12 = W1 { i -> i } // oi- ni- - val i12: E0 = id { i -> i } // oi- ni- - val j12 = id { i -> i } // oi- ni- + val w12 = W1 { i -> i } // oi- ni- + val i12: E0 = id { i -> i } // oi- ni- + val j12 = id { i -> i } // oi- ni- // yet unsupported cases - considering lambdas as extension ones unconditionally // val w13 = W1 { it } // this or it: oi- ni- diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index a0c76e07f13..c82e87b6838 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -16987,6 +16987,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @Test + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @Test + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index ffd3d070ab1..dbfa4f4d912 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -16987,6 +16987,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @Test + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @Test + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e10f80f65bd..ef7967fe814 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -14067,6 +14067,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { runTest("compiler/testData/codegen/box/inference/builderInference/propagateInferenceSessionIntoDeclarationAnalyzers.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ReceiverParameterDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ReceiverParameterDescriptorImpl.java index a2a04279f70..4c3147a5e6a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ReceiverParameterDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ReceiverParameterDescriptorImpl.java @@ -57,7 +57,7 @@ public class ReceiverParameterDescriptorImpl extends AbstractReceiverParameterDe } public void setOutType(@NotNull KotlinType outType) { - assert TypeUtilsKt.shouldBeSubstituted(this.value.getType()); + assert TypeUtilsKt.shouldBeUpdated(this.value.getType()); this.value = value.replaceType(outType); } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/VariableDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/VariableDescriptorImpl.java index b96d76d1edd..2bc836912e3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/VariableDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/VariableDescriptorImpl.java @@ -50,7 +50,7 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorNonRoo } public void setOutType(KotlinType outType) { - assert this.outType == null || TypeUtilsKt.shouldBeSubstituted(this.outType); + assert this.outType == null || TypeUtilsKt.shouldBeUpdated(this.outType); this.outType = outType; } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index bc57c873ba0..8990cc01e61 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -308,4 +308,4 @@ private fun NewCapturedType.unCaptureTopLevelType(): UnwrappedType { return constructor.projection.type.unwrap() } -fun KotlinType.shouldBeSubstituted() = contains { it is StubType || it.constructor is TypeVariableTypeConstructorMarker } +fun KotlinType.shouldBeUpdated() = contains { it is StubType || it.constructor is TypeVariableTypeConstructorMarker || it.isError } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index fc94c3436ab..c7ec2672952 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -12356,6 +12356,16 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { runTest("compiler/testData/codegen/box/inference/builderInference/propagateInferenceSessionIntoDeclarationAnalyzers.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 0e68391fdd0..1ebfb78162e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -11777,6 +11777,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { runTest("compiler/testData/codegen/box/inference/builderInference/propagateInferenceSessionIntoDeclarationAnalyzers.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index c7432d3e7be..5accdff17c8 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -11842,6 +11842,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { runTest("compiler/testData/codegen/box/inference/builderInference/propagateInferenceSessionIntoDeclarationAnalyzers.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 18605827157..c4c77956256 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -6288,6 +6288,16 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/inference/builderInference/lackOfNullCheckOnNullableInsideBuild.kt"); } + @TestMetadata("multiStepCompletionWithinThreeBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinThreeBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinThreeBuilderInferenceCalls.kt"); + } + + @TestMetadata("multiStepCompletionWithinTwoBuilderInferenceCalls.kt") + public void testMultiStepCompletionWithinTwoBuilderInferenceCalls() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/multiStepCompletionWithinTwoBuilderInferenceCalls.kt"); + } + @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { runTest("compiler/testData/codegen/box/inference/builderInference/propagateInferenceSessionIntoDeclarationAnalyzers.kt");