diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index a12be7e9920..2ef8a32b41d 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -10741,6 +10741,44 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte public void testWithExact() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); } + + @TestMetadata("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PostponedArgumentsAnalysis extends AbstractFirOldFrontendDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPostponedArgumentsAnalysis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt"); + } + + @TestMetadata("callableReferenceLambdaCombinationInsideCall.kt") + public void testCallableReferenceLambdaCombinationInsideCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.kt"); + } + + @TestMetadata("callableReferences.kt") + public void testCallableReferences() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.kt"); + } + + @TestMetadata("lackOfDeepIncorporation.kt") + public void testLackOfDeepIncorporation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt"); + } + + @TestMetadata("lambdasInTryCatch.kt") + public void testLambdasInTryCatch() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt"); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/inference/constraints") diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java index c4e4ca48d69..5d9b819ede9 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java @@ -2059,6 +2059,82 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/completion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Completion extends AbstractFirOldFrontendDiagnosticsTestWithStdlib { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCompletion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PostponedArgumentsAnalysis extends AbstractFirOldFrontendDiagnosticsTestWithStdlib { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPostponedArgumentsAnalysis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("callableReferences.kt") + public void testCallableReferences() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.kt"); + } + + @TestMetadata("complexInterdependentInputOutputTypes.kt") + public void testComplexInterdependentInputOutputTypes() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.kt"); + } + + @TestMetadata("deepLambdas.kt") + public void testDeepLambdas() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.kt"); + } + + @TestMetadata("fixIndependentVariables.kt") + public void testFixIndependentVariables() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.kt"); + } + + @TestMetadata("fixInputTypeToMoreSpecificType.kt") + public void testFixInputTypeToMoreSpecificType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.kt"); + } + + @TestMetadata("fixReceiverToMoreSpecificType.kt") + public void testFixReceiverToMoreSpecificType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.kt"); + } + + @TestMetadata("moreSpecificOutputType.kt") + public void testMoreSpecificOutputType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.kt"); + } + + @TestMetadata("rerunStagesAfterFixationInFullMode.kt") + public void testRerunStagesAfterFixationInFullMode() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.kt"); + } + + @TestMetadata("rerunStagesAfterFixationInPartialMode.kt") + public void testRerunStagesAfterFixationInPartialMode() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.kt"); + } + + @TestMetadata("suspendFunctions.kt") + public void testSuspendFunctions() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.kt"); + } + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/delegates") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 032e13f41c9..173198ae998 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -204,6 +204,8 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo return this.typeConstructor().isUnitTypeConstructor() && !this.isNullable } + override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype() = TODO() + override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker { require(this is ConeKotlinType) return this.withNullability(ConeNullability.create(nullable), this@ConeInferenceContext) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index e3e0f446623..ec6f82b9ec0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt @@ -93,7 +93,7 @@ private fun extraLambdaInfo( val isFunctionSupertype = expectedType != null && KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType) val argumentAsFunctionExpression = argument.safeAs() - val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L") + val typeVariable = TypeVariableForLambdaReturnType(builtIns, "_L") val receiverType = argumentAsFunctionExpression?.receiverType val returnType = diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 2901f4b0454..17d8ebde48f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -150,10 +150,7 @@ class PostponedArgumentsAnalyzer( val subResolvedKtPrimitives = allReturnArguments.map { resolveKtPrimitive( c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, ReceiverInfo.notReceiver, convertedType = null - ).apply { - if (this is LambdaWithTypeVariableAsExpectedTypeAtom) - isReturnArgumentOfAnotherLambda = true - } + ) } if (!returnArgumentsInfo.returnArgumentsExist) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt index 4dae8193500..39e153045c9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.components.PostponedArgumentInputTypesResolver import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic @@ -35,4 +36,5 @@ interface NewConstraintSystem { fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context + fun asPostponedArgumentInputTypesResolverContext(): PostponedArgumentInputTypesResolver.Context } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt index 8a1b9c79658..a53eee72608 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt @@ -5,28 +5,23 @@ package org.jetbrains.kotlin.resolve.calls.inference.components -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType -import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype -import org.jetbrains.kotlin.builtins.isExtensionFunctionType -import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus -import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder -import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeVariableMarker -import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import kotlin.collections.LinkedHashSet class KotlinConstraintSystemCompleter( private val resultTypeResolver: ResultTypeResolver, val variableFixationFinder: VariableFixationFinder, ) { + private val postponedArgumentInputTypesResolver = PostponedArgumentInputTypesResolver(resultTypeResolver, variableFixationFinder) + enum class ConstraintSystemCompletionMode { FULL, PARTIAL @@ -37,6 +32,8 @@ class KotlinConstraintSystemCompleter( override val notFixedTypeVariables: Map override val postponedTypeVariables: List + fun getBuilder(): ConstraintSystemBuilder + // type can be proper if it not contains not fixed type variables fun canBeProper(type: KotlinTypeMarker): Boolean @@ -46,6 +43,8 @@ class KotlinConstraintSystemCompleter( fun addError(error: KotlinCallDiagnostic) fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, atom: ResolvedAtom?) + + fun asPostponedArgumentInputTypesResolverContext(): PostponedArgumentInputTypesResolver.Context } fun runCompletion( @@ -56,8 +55,7 @@ class KotlinConstraintSystemCompleter( diagnosticsHolder: KotlinDiagnosticsHolder, analyze: (PostponedResolvedAtom) -> Unit ) { - runCompletion( - c, + c.runCompletion( completionMode, topLevelAtoms, topLevelType, @@ -73,8 +71,7 @@ class KotlinConstraintSystemCompleter( topLevelAtoms: List, diagnosticsHolder: KotlinDiagnosticsHolder ) { - runCompletion( - c, + c.runCompletion( ConstraintSystemCompletionMode.FULL, topLevelAtoms, topLevelType, @@ -85,8 +82,8 @@ class KotlinConstraintSystemCompleter( } } - private fun runCompletion( - c: Context, + // TODO: investigate type variables fixation order and incorporation depth (see `diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt`) + private fun Context.runCompletion( completionMode: ConstraintSystemCompletionMode, topLevelAtoms: List, topLevelType: UnwrappedType, @@ -94,241 +91,242 @@ class KotlinConstraintSystemCompleter( collectVariablesFromContext: Boolean, analyze: (PostponedResolvedAtom) -> Unit ) { - while (true) { - if (analyzePostponeArgumentIfPossible(c, topLevelAtoms, analyze)) continue + completion@ while (true) { + val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) - val allTypeVariables = getOrderedAllTypeVariables(c, collectVariablesFromContext, topLevelAtoms) - val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) - val variableForFixation = - variableFixationFinder.findFirstVariableForFixation( - c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType - ) ?: break - - if ( - completionMode == ConstraintSystemCompletionMode.FULL && - c.resolveLambdaByAdditionalConditions( - variableForFixation, - topLevelAtoms, - diagnosticsHolder, - analyze, - variableFixationFinder - ) - ) { + // Stage 1: analyze postponed arguments with fixed parameter types + if (analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze)) continue + + val isThereAnyReadyForFixationVariable = isThereAnyReadyForFixationVariable( + completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext, postponedArguments + ) + + // If there aren't any postponed arguments and ready for fixation variables, then completion isn't needed: nothing to do + if (postponedArguments.isEmpty() && !isThereAnyReadyForFixationVariable) + break + + val postponedArgumentsWithRevisableType = postponedArguments.filterIsInstance() + val dependencyProvider = + TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, topLevelType, this) + + // Stage 2: collect parameter types for postponed arguments + postponedArgumentInputTypesResolver.collectParameterTypesAndBuildNewExpectedTypes( + asPostponedArgumentInputTypesResolverContext(), postponedArgumentsWithRevisableType, completionMode, dependencyProvider + ) + + if (completionMode == ConstraintSystemCompletionMode.FULL) { + // Stage 3: fix variables for parameter types of all postponed arguments + for (argument in postponedArguments) { + val wasFixedSomeVariable = postponedArgumentInputTypesResolver.fixNextReadyVariableForParameterTypeIfNeeded( + asPostponedArgumentInputTypesResolverContext(), + argument, + postponedArguments, + topLevelType, + topLevelAtoms, + dependencyProvider + ) + + if (wasFixedSomeVariable) + continue@completion + } + + // Stage 4: create atoms with revised expected types if needed + for (argument in postponedArgumentsWithRevisableType) { + postponedArgumentInputTypesResolver.transformToAtomWithNewFunctionalExpectedType( + asPostponedArgumentInputTypesResolverContext(), argument, diagnosticsHolder + ) + } } - if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) { - val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable) - - if (variableForFixation.hasProperConstraint) - fixVariable(c, variableWithConstraints, topLevelAtoms) - else - processVariableWhenNotEnoughInformation(c, variableWithConstraints, topLevelAtoms) + /* + * We should get not analyzed postponed arguments again because they can be changed by + * the stage of fixation type variables for parameters or analysing postponed arguments with fixed parameter types (see stage #1 and #4) + */ + val revisedPostponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) + // Stage 5: analyze the next ready postponed argument + if (analyzeNextReadyPostponedArgument(revisedPostponedArguments, completionMode, analyze)) continue + + // Stage 6: fix type variables – fix if possible or report not enough information (if completion mode is full) + val wasFixedSomeVariable = fixVariablesOrReportNotEnoughInformation( + completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext, revisedPostponedArguments, diagnosticsHolder + ) + if (wasFixedSomeVariable) + continue + + // Stage 7: force analysis of remaining not analyzed postponed arguments and rerun stages if there are + if (completionMode == ConstraintSystemCompletionMode.FULL) { + if (analyzeRemainingNotAnalyzedPostponedArgument(revisedPostponedArguments, analyze)) + continue } break } - - if (completionMode == ConstraintSystemCompletionMode.FULL) { - // force resolution for all not-analyzed argument's - getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze) - - if (c.notFixedTypeVariables.isNotEmpty() && c.postponedTypeVariables.isEmpty()) { - runCompletion(c, completionMode, topLevelAtoms, topLevelType, diagnosticsHolder, analyze) - } - } } - /* - * returns true -> analyzed - */ - private fun Context.resolveLambdaByAdditionalConditions( - variableForFixation: VariableFixationFinder.VariableForFixation, - topLevelAtoms: List, - diagnosticsHolder: KotlinDiagnosticsHolder, - analyze: (PostponedResolvedAtom) -> Unit, - fixationFinder: VariableFixationFinder - ): Boolean { - val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) - - if (postponedArguments.isEmpty()) - return false - - val groupedPostponedArguments = postponedArguments.filterIsInstance() - .ifEmpty { postponedArguments.filter { it !is LambdaWithTypeVariableAsExpectedTypeAtom } } - - if (groupedPostponedArguments.isEmpty()) - return false - - fun shouldAnalyzeLambdaWithTypeVariableAsExpectedType(argument: PostponedResolvedAtom): Boolean { - val hasProperAtom = when (argument) { - is LambdaWithTypeVariableAsExpectedTypeAtom, is PostponedCallableReferenceAtom -> - argument.expectedType?.constructor == variableForFixation.variable - else -> false - } - - return hasProperAtom || !variableForFixation.hasProperConstraint || variableForFixation.hasOnlyTrivialProperConstraint - } - - fun shouldAnalyzeLambdaWhichIsReturnArgument(argument: PostponedResolvedAtom): Boolean { - val isReturnArgumentOfAnotherLambda = - argument is LambdaWithTypeVariableAsExpectedTypeAtom && argument.isReturnArgumentOfAnotherLambda - val atomExpectedType = argument.expectedType - - return isReturnArgumentOfAnotherLambda && atomExpectedType != null && - with(fixationFinder) { variableHasTrivialOrNonProperConstraints(atomExpectedType.constructor) } - } - - return resolveLambdaByCondition( - variableForFixation, groupedPostponedArguments, diagnosticsHolder, analyze, ::shouldAnalyzeLambdaWithTypeVariableAsExpectedType - ) || resolveLambdaByCondition( - variableForFixation, groupedPostponedArguments, diagnosticsHolder, analyze, ::shouldAnalyzeLambdaWhichIsReturnArgument - ) - } - - /* - * returns true -> analyzed - */ - private fun Context.resolveLambdaByCondition( - variableForFixation: VariableFixationFinder.VariableForFixation, + private fun Context.analyzeArgumentWithFixedParameterTypes( postponedArguments: List, - diagnosticsHolder: KotlinDiagnosticsHolder, - analyze: (PostponedResolvedAtom) -> Unit, - shouldAnalyze: (PostponedResolvedAtom) -> Boolean - ): Boolean { - val variable = variableForFixation.variable as? TypeConstructor ?: return false - - return postponedArguments.all { argument -> - if (!shouldAnalyze(argument)) - return@all false - - val expectedTypeVariable = argument.expectedType?.constructor?.takeIf { it in allTypeVariables } ?: variable - - val preparedAtom = - preparePostponedAtom(expectedTypeVariable, argument, expectedTypeVariable.builtIns, diagnosticsHolder) - ?: return@all false - - analyze(preparedAtom) - - true - } - } - - private fun Context.preparePostponedAtom( - expectedTypeVariable: TypeConstructor, - postponedAtom: PostponedResolvedAtom, - builtIns: KotlinBuiltIns, - diagnosticsHolder: KotlinDiagnosticsHolder - ): PostponedResolvedAtom? { - val csBuilder = (this as? NewConstraintSystem)?.getBuilder() ?: return null - - return when (postponedAtom) { - is PostponedCallableReferenceAtom -> postponedAtom.preparePostponedAtomWithTypeVariableAsExpectedType( - this, csBuilder, expectedTypeVariable, - parameterTypes = null, - isSuitable = KotlinType::isBuiltinFunctionalTypeOrSubtype, - typeVariableCreator = { TypeVariableForCallableReferenceReturnType(builtIns, "_Q") }, - newAtomCreator = { returnVariable, expectedType -> - CallableReferenceWithTypeVariableAsExpectedTypeAtom(postponedAtom.atom, expectedType, returnVariable).also { - postponedAtom.setAnalyzedResults(null, listOf(it)) - } - } - ) - is LambdaWithTypeVariableAsExpectedTypeAtom -> postponedAtom.preparePostponedAtomWithTypeVariableAsExpectedType( - this, csBuilder, expectedTypeVariable, - parameterTypes = postponedAtom.atom.parametersTypes, - isSuitable = KotlinType::isBuiltinFunctionalType, - typeVariableCreator = { TypeVariableForLambdaReturnType(postponedAtom.atom, builtIns, "_R") }, - newAtomCreator = { returnVariable, expectedType -> - postponedAtom.transformToResolvedLambda(csBuilder, diagnosticsHolder, expectedType, returnVariable) - } - ) - else -> null - } - } - - private inline fun T.preparePostponedAtomWithTypeVariableAsExpectedType( - c: Context, - csBuilder: ConstraintSystemBuilder, - variable: TypeConstructor, - parameterTypes: Array?, - isSuitable: KotlinType.() -> Boolean, - typeVariableCreator: () -> V, - newAtomCreator: (V, SimpleType) -> PostponedResolvedAtom - ): PostponedResolvedAtom { - val functionalType = resultTypeResolver.findResultType( - c, - c.notFixedTypeVariables.getValue(variable), - TypeVariableDirectionCalculator.ResolveDirection.TO_SUPERTYPE - ) as KotlinType - - val isExtensionFunction = functionalType.isExtensionFunctionType - val isExtensionFunctionWithReceiverAsDeclaredParameter = - isExtensionFunction && functionalType.arguments.size - 1 == parameterTypes?.count { it != null } - if (parameterTypes?.all { it != null } == true && (!isExtensionFunction || isExtensionFunctionWithReceiverAsDeclaredParameter)) return this - - if (!functionalType.isSuitable()) return this - val returnVariable = typeVariableCreator() - csBuilder.registerVariable(returnVariable) - val expectedType = KotlinTypeFactory.simpleType( - functionalType.annotations, - functionalType.constructor, - functionalType.arguments.dropLast(1) + returnVariable.defaultType.asTypeProjection(), - functionalType.isMarkedNullable - ) - csBuilder.addSubtypeConstraint( - expectedType, - variable.typeForTypeVariable(), - ArgumentConstraintPosition(atom as KotlinCallArgument) - ) - return newAtomCreator(returnVariable, expectedType) - } - - // true if we do analyze - private fun analyzePostponeArgumentIfPossible( - c: Context, - topLevelAtoms: List, analyze: (PostponedResolvedAtom) -> Unit ): Boolean { - for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)) { - ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() - if (canWeAnalyzeIt(c, argument)) { - analyze(argument) - return true - } + val argumentWithFixedOrPostponedInputTypes = findPostponedArgumentWithFixedOrPostponedInputTypes(postponedArguments) + + if (argumentWithFixedOrPostponedInputTypes != null) { + analyze(argumentWithFixedOrPostponedInputTypes) + return true } + return false } - private fun getOrderedAllTypeVariables( + private fun Context.analyzeNextReadyPostponedArgument( + postponedArguments: List, + completionMode: ConstraintSystemCompletionMode, + analyze: (PostponedResolvedAtom) -> Unit + ): Boolean { + if (completionMode == ConstraintSystemCompletionMode.FULL) { + val argumentWithTypeVariableAsExpectedType = findPostponedArgumentWithRevisableExpectedType(postponedArguments) + + if (argumentWithTypeVariableAsExpectedType != null) { + analyze(argumentWithTypeVariableAsExpectedType) + return true + } + } + + return analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze) + } + + private fun analyzeRemainingNotAnalyzedPostponedArgument( + postponedArguments: List, + analyze: (PostponedResolvedAtom) -> Unit + ): Boolean { + val remainingNotAnalyzedPostponedArgument = postponedArguments.firstOrNull { !it.analyzed } + + if (remainingNotAnalyzedPostponedArgument != null) { + analyze(remainingNotAnalyzedPostponedArgument) + return true + } + + return false + } + + private fun findPostponedArgumentWithRevisableExpectedType(postponedArguments: List) = + postponedArguments.firstOrNull { argument -> argument is PostponedAtomWithRevisableExpectedType } + + private fun Context.findPostponedArgumentWithFixedOrPostponedInputTypes(postponedArguments: List) = + postponedArguments.firstOrNull { argument -> argument.inputTypes.all { containsOnlyFixedOrPostponedVariables(it) } } + + private fun fixVariable( c: Context, + variableWithConstraints: VariableWithConstraints, + topLevelAtoms: List + ) { + fixVariable(c, variableWithConstraints, TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN, topLevelAtoms) + } + + private fun fixVariable( + c: Context, + variableWithConstraints: VariableWithConstraints, + direction: TypeVariableDirectionCalculator.ResolveDirection, + topLevelAtoms: List + ) { + val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction) + val resolvedAtom = findResolvedAtomBy(variableWithConstraints.typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull() + c.fixVariable(variableWithConstraints.typeVariable, resultType, resolvedAtom) + } + + private fun Context.fixVariablesOrReportNotEnoughInformation( + completionMode: ConstraintSystemCompletionMode, + topLevelAtoms: List, + topLevelType: UnwrappedType, + collectVariablesFromContext: Boolean, + postponedArguments: List, + diagnosticsHolder: KotlinDiagnosticsHolder + ): Boolean { + while (true) { + val variableForFixation = getVariableReadyForFixation( + completionMode, + topLevelAtoms, + topLevelType, + collectVariablesFromContext, + postponedArguments + ) ?: break + + if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL) + break + + val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable) + + if (variableForFixation.hasProperConstraint) { + fixVariable(this, variableWithConstraints, topLevelAtoms) + return true + } else { + processVariableWhenNotEnoughInformation(this, variableWithConstraints, topLevelAtoms, diagnosticsHolder) + } + } + + return false + } + + private fun processVariableWhenNotEnoughInformation( + c: Context, + variableWithConstraints: VariableWithConstraints, + topLevelAtoms: List, + diagnosticsHolder: KotlinDiagnosticsHolder + ) { + val typeVariable = variableWithConstraints.typeVariable + val resolvedAtom = findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull() + + if (resolvedAtom != null) { + c.addError(NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom)) + } + + val resultErrorType = when { + typeVariable is TypeVariableFromCallableDescriptor -> + ErrorUtils.createUninferredParameterType(typeVariable.originalTypeParameter) + typeVariable is TypeVariableForLambdaParameterType && typeVariable.atom is LambdaKotlinCallArgument -> { + diagnosticsHolder.addDiagnostic( + NotEnoughInformationForLambdaParameter(typeVariable.atom, typeVariable.index) + ) + ErrorUtils.createErrorType("Cannot infer lambda parameter type") + } + else -> ErrorUtils.createErrorType("Cannot infer type variable $typeVariable") + } + + c.fixVariable(typeVariable, resultErrorType, resolvedAtom) + } + + private fun Context.getOrderedAllTypeVariables( collectVariablesFromContext: Boolean, topLevelAtoms: List ): List { - if (collectVariablesFromContext) return c.notFixedTypeVariables.keys.toList() + if (collectVariablesFromContext) + return notFixedTypeVariables.keys.toList() + + fun getVariablesFromRevisedExpectedType(revisedExpectedType: KotlinType?) = + revisedExpectedType?.arguments?.map { it.type.constructor }?.filterIsInstance() fun ResolvedAtom.process(to: LinkedHashSet) { val typeVariables = when (this) { - is ResolvedCallAtom -> freshVariablesSubstitutor.freshVariables - is CallableReferenceWithTypeVariableAsExpectedTypeAtom -> mutableListOf().apply { - addIfNotNull(typeVariableForReturnType) - addAll(candidate?.freshSubstitutor?.freshVariables.orEmpty()) - } - is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables.orEmpty() - is ResolvedLambdaAtom -> listOfNotNull(typeVariableForLambdaReturnType) + is LambdaWithTypeVariableAsExpectedTypeAtom -> getVariablesFromRevisedExpectedType(revisedExpectedType).orEmpty() + is ResolvedCallAtom -> freshVariablesSubstitutor.freshVariables.map { it.freshTypeConstructor } + is PostponedCallableReferenceAtom -> + getVariablesFromRevisedExpectedType(revisedExpectedType).orEmpty() + + candidate?.freshSubstitutor?.freshVariables?.map { it.freshTypeConstructor }.orEmpty() + is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables?.map { it.freshTypeConstructor }.orEmpty() + is ResolvedLambdaAtom -> listOfNotNull(typeVariableForLambdaReturnType?.freshTypeConstructor) else -> emptyList() } + typeVariables.mapNotNullTo(to) { - val typeConstructor = it.freshTypeConstructor - typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) } + it.takeIf { notFixedTypeVariables.containsKey(it) } } /* * Hack for completing error candidates in delegate resolve */ - if (this is StubResolvedAtom && typeVariable in c.notFixedTypeVariables) { + if (this is StubResolvedAtom && typeVariable in notFixedTypeVariables) { to += typeVariable } @@ -343,86 +341,35 @@ class KotlinConstraintSystemCompleter( primitive.process(result) } - assert(result.size == c.notFixedTypeVariables.size) { - val notFoundTypeVariables = c.notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) } + assert(result.size == notFixedTypeVariables.size) { + val notFoundTypeVariables = notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) } "Not all type variables found: $notFoundTypeVariables" } return result.toList() } + private fun Context.getVariableReadyForFixation( + completionMode: ConstraintSystemCompletionMode, + topLevelAtoms: List, + topLevelType: UnwrappedType, + collectVariablesFromContext: Boolean, + postponedArguments: List + ) = variableFixationFinder.findFirstVariableForFixation( + this, + getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), + postponedArguments, + completionMode, + topLevelType + ) - private fun canWeAnalyzeIt(c: Context, argument: PostponedResolvedAtom): Boolean { - if (argument.analyzed) return false - - return argument.inputTypes.all { c.containsOnlyFixedOrPostponedVariables(it) } - } - - private fun fixVariable( - c: Context, - variableWithConstraints: VariableWithConstraints, - topLevelAtoms: List - ) { - fixVariable(c, variableWithConstraints, TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN, topLevelAtoms) - } - - fun fixVariable( - c: Context, - variableWithConstraints: VariableWithConstraints, - direction: TypeVariableDirectionCalculator.ResolveDirection, - topLevelAtoms: List - ) { - val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction) - val resolvedAtom = findResolvedAtomBy(variableWithConstraints.typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull() - c.fixVariable(variableWithConstraints.typeVariable, resultType, resolvedAtom) - } - - private fun processVariableWhenNotEnoughInformation( - c: Context, - variableWithConstraints: VariableWithConstraints, - topLevelAtoms: List - ) { - val typeVariable = variableWithConstraints.typeVariable - - val resolvedAtom = findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull() - if (resolvedAtom != null) { - c.addError(NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom)) - } - - val resultErrorType = if (typeVariable is TypeVariableFromCallableDescriptor) - ErrorUtils.createUninferredParameterType(typeVariable.originalTypeParameter) - else - ErrorUtils.createErrorType("Cannot infer type variable $typeVariable") - - c.fixVariable(typeVariable, resultErrorType, resolvedAtom) - } - - private fun findResolvedAtomBy(typeVariable: TypeVariableMarker, topLevelAtoms: List): ResolvedAtom? { - fun ResolvedAtom.check(): ResolvedAtom? { - val suitableCall = when (this) { - is ResolvedCallAtom -> typeVariable in freshVariablesSubstitutor.freshVariables - is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables?.let { typeVariable in it } ?: false - is ResolvedLambdaAtom -> typeVariable == typeVariableForLambdaReturnType - else -> false - } - - if (suitableCall) { - return this - } - - subResolvedAtoms?.forEach { subResolvedAtom -> - subResolvedAtom.check()?.let { result -> return@check result } - } - - return null - } - - for (topLevelAtom in topLevelAtoms) { - topLevelAtom.check()?.let { return it } - } - - return null - } + private fun Context.isThereAnyReadyForFixationVariable( + completionMode: ConstraintSystemCompletionMode, + topLevelAtoms: List, + topLevelType: UnwrappedType, + collectVariablesFromContext: Boolean, + postponedArguments: List + ) = getVariableReadyForFixation(completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext, postponedArguments) != null companion object { fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List): List { @@ -441,5 +388,32 @@ class KotlinConstraintSystemCompleter( return notAnalyzedArguments } + + fun findResolvedAtomBy(typeVariable: TypeVariableMarker, topLevelAtoms: List): ResolvedAtom? { + fun ResolvedAtom.check(): ResolvedAtom? { + val suitableCall = when (this) { + is ResolvedCallAtom -> typeVariable in freshVariablesSubstitutor.freshVariables + is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables?.let { typeVariable in it } ?: false + is ResolvedLambdaAtom -> typeVariable == typeVariableForLambdaReturnType + else -> false + } + + if (suitableCall) { + return this + } + + subResolvedAtoms?.forEach { subResolvedAtom -> + subResolvedAtom.check()?.let { result -> return@check result } + } + + return null + } + + for (topLevelAtom in topLevelAtoms) { + topLevelAtom.check()?.let { return it } + } + + return null + } } -} \ No newline at end of file +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt new file mode 100644 index 00000000000..01566a569b6 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt @@ -0,0 +1,473 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.inference.components + +import org.jetbrains.kotlin.builtins.* +import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda +import org.jetbrains.kotlin.resolve.calls.inference.model.* +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.builtIns +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +class PostponedArgumentInputTypesResolver( + private val resultTypeResolver: ResultTypeResolver, + private val variableFixationFinder: VariableFixationFinder +) { + interface Context : KotlinConstraintSystemCompleter.Context + + data class ParameterTypesInfo( + val parametersFromDeclaration: List?, + val parametersFromDeclarationOfRelatedLambdas: Set>?, + val parametersFromConstraints: Set>?, + val annotations: Annotations, + val isSuspend: Boolean, + val isNullable: Boolean + ) + + data class TypeWithKind( + val type: KotlinType, + val direction: ConstraintKind = ConstraintKind.UPPER + ) + + private fun Context.findFunctionalTypesInConstraints( + variable: VariableWithConstraints, + variableDependencyProvider: TypeVariableDependencyInformationProvider + ): List? { + fun List.extractFunctionalTypes() = mapNotNull { constraint -> + val type = constraint.type as? KotlinType ?: return@mapNotNull null + TypeWithKind(type.extractFunctionalTypeFromSupertypes(), constraint.kind) + } + + val typeVariableTypeConstructor = variable.typeVariable.freshTypeConstructor() as? TypeVariableTypeConstructor ?: return null + val dependentVariables = + variableDependencyProvider.getShallowlyDependentVariables(typeVariableTypeConstructor).orEmpty() + typeVariableTypeConstructor + + return dependentVariables.mapNotNull { type -> + val constraints = notFixedTypeVariables[type]?.constraints ?: return@mapNotNull null + val constraintsWithFunctionalType = constraints.filter { (it.type as? KotlinType)?.isBuiltinFunctionalTypeOrSubtype == true } + constraintsWithFunctionalType.extractFunctionalTypes() + }.flatten() + } + + private fun extractParameterTypesFromDeclaration(atom: ResolutionAtom) = + when (atom) { + is FunctionExpression -> { + val receiverType = atom.receiverType + if (receiverType != null) listOf(receiverType) + atom.parametersTypes else atom.parametersTypes.toList() + } + is LambdaKotlinCallArgument -> atom.parametersTypes?.toList() + else -> null + } + + private fun Context.extractParameterTypesInfo( + argument: PostponedAtomWithRevisableExpectedType, + postponedArguments: List, + variableDependencyProvider: TypeVariableDependencyInformationProvider + ): ParameterTypesInfo? { + val expectedType = argument.expectedType ?: return null + val variableWithConstraints = notFixedTypeVariables[expectedType.constructor] ?: return null + + // We shouldn't collect functional types from constraints for anonymous functions as they have fully explicit declaration form + val functionalTypesFromConstraints = if (!isAnonymousFunction(argument)) { + findFunctionalTypesInConstraints(variableWithConstraints, variableDependencyProvider) + } else null + + // Don't create functional expected type for further error reporting about a different number of arguments + if (functionalTypesFromConstraints != null && functionalTypesFromConstraints.distinctBy { it.type.argumentsCount() }.size > 1) + return null + + val parameterTypesFromDeclaration = + if (argument is LambdaWithTypeVariableAsExpectedTypeAtom) argument.parameterTypesFromDeclaration else null + + val parameterTypesFromConstraints = functionalTypesFromConstraints?.map { typeWithKind -> + typeWithKind.type.getPureArgumentsForFunctionalTypeOrSubtype().map { + // We should use opposite kind as lambda's parameters are contravariant + TypeWithKind(it, typeWithKind.direction.opposite()) + } + }?.toSet() + + val annotations = functionalTypesFromConstraints?.run { + Annotations.create(map { it.type.annotations }.flatten()) + } + + val parameterTypesFromDeclarationOfRelatedLambdas = + getDeclaredParametersFromRelatedLambdas(argument, postponedArguments, variableDependencyProvider) + + return ParameterTypesInfo( + parameterTypesFromDeclaration, + parameterTypesFromDeclarationOfRelatedLambdas, + parameterTypesFromConstraints, + annotations ?: Annotations.EMPTY, + isSuspend = !functionalTypesFromConstraints.isNullOrEmpty() && functionalTypesFromConstraints.any { it.type.isSuspendFunctionTypeOrSubtype }, + isNullable = !functionalTypesFromConstraints.isNullOrEmpty() && functionalTypesFromConstraints.all { it.type.isMarkedNullable } + ) + } + + private fun Context.getDeclaredParametersFromRelatedLambdas( + argument: PostponedAtomWithRevisableExpectedType, + postponedArguments: List, + dependencyProvider: TypeVariableDependencyInformationProvider + ): Set>? { + fun PostponedAtomWithRevisableExpectedType.getExpectedTypeConstructor() = expectedType?.typeConstructor() + + val parameterTypesFromDeclarationOfRelatedLambdas = postponedArguments + .filterIsInstance() + .filter { it.parameterTypesFromDeclaration != null && it != argument } + .mapNotNull { anotherArgument -> + val argumentExpectedTypeConstructor = argument.getExpectedTypeConstructor() ?: return@mapNotNull null + val anotherArgumentExpectedTypeConstructor = anotherArgument.getExpectedTypeConstructor() ?: return@mapNotNull null + val areTypeVariablesRelated = dependencyProvider.areVariablesDependentShallowly( + argumentExpectedTypeConstructor, + anotherArgumentExpectedTypeConstructor + ) + + if (areTypeVariablesRelated) anotherArgument.parameterTypesFromDeclaration else null + } + + return parameterTypesFromDeclarationOfRelatedLambdas.toSet().takeIf { it.isNotEmpty() } + } + + private fun Context.createTypeVariableForReturnType(argument: PostponedAtomWithRevisableExpectedType): NewTypeVariable { + val expectedType = argument.expectedType + ?: throw IllegalStateException("Postponed argument's expected type must not be null") + + return when (argument) { + is LambdaWithTypeVariableAsExpectedTypeAtom -> TypeVariableForLambdaReturnType( + expectedType.builtIns, + TYPE_VARIABLE_NAME_FOR_LAMBDA_RETURN_TYPE + ) + is PostponedCallableReferenceAtom -> TypeVariableForCallableReferenceReturnType( + expectedType.builtIns, + TYPE_VARIABLE_NAME_FOR_CR_RETURN_TYPE + ) + else -> throw IllegalStateException("Unsupported postponed argument type of $argument") + }.also { getBuilder().registerVariable(it) } + } + + private fun Context.createTypeVariableForParameterType( + argument: PostponedAtomWithRevisableExpectedType, + index: Int + ): NewTypeVariable { + val expectedType = argument.expectedType + ?: throw IllegalStateException("Postponed argument's expected type must not be null") + + return when (argument) { + is LambdaWithTypeVariableAsExpectedTypeAtom -> TypeVariableForLambdaParameterType( + argument.atom, + index, + expectedType.builtIns, + TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE + (index + 1) + ) + is PostponedCallableReferenceAtom -> TypeVariableForCallableReferenceParameterType( + expectedType.builtIns, + TYPE_VARIABLE_NAME_PREFIX_FOR_CR_PARAMETER_TYPE + (index + 1) + ) + else -> throw IllegalStateException("Unsupported postponed argument type of $argument") + }.also { getBuilder().registerVariable(it) } + } + + private fun Context.createTypeVariablesForParameters( + argument: PostponedAtomWithRevisableExpectedType, + parameterTypes: List> + ): List { + val atom = argument.atom + val csBuilder = getBuilder() + val allGroupedParameterTypes = parameterTypes.first().indices.map { i -> parameterTypes.map { it.getOrNull(i) } } + + return allGroupedParameterTypes.mapIndexed { index, types -> + val parameterTypeVariable = createTypeVariableForParameterType(argument, index) + + for (typeWithKind in types.filterNotNull()) { + when (typeWithKind.direction) { + ConstraintKind.EQUALITY -> csBuilder.addEqualityConstraint( + parameterTypeVariable.defaultType, typeWithKind.type, ArgumentConstraintPosition(atom) + ) + ConstraintKind.UPPER -> csBuilder.addSubtypeConstraint( + parameterTypeVariable.defaultType, typeWithKind.type, ArgumentConstraintPosition(atom) + ) + ConstraintKind.LOWER -> csBuilder.addSubtypeConstraint( + typeWithKind.type, parameterTypeVariable.defaultType, ArgumentConstraintPosition(atom) + ) + } + } + + parameterTypeVariable.defaultType.asTypeProjection() + } + } + + private fun Context.computeResultingFunctionalConstructor( + argument: PostponedAtomWithRevisableExpectedType, + parametersNumber: Int, + isSuspend: Boolean, + resultTypeResolver: ResultTypeResolver + ): TypeConstructor { + val expectedType = argument.expectedType + ?: throw IllegalStateException("Postponed argument's expected type must not be null") + + val expectedTypeConstructor = expectedType.constructor + + return when (argument) { + is LambdaWithTypeVariableAsExpectedTypeAtom -> + getFunctionDescriptor(expectedTypeConstructor.builtIns, parametersNumber, isSuspend).typeConstructor + is PostponedCallableReferenceAtom -> { + val computedResultType = resultTypeResolver.findResultType( + this, + notFixedTypeVariables.getValue(expectedTypeConstructor), + TypeVariableDirectionCalculator.ResolveDirection.TO_SUPERTYPE + ) + + // Avoid KFunction<...>/Function<...> types + if (computedResultType.isBuiltinFunctionalTypeOrSubtype() && computedResultType.argumentsCount() > 1) { + computedResultType.typeConstructor() as TypeConstructor + } else { + getKFunctionDescriptor(expectedTypeConstructor.builtIns, parametersNumber, isSuspend).typeConstructor + } + } + else -> throw IllegalStateException("Unsupported postponed argument type of $argument") + } + } + + private fun Context.buildNewFunctionalExpectedType( + argument: PostponedAtomWithRevisableExpectedType, + parameterTypesInfo: ParameterTypesInfo + ): UnwrappedType? { + val expectedType = argument.expectedType + + if (expectedType == null || expectedType.constructor !in notFixedTypeVariables) + return null + + val atom = argument.atom + val parametersFromConstraints = parameterTypesInfo.parametersFromConstraints + val parametersFromDeclaration = getDeclaredParametersConsideringExtensionFunctionsPresence(parameterTypesInfo) + val areAllParameterTypesSpecified = !parametersFromDeclaration.isNullOrEmpty() && parametersFromDeclaration.all { it != null } + val isExtensionFunction = parameterTypesInfo.annotations.hasExtensionFunctionAnnotation() + val parametersFromDeclarations = parameterTypesInfo.parametersFromDeclarationOfRelatedLambdas.orEmpty() + parametersFromDeclaration + + /* + * We shouldn't create synthetic functional type if all lambda's parameter types are specified explicitly + * + * TODO: regarding anonymous functions: see info about need for analysis in partial mode in `collectParameterTypesAndBuildNewExpectedTypes` + */ + if (areAllParameterTypesSpecified && !isExtensionFunction && !isAnonymousFunction(argument)) + return null + + val allParameterTypes = + (parametersFromConstraints.orEmpty() + parametersFromDeclarations.map { parameters -> parameters?.map { it.wrapToTypeWithKind() } }).filterNotNull() + + if (allParameterTypes.isEmpty()) + return null + + val variablesForParameterTypes = createTypeVariablesForParameters(argument, allParameterTypes) + val variableForReturnType = createTypeVariableForReturnType(argument) + val functionalConstructor = computeResultingFunctionalConstructor( + argument, + variablesForParameterTypes.size, + parameterTypesInfo.isSuspend, + resultTypeResolver + ) + + val isExtensionFunctionType = parameterTypesInfo.annotations.hasExtensionFunctionAnnotation() + val areParametersNumberInDeclarationAndConstraintsEqual = + !parametersFromDeclaration.isNullOrEmpty() && !parametersFromConstraints.isNullOrEmpty() + && parametersFromDeclaration.size == parametersFromConstraints.first().size + + /* + * We need to exclude further considering a postponed argument as an extension function + * to support cases with explicitly specified receiver as a value parameter (only if all parameter types are specified) + * + * Example: `val x: String.() -> Int = id { x: String -> 42 }` + */ + val shouldDiscriminateExtensionFunctionAnnotation = + isExtensionFunctionType && areAllParameterTypesSpecified && areParametersNumberInDeclarationAndConstraintsEqual + + /* + * We need to add an extension function annotation for anonymous functions with an explicitly specified receiver + * + * Example: `val x = id(fun String.() = this)` + */ + val shouldAddExtensionFunctionAnnotation = atom is FunctionExpression && atom.receiverType != null + + val annotations = when { + shouldDiscriminateExtensionFunctionAnnotation -> + parameterTypesInfo.annotations.withoutExtensionFunctionAnnotation() + shouldAddExtensionFunctionAnnotation -> + parameterTypesInfo.annotations.withExtensionFunctionAnnotation(expectedType.builtIns) + else -> parameterTypesInfo.annotations + } + + val nexExpectedType = KotlinTypeFactory.simpleType( + annotations, + functionalConstructor, + variablesForParameterTypes + variableForReturnType.defaultType.asTypeProjection(), + parameterTypesInfo.isNullable + ) + + getBuilder().addSubtypeConstraint( + nexExpectedType, + expectedType, + ArgumentConstraintPosition(argument.atom) + ) + + return nexExpectedType + } + + fun collectParameterTypesAndBuildNewExpectedTypes( + c: Context, + postponedArguments: List, + completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode, + dependencyProvider: TypeVariableDependencyInformationProvider + ) { + // We can collect parameter types from declaration in any mode, they can't change during completion. + val postponedArgumentsToCollectTypesFromDeclaredParameters = postponedArguments + .filterIsInstance() + .filter { it.parameterTypesFromDeclaration == null } + + for (argument in postponedArgumentsToCollectTypesFromDeclaredParameters) { + argument.parameterTypesFromDeclaration = extractParameterTypesFromDeclaration(argument.atom) + } + + /* + * We can build new functional expected types in partial mode only for anonymous functions, + * because more exact type can't appear from constraints in full mode (anonymous functions have fully explicit declaration). + * It can be so for lambdas: for instance, an extension function type can appear in full mode (it may not be known in partial mode). + * + * TODO: investigate why we can't do it for anonymous functions in full mode always (see `diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt`) + */ + val postponedArgumentsToCollectParameterTypesAndBuildNewExpectedType = + if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL) { + postponedArguments.filter(::isAnonymousFunction) + } else { + postponedArguments + } + + do { + val wasTransformedSomePostponedArgument = + postponedArgumentsToCollectParameterTypesAndBuildNewExpectedType.filter { it.revisedExpectedType == null }.any { argument -> + val parameterTypesInfo = + c.extractParameterTypesInfo(argument, postponedArguments, dependencyProvider) ?: return@any false + val newExpectedType = + c.buildNewFunctionalExpectedType(argument, parameterTypesInfo) ?: return@any false + + argument.revisedExpectedType = newExpectedType + + true + } + } while (wasTransformedSomePostponedArgument) + } + + fun transformToAtomWithNewFunctionalExpectedType( + c: Context, + argument: PostponedAtomWithRevisableExpectedType, + diagnosticsHolder: KotlinDiagnosticsHolder + ) { + val revisedExpectedType = argument.revisedExpectedType?.takeIf { it.isFunctionOrKFunctionTypeWithAnySuspendability } ?: return + + when (argument) { + is PostponedCallableReferenceAtom -> + CallableReferenceWithRevisedExpectedTypeAtom(argument.atom, revisedExpectedType).also { + argument.setAnalyzedResults(null, listOf(it)) + } + is LambdaWithTypeVariableAsExpectedTypeAtom -> + argument.transformToResolvedLambda(c.getBuilder(), diagnosticsHolder, revisedExpectedType) + else -> throw IllegalStateException("Unsupported postponed argument type of $argument") + } + } + + private fun getAllDeeplyRelatedTypeVariables( + type: KotlinType, + variableDependencyProvider: TypeVariableDependencyInformationProvider + ): List { + val typeConstructor = type.constructor + + return when { + typeConstructor is TypeVariableTypeConstructor -> { + val relatedVariables = variableDependencyProvider.getDeeplyDependentVariables(typeConstructor).orEmpty() + listOf(typeConstructor) + relatedVariables.filterIsInstance() + } + type.arguments.isNotEmpty() -> { + type.arguments.map { getAllDeeplyRelatedTypeVariables(it.type, variableDependencyProvider) }.flatten() + } + else -> listOf() + } + } + + private fun getDeclaredParametersConsideringExtensionFunctionsPresence(parameterTypesInfo: ParameterTypesInfo): List? { + val (parametersFromDeclaration, _, parametersFromConstraints, annotations) = parameterTypesInfo + + if (parametersFromConstraints.isNullOrEmpty() || parametersFromDeclaration.isNullOrEmpty()) + return parametersFromDeclaration + + val oneLessParameterInDeclarationThanInConstraints = parametersFromConstraints.first().size == parametersFromDeclaration.size + 1 + + return if (oneLessParameterInDeclarationThanInConstraints && annotations.hasExtensionFunctionAnnotation()) { + listOf(null) + parametersFromDeclaration + } else { + parametersFromDeclaration + } + } + + fun fixNextReadyVariableForParameterTypeIfNeeded( + c: Context, + argument: PostponedResolvedAtom, + postponedArguments: List, + topLevelType: UnwrappedType, + topLevelAtoms: List, + dependencyProvider: TypeVariableDependencyInformationProvider + ): Boolean { + val expectedType = argument.run { safeAs()?.revisedExpectedType ?: expectedType } + + if (expectedType != null && expectedType.isFunctionOrKFunctionTypeWithAnySuspendability) { + val wasFixedSomeVariable = + c.fixNextReadyVariableForParameterType(expectedType, postponedArguments, topLevelType, topLevelAtoms, dependencyProvider) + + if (wasFixedSomeVariable) + return true + } + + return false + } + + private fun Context.fixNextReadyVariableForParameterType( + type: KotlinType, + postponedArguments: List, + topLevelType: UnwrappedType, + topLevelAtoms: List, + dependencyProvider: TypeVariableDependencyInformationProvider + ): Boolean { + val relatedVariables = type.getPureArgumentsForFunctionalTypeOrSubtype() + .map { getAllDeeplyRelatedTypeVariables(it, dependencyProvider) }.flatten() + val variableForFixation = variableFixationFinder.findFirstVariableForFixation( + this, relatedVariables, postponedArguments, KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL, topLevelType + ) + + if (variableForFixation == null || !variableForFixation.hasProperConstraint) + return false + + val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable) + val resultType = + resultTypeResolver.findResultType(this, variableWithConstraints, TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN) + val resolvedAtom = KotlinConstraintSystemCompleter.findResolvedAtomBy(variableWithConstraints.typeVariable, topLevelAtoms) + ?: topLevelAtoms.firstOrNull() + + fixVariable(variableWithConstraints.typeVariable, resultType, resolvedAtom) + + return true + } + + private fun KotlinType?.wrapToTypeWithKind() = this?.let { TypeWithKind(it) } + + private fun isAnonymousFunction(argument: PostponedAtomWithRevisableExpectedType) = argument.atom is FunctionExpression + + companion object { + private const val TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE = "_RP" + private const val TYPE_VARIABLE_NAME_FOR_LAMBDA_RETURN_TYPE = "_R" + private const val TYPE_VARIABLE_NAME_PREFIX_FOR_CR_PARAMETER_TYPE = "_QP" + private const val TYPE_VARIABLE_NAME_FOR_CR_RETURN_TYPE = "_Q" + } +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt index 75c6318c7f3..2bd6a0b15ba 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt @@ -18,10 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker -import org.jetbrains.kotlin.types.model.KotlinTypeMarker -import org.jetbrains.kotlin.types.model.TypeConstructorMarker -import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext -import org.jetbrains.kotlin.types.model.freshTypeConstructor +import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.utils.SmartSet class TypeVariableDependencyInformationProvider( @@ -30,10 +27,19 @@ class TypeVariableDependencyInformationProvider( private val topLevelType: KotlinTypeMarker?, private val typeSystemContext: TypeSystemInferenceExtensionContext ) { - // not oriented edges - private val constrainEdges: MutableMap> = hashMapOf() + /* + * Not oriented edges + * TypeVariable(A) has UPPER(Function1) => A and B are related deeply + */ + private val deepTypeVariableDependencies: MutableMap> = hashMapOf() - // oriented edges + /* + * Not oriented edges + * TypeVariable(A) has UPPER(TypeVariable(B)) => A and B are related shallowly + */ + private val shallowTypeVariableDependencies: MutableMap> = hashMapOf() + + // Oriented edges private val postponeArgumentsEdges: MutableMap> = hashMapOf() private val relatedToAllOutputTypes: MutableSet = hashSetOf() @@ -49,21 +55,43 @@ class TypeVariableDependencyInformationProvider( fun isVariableRelatedToTopLevelType(variable: TypeConstructorMarker) = relatedToTopLevelType.contains(variable) fun isVariableRelatedToAnyOutputType(variable: TypeConstructorMarker) = relatedToAllOutputTypes.contains(variable) + fun getDeeplyDependentVariables(variable: TypeConstructorMarker) = deepTypeVariableDependencies[variable] + fun getShallowlyDependentVariables(variable: TypeConstructorMarker) = shallowTypeVariableDependencies[variable] + + fun areVariablesDependentShallowly(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean { + if (a == b) return true + + val shallowDependencies = shallowTypeVariableDependencies[a] ?: return false + + return shallowDependencies.any { it == b } || + shallowTypeVariableDependencies.values.any { dependencies -> a in dependencies && b in dependencies } + } + private fun computeConstraintEdges() { - fun addConstraintEdge(from: TypeConstructorMarker, to: TypeConstructorMarker) { - constrainEdges.getOrPut(from) { hashSetOf() }.add(to) - constrainEdges.getOrPut(to) { hashSetOf() }.add(from) + fun addConstraintEdgeForDeepDependency(from: TypeConstructorMarker, to: TypeConstructorMarker) { + deepTypeVariableDependencies.getOrPut(from) { linkedSetOf() }.add(to) + deepTypeVariableDependencies.getOrPut(to) { linkedSetOf() }.add(from) + } + + fun addConstraintEdgeForShallowDependency(from: TypeConstructorMarker, to: TypeConstructorMarker) { + shallowTypeVariableDependencies.getOrPut(from) { linkedSetOf() }.add(to) + shallowTypeVariableDependencies.getOrPut(to) { linkedSetOf() }.add(from) } for (variableWithConstraints in notFixedTypeVariables.values) { val from = variableWithConstraints.typeVariable.freshTypeConstructor(typeSystemContext) for (constraint in variableWithConstraints.constraints) { + val constraintTypeConstructor = constraint.type.typeConstructor(typeSystemContext) + constraint.type.forAllMyTypeVariables { if (isMyTypeVariable(it)) { - addConstraintEdge(from, it) + addConstraintEdgeForDeepDependency(from, it) } } + if (isMyTypeVariable(constraintTypeConstructor)) { + addConstraintEdgeForShallowDependency(from, constraintTypeConstructor) + } } } } @@ -118,7 +146,7 @@ class TypeVariableDependencyInformationProvider( } - private fun getConstraintEdges(from: TypeConstructorMarker): Set = constrainEdges[from] ?: emptySet() + private fun getConstraintEdges(from: TypeConstructorMarker): Set = deepTypeVariableDependencies[from] ?: emptySet() private fun getPostponeEdges(from: TypeConstructorMarker): Set = postponeArgumentsEdges[from] ?: emptySet() private fun addAllRelatedNodes(to: MutableSet, node: TypeConstructorMarker, includePostponedEdges: Boolean) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt index 161f3bd2da2..f11ac24434d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt @@ -61,6 +61,12 @@ enum class ConstraintKind { fun isLower(): Boolean = this == LOWER fun isUpper(): Boolean = this == UPPER fun isEqual(): Boolean = this == EQUALITY + + fun opposite() = when (this) { + LOWER -> UPPER + UPPER -> LOWER + EQUALITY -> EQUALITY + } } class Constraint( diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index d5380cc6b4f..90f897cfc91 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.components.PostponedArgumentInputTypesResolver import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.model.OnlyInputTypesDiagnostic @@ -31,6 +32,7 @@ class NewConstraintSystemImpl( ConstraintInjector.Context, ResultTypeResolver.Context, KotlinConstraintSystemCompleter.Context, + PostponedArgumentInputTypesResolver.Context, PostponedArgumentsAnalyzer.Context { private val storage = MutableConstraintStorage() private var state = State.BUILDING @@ -87,6 +89,8 @@ class NewConstraintSystemImpl( override fun asPostponedArgumentsAnalyzerContext() = apply { checkState(State.BUILDING) } + override fun asPostponedArgumentInputTypesResolverContext() = apply { checkState(State.BUILDING) } + // ConstraintSystemOperation override fun registerVariable(variable: TypeVariableMarker) { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt index ef22b96113e..f1c4a2e5107 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.PostponableKotlinCallArgument import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation import org.jetbrains.kotlin.types.KotlinType @@ -79,7 +80,15 @@ class TypeVariableFromCallableDescriptor( } class TypeVariableForLambdaReturnType( - val lambdaArgument: LambdaKotlinCallArgument, + builtIns: KotlinBuiltIns, + name: String +) : NewTypeVariable(builtIns, name) { + override fun hasOnlyInputTypesAnnotation(): Boolean = false +} + +class TypeVariableForLambdaParameterType( + val atom: PostponableKotlinCallArgument, + val index: Int, builtIns: KotlinBuiltIns, name: String ) : NewTypeVariable(builtIns, name) { @@ -92,3 +101,10 @@ class TypeVariableForCallableReferenceReturnType( ) : NewTypeVariable(builtIns, name) { override fun hasOnlyInputTypesAnnotation(): Boolean = false } + +class TypeVariableForCallableReferenceParameterType( + builtIns: KotlinBuiltIns, + name: String +) : NewTypeVariable(builtIns, name) { + override fun hasOnlyInputTypesAnnotation(): Boolean = false +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index 9fb88d69baa..3129ec2dc60 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -13,10 +13,7 @@ import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMa import org.jetbrains.kotlin.resolve.calls.components.extractInputOutputTypesFromCallableReferenceExpectedType import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor -import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage -import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintError -import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForCallableReferenceReturnType -import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType +import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant import org.jetbrains.kotlin.types.KotlinType @@ -98,6 +95,12 @@ interface PostponedResolvedAtomMarker { val analyzed: Boolean } +interface PostponedAtomWithRevisableExpectedType { + var revisedExpectedType: UnwrappedType? + val expectedType: UnwrappedType? + val atom: PostponableKotlinCallArgument +} + sealed class PostponedResolvedAtom : ResolvedAtom(), PostponedResolvedAtomMarker { abstract override val inputTypes: Collection abstract override val outputType: UnwrappedType? @@ -107,10 +110,13 @@ sealed class PostponedResolvedAtom : ResolvedAtom(), PostponedResolvedAtomMarker class LambdaWithTypeVariableAsExpectedTypeAtom( override val atom: LambdaKotlinCallArgument, override val expectedType: UnwrappedType -) : PostponedResolvedAtom() { +) : PostponedResolvedAtom(), PostponedAtomWithRevisableExpectedType { override val inputTypes: Collection get() = listOf(expectedType) override val outputType: UnwrappedType? get() = null - var isReturnArgumentOfAnotherLambda: Boolean = false + + override var revisedExpectedType: UnwrappedType? = null + + var parameterTypesFromDeclaration: List? = null fun setAnalyzed(resolvedLambdaAtom: ResolvedLambdaAtom) { setAnalyzedResults(listOf(resolvedLambdaAtom)) @@ -180,15 +186,16 @@ sealed class AbstractPostponedCallableReferenceAtom( get() = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.outputType } -class CallableReferenceWithTypeVariableAsExpectedTypeAtom( +class CallableReferenceWithRevisedExpectedTypeAtom( atom: CallableReferenceKotlinCallArgument, expectedType: UnwrappedType?, - val typeVariableForReturnType: TypeVariableForCallableReferenceReturnType? ) : AbstractPostponedCallableReferenceAtom(atom, expectedType) class PostponedCallableReferenceAtom( eagerCallableReferenceAtom: EagerCallableReferenceAtom -) : AbstractPostponedCallableReferenceAtom(eagerCallableReferenceAtom.atom, eagerCallableReferenceAtom.expectedType) +) : AbstractPostponedCallableReferenceAtom(eagerCallableReferenceAtom.atom, eagerCallableReferenceAtom.expectedType), PostponedAtomWithRevisableExpectedType { + override var revisedExpectedType: UnwrappedType? = null +} class ResolvedCollectionLiteralAtom( override val atom: CollectionLiteralKotlinCallArgument, diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt index 74317571e4d..af8867fde95 100644 --- a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt @@ -19,6 +19,4 @@ fun test() { baz<(Int) -> Unit>(id(::foo), id(id(::foo))) baz(id(::foo), id(id<(Int) -> Unit>(::foo))) baz(id(::foo), id<(Int) -> Unit>(id(::foo))) - - baz(id { it.inv() }, id<(Int) -> Unit> { }) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt index 477ab16ce32..4dcb4810326 100644 --- a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt +++ b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt @@ -19,6 +19,4 @@ fun test() { baz<(Int) -> Unit>(id(::foo), id(id(::foo))) baz(id(::foo), id(id<(Int) -> Unit>(::foo))) baz(id(::foo), id<(Int) -> Unit>(id(::foo))) - - baz(id { it.inv() }, id<(Int) -> Unit> { }) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/elvisNotProcessed.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/elvisNotProcessed.kt index 83a43ec4c73..285fee4684d 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/elvisNotProcessed.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/elvisNotProcessed.kt @@ -34,6 +34,6 @@ val bbb = null ?: ( l() ?: null) val bbbb = ( l() ?: null) ?: ( l() ?: null) fun f(x : Long?): Long { - var a = x ?: (fun() {} ?: fun() {}) - return a + var a = x ?: (fun() {} ?: fun() {}) + return a } diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.fail b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.fail new file mode 100644 index 00000000000..6de8440105e --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.fail @@ -0,0 +1,11 @@ +Failures detected in FirBodyResolveTransformerAdapter, file: /basic.fir.kt +Cause: java.lang.RuntimeException: While resolving call R?C|/selectFloat|(R?C|/id|( = id@fun .(): { + ^@id Unit +} +), R?C|/id|( = id@fun .(x: ): { + ^@id Unit +} +), R?C|/id|( = id@fun .(): { + it# +} +)) diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt new file mode 100644 index 00000000000..27c25ec6bf0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -0,0 +1,195 @@ +import kotlin.reflect.KFunction1 + +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +fun foo(i: Int) {} +fun foo(s: String) {} +fun foo2(i: Int) {} +fun foo3(i: Number) {} +fun id(x: K): K = x +fun id1(x: K): K = x +fun id2(x: L): L = x +fun baz1(x: T, y: T): T = TODO() +fun baz2(x: T, y: Inv): T = TODO() +fun select(vararg x: T) = x[0] + +fun takeInterdependentLambdas(x: (T) -> R, y: (R) -> T) {} + +fun takeDependentLambdas(x: (T) -> Int, y: (Int) -> T) {} + +class Inv(val x: T) + +fun test1() { + val x1: (Int) -> Unit = id(id(::foo)) + val x2: (Int) -> Unit = baz1(id(::foo), ::foo) + val x3: (Int) -> Unit = baz1(id(::foo), id(id(::foo))) + val x4: (String) -> Unit = baz1(id(::foo), id(id(::foo))) + + id<(Int) -> Unit>(id(id(::foo))) + id(id<(Int) -> Unit>(::foo)) + baz1<(Int) -> Unit>(id(::foo), id(id(::foo))) + baz1(id(::foo), id(id<(Int) -> Unit>(::foo))) + baz1(id(::foo), id<(Int) -> Unit>(id(::foo))) + + baz1(id { it.inv() }, id<(Int) -> Unit> { }) + baz1(id1 { x -> x.inv() }, id2 { x: Int -> }) + baz1(id1 { it.inv() }, id2 { x: Int -> }) + + baz2(id1 { it.inv() }, id2(Inv { x: Int -> })) + + select(id1 { it.inv() }, id1 { x: Number -> TODO() }, id1(id2 { x: Int -> x })) + + select(id1 { it.inv() }, id1 { x: Number -> TODO() }, id1(id2(::foo2))) + select(id1 { x: Inv -> TODO() }, id1 { ")!>it.x.inv() }, id1 { x: Inv -> TODO() }) + + select(id1 { & Inv}")!>it }, id1 { x: Inv -> TODO() }, id1 { x: Inv -> TODO() }) + + ")!>select(id1(::foo), id(::foo3), id1(id2(::foo2))) + + select({ it }, { x: Int -> TODO() }) + + // Interdependent postponed arguments are unsupported + takeInterdependentLambdas({}, {}) + takeInterdependentLambdas({ it }, { 10 }) + takeInterdependentLambdas({ 10 }, { it }) + takeInterdependentLambdas({ 10 }, { x -> x }) + takeInterdependentLambdas({ x -> 10 }, { it }) + takeInterdependentLambdas({ it }, { x -> 10 }) + + takeDependentLambdas({ it }, { it }) + takeDependentLambdas({ it.length }, { "it" }) + takeDependentLambdas({ it; 10 }, { }) + + select({ it }, fun(x: Int) = 1) + + val x5: (Int) -> Unit = select({ it }, { x: Number -> Unit }) + val x6 = select(id { it }, id(id<(Int) -> Unit> { x: Number -> Unit })) + + select(id(id2 { it.inv() }), id(id { x: Int -> x })) + + val x7: (Int) -> Unit = selectNumber(id {}, id {}, id {}) + val x8: (Int) -> Unit = selectNumber(id { x -> x }, id { x -> }, id { x -> }) + val x9: (Int) -> Unit = selectNumber(id { }, id { x -> }, id { it }) + + val x10: (Int) -> Unit = selectFloat(id { }, id { x -> }, id { & Number}")!>it }) + + val x11: (B) -> Unit = selectC(id { }, id { x -> x }, id { it }) + + /* + * Upper constraint is less specific than lower (it's error): + * K <: (A) -> Unit -> TypeVariable(_RP1) >: A + * K >: (C) -> TypeVariable(_R) -> TypeVariable(_RP1) <: C + */ + val x12 = selectC(id { it }, id { x: B -> }) + val x13 = selectA(id { it }, id { x: C -> }) + + // one upper constraint and one lower + val x14 = selectC(id { it }, id { x: A -> }, { x -> x }) + val x15 = selectC(id { it }, { x: A -> }, id { x -> x }) + + /* + * Two upper constraints and one lower + * K <: (C) -> Unit -> TypeVariable(_RP1) >: C + * K <: (B) -> Unit -> TypeVariable(_RP1) >: B + * K >: (A) -> TypeVariable(_R) -> TypeVariable(_RP1) <: A + * K == intersect(CST(C, B), A) == A + */ + val x16: (C) -> Unit = selectB(id { it }, { x -> }, id { x: A -> x }) + + /* + * two upper constraints and one equality (it's error) + * K <: (C) -> Unit -> TypeVariable(_RP1) >: C + * K == (B) -> Unit -> TypeVariable(_RP1) == B + */ + val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) + val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) + + val x19: String.() -> Unit = select( kotlin.Unit")!>id {}, kotlin.Unit")!>id(fun(x: String) {})) + val x20: String.() -> Unit = select( kotlin.Unit")!>{}, kotlin.Unit")!>(fun(x: String) {})) + val x21: String.() -> Unit = select( kotlin.Unit")!>id(fun(x: String) {}), kotlin.Unit")!>id(fun(x: String) {})) + val x22 = select(id Unit>(fun(x: String) {}), kotlin.Unit")!>id(fun(x: String) {})) + val x23 = select( kotlin.Unit")!>id(fun String.(x: String) {}), kotlin.Unit")!>id(fun(x: String, y: String) {})) + val x24 = select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x: String -> this }) + val x25 = select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x: String, y: String -> x }) + + // It isn't related with posponed arguments, see KT-38439 + val x26: Int.(String) -> Int = fun (x: String) = 10 + val x27: Int.(String) -> Int = id(fun (x: String) = 10) + + val x28 = select(id { x, y -> x.inv() + y.toByte() }, { x: Int, y -> y.toByte() }, { x, y: Number -> x.inv() }) + val x29 = select(id { x, y -> x.inv() + y.toByte() }, id { x: Int, y -> y.toByte() }, id { x, y: Number -> x.inv() }) + val x30 = select({ x, y -> x.inv() + y.toByte() }, id { x: Int, y -> y.toByte() }, id { x, y: Number -> x.inv() }) + + val x31 = select( + id { x, y -> x.inv() + y.toByte() }, + id<(Int, Number) -> Int> { x, y -> x.inv() }, + {} as (Number, Number) -> Int + ) + + val x32 = selectPosponedArgument({ it }, { x: Int -> }, { x: Nothing -> x }) + val x33 = selectPosponedArgument({ it }, { } as (Int) -> Unit, { x: Nothing -> x }) + val x34 = selectPosponedArgument({ it }, { } as (Nothing) -> Unit, { x: Int -> x }) + val x35 = selectPosponedArgument({ it }, { } as (Int) -> Unit, { } as (Nothing) -> Unit) + + val x36 = selectPosponedArgument3({ it }, { it }, { x: Int -> x }) + val x37 = selectPosponedArgument3({ it }, { x: Number -> x }, { x: Int -> x }) + val x38 = selectPosponedArgument3Revert({ it }, { it }, { x: Int -> x }) + val x39 = selectPosponedArgument3Revert({ it }, { x: Number -> x }, { x: Int -> x }) + + val x40 = select(id Unit> {}, { x: Int, y: String -> x }) + + val x41 = select(A2(), { a, b, c -> a; b; c }) + val x42 = select(A3(), { it }, { a -> a }) + val x43 = select(A3(), ")!>A3::foo1) + val x44 = select(A3(), ")!>A3::foo1, { a -> a }, { it -> it }) + + val x45 = select(A4(), { x: Number -> "" }) + val x46 = select(A5(), { x: Number, y: Int -> "" }) + + val x47 = select(A2(), id { a, b, c -> a; b; c }) + val x48 = select(id(A3()), { it }, { a -> a }) + val x49 = select(A3(), id(")!>A3::foo1)) + val x50 = select(A3(), ")!>A3::foo1, { a -> a }, { it -> it }) + + val x51 = select(A4(), id { x: Number -> x }) + val x52 = select(id(A5()), id { x: Number, y: Int -> x;y }) + val x53 = select(id(A5()), id { x, y -> x;y }) + val x54 = select(id(")!>A5()), id { x: Number, y: Int -> x;y }) + val x55: Function2 = select(id(A5()), id { x, y -> x;y; 1f }) +} + +fun Unit> selectNumber(arg1: T, arg2: T, arg3: T) = arg1 + +fun Unit> selectFloat(arg1: T, arg2: T, arg3: T) = arg2 + +fun Unit> selectA(arg1: T, arg2: T, arg3: T) = arg2 +fun Unit> selectB(arg1: T, arg2: T, arg3: T) = arg2 +fun Unit> selectC(arg1: T, arg2: T, arg3: T) = arg2 + +fun selectPosponedArgument(vararg x: (T) -> Unit) = x[0] +fun selectPosponedArgument3(x: (T) -> Unit, y: (R) -> Unit, z: (L) -> Unit) = x +fun selectPosponedArgument3Revert(x: (T) -> Unit, y: (R) -> Unit, z: (L) -> Unit) = x + +interface A +class B: A +class C: A + +class A2: Function3 { + override fun invoke(p1: Int, p2: String, p3: Float): Float = 4f +} + +class A3: KFunction1 { + override fun invoke(p1: Number): String = TODO() + override val name: String = TODO() + + fun foo1(x: Int) {} + fun foo1(x: Any?) {} +} + +class A4: Function1 { + override fun invoke(p1: Int): Float = TODO() +} + +class A5: Function2 { + override fun invoke(p1: K, p2: Q): Float = 5f +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt new file mode 100644 index 00000000000..8a948df4410 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt @@ -0,0 +1,223 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST + +import kotlin.reflect.KFunction1 + +fun withOverload(i: Int) {} +fun withOverload(s: String) {} + +fun takeInt(i: Int) {} +fun takeNumber(i: Number) {} + +fun id(x: K): K = x +fun id1(x: K): K = x +fun id2(x: L): L = x + +fun selectWithInv(x: T, y: Inv): T = TODO() +fun select(vararg x: T) = x[0] + +fun takeLambdas(vararg x: (T) -> Unit) = x[0] +fun takeLambdasWithDirectlyDependentTypeParameters(x: (T) -> Unit, y: (R) -> Unit, z: (L) -> Unit) = x +fun takeLambdasWithInverselyDependentTypeParameters(x: (T) -> Unit, y: (R) -> Unit, z: (L) -> Unit) = x + +fun takeInterdependentLambdas(x: (T) -> R, y: (R) -> T) {} + +fun takeDependentLambdas(x: (T) -> Int, y: (Int) -> T) {} + +class Inv(val x: T) + +fun Unit> selectNumber(arg1: T, arg2: T, arg3: T) = arg1 + +fun Unit> selectFloat(arg1: T, arg2: T, arg3: T) = arg2 + +fun Unit> selectA(arg1: T, arg2: T, arg3: T) = arg2 +fun Unit> selectB(arg1: T, arg2: T, arg3: T) = arg2 +fun Unit> selectC(arg1: T, arg2: T, arg3: T) = arg2 + +interface A +class B: A +class C: A + +class A2: Function3 { + override fun invoke(p1: Int, p2: String, p3: Float): Float = 4f +} + +class A3: KFunction1 { + override fun invoke(p1: Number): String = TODO() + override val name: String = TODO() + + fun foo1(x: Int) {} + fun foo1(x: Any?) {} + + companion object { + fun foo2(x: Int) {} + fun foo2(x: Any?) {} + } +} + +class A4: Function1 { + override fun invoke(p1: Int): Float = TODO() +} + +class A5: Function2 { + override fun invoke(p1: K, p2: Q): Float = 5f +} + + +fun test1() { + // Inferring lambda parameter types by other lambda explicit parameters; expected type is type variable + select(id1 { x -> x.inv() }, id2 { x: Int -> }) + select(id1 { it.inv() }, id2 { x: Int -> }) + selectWithInv(id1 { it.inv() }, id2(Inv { x: Int -> })) + select(id1 { it.inv() }, id1 { x: Number -> TODO() }, id1(id2 { x: Int -> x })) + select(id1 { it.inv() }, id1 { x: Number -> TODO() }, id1(id2(::takeInt))) + select(id1 { x: Inv -> TODO() }, id1 { ")!>it.x.inv() }, id1 { x: Inv -> TODO() }) + select(id1 { & Inv}")!>it }, id1 { x: Inv -> TODO() }, id1 { x: Inv -> TODO() }) + select(id(id2 { it.inv() }), id(id { x: Int -> x })) + + // Disambiguating callable references by other callable references without overloads + ")!>select(id(::withOverload), id(::takeInt), id(id(::takeNumber))) + + // Interdependent lambdas by input-output types aren't supported + takeInterdependentLambdas({}, {}) + takeInterdependentLambdas({ it }, { 10 }) + takeInterdependentLambdas({ 10 }, { it }) + takeInterdependentLambdas({ 10 }, { x -> x }) + takeInterdependentLambdas({ x -> 10 }, { it }) + takeInterdependentLambdas({ it }, { x -> 10 }) + + // Dependent lambdas by input-output types + takeDependentLambdas({ it }, { it }) + takeDependentLambdas({ it.length }, { "it" }) + takeDependentLambdas({ it; 10 }, { }) + + // Inferring lambda parameter types by anonymous function parameters + select({ it }, fun(x: Int) = 1) + + // Inferring lambda parameter types by other lambda explicit parameters (lower constraints) and expected type (upper constraints) + val x5: (Int) -> Unit = select({ it }, { x: Number -> Unit }) + + // Inferring lambda parameter types by other lambda explicit parameters (lower constraints) and specified type arguments (equality constraints) + select(id { it }, id(id<(Int) -> Unit> { x: Number -> Unit })) + + // Inferring lambda parameter types by specified type arguments (equality constraints) of other lambdas + select(id { it.inv() }, id<(Int) -> Unit> { }) + select( + id { x, y -> x.inv() + y.toByte() }, + id<(Int, Number) -> Int> { x, y -> x.inv() }, + {} as (Number, Number) -> Int + ) + + // Inferring lambda parameter types by a few expected types (a few upper constraints) + val x7: (Int) -> Unit = kotlin.Unit")!>selectNumber(id {}, id {}, id {}) + val x8: (Int) -> Unit = selectNumber(id { x -> x }, id { x -> }, id { x -> }) + val x9: (Int) -> Unit = selectNumber(id { }, id { x -> }, id { it }) + val x10: (Int) -> Unit = selectFloat(id { }, id { x -> }, id { & Number}")!>it }) + val x11: (B) -> Unit = selectC(id { }, id { x -> x }, id { it }) + + // Inferring lambda parameter types by expected types (upper constraints) and other lambda explicit parameters (lower constraints) + /* + * Upper constraint is less specific than lower (it's error): + * K <: (A) -> Unit -> TypeVariable(_RP1) >: A + * K >: (C) -> TypeVariable(_R) -> TypeVariable(_RP1) <: C + */ + val x12 = selectC(id { it }, id { x: B -> }) + val x13 = selectA(id { it }, id { x: C -> }) + val x14 = selectC(id { it }, id { x: A -> }, { x -> x }) + val x15 = selectC(id { it }, { x: A -> }, id { x -> x }) + /* + * Two upper constraints and one lower + * K <: (C) -> Unit -> TypeVariable(_RP1) >: C + * K <: (B) -> Unit -> TypeVariable(_RP1) >: B + * K >: (A) -> TypeVariable(_R) -> TypeVariable(_RP1) <: A + * K == intersect(CST(C, B), A) == A + */ + val x16: (C) -> Unit = selectB(id { it }, { x -> }, id { x: A -> x }) + + // Inferring lambda parameter types by expected types (upper constraints) and specified type arguments (equality constraints) of other lambdas + /* + * two upper constraints and one equality (it's error) + * K <: (C) -> Unit -> TypeVariable(_RP1) >: C + * K == (B) -> Unit -> TypeVariable(_RP1) == B + */ + val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) + val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) + + // Resolution of extension/non-extension functions combination + val x19: String.() -> Unit = select( kotlin.Unit")!>id {}, kotlin.Unit")!>id(fun(x: String) {})) + val x20: String.() -> Unit = select( kotlin.Unit")!>{}, kotlin.Unit")!>(fun(x: String) {})) + val x21: String.() -> Unit = select( kotlin.Unit")!>id(fun(x: String) {}), kotlin.Unit")!>id(fun(x: String) {})) + select(id Unit>(fun(x: String) {}), kotlin.Unit")!>id(fun(x: String) {})) + select( kotlin.Unit")!>id(fun String.(x: String) {}), kotlin.Unit")!>id(fun(x: String, y: String) {})) + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x: String -> this }) + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x -> this }) + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x: String, y: String -> x }) + // Convert to extension lambda is impossible because the lambda parameter types aren't specified explicitly + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x, y -> x }) + select(id(id(fun(x: String, y: String) { }), fun String.(x: String) {}), { x, y -> x }) + val x26: Int.(String) -> Int = fun (x: String) = 10 // it must be error, see KT-38439 + // Receiver must be specified in anonymous function declaration + val x27: Int.(String) -> Int = id(fun (x: String) = 10) + select(id Unit> {}, { x: Int, y: String -> x }) + + // Inferring lambda parameter types by partially specified parameter types of other lambdas + select(id { x, y -> x.inv() + y.toByte() }, { x: Int, y -> y.toByte() }, { x, y: Number -> x.inv() }) + select(id { x, y -> x.inv() + y.toByte() }, id { x: Int, y -> y.toByte() }, id { x, y: Number -> x.inv() }) + select({ x, y -> x.inv() + y.toByte() }, id { x: Int, y -> y.toByte() }, id { x, y: Number -> x.inv() }) + + // Inferring lambda parameter types by other specified lambda parameters; expected type is a functional type with type variables in parameter types + takeLambdas({ it }, { x: Int -> }, { x: Nothing -> x }) + takeLambdas({ it }, { } as (Int) -> Unit, { x: Nothing -> x }) + takeLambdas({ it }, { } as (Nothing) -> Unit, { x: Int -> x }) + takeLambdas({ it }, { } as (Int) -> Unit, { } as (Nothing) -> Unit) + + // Inferring lambda parameter types by other specified lambda parameters; expected type is a functional type with type variables in parameter types; dependent type parameters + takeLambdasWithDirectlyDependentTypeParameters({ it }, { it }, { x: Int -> x }) + takeLambdasWithDirectlyDependentTypeParameters({ it }, { x: Number -> x }, { x: Int -> x }) + takeLambdasWithInverselyDependentTypeParameters({ it }, { it }, { x: Int -> x }) + /* + * Interesting test case: variable can be fixed to different types randomly (`Int` or `Number`; it depends on variable fixation order) + * if in `TypeVariableDependencyInformationProvider` `hashSet` instead of `linkedSet` for `deepTypeVariableDependencies` and `shallowTypeVariableDependencies` will be used + */ + takeLambdasWithInverselyDependentTypeParameters({ it }, { x: Number -> x }, { x: Int -> x }) + + // Inferring lambda parameter types by subtypes of functional type + kotlin.Float")!>select(A2(), { a, b, c -> a; b; c }) + java.io.Serializable")!>select(A3(), { it }, { a -> a }) + ")!>select(A3(), ")!>A3::foo1) + // Should be error as `A3::foo1` is `KFunction2`, but the remaining arguments are `KFuncion1` or `Function1` + ")!>select(A3(), ")!>A3::foo1, { a -> ]")!>a }, { it -> ]")!>it }) + // It's OK because `A3::foo2` is from companion of `A3` + kotlin.Any")!>select(A3(), ")!>A3::foo2, { a -> a }, { it -> it }) + {Comparable<*> & java.io.Serializable}")!>select(A4(), { x: Number -> "" }) + {Comparable<*> & java.io.Serializable}")!>select(A5(), { x: Number, y: Int -> "" }) + kotlin.Float")!>select(A2(), id { a, b, c -> a; b; c }) + java.io.Serializable")!>select(id(A3()), { it }, { a -> a }) + ")!>select(A3(), id(")!>A3::foo1)) + ")!>select(A3(), ")!>A3::foo1, id { a -> ]")!>a }, { it -> ]")!>it }) + ")!>select(A3(), ")!>A3::foo1, { a -> ]")!>a }, id { it -> ]")!>it }) + ")!>select(id(A3()), id(")!>A3::foo1), { a -> ]")!>a }, { it -> ]")!>it }) + ")!>select(id(A3()), id(")!>A3::foo1), { a -> ]")!>a }, id { it -> ]")!>it }) + // If lambdas' parameters are specified explicitly, we don't report an error, because there is proper CST – Function + ")!>select(id(A3()), id(")!>A3::foo1), { a: Number -> a }) + ")!>select(id(A3()), id(")!>A3::foo1), id { a: Number -> a }) + kotlin.Number")!>select(A4(), id { x: Number -> x }) + {Comparable<*> & Number}")!>select(id(A5()), id { x: Number, y: Int -> x;y }) + {Comparable<*> & Number}")!>select(id(A5()), id { x, y -> x;y }) + {Comparable<*> & Number}")!>select(id(")!>A5()), id { x: Number, y: Int -> x;y }) + val x55: Function2 = select(id(A5()), id { x, y -> x;y; 1f }) + + // Diffrerent lambda's parameters with proper CST + ")!>select({ x: Int -> }, { x: String -> }) + ")!>select({ x: Int -> }, { x: Int, y: Number -> }) + ")!>select(id { x: Int -> }, { x: String -> }) + ")!>select({ x: Int -> }, id { x: Int, y: Number -> }) + ")!>select(id { x: Int -> }, id { x: String -> }) + ")!>select(id { x: Int -> }, id { x: Int, y: Number -> }) + & java.io.Serializable}>")!>select({ x: Int -> 1 }, { x: String -> "" }) + & Number}>")!>select({ x: Int -> 1 }, { x: Int, y: Number -> 1f }) + & java.io.Serializable}>>")!>select(id { x: Int -> Inv(10) }, { x: String -> Inv("") }) + ")!>select({ x: Int -> TODO() }, id { x: Int, y: Number -> Any() }) + ")!>select(id { x: Int -> null }, id { x: String -> "" }) + ")!>select(id { x: Int -> 10 }, id { x: Int, y: Number -> TODO() }) + val x68: String.(String) -> String = select(id { x: String, y: String -> "10" }, id { x: String, y: String -> "TODO()" }) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt new file mode 100644 index 00000000000..3766c363583 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt @@ -0,0 +1,94 @@ +package + +public fun id(/*0*/ x: K): K +public fun id1(/*0*/ x: K): K +public fun id2(/*0*/ x: L): L +public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T +public fun kotlin.Unit> selectA(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T +public fun kotlin.Unit> selectB(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T +public fun kotlin.Unit> selectC(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T +public fun kotlin.Unit> selectFloat(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T +public fun kotlin.Unit> selectNumber(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T +public fun selectWithInv(/*0*/ x: T, /*1*/ y: Inv): T +public fun takeDependentLambdas(/*0*/ x: (T) -> kotlin.Int, /*1*/ y: (kotlin.Int) -> T): kotlin.Unit +public fun takeInt(/*0*/ i: kotlin.Int): kotlin.Unit +public fun takeInterdependentLambdas(/*0*/ x: (T) -> R, /*1*/ y: (R) -> T): kotlin.Unit +public fun takeLambdas(/*0*/ vararg x: (T) -> kotlin.Unit /*kotlin.Array kotlin.Unit>*/): (T) -> kotlin.Unit +public fun takeLambdasWithDirectlyDependentTypeParameters(/*0*/ x: (T) -> kotlin.Unit, /*1*/ y: (R) -> kotlin.Unit, /*2*/ z: (L) -> kotlin.Unit): (T) -> kotlin.Unit +public fun takeLambdasWithInverselyDependentTypeParameters(/*0*/ x: (T) -> kotlin.Unit, /*1*/ y: (R) -> kotlin.Unit, /*2*/ z: (L) -> kotlin.Unit): (T) -> kotlin.Unit +public fun takeNumber(/*0*/ i: kotlin.Number): kotlin.Unit +public fun test1(): kotlin.Unit +public fun withOverload(/*0*/ i: kotlin.Int): kotlin.Unit +public fun withOverload(/*0*/ s: kotlin.String): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A2 : (kotlin.Int, kotlin.String, kotlin.Float) -> kotlin.Float { + public constructor A2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun invoke(/*0*/ p1: kotlin.Int, /*1*/ p2: kotlin.String, /*2*/ p3: kotlin.Float): kotlin.Float + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A3 : kotlin.reflect.KFunction1 { + public constructor A3() + public open override /*1*/ val name: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo1(/*0*/ x: kotlin.Any?): kotlin.Unit + public final fun foo1(/*0*/ x: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun invoke(/*0*/ p1: kotlin.Number): kotlin.String + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo2(/*0*/ x: kotlin.Any?): kotlin.Unit + public final fun foo2(/*0*/ x: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class A4 : (kotlin.Int) -> kotlin.Float { + public constructor A4() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun invoke(/*0*/ p1: kotlin.Int): kotlin.Float + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A5 : (K, Q) -> kotlin.Float { + public constructor A5() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun invoke(/*0*/ p1: K, /*1*/ p2: Q): kotlin.Float + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B : A { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class C : A { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ x: T) + public final val x: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.kt new file mode 100644 index 00000000000..b6f9434a539 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.kt @@ -0,0 +1,10 @@ +// FIR_IDENTICAL + +fun select(vararg x: T) = x[0] +fun id1(x: T): T = x +fun id2(x: T): T = x + +fun test() { + fun foo() {} + select(id1(::foo), id2 { }) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.txt new file mode 100644 index 00000000000..4f36635523e --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.txt @@ -0,0 +1,6 @@ +package + +public fun id1(/*0*/ x: T): T +public fun id2(/*0*/ x: T): T +public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T +public fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.kt new file mode 100644 index 00000000000..7e425beda63 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE + +class Foo +class P(x: K, y: T) + +val Foo.bar: Foo get() = this + +fun Foo.bar(x: String) = null as Foo + +fun main() { + val x: P.() -> Foo> = P("", Foo::bar) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.kt new file mode 100644 index 00000000000..59af82211ba --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -CAST_NEVER_SUCCEEDS -UNUSED_VARIABLE + +class Foo +class P(x: K, y: T) + +val Foo.bar: Foo get() = this + +fun Foo.bar(x: String) = null as Foo + +fun main() { + val x: P.() -> Foo> = P("", , Foo>")!>Foo::bar) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.txt new file mode 100644 index 00000000000..1d5c63b4f43 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.txt @@ -0,0 +1,19 @@ +package + +public val Foo.bar: Foo +public fun main(): kotlin.Unit +public fun Foo.bar(/*0*/ x: kotlin.String): Foo + +public final class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class P { + public constructor P(/*0*/ x: K, /*1*/ y: T) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.fir.kt new file mode 100644 index 00000000000..d04749b5711 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.fir.kt @@ -0,0 +1,59 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNCHECKED_CAST -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +fun materialize(): T = null as T + +class Foo { + fun product(other: Foo<(A) -> B>) = materialize>() + + fun foo1(other1: Foo, function: (A, B) -> R) { + val x = product( + other1.product( + bar { b -> { a -> function(a, b) } } + ) + ) + x + } + + fun foo2(other1: Foo, other2: Foo, function: (A, B, C) -> R) { + val x = product( + other1.product( + other2.product( + bar { c -> { b -> { a -> function(a, b, c) } } } + ) + ) + ) + x + } + + fun foo3(other1: Foo, other2: Foo, other3: Foo, other4: Foo, function: (A, B, C, D) -> R) { + val x = product( + other1.product( + other2.product( + other3.product( + bar { d -> { c -> { b -> { a -> function(a, b, c, d) } } } } + ) + ) + ) + ) + x + } + + fun foo4(other1: Foo, other2: Foo, other3: Foo, other4: Foo, function: (A, B, C, D, E) -> R) { + val x = product( + other1.product( + other2.product( + other3.product( + other4.product( + bar { e -> { d -> { c -> { b -> { a -> function(a, b, c, d, e) } } } } } + ) + ) + ) + ) + ) + x + } + + companion object { + fun bar(x: A) = materialize>() + } +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt new file mode 100644 index 00000000000..b7ca2e10762 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt @@ -0,0 +1,59 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNCHECKED_CAST -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +fun materialize(): T = null as T + +class Foo { + fun product(other: Foo<(A) -> B>) = materialize>() + + fun foo1(other1: Foo, function: (A, B) -> R) { + val x = product( + other1.product( + bar { b -> { a -> function(a, b) } } + ) + ) + ")!>x + } + + fun foo2(other1: Foo, other2: Foo, function: (A, B, C) -> R) { + val x = product( + other1.product( + other2.product( + bar { c -> { b -> { a -> function(a, b, c) } } } + ) + ) + ) + ")!>x + } + + fun foo3(other1: Foo, other2: Foo, other3: Foo, other4: Foo, function: (A, B, C, D) -> R) { + val x = product( + other1.product( + other2.product( + other3.product( + bar { d -> { c -> { b -> { a -> function(a, b, c, d) } } } } + ) + ) + ) + ) + ")!>x + } + + fun foo4(other1: Foo, other2: Foo, other3: Foo, other4: Foo, function: (A, B, C, D, E) -> R) { + val x = product( + other1.product( + other2.product( + other3.product( + other4.product( + bar { e -> { d -> { c -> { b -> { a -> function(a, b, c, d, e) } } } } } + ) + ) + ) + ) + ) + ")!>x + } + + companion object { + fun bar(x: A) = materialize>() + } +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.txt new file mode 100644 index 00000000000..1c3f452d17d --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.txt @@ -0,0 +1,23 @@ +package + +public fun materialize(): T + +public final class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo1(/*0*/ other1: Foo, /*1*/ function: (A, B) -> R): kotlin.Unit + public final fun foo2(/*0*/ other1: Foo, /*1*/ other2: Foo, /*2*/ function: (A, B, C) -> R): kotlin.Unit + public final fun foo3(/*0*/ other1: Foo, /*1*/ other2: Foo, /*2*/ other3: Foo, /*3*/ other4: Foo, /*4*/ function: (A, B, C, D) -> R): kotlin.Unit + public final fun foo4(/*0*/ other1: Foo, /*1*/ other2: Foo, /*2*/ other3: Foo, /*3*/ other4: Foo, /*4*/ function: (A, B, C, D, E) -> R): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun product(/*0*/ other: Foo<(A) -> B>): Foo + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final fun bar(/*0*/ x: A): Foo + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.fir.kt new file mode 100644 index 00000000000..5a9e4dcb4c6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.fir.kt @@ -0,0 +1,41 @@ +// !DIAGNOSTICS: -UNUSED_LAMBDA_EXPRESSION, -UNUSED_EXPRESSION + +fun case1(x: Any){ + when (x){ + 1 -> try { {"1"}; ""; 1} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } + + when (x){ + 1 -> try { {"1"}; ""} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } +} + +fun case2(x: Any){ + when (x){ + 1 -> try { {"1"}; ""; TODO()} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } + when (x){ + 1 -> try { {"1"}; ""; TODO(); ""} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } + when (x){ + 1 -> try { {"1"}; ""; TODO()} catch (e: Exception) { { }} + "1" -> try { 1; "" } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } +} + +fun case3(x: Any){ + when (x){ + 1 -> try { {"1"}} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt new file mode 100644 index 00000000000..c13aaabc66c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt @@ -0,0 +1,41 @@ +// !DIAGNOSTICS: -UNUSED_LAMBDA_EXPRESSION, -UNUSED_EXPRESSION + +fun case1(x: Any){ + when (x){ + 1 -> try { {"1"}; ""; 1} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } + + when (x){ + 1 -> try { {"1"}; ""} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } +} + +fun case2(x: Any){ + when (x){ + 1 -> try { {"1"}; ""; TODO()} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } + when (x){ + 1 -> try { {"1"}; ""; TODO(); ""} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } + when (x){ + 1 -> try { {"1"}; ""; TODO()} catch (e: Exception) { { }} + "1" -> try { 1; "" } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } +} + +fun case3(x: Any){ + when (x){ + 1 -> try { {"1"}} catch (e: Exception) { { }} + "1" -> try { 1 } catch (e: Exception) { { }} + else -> try { 1 } catch (e: Exception) { {1 }} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.txt new file mode 100644 index 00000000000..874653577c5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.txt @@ -0,0 +1,5 @@ +package + +public fun case1(/*0*/ x: kotlin.Any): kotlin.Unit +public fun case2(/*0*/ x: kotlin.Any): kotlin.Unit +public fun case3(/*0*/ x: kotlin.Any): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.fir.kt b/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.fir.kt index 1c13bf01c69..1e63cd4b0d3 100644 --- a/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.fir.kt @@ -7,6 +7,8 @@ fun main() { val x2: String.() -> String = if (true) {{ -> this }} else {{ -> this }} val x3: () -> String = if (true) {{ -> "this" }} else {{ -> "this" }} val x4: String.() -> String = if (true) {{ str: String -> "this" }} else {{ str: String -> "this" }} + val x41: String.(String) -> String = if (true) {{ str: String, str2: String -> "this" }} else {{ str: String, str2: String -> "this" }} + val x42: String.(String) -> String = if (true) {{ str, str2 -> "this" }} else {{ str, str2 -> "this" }} val x5: String.() -> String = if (true) {{ str -> "this" }} else {{ str -> "this" }} val x6: String.() -> String = if (true) {{ str -> "this" }} else {{ "this" }} val x7: String.() -> String = select({ -> this }, { -> this }) diff --git a/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.kt b/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.kt index 1f8163060a5..1325bf3cbed 100644 --- a/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.kt +++ b/compiler/testData/diagnostics/tests/inference/extensionLambdasAndArrow.kt @@ -7,6 +7,8 @@ fun main() { val x2: String.() -> String = if (true) {{ -> this }} else {{ -> this }} val x3: () -> String = if (true) {{ -> "this" }} else {{ -> "this" }} val x4: String.() -> String = if (true) {{ str: String -> "this" }} else {{ str: String -> "this" }} + val x41: String.(String) -> String = if (true) {{ str: String, str2: String -> "this" }} else {{ str: String, str2: String -> "this" }} + val x42: String.(String) -> String = if (true) {{ str, str2 -> "this" }} else {{ str, str2 -> "this" }} val x5: String.() -> String = if (true) {{ str -> "this" }} else {{ str -> "this" }} val x6: String.() -> String = if (true) {{ str -> "this" }} else {{ "this" }} val x7: String.() -> String = select({ -> this }, { -> this }) diff --git a/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt b/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt index 626182c5195..67b4400b312 100644 --- a/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt +++ b/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt @@ -22,11 +22,11 @@ fun foo(i: Int, f: (Int) -> Int) = f(i) fun id(t: T) = t fun test() { - foo(1, id(fun(x1: Int) = - foo(2, id(fun(x2: Int) = - foo(3, id(fun(x3: Int) = - foo(4, id(fun(x4: Int) = - foo(5, id(fun(x5: Int) = + foo(1, id(fun(x1: Int) = + foo(2, id(fun(x2: Int) = + foo(3, id(fun(x3: Int) = + foo(4, id(fun(x4: Int) = + foo(5, id(fun(x5: Int) = x1 + x2 + x3 + x4 + x5 + A.iii )) )) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.fail b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.fail new file mode 100644 index 00000000000..1f87de94e93 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.fail @@ -0,0 +1,8 @@ +Failures detected in FirBodyResolveTransformerAdapter, file: /callableReferences.fir.kt +Cause: java.lang.RuntimeException: While resolving call R?C|/selectNumber|(R?C|/id|(::R?C|/foo6|), R?C|/id|( = id@fun .(x: ): { + x# +} +), R?C|/id|( = id@fun .(): { + it# +} +)) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.kt new file mode 100644 index 00000000000..96b52e45bb3 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.fir.kt @@ -0,0 +1,57 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +import kotlin.reflect.* + +fun id(x: T) = x + +fun select(vararg x: T) = x[0] + +fun foo(x: Int) {} +fun foo2(x: Number) {} + +fun foo3(x: Int) {} +fun foo3(x: Number) {} + +interface A +interface B + +fun foo4(x: A) {} +fun foo4(x: B) {} + +interface C: A, B + +fun foo5(x: A) {} +fun foo5(x: B) {} +fun foo5(x: C) {} + +fun Unit> selectNumber(vararg x: T) = x[0] + +fun foo6(x: Int) {} +fun foo6(x: Float) {} +fun foo6(x: Number) {} + +fun main() { + select(::foo, { it }) + select(id(::foo), { x: Number -> }, { it }) + + val x1 = select(")!>id(::foo), kotlin.Number")!>id { x: Number -> x }) + kotlin.Any")!>x1 + + val x11 = select(id(::foo), id { x: Number -> }, id { it }) + kotlin.Any")!>x11 + + select(id(::foo2), id { x: Int -> }, id { it }) + + select(id(")!>::foo3), id { x: Int -> }, id { it }) + select(id(")!>::foo3), id { x: Number -> }, id { it }) + select(id(")!>::foo3), id { x: Number -> }, id { x: Int -> }, id { it }) + + select(id(")!>::foo4), id { x: A -> }, id { it }) + select(id(")!>::foo4), id { x: B -> }, id { it }) + // Expected ambiguity + select(id(::foo4), id { x: A -> }, id { x: B -> }, id { it }) + + select(id(::foo5), id { x: A -> }, id { x: B -> }, id { it }) + + val x2: (Int) -> Unit = selectNumber(id(")!>::foo6), id { x -> & Number}")!>x }, id { & Number}")!>it }) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.kt new file mode 100644 index 00000000000..96b52e45bb3 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.kt @@ -0,0 +1,57 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +import kotlin.reflect.* + +fun id(x: T) = x + +fun select(vararg x: T) = x[0] + +fun foo(x: Int) {} +fun foo2(x: Number) {} + +fun foo3(x: Int) {} +fun foo3(x: Number) {} + +interface A +interface B + +fun foo4(x: A) {} +fun foo4(x: B) {} + +interface C: A, B + +fun foo5(x: A) {} +fun foo5(x: B) {} +fun foo5(x: C) {} + +fun Unit> selectNumber(vararg x: T) = x[0] + +fun foo6(x: Int) {} +fun foo6(x: Float) {} +fun foo6(x: Number) {} + +fun main() { + select(::foo, { it }) + select(id(::foo), { x: Number -> }, { it }) + + val x1 = select(")!>id(::foo), kotlin.Number")!>id { x: Number -> x }) + kotlin.Any")!>x1 + + val x11 = select(id(::foo), id { x: Number -> }, id { it }) + kotlin.Any")!>x11 + + select(id(::foo2), id { x: Int -> }, id { it }) + + select(id(")!>::foo3), id { x: Int -> }, id { it }) + select(id(")!>::foo3), id { x: Number -> }, id { it }) + select(id(")!>::foo3), id { x: Number -> }, id { x: Int -> }, id { it }) + + select(id(")!>::foo4), id { x: A -> }, id { it }) + select(id(")!>::foo4), id { x: B -> }, id { it }) + // Expected ambiguity + select(id(::foo4), id { x: A -> }, id { x: B -> }, id { it }) + + select(id(::foo5), id { x: A -> }, id { x: B -> }, id { it }) + + val x2: (Int) -> Unit = selectNumber(id(")!>::foo6), id { x -> & Number}")!>x }, id { & Number}")!>it }) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.txt new file mode 100644 index 00000000000..ef2fa367a5a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.txt @@ -0,0 +1,36 @@ +package + +public fun foo(/*0*/ x: kotlin.Int): kotlin.Unit +public fun foo2(/*0*/ x: kotlin.Number): kotlin.Unit +public fun foo3(/*0*/ x: kotlin.Int): kotlin.Unit +public fun foo3(/*0*/ x: kotlin.Number): kotlin.Unit +public fun foo4(/*0*/ x: A): kotlin.Unit +public fun foo4(/*0*/ x: B): kotlin.Unit +public fun foo5(/*0*/ x: A): kotlin.Unit +public fun foo5(/*0*/ x: B): kotlin.Unit +public fun foo5(/*0*/ x: C): kotlin.Unit +public fun foo6(/*0*/ x: kotlin.Float): kotlin.Unit +public fun foo6(/*0*/ x: kotlin.Int): kotlin.Unit +public fun foo6(/*0*/ x: kotlin.Number): kotlin.Unit +public fun id(/*0*/ x: T): T +public fun main(): kotlin.Unit +public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T +public fun kotlin.Unit> selectNumber(/*0*/ vararg x: T /*kotlin.Array*/): T + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C : A, B { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.fir.kt new file mode 100644 index 00000000000..f7f948f907a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.fir.kt @@ -0,0 +1,41 @@ +// !DIAGNOSTICS: -CAST_NEVER_SUCCEEDS -UNUSED_PARAMETER + +interface AssertionPlant +interface AssertionPlantNullable: BaseAssertionPlant> +interface BaseAssertionPlant> + +interface BaseCollectingAssertionPlant, out C : BaseCollectingAssertionPlant> : BaseAssertionPlant + +interface CreatorLike, C : BaseCollectingAssertionPlant> + +interface ParameterObjectOption { + fun withParameterObjectNullable( + parameterObject: ParameterObject + ) = null as CreatorNullable +} + +class ParameterObject +interface CollectingAssertionPlantNullable : AssertionPlantNullable, + BaseCollectingAssertionPlant, CollectingAssertionPlantNullable> +interface CreatorNullable: CreatorLike, CollectingAssertionPlantNullable> + +fun , C : BaseCollectingAssertionPlant> contains( + pairs: List>, + parameterObjectOption: (ParameterObjectOption, K) -> CreatorLike, V, A, C>, + assertionCreator: C.(M) -> Unit +) {} + +private fun createGetParameterObject( + plant: AssertionPlant>, + key: K +) = null as ParameterObject, V> + +private fun containsNullable( + plant: AssertionPlant>, + pairs: List>, + assertionCreator: AssertionPlantNullable.(M) -> Unit +) = contains( + pairs, + { option, key -> option.withParameterObjectNullable(createGetParameterObject(plant, key)) }, + assertionCreator +) \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.kt new file mode 100644 index 00000000000..bd1544a44e4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.kt @@ -0,0 +1,41 @@ +// !DIAGNOSTICS: -CAST_NEVER_SUCCEEDS -UNUSED_PARAMETER + +interface AssertionPlant +interface AssertionPlantNullable: BaseAssertionPlant> +interface BaseAssertionPlant> + +interface BaseCollectingAssertionPlant, out C : BaseCollectingAssertionPlant> : BaseAssertionPlant + +interface CreatorLike, C : BaseCollectingAssertionPlant> + +interface ParameterObjectOption { + fun withParameterObjectNullable( + parameterObject: ParameterObject + ) = null as CreatorNullable +} + +class ParameterObject +interface CollectingAssertionPlantNullable : AssertionPlantNullable, + BaseCollectingAssertionPlant, CollectingAssertionPlantNullable> +interface CreatorNullable: CreatorLike, CollectingAssertionPlantNullable> + +fun , C : BaseCollectingAssertionPlant> contains( + pairs: List>, + parameterObjectOption: (ParameterObjectOption, K) -> CreatorLike, V, A, C>, + assertionCreator: C.(M) -> Unit +) {} + +private fun createGetParameterObject( + plant: AssertionPlant>, + key: K +) = null as ParameterObject, V> + +private fun containsNullable( + plant: AssertionPlant>, + pairs: List>, + assertionCreator: AssertionPlantNullable.(M) -> Unit +) = contains( + pairs, + { option, key -> , V?>")!>option.withParameterObjectNullable(createGetParameterObject(plant, key)) }, + assertionCreator +) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.txt new file mode 100644 index 00000000000..d510e40341d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.txt @@ -0,0 +1,61 @@ +package + +public fun , /*4*/ C : BaseCollectingAssertionPlant> contains(/*0*/ pairs: kotlin.collections.List>, /*1*/ parameterObjectOption: (ParameterObjectOption, K) -> CreatorLike, V, A, C>, /*2*/ assertionCreator: C.(M) -> kotlin.Unit): kotlin.Unit +private fun containsNullable(/*0*/ plant: AssertionPlant>, /*1*/ pairs: kotlin.collections.List>, /*2*/ assertionCreator: AssertionPlantNullable.(M) -> kotlin.Unit): kotlin.Unit +private fun createGetParameterObject(/*0*/ plant: AssertionPlant>, /*1*/ key: K): ParameterObject, V> + +public interface AssertionPlant { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface AssertionPlantNullable : BaseAssertionPlant> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface BaseAssertionPlant> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface BaseCollectingAssertionPlant, /*2*/ out C : BaseCollectingAssertionPlant> : BaseAssertionPlant { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface CollectingAssertionPlantNullable : AssertionPlantNullable, BaseCollectingAssertionPlant, CollectingAssertionPlantNullable> { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface CreatorLike, /*3*/ C : BaseCollectingAssertionPlant> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface CreatorNullable : CreatorLike, CollectingAssertionPlantNullable> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ParameterObject { + public constructor ParameterObject() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface ParameterObjectOption { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + public open fun withParameterObjectNullable(/*0*/ parameterObject: ParameterObject): CreatorNullable +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.kt new file mode 100644 index 00000000000..63bcaf24468 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.kt @@ -0,0 +1,14 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun useList(list: List) { } +fun useMap(map: Map) { } + +enum class Color {BLUE} + +fun Color.grayValue() {} + +fun test() { + useList(listOf({ x: Color -> x.grayValue() }, Color.BLUE)) + useMap(mapOf("a" to { x: Color -> x.grayValue() }, "b" to Color.BLUE)) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.txt new file mode 100644 index 00000000000..6711ef7dbab --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.txt @@ -0,0 +1,25 @@ +package + +public fun test(): kotlin.Unit +public fun useList(/*0*/ list: kotlin.collections.List): kotlin.Unit +public fun useMap(/*0*/ map: kotlin.collections.Map): kotlin.Unit +public fun Color.grayValue(): kotlin.Unit + +public final enum class Color : kotlin.Enum { + enum entry BLUE + + private constructor Color() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Color): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): Color + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.fir.kt new file mode 100644 index 00000000000..404707f49d8 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.fir.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNCHECKED_CAST + +fun foo(items: List, handler: (T) -> Unit) {} + +class Foo(x: T) + +fun materialize(): T = null as T + +fun main(x: List?) { + foo(x?.map { Foo(it) } ?: listOf(materialize>())) {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.kt new file mode 100644 index 00000000000..09f17724e5b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNCHECKED_CAST + +fun foo(items: List, handler: (T) -> Unit) {} + +class Foo(x: T) + +fun materialize(): T = null as T + +fun main(x: List?) { + foo(x?.map { Foo(it) } ?: listOf(materialize>())) {} +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.txt new file mode 100644 index 00000000000..12903f8bc8f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.txt @@ -0,0 +1,12 @@ +package + +public fun foo(/*0*/ items: kotlin.collections.List, /*1*/ handler: (T) -> kotlin.Unit): kotlin.Unit +public fun main(/*0*/ x: kotlin.collections.List?): kotlin.Unit +public fun materialize(): T + +public final class Foo { + public constructor Foo(/*0*/ x: T) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.kt new file mode 100644 index 00000000000..e1b3d9f6847 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.kt @@ -0,0 +1,10 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -CAST_NEVER_SUCCEEDS -UNUSED_PARAMETER -UNCHECKED_CAST + +fun materialize() = null as T + +val x: Map = materialize>>().fold(mutableMapOf()) { m, x -> + val (s, action) = x.entries.first() + m[s] = action + m +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.txt new file mode 100644 index 00000000000..6b8be614736 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.txt @@ -0,0 +1,4 @@ +package + +public val x: kotlin.collections.Map +public fun materialize(): T diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.kt new file mode 100644 index 00000000000..4f8d5dfe6bc --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.kt @@ -0,0 +1,9 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +fun xSelectButton2(items: (matcher: String) -> List, handler: T.() -> Unit) {} + +fun main() { + val x: List? = listOf() + xSelectButton2({ matcher -> x ?: emptyList() }) { this.inv() } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.txt new file mode 100644 index 00000000000..5e1946ce58e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.txt @@ -0,0 +1,4 @@ +package + +public fun main(): kotlin.Unit +public fun xSelectButton2(/*0*/ items: (matcher: kotlin.String) -> kotlin.collections.List, /*1*/ handler: T.() -> kotlin.Unit): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.kt new file mode 100644 index 00000000000..3a1dca5dc0b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.kt @@ -0,0 +1,6 @@ +// FIR_IDENTICAL +interface ObservableSet : Set {} + +fun test(x: List>) { + x.reduce { acc: Set, set: Set -> acc + set } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.txt new file mode 100644 index 00000000000..4480615899f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.txt @@ -0,0 +1,14 @@ +package + +public fun test(/*0*/ x: kotlin.collections.List>): kotlin.Unit + +public interface ObservableSet : kotlin.collections.Set { + public abstract override /*1*/ /*fake_override*/ val size: kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun contains(/*0*/ element: T): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun containsAll(/*0*/ elements: kotlin.collections.Collection): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun iterator(): kotlin.collections.Iterator + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.kt new file mode 100644 index 00000000000..dc288332212 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.kt @@ -0,0 +1,12 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class ArraySortedChecker(val array: A, val comparator: Comparator) { + fun checkSorted(sorted: A.() -> R, sortedDescending: A.() -> R, iterator: R.() -> Iterator) {} +} + +fun > arrayData(vararg values: T, toArray: Array.() -> A) = ArraySortedChecker(values.toArray(), naturalOrder()) + +fun main() { + with (arrayData("ac", "aD", "aba") { toList().toTypedArray() }) {} +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.txt new file mode 100644 index 00000000000..627692d7763 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.txt @@ -0,0 +1,14 @@ +package + +public fun > arrayData(/*0*/ vararg values: T /*kotlin.Array*/, /*1*/ toArray: kotlin.Array.() -> A): ArraySortedChecker +public fun main(): kotlin.Unit + +public final class ArraySortedChecker { + public constructor ArraySortedChecker(/*0*/ array: A, /*1*/ comparator: kotlin.Comparator /* = java.util.Comparator */) + public final val array: A + public final val comparator: kotlin.Comparator /* = java.util.Comparator */ + public final fun checkSorted(/*0*/ sorted: A.() -> R, /*1*/ sortedDescending: A.() -> R, /*2*/ iterator: R.() -> kotlin.collections.Iterator): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.kt new file mode 100644 index 00000000000..64d4b84132b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.kt @@ -0,0 +1,27 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class Wrapper (val x: T) + +inline fun Wrapper.unwrap(validator: (T) -> R): R = validator(x) + +fun select(x: T) {} + +class Foo(y: Wrapper>) { + fun MutableCollection.foo(x: T) {} + fun MutableCollection.foo(x: Iterable) {} + + init { + /* + * Before the fix, `foo` can't be disambiguated because the lambda is alanyzed in full mode, + * not in partial as before the inroducing new posponed arguments analysis. + * + * It happens due to the lack of rerun stages after fixation variables + * (stage 5 – see `fixVariablesOrReportNotEnoughInformation` in `KotlinConstraintSystemCompleter.kt`). + * Rerun is need as fixation of variables can be make lambda available for analysis. + * + * TODO: add tests with lambdas, which can't be analyzed in partial mode, but if can, the code will be successfully resolved. + */ + ArrayList().foo(y.unwrap { it }) + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.txt new file mode 100644 index 00000000000..6c43da90cf9 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.txt @@ -0,0 +1,21 @@ +package + +public fun select(/*0*/ x: T): kotlin.Unit +public inline fun Wrapper.unwrap(/*0*/ validator: (T) -> R): R + +public final class Foo { + public constructor Foo(/*0*/ y: Wrapper>) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + public final fun kotlin.collections.MutableCollection.foo(/*0*/ x: T): kotlin.Unit + public final fun kotlin.collections.MutableCollection.foo(/*0*/ x: kotlin.collections.Iterable): kotlin.Unit +} + +public final class Wrapper { + public constructor Wrapper(/*0*/ x: T) + public final val x: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.fail b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.fail new file mode 100644 index 00000000000..5ff560136a0 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.fail @@ -0,0 +1,8 @@ +Failures detected in FirBodyResolveTransformerAdapter, file: /suspendFunctions.fir.kt +Cause: java.lang.RuntimeException: While resolving call R?C|/takeSuspend|(R?C|/id|( = id@fun .(): { + it# +} +), takeSuspend@fun (x: R|kotlin/Int|): R|kotlin/Unit| { + ^ R|/x| +} +) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt new file mode 100644 index 00000000000..770c150974a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +fun select(vararg x: T) = x[0] + +fun id(x: K): K = x + +fun Unit, K: T> takeSuspend(x: T, y: K) = x +fun Unit, K: T> takeSimpleFunction(x: T, y: K) = x + +fun main() { + select(suspend {}, kotlin.Unit")!>{}) + select( kotlin.Unit")!>{}, suspend {}) + select( kotlin.Unit")!>id {}, suspend {}) + select( kotlin.Unit")!>id {}, id(suspend {})) + select( kotlin.Unit")!>id {}, id Unit> {}) + + takeSuspend( kotlin.Unit")!>id { it }, kotlin.Unit")!>{ x -> x }) + + val x1: suspend (Int) -> Unit = takeSuspend( kotlin.Unit")!>id { it }, kotlin.Unit")!>{ x -> x }) + + // Here, the error should be + val x2: (Int) -> Unit = takeSuspend( kotlin.Unit")!>id { it }, kotlin.Unit"), TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>{ x -> x }) + val x3: suspend (Int) -> Unit = takeSimpleFunction( kotlin.Unit")!>id { it }, kotlin.Unit"), TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>{ x -> x }) + val x4: (Int) -> Unit = takeSimpleFunction(id Unit> {}, kotlin.Unit"), TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>{}) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.kt new file mode 100644 index 00000000000..770c150974a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER + +fun select(vararg x: T) = x[0] + +fun id(x: K): K = x + +fun Unit, K: T> takeSuspend(x: T, y: K) = x +fun Unit, K: T> takeSimpleFunction(x: T, y: K) = x + +fun main() { + select(suspend {}, kotlin.Unit")!>{}) + select( kotlin.Unit")!>{}, suspend {}) + select( kotlin.Unit")!>id {}, suspend {}) + select( kotlin.Unit")!>id {}, id(suspend {})) + select( kotlin.Unit")!>id {}, id Unit> {}) + + takeSuspend( kotlin.Unit")!>id { it }, kotlin.Unit")!>{ x -> x }) + + val x1: suspend (Int) -> Unit = takeSuspend( kotlin.Unit")!>id { it }, kotlin.Unit")!>{ x -> x }) + + // Here, the error should be + val x2: (Int) -> Unit = takeSuspend( kotlin.Unit")!>id { it }, kotlin.Unit"), TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>{ x -> x }) + val x3: suspend (Int) -> Unit = takeSimpleFunction( kotlin.Unit")!>id { it }, kotlin.Unit"), TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>{ x -> x }) + val x4: (Int) -> Unit = takeSimpleFunction(id Unit> {}, kotlin.Unit"), TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>{}) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.txt new file mode 100644 index 00000000000..99fb856af18 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.txt @@ -0,0 +1,7 @@ +package + +public fun id(/*0*/ x: K): K +public fun main(): kotlin.Unit +public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T +public fun kotlin.Unit, /*1*/ K : T> takeSimpleFunction(/*0*/ x: T, /*1*/ y: K): T +public fun kotlin.Unit, /*1*/ K : T> takeSuspend(/*0*/ x: T, /*1*/ y: K): T diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt index e9e07e0684e..0dbda849b22 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-2/pos/1.1.kt @@ -118,13 +118,12 @@ fun case_8(value_1: Int, value_2: Int) = when { /* * TESTCASE NUMBER: 9 - * UNEXPECTED BEHAVIOUR * ISSUES: KT-37249 */ fun case_9(value_1: Int, value_2: String, value_3: String) = when { - value_1 == 1 -> try { 4 } catch (e: Exception) { 5 } - value_1 == 2 -> try { throw Exception() } catch (e: Exception) { value_2 } - else -> try { throw Exception() } catch (e: Exception) { {value_3} } finally { } + value_1 == 1 -> try { 4 } catch (e: Exception) { 5 } + value_1 == 2 -> try { throw Exception() } catch (e: Exception) { value_2 } + else -> try { throw Exception() } catch (e: Exception) { {value_3} } finally { } } // TESTCASE NUMBER: 10 diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt index 8b4c81115e1..61840798d07 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-5/pos/1.1.kt @@ -119,14 +119,13 @@ fun case_8(value_1: Int, value_2: Int) = when (value_1) { /* * TESTCASE NUMBER: 9 - * UNEXPECTED BEHAVIOUR * ISSUES: KT-37249 */ fun case_9(value_1: Int, value_2: String, value_3: String): Any { return when (value_1) { 1 -> try { 4 } catch (e: Exception) { 5 } 2 -> try { throw Exception() } catch (e: Exception) { value_2 } - else -> try { throw Exception() } catch (e: Exception) { {value_3} } finally { } + else -> try { throw Exception() } catch (e: Exception) { {value_3} } finally { } } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 0e30e57079d..94fe68ce5e0 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10748,6 +10748,44 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali public void testWithExact() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); } + + @TestMetadata("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PostponedArgumentsAnalysis extends AbstractDiagnosticsTestWithFirValidation { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPostponedArgumentsAnalysis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt"); + } + + @TestMetadata("callableReferenceLambdaCombinationInsideCall.kt") + public void testCallableReferenceLambdaCombinationInsideCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.kt"); + } + + @TestMetadata("callableReferences.kt") + public void testCallableReferences() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.kt"); + } + + @TestMetadata("lackOfDeepIncorporation.kt") + public void testLackOfDeepIncorporation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt"); + } + + @TestMetadata("lambdasInTryCatch.kt") + public void testLambdasInTryCatch() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt"); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/inference/constraints") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 11de66aa3f4..ca2455fc8d8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -3069,6 +3069,82 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/completion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Completion extends AbstractDiagnosticsTestWithStdLib { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCompletion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PostponedArgumentsAnalysis extends AbstractDiagnosticsTestWithStdLib { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPostponedArgumentsAnalysis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("callableReferences.kt") + public void testCallableReferences() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.kt"); + } + + @TestMetadata("complexInterdependentInputOutputTypes.kt") + public void testComplexInterdependentInputOutputTypes() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.kt"); + } + + @TestMetadata("deepLambdas.kt") + public void testDeepLambdas() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.kt"); + } + + @TestMetadata("fixIndependentVariables.kt") + public void testFixIndependentVariables() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.kt"); + } + + @TestMetadata("fixInputTypeToMoreSpecificType.kt") + public void testFixInputTypeToMoreSpecificType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.kt"); + } + + @TestMetadata("fixReceiverToMoreSpecificType.kt") + public void testFixReceiverToMoreSpecificType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.kt"); + } + + @TestMetadata("moreSpecificOutputType.kt") + public void testMoreSpecificOutputType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.kt"); + } + + @TestMetadata("rerunStagesAfterFixationInFullMode.kt") + public void testRerunStagesAfterFixationInFullMode() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.kt"); + } + + @TestMetadata("rerunStagesAfterFixationInPartialMode.kt") + public void testRerunStagesAfterFixationInPartialMode() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.kt"); + } + + @TestMetadata("suspendFunctions.kt") + public void testSuspendFunctions() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.kt"); + } + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/delegates") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 5742ead30a2..e8000fe3c24 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -3069,6 +3069,82 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/completion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Completion extends AbstractDiagnosticsTestWithStdLibUsingJavac { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCompletion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PostponedArgumentsAnalysis extends AbstractDiagnosticsTestWithStdLibUsingJavac { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPostponedArgumentsAnalysis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("callableReferences.kt") + public void testCallableReferences() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/callableReferences.kt"); + } + + @TestMetadata("complexInterdependentInputOutputTypes.kt") + public void testComplexInterdependentInputOutputTypes() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/complexInterdependentInputOutputTypes.kt"); + } + + @TestMetadata("deepLambdas.kt") + public void testDeepLambdas() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/deepLambdas.kt"); + } + + @TestMetadata("fixIndependentVariables.kt") + public void testFixIndependentVariables() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixIndependentVariables.kt"); + } + + @TestMetadata("fixInputTypeToMoreSpecificType.kt") + public void testFixInputTypeToMoreSpecificType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixInputTypeToMoreSpecificType.kt"); + } + + @TestMetadata("fixReceiverToMoreSpecificType.kt") + public void testFixReceiverToMoreSpecificType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/fixReceiverToMoreSpecificType.kt"); + } + + @TestMetadata("moreSpecificOutputType.kt") + public void testMoreSpecificOutputType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/moreSpecificOutputType.kt"); + } + + @TestMetadata("rerunStagesAfterFixationInFullMode.kt") + public void testRerunStagesAfterFixationInFullMode() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInFullMode.kt"); + } + + @TestMetadata("rerunStagesAfterFixationInPartialMode.kt") + public void testRerunStagesAfterFixationInPartialMode() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/rerunStagesAfterFixationInPartialMode.kt"); + } + + @TestMetadata("suspendFunctions.kt") + public void testSuspendFunctions() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.kt"); + } + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/delegates") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 70cc96ecf19..5fd00971eb5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10743,6 +10743,44 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing public void testWithExact() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); } + + @TestMetadata("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PostponedArgumentsAnalysis extends AbstractDiagnosticsUsingJavacTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInPostponedArgumentsAnalysis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt"); + } + + @TestMetadata("callableReferenceLambdaCombinationInsideCall.kt") + public void testCallableReferenceLambdaCombinationInsideCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferenceLambdaCombinationInsideCall.kt"); + } + + @TestMetadata("callableReferences.kt") + public void testCallableReferences() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/callableReferences.kt"); + } + + @TestMetadata("lackOfDeepIncorporation.kt") + public void testLackOfDeepIncorporation() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lackOfDeepIncorporation.kt"); + } + + @TestMetadata("lambdasInTryCatch.kt") + public void testLambdasInTryCatch() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt"); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/inference/constraints") diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 7d5553ed7d0..870f412722e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -442,6 +442,11 @@ public abstract class KotlinBuiltIns { return "Function" + parameterCount; } + @NotNull + private static FqNameUnsafe getKFunctionFqName(int parameterCount) { + return FqNames.reflect(FunctionClassDescriptor.Kind.KFunction.getClassNamePrefix() + parameterCount); + } + @NotNull public static ClassId getFunctionClassId(int parameterCount) { return new ClassId(BUILT_INS_PACKAGE_FQ_NAME, Name.identifier(getFunctionName(parameterCount))); @@ -467,6 +472,17 @@ public abstract class KotlinBuiltIns { return getBuiltInClassByFqName(COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier(getSuspendFunctionName(parameterCount)))); } + @NotNull + public ClassDescriptor getKFunction(int parameterCount) { + return getBuiltInClassByFqName(getKFunctionFqName(parameterCount).toSafe()); + } + + @NotNull + public ClassDescriptor getKSuspendFunction(int parameterCount) { + Name name = Name.identifier(FunctionClassDescriptor.Kind.KSuspendFunction.getClassNamePrefix() + parameterCount); + return getBuiltInClassByFqName(COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(name)); + } + @NotNull public ClassDescriptor getThrowable() { return getBuiltInClassByName("Throwable"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt index d0d763391ed..fa6e67519b0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name @@ -19,6 +20,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations +import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* @@ -67,6 +69,9 @@ val KotlinType.isKSuspendFunctionType: Boolean val KotlinType.isFunctionOrSuspendFunctionType: Boolean get() = isFunctionType || isSuspendFunctionType +val KotlinType.isFunctionOrKFunctionTypeWithAnySuspendability: Boolean + get() = isFunctionType || isSuspendFunctionType || isKFunctionType || isKSuspendFunctionType + val KotlinType.isBuiltinFunctionalType: Boolean get() = constructor.declarationDescriptor?.isBuiltinFunctionalClassDescriptor == true @@ -154,6 +159,16 @@ fun KotlinType.getValueParameterTypesFromCallableReflectionType(isCallableTypeWi return arguments.subList(first, last) } +fun KotlinType.extractFunctionalTypeFromSupertypes(): KotlinType { + assert(isBuiltinFunctionalTypeOrSubtype) { "Not a function type or subtype: $this" } + return if (isBuiltinFunctionalType) this else supertypes().first { it.isBuiltinFunctionalType } +} + +fun KotlinType.getPureArgumentsForFunctionalTypeOrSubtype(): List { + assert(isBuiltinFunctionalTypeOrSubtype) { "Not a function type or subtype: $this" } + return extractFunctionalTypeFromSupertypes().arguments.dropLast(1).map { it.type } +} + fun KotlinType.extractParameterNameFromFunctionTypeArgument(): Name? { val annotation = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.parameterName) ?: return null val name = (annotation.allValueArguments.values.singleOrNull() as? StringValue) @@ -197,29 +212,38 @@ fun getFunctionTypeArgumentProjections( @JvmOverloads fun createFunctionType( - builtIns: KotlinBuiltIns, - annotations: Annotations, - receiverType: KotlinType?, - parameterTypes: List, - parameterNames: List?, - returnType: KotlinType, - suspendFunction: Boolean = false + builtIns: KotlinBuiltIns, + annotations: Annotations, + receiverType: KotlinType?, + parameterTypes: List, + parameterNames: List?, + returnType: KotlinType, + suspendFunction: Boolean = false ): SimpleType { val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) - val size = parameterTypes.size - val parameterCount = if (receiverType == null) size else size + 1 - val classDescriptor = if (suspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount) + val parameterCount = if (receiverType == null) parameterTypes.size else parameterTypes.size + 1 + val classDescriptor = getFunctionDescriptor(builtIns, parameterCount, suspendFunction) // TODO: preserve laziness of given annotations - val typeAnnotations = - if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) { - annotations - } - else { - Annotations.create( - annotations + BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.extensionFunctionType, emptyMap()) - ) - } + val typeAnnotations = if (receiverType != null) annotations.withExtensionFunctionAnnotation(builtIns) else annotations return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments) } + +fun Annotations.hasExtensionFunctionAnnotation() = hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) + +fun Annotations.withoutExtensionFunctionAnnotation() = + FilteredAnnotations(this, true) { it != KotlinBuiltIns.FQ_NAMES.extensionFunctionType } + +fun Annotations.withExtensionFunctionAnnotation(builtIns: KotlinBuiltIns) = + if (hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType)) { + this + } else { + Annotations.create(this + BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.extensionFunctionType, emptyMap())) + } + +fun getFunctionDescriptor(builtIns: KotlinBuiltIns, parameterCount: Int, isSuspendFunction: Boolean) = + if (isSuspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount) + +fun getKFunctionDescriptor(builtIns: KotlinBuiltIns, parameterCount: Int, isSuspendFunction: Boolean) = + if (isSuspendFunction) builtIns.getKSuspendFunction(parameterCount) else builtIns.getKFunction(parameterCount) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 241a93ae444..fb45b2c32f8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.types.checker import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -318,6 +319,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return KotlinBuiltIns.isUnit(this) } + override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean { + require(this is UnwrappedType, this::errorMessage) + return isBuiltinFunctionalTypeOrSubtype + } + override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker { require(lowerBound is SimpleType, this::errorMessage) require(upperBound is SimpleType, this::errorMessage) diff --git a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 5b2ede931f7..d64711b1103 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -132,6 +132,8 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun KotlinTypeMarker.isUnit(): Boolean + fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean + fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker