From 712a2ce1abe2922e4443abacd731a6a266e4ed88 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Wed, 30 Sep 2020 16:07:03 +0300 Subject: [PATCH] [FIR] Improved lambda completion: initial implementation Repeat the logic of KotlinConstraintSystemCompleter in ConstraintSystemCompleter. Implement additional context operations required for updated lambda completion algorithm. --- ...irOldFrontendDiagnosticsTestGenerated.java | 5 + .../ConeConstraintSystemUtilContext.kt | 96 ++--- .../inference/ConstraintSystemCompleter.kt | 346 +++++++++++------- .../resolve/inference/InferenceComponents.kt | 5 +- .../fir/resolve/inference/PostponedAtoms.kt | 45 ++- .../model/FirConstraintPositionAndErrors.kt | 3 + ...ControlFlowStatementsResolveTransformer.kt | 1 + .../kotlin/fir/types/ConeInferenceContext.kt | 114 +++++- .../components/ConstraintSystemUtilContext.kt | 11 +- .../PostponedArgumentInputTypesResolver.kt | 15 +- .../ClassicConstraintSystemUtilContext.kt | 39 +- .../KotlinConstraintSystemCompleter.kt | 4 +- .../resolve/calls/model/ResolutionAtoms.kt | 3 +- .../capturedInInlineOnlyIndexedCAO.kt | 1 - .../ambiguityTopLevelVsTopLevel.fir.kt | 2 +- .../completion/anonymousFunction.fir.kt | 4 +- .../postponedArgumentsAnalysis/basic.fir.kt | 94 ++--- ...yFromDeclarationOfAnonymousFunction.fir.kt | 8 - ...ilityFromDeclarationOfAnonymousFunction.kt | 1 + .../expectedTypeAdditionalTest.fir.kt | 3 +- .../tests/inference/kt32462.fir.kt | 2 +- .../inference/lambdaParameterTypeInElvis.kt | 15 + .../inference/lambdaParameterTypeInElvis.txt | 12 + .../inference/regressions/kt41394.fir.kt | 10 + .../tests/inference/regressions/kt41394.kt | 1 - ...thAnotherLambdaWithBuilderInference.fir.kt | 20 - ...llWithAnotherLambdaWithBuilderInference.kt | 1 + ...eWithSpecifiedFunctionLiteralWithId.fir.kt | 36 -- ...solveWithSpecifiedFunctionLiteralWithId.kt | 1 + .../inferenceForElvis.fir.kt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 5 + .../DiagnosticsUsingJavacTestGenerated.java | 5 + .../kotlin/builtins/StandardNames.kt | 21 +- .../kotlin/types/model/TypeSystemContext.kt | 14 + .../types/checker/ClassicTypeSystemContext.kt | 37 +- 35 files changed, 614 insertions(+), 368 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt create mode 100644 compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.txt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt41394.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.fir.kt 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 3fa491c5409..ed8d5714d13 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 @@ -10447,6 +10447,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt"); } + @TestMetadata("lambdaParameterTypeInElvis.kt") + public void testLambdaParameterTypeInElvis() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt"); + } + @TestMetadata("listConstructor.kt") public void testListConstructor() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/listConstructor.kt"); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConeConstraintSystemUtilContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConeConstraintSystemUtilContext.kt index 99ab910ce14..e62abf21edb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConeConstraintSystemUtilContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConeConstraintSystemUtilContext.kt @@ -5,14 +5,18 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeFixVariableConstraintPosition import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemUtilContext +import org.jetbrains.kotlin.resolve.calls.inference.components.PostponedArgumentInputTypesResolver import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.FixVariableConstraintPosition -import org.jetbrains.kotlin.resolve.calls.model.LambdaWithTypeVariableAsExpectedTypeMarker import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType import org.jetbrains.kotlin.types.model.KotlinTypeMarker -import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeVariableMarker object ConeConstraintSystemUtilContext : ConstraintSystemUtilContext { @@ -41,67 +45,77 @@ object ConeConstraintSystemUtilContext : ConstraintSystemUtilContext { return this } - override fun KotlinTypeMarker.isFunctionOrKFunctionTypeWithAnySuspendability(): Boolean { - TODO() - } - - override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean { - TODO() - } - - override fun extractFunctionalTypeFromSupertypes(type: KotlinTypeMarker): KotlinTypeMarker { - TODO() - } - - override fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List { - TODO() - } - override fun createArgumentConstraintPosition(argument: T): ArgumentConstraintPosition { - TODO() + @Suppress("UNCHECKED_CAST") + return ConeArgumentConstraintPosition() as ArgumentConstraintPosition } override fun createFixVariableConstraintPosition(variable: TypeVariableMarker, atom: T): FixVariableConstraintPosition { - TODO() + require(atom == null) + @Suppress("UNCHECKED_CAST") + return ConeFixVariableConstraintPosition(variable) as FixVariableConstraintPosition } override fun extractParameterTypesFromDeclaration(declaration: PostponedAtomWithRevisableExpectedType): List? { - TODO() + require(declaration is PostponedResolvedAtom) + return when (declaration) { + is LambdaWithTypeVariableAsExpectedTypeAtom -> { + val atom = declaration.atom + return if (atom.isLambda) { // lambda - must return null in case of absent parameters + if (atom.valueParameters.isNotEmpty()) + atom.collectDeclaredValueParameterTypes() + else null + } else { // function expression - all types are explicit, shouldn't return null + mutableListOf().apply { + atom.receiverTypeRef?.coneType?.let { add(it) } + addAll(atom.collectDeclaredValueParameterTypes()) + } + } + } + else -> null + } } - override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean { - TODO() - } + private fun FirAnonymousFunction.collectDeclaredValueParameterTypes(): List = + valueParameters.map { + if (it.returnTypeRef !is FirImplicitTypeRef) + it.returnTypeRef.coneType + else null + } - override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - TODO() - } - - override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - TODO() - } - - override fun isAnonymousFunction(argument: PostponedAtomWithRevisableExpectedType): Boolean { - TODO() + override fun PostponedAtomWithRevisableExpectedType.isAnonymousFunction(): Boolean { + require(this is PostponedResolvedAtom) + return this is LambdaWithTypeVariableAsExpectedTypeAtom && !this.atom.isLambda } override fun PostponedAtomWithRevisableExpectedType.isFunctionExpressionWithReceiver(): Boolean { - TODO() + require(this is PostponedResolvedAtom) + return this is LambdaWithTypeVariableAsExpectedTypeAtom && !this.atom.isLambda && this.atom.receiverTypeRef?.coneType != null } override fun createTypeVariableForLambdaReturnType(): TypeVariableMarker { - TODO() + return ConeTypeVariableForPostponedAtom(PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_FOR_LAMBDA_RETURN_TYPE) } - override fun createTypeVariableForLambdaParameterType(argument: PostponedAtomWithRevisableExpectedType, index: Int): TypeVariableMarker { - TODO() + override fun createTypeVariableForLambdaParameterType( + argument: PostponedAtomWithRevisableExpectedType, + index: Int + ): TypeVariableMarker { + return ConeTypeVariableForPostponedAtom( + "${PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE}$index" + ) } - override fun createTypeVariableForCallableReferenceParameterType(argument: PostponedAtomWithRevisableExpectedType, index: Int): TypeVariableMarker { - TODO() + override fun createTypeVariableForCallableReferenceParameterType( + argument: PostponedAtomWithRevisableExpectedType, + index: Int + ): TypeVariableMarker { + return ConeTypeVariableForPostponedAtom( + "${PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_PREFIX_FOR_CR_PARAMETER_TYPE}$index" + ) } override fun createTypeVariableForCallableReferenceReturnType(): TypeVariableMarker { - TODO() + return ConeTypeVariableForPostponedAtom(PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_FOR_LAMBDA_RETURN_TYPE) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt index 2aa4bd313ef..f60e198ab8b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt @@ -13,25 +13,19 @@ import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext import org.jetbrains.kotlin.fir.resolve.inference.model.ConeFixVariableConstraintPosition import org.jetbrains.kotlin.fir.returnExpressions import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder -import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext -import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator -import org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder +import org.jetbrains.kotlin.resolve.calls.inference.components.* import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl -import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition 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.resolve.calls.model.PostponedAtomWithRevisableExpectedType import org.jetbrains.kotlin.types.model.TypeConstructorMarker -import org.jetbrains.kotlin.types.model.typeConstructor import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.safeAs class ConstraintSystemCompleter(private val components: BodyResolveComponents) { private val inferenceComponents = components.session.inferenceComponents val variableFixationFinder = inferenceComponents.variableFixationFinder + private val postponedArgumentsInputTypesResolver = inferenceComponents.postponedArgumentInputTypesResolver fun complete( c: ConstraintSystemCompletionContext, @@ -41,133 +35,219 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { context: ResolutionContext, collectVariablesFromContext: Boolean = false, analyze: (PostponedResolvedAtom) -> Unit - ) { + ) = with(c) { - while (true) { - if (analyzePostponeArgumentIfPossible(c, topLevelAtoms, analyze)) continue + completion@ while (true) { + val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) - val allTypeVariables = getOrderedAllTypeVariables(c, topLevelAtoms, collectVariablesFromContext) - val postponedAtoms = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) - val variableForFixation = - variableFixationFinder.findFirstVariableForFixation( - c, allTypeVariables, postponedAtoms, completionMode, candidateReturnType - ) ?: break + if (completionMode == ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA && hasLambdaToAnalyze(postponedArguments)) return - if ( - completionMode == ConstraintSystemCompletionMode.FULL && - resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType(c, variableForFixation, postponedAtoms, context, analyze) - ) { + // Stage 1 + if (analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze)) continue + + val someVariableIsReadyForFixation = isAnyVariableReadyForFixation( + completionMode, topLevelAtoms, candidateReturnType, collectVariablesFromContext, postponedArguments + ) + + if (postponedArguments.isEmpty() && !someVariableIsReadyForFixation) + break + + val postponedArgumentsWithRevisableType = postponedArguments + .filterIsInstance() + .filter { it.revisedExpectedType == null } + val dependencyProvider = + TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, candidateReturnType, this) + + // Stage 2 + val newExpectedTypeWasBuilt = postponedArgumentsInputTypesResolver.collectParameterTypesAndBuildNewExpectedTypes( + asConstraintSystemCompletionContext(), postponedArgumentsWithRevisableType, completionMode, dependencyProvider + ) + + if (newExpectedTypeWasBuilt) + continue + + if (completionMode == ConstraintSystemCompletionMode.FULL) { + // Stage 3 + for (argument in postponedArguments) { + val variableWasFixed = postponedArgumentsInputTypesResolver.fixNextReadyVariableForParameterTypeIfNeeded( + asConstraintSystemCompletionContext(), + argument, + postponedArguments, + candidateReturnType, + dependencyProvider, + ) { // atom provided here is used only inside constraint positions, omitting right now + null + } + + if (variableWasFixed) + continue@completion + } + + // Stage 4 + for (argument in postponedArgumentsWithRevisableType) { + val argumentWasTransformed = + transformToAtomWithNewFunctionalExpectedType(asConstraintSystemCompletionContext(), context, argument) + + if (argumentWasTransformed) + continue@completion + } } - if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) { - val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable) - - fixVariable(c, candidateReturnType, variableWithConstraints, emptyList()) - -// if (!variableForFixation.hasProperConstraint) { -// c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable)) -// } + // Stage 5: analyze the next ready postponed argument + if (analyzeNextReadyPostponedArgument(postponedArguments, completionMode, analyze)) continue + + // Stage 6: fix type variables – fix if possible or report not enough information (if completion mode is full) + val variableWasFixed = fixVariablesOrReportNotEnoughInformation( + completionMode, topLevelAtoms, candidateReturnType, collectVariablesFromContext, postponedArguments + ) + if (variableWasFixed) + continue + + // Stage 7: force analysis of remaining not analyzed postponed arguments and rerun stages if there are + if (completionMode == ConstraintSystemCompletionMode.FULL) { + if (analyzeRemainingNotAnalyzedPostponedArgument(postponedArguments, analyze)) + continue } break } - - if (completionMode == ConstraintSystemCompletionMode.FULL) { - // force resolution for all not-analyzed argument's - getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze) - } } - private fun resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType( - c: ConstraintSystemCompletionContext, - variableForFixation: VariableFixationFinder.VariableForFixation, - postponedAtoms: List, - context: ResolutionContext, + private fun ConstraintSystemCompletionContext.analyzeArgumentWithFixedParameterTypes( + postponedArguments: List, analyze: (PostponedResolvedAtom) -> Unit ): Boolean { - val variable = variableForFixation.variable as ConeTypeVariableTypeConstructor - val hasProperAtom = postponedAtoms.any { - when (it) { - is LambdaWithTypeVariableAsExpectedTypeAtom/*, is PostponedCallableReferenceAtom*/ - -> it.expectedType.typeConstructor(c) == variable // TODO - else -> false - } - } - if ( - !hasProperAtom && - variableForFixation.hasProperConstraint && - !variableForFixation.hasOnlyTrivialProperConstraint - ) return false + val argumentWithFixedOrPostponedInputTypes = findPostponedArgumentWithFixedOrPostponedInputTypes(postponedArguments) - val postponedAtom = postponedAtoms.firstOrNull() ?: return false - val csBuilder = (c as NewConstraintSystemImpl).getBuilder() - val expectedTypeVariableConstructor = postponedAtom.expectedType?.typeConstructor(c)?.takeIf { it in c.allTypeVariables } as? ConeTypeVariableTypeConstructor ?: variable - val expectedTypeVariable = csBuilder.currentStorage().allTypeVariables[expectedTypeVariableConstructor] as ConeTypeVariable? ?: return false - - val atomToAnalyze = when (postponedAtom) { - is LambdaWithTypeVariableAsExpectedTypeAtom -> { - postponedAtom.preparePostponedAtomWithTypeVariableAsExpectedType( - c, csBuilder, expectedTypeVariable, - parameterTypes = null, - isSuitable = { isBuiltinFunctionalType(components.session) }, - typeVariableCreator = { ConeTypeVariableForLambdaReturnType(postponedAtom.atom, "_R") }, - newAtomCreator = { returnTypeVariable, expectedType -> - postponedAtom.transformToResolvedLambda(csBuilder, context, expectedType, returnTypeVariable) - } - ) - } - // is PostponedCallableReferenceAtom -> TODO() - else -> return false + if (argumentWithFixedOrPostponedInputTypes != null) { + analyze(argumentWithFixedOrPostponedInputTypes) + return true } - analyze(atomToAnalyze) + + return false + } + + private fun ConstraintSystemCompletionContext.findPostponedArgumentWithFixedOrPostponedInputTypes(postponedArguments: List) = + postponedArguments.firstOrNull { argument -> argument.inputTypes.all { containsOnlyFixedOrPostponedVariables(it) } } + + private fun ConstraintSystemCompletionContext.isAnyVariableReadyForFixation( + completionMode: ConstraintSystemCompletionMode, + topLevelAtoms: List, + topLevelType: ConeKotlinType, + collectVariablesFromContext: Boolean, + postponedArguments: List, + ): Boolean { + return variableFixationFinder.findFirstVariableForFixation( + this, + getOrderedAllTypeVariables(this, topLevelAtoms, collectVariablesFromContext), + postponedArguments, + completionMode, + topLevelType + ) != null + } + + private fun transformToAtomWithNewFunctionalExpectedType( + c: ConstraintSystemCompletionContext, + resolutionContext: ResolutionContext, + argument: PostponedAtomWithRevisableExpectedType, + ): Boolean = with(c) { + val revisedExpectedType: ConeKotlinType = + argument.revisedExpectedType?.takeIf { it.isFunctionOrKFunctionWithAnySuspendability() }?.cast() ?: return false + + when (argument) { + is ResolvedCallableReferenceAtom -> { + argument.reviseExpectedType(revisedExpectedType) + } + + is LambdaWithTypeVariableAsExpectedTypeAtom -> + argument.transformToResolvedLambda(c.getBuilder(), resolutionContext, revisedExpectedType, null /*TODO()*/) + else -> throw IllegalStateException("Unsupported postponed argument type of $argument") + } + return true } - private inline fun T.preparePostponedAtomWithTypeVariableAsExpectedType( - c: ConstraintSystemCompletionContext, - csBuilder: ConstraintSystemBuilder, - variable: ConeTypeVariable, - parameterTypes: Array?, - isSuitable: ConeKotlinType.() -> Boolean, - typeVariableCreator: () -> V, - newAtomCreator: (V, ConeKotlinType) -> PostponedResolvedAtom - ): PostponedResolvedAtom { - val functionalType = (inferenceComponents.resultTypeResolver.findResultType( - c, - c.notFixedTypeVariables.getValue(variable.typeConstructor), - TypeVariableDirectionCalculator.ResolveDirection.TO_SUPERTYPE - ) as ConeKotlinType).lowerBoundIfFlexible() - val isExtensionWithoutParameters = functionalType.isExtensionFunctionType && functionalType.typeArguments.size == 2 && parameterTypes?.isEmpty() == true - if (parameterTypes?.all { type -> type != null } == true && !isExtensionWithoutParameters) return this - if (!functionalType.isSuitable()) return this - require(functionalType is ConeClassLikeType) - val returnVariable = typeVariableCreator() - csBuilder.registerVariable(returnVariable) + private fun ConstraintSystemCompletionContext.analyzeNextReadyPostponedArgument( + postponedArguments: List, + completionMode: ConstraintSystemCompletionMode, + analyze: (PostponedResolvedAtom) -> Unit, + ): Boolean { + if (completionMode == ConstraintSystemCompletionMode.FULL) { + val argumentWithTypeVariableAsExpectedType = findPostponedArgumentWithRevisableExpectedType(postponedArguments) - val expectedType = ConeClassLikeTypeImpl( - lookupTag = functionalType.lookupTag, - typeArguments = (functionalType.typeArguments.dropLast(1) + returnVariable.defaultType).toTypedArray(), - isNullable = functionalType.isNullable, - attributes = functionalType.attributes - ) + if (argumentWithTypeVariableAsExpectedType != null) { + analyze(argumentWithTypeVariableAsExpectedType) + return true + } + } - csBuilder.addSubtypeConstraint( - expectedType, - variable.defaultType, - SimpleConstraintSystemConstraintPosition -// ArgumentConstraintPosition(atom as KotlinCallArgument) - ) - return newAtomCreator(returnVariable, expectedType) + return analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze) } + // Avoiding smart cast from filterIsInstanceOrNull looks dirty + private fun findPostponedArgumentWithRevisableExpectedType(postponedArguments: List) = + postponedArguments.firstOrNull { argument -> argument is PostponedAtomWithRevisableExpectedType } + + private fun ConstraintSystemCompletionContext.fixVariablesOrReportNotEnoughInformation( + completionMode: ConstraintSystemCompletionMode, + topLevelAtoms: List, + topLevelType: ConeKotlinType, + collectVariablesFromContext: Boolean, + postponedArguments: List, + ): Boolean { + while (true) { + val variableForFixation = variableFixationFinder.findFirstVariableForFixation( + this, + getOrderedAllTypeVariables(asConstraintSystemCompletionContext(), topLevelAtoms, collectVariablesFromContext), + postponedArguments, + completionMode, + topLevelType + ) ?: break + + if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL) + break + + val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable) + + if (variableForFixation.hasProperConstraint) { + fixVariable(asConstraintSystemCompletionContext(), variableWithConstraints) + return true + } else { +// TODO("Not enough information for parameter") + fixVariable(asConstraintSystemCompletionContext(), variableWithConstraints) // means Nothing/Any instead of Error type + } + } + + return false + } + + 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 ConstraintSystemCompletionContext.hasLambdaToAnalyze( + postponedArguments: List + ): Boolean { + return analyzeArgumentWithFixedParameterTypes(postponedArguments) {} + } private fun getOrderedAllTypeVariables( c: ConstraintSystemCompletionContext, topLevelAtoms: List, collectVariablesFromContext: Boolean - ): List { + ): List = with(c) { if (collectVariablesFromContext) { return c.notFixedTypeVariables.keys.toList() } @@ -175,15 +255,31 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { fun ConeTypeVariable?.toTypeConstructor(): TypeConstructorMarker? = this?.typeConstructor?.takeIf { it in c.notFixedTypeVariables.keys } + // TODO: non-top-level variables? + fun PostponedAtomWithRevisableExpectedType.collectNotFixedVariables() { + revisedExpectedType?.getArguments()?.map { it.getType().typeConstructor() } + ?.filterIsInstance().orEmpty() + .mapNotNullTo(result) { it.takeIf { it in notFixedTypeVariables } } + } + fun FirStatement.collectAllTypeVariables() { this.processAllContainingCallCandidates(processBlocks = true) { candidate -> candidate.freshVariables.mapNotNullTo(result) { typeVariable -> typeVariable.toTypeConstructor() } - for (lambdaAtom in candidate.postponedAtoms) { - if (lambdaAtom is ResolvedLambdaAtom) { - result.addIfNotNull(lambdaAtom.typeVariableForLambdaReturnType.toTypeConstructor()) + for (postponedAtom in candidate.postponedAtoms) { + when { + postponedAtom is ResolvedLambdaAtom -> { + result.addIfNotNull(postponedAtom.typeVariableForLambdaReturnType.toTypeConstructor()) + } + postponedAtom is LambdaWithTypeVariableAsExpectedTypeAtom -> { + postponedAtom.collectNotFixedVariables() + } + postponedAtom is ResolvedCallableReferenceAtom -> { + if (postponedAtom.postponed) + postponedAtom.collectNotFixedVariables() + } } } } @@ -203,30 +299,17 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { private fun fixVariable( c: ConstraintSystemCompletionContext, - topLevelType: KotlinTypeMarker, variableWithConstraints: VariableWithConstraints, - postponedResolveKtPrimitives: List ) { - val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints) - val resultType = inferenceComponents.resultTypeResolver.findResultType(c, variableWithConstraints, direction) + val resultType = inferenceComponents.resultTypeResolver.findResultType( + c, + variableWithConstraints, + TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN + ) val variable = variableWithConstraints.typeVariable c.fixVariable(variable, resultType, ConeFixVariableConstraintPosition(variable)) // TODO: obtain atom for diagnostics } - private fun analyzePostponeArgumentIfPossible( - c: ConstraintSystemCompletionContext, - topLevelAtoms: List, - analyze: (PostponedResolvedAtom) -> Unit - ): Boolean { - for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)) { - if (canWeAnalyzeIt(c, argument)) { - analyze(argument) - return true - } - } - return false - } - private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List): List { val notAnalyzedArguments = arrayListOf() for (primitive in topLevelAtoms) { @@ -243,11 +326,6 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { return notAnalyzedArguments } - - private fun canWeAnalyzeIt(c: ConstraintSystemCompletionContext, argument: PostponedResolvedAtomMarker): Boolean { - if (argument.analyzed) return false - return argument.inputTypes.all { c.containsOnlyFixedOrPostponedVariables(it) } - } } fun FirStatement.processAllContainingCallCandidates(processBlocks: Boolean, processor: (Candidate) -> Unit) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt index 8840235b13d..cb1df83b5c1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt @@ -25,11 +25,12 @@ class InferenceComponents(val session: FirSession) : FirSessionComponent { session.languageVersionSettings, ) val resultTypeResolver = ResultTypeResolver(approximator, trivialConstraintTypeInferenceOracle) + val variableFixationFinder = VariableFixationFinder(trivialConstraintTypeInferenceOracle, session.languageVersionSettings) + val postponedArgumentInputTypesResolver = + PostponedArgumentInputTypesResolver(resultTypeResolver, variableFixationFinder, ConeConstraintSystemUtilContext) val constraintSystemFactory = ConstraintSystemFactory() - val variableFixationFinder = VariableFixationFinder(trivialConstraintTypeInferenceOracle, session.languageVersionSettings) - fun createConstraintSystem(): NewConstraintSystemImpl { return NewConstraintSystemImpl(injector, ctx) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt index e73d0979fd1..3eafe7e786f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt @@ -17,7 +17,8 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeVariable import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType +import org.jetbrains.kotlin.resolve.calls.model.LambdaWithTypeVariableAsExpectedTypeMarker +import org.jetbrains.kotlin.resolve.calls.model.PostponedCallableReferenceMarker import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.types.model.KotlinTypeMarker @@ -25,6 +26,7 @@ import org.jetbrains.kotlin.types.model.KotlinTypeMarker // --------------------------- Variables --------------------------- class ConeTypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name) +class ConeTypeVariableForPostponedAtom(name: String) : ConeTypeVariable(name) // -------------------------- Atoms -------------------------- @@ -61,15 +63,27 @@ class ResolvedLambdaAtom( class LambdaWithTypeVariableAsExpectedTypeAtom( val atom: FirAnonymousFunction, - override val expectedType: ConeKotlinType, + private val initialExpectedTypeType: ConeKotlinType, val expectedTypeRef: FirTypeRef, - val candidateOfOuterCall: Candidate -) : PostponedResolvedAtom(), PostponedAtomWithRevisableExpectedType { + val candidateOfOuterCall: Candidate, +) : PostponedResolvedAtom(), LambdaWithTypeVariableAsExpectedTypeMarker { init { candidateOfOuterCall.postponedAtoms += this } - override val inputTypes: Collection get() = listOf(expectedType) + override var parameterTypesFromDeclaration: List? = null + private set + + override fun updateParameterTypesFromDeclaration(types: List?) { + @Suppress("UNCHECKED_CAST") + types as List? + parameterTypesFromDeclaration = types + } + + override val expectedType: ConeKotlinType + get() = revisedExpectedType ?: initialExpectedTypeType + + override val inputTypes: Collection get() = listOf(initialExpectedTypeType) override val outputType: ConeKotlinType? get() = null override var revisedExpectedType: ConeKotlinType? = null private set @@ -84,10 +98,11 @@ class LambdaWithTypeVariableAsExpectedTypeAtom( class ResolvedCallableReferenceAtom( val reference: FirCallableReferenceAccess, - override val expectedType: ConeKotlinType?, + private val initialExpectedType: ConeKotlinType?, val lhs: DoubleColonLHS?, private val session: FirSession -) : PostponedResolvedAtom() { +) : PostponedResolvedAtom(), PostponedCallableReferenceMarker { + // TODO: in several places atoms are filtered by the marker interface - potential overhead/errors var postponed: Boolean = false var resultingCandidate: Pair? = null @@ -103,6 +118,22 @@ class ResolvedCallableReferenceAtom( if (!postponed) return null return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.outputType } + + override val expectedType: ConeKotlinType? + get() = if (!postponed) + initialExpectedType + else + revisedExpectedType ?: initialExpectedType + + override var revisedExpectedType: ConeKotlinType? = null + get() = if (postponed) field else expectedType + private set + + override fun reviseExpectedType(expectedType: KotlinTypeMarker) { + if (!postponed) return + require(expectedType is ConeKotlinType) + revisedExpectedType = expectedType + } } // -------------------------- Utils -------------------------- diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt index 109d00e8af7..b47668ca492 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.inference.model +import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.FixVariableConstraintPosition import org.jetbrains.kotlin.types.model.TypeVariableMarker @@ -12,3 +13,5 @@ import org.jetbrains.kotlin.types.model.TypeVariableMarker class ConeDeclaredUpperBoundConstraintPosition : DeclaredUpperBoundConstraintPosition(null) class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVariableConstraintPosition(variable, null) + +class ConeArgumentConstraintPosition : ArgumentConstraintPosition(null) \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt index 9ace81aa110..166ab8f9f74 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirTargetElement import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind 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 e293af86084..b7257206100 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 @@ -5,10 +5,13 @@ package org.jetbrains.kotlin.fir.types +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic import org.jetbrains.kotlin.fir.isPrimitiveNumberOrUnsignedNumberType import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.NoSubstitutor +import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType +import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor @@ -20,7 +23,9 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.kotlin.utils.addToStdlib.safeAs interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeContext { @@ -49,19 +54,22 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo return coneFlexibleOrSimpleType(this, lowerBound, upperBound) } - // TODO: implement taking into account `isExtensionFunction` override fun createSimpleType( constructor: TypeConstructorMarker, arguments: List, nullable: Boolean, isExtensionFunction: Boolean ): SimpleTypeMarker { + val attributes = if (isExtensionFunction) // TODO: assert correct type constructor + ConeAttributes.create(listOf(CompilerConeAttributes.ExtensionFunctionType)) + else ConeAttributes.Empty @Suppress("UNCHECKED_CAST") return when (constructor) { is ConeClassLikeLookupTag -> ConeClassLikeTypeImpl( constructor, (arguments as List).toTypedArray(), - nullable + nullable, + attributes, ) is ConeTypeParameterLookupTag -> ConeTypeParameterTypeImpl( constructor, @@ -203,7 +211,14 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo return this.typeConstructor().isUnitTypeConstructor() && !this.isNullable } - override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype() = TODO() + override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean { + require(this is ConeKotlinType) + return this.isTypeOrSubtypeOf { + it.lowerBoundIfFlexible().safeAs()?.isBuiltinFunctionalType(session) + ?: error("Unexpected lower bound for type: ${it.render()}") + } + } + override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker { require(this is ConeKotlinType) @@ -376,4 +391,97 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo if (this !is ConeClassLikeType) return false return isPrimitiveNumberOrUnsignedNumberType() } + + override fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean { + require(this is ConeKotlinType) + return this.isBuiltinFunctionalType(session) + } + + private fun ConeKotlinType.isTypeOrSubtypeOf(predicate: (ConeKotlinType) -> Boolean): Boolean { + return predicate(this) || DFS.dfsFromNode( + this, + { + // FIXME supertypes of type constructor contain unsubstituted arguments + it.typeConstructor().supertypes().cast>() + }, + DFS.VisitedWithSet(), + object : DFS.AbstractNodeHandler() { + private var result = false + + override fun beforeChildren(current: ConeKotlinType): Boolean { + if (predicate(current)) { + result = true + } + return !result + } + + override fun result() = result + } + ) + } + + override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean { + require(this is ConeKotlinType) + return isTypeOrSubtypeOf { + it.lowerBoundIfFlexible().safeAs()?.isSuspendFunctionType(session) + ?: error("Unexpected lower bound for type: ${it.render()}") + } + } + + override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean { + require(this is ConeKotlinType) + return this.lowerBoundIfFlexible().safeAs()?.isExtensionFunctionType(session) == true + } + + @ExperimentalStdlibApi + override fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List { + val builtInFunctionalType = getFunctionalTypeFromSupertypes().cast() + return buildList { + // excluding return type + for (index in 0 until builtInFunctionalType.argumentsCount() - 1) { + add(builtInFunctionalType.getArgument(index).getType()) + } + } + } + + override fun KotlinTypeMarker.getFunctionalTypeFromSupertypes(): KotlinTypeMarker { + require(this is ConeKotlinType) + assert(this.isBuiltinFunctionalTypeOrSubtype()) { + "Not a function type or subtype: ${this.render()}" + } + + return fullyExpandedType(session).let { + val simpleType = it.lowerBoundIfFlexible() + if (simpleType.safeAs()?.isBuiltinFunctionalType(session) == true) + this + else { + var functionalSupertype: KotlinTypeMarker? = null + simpleType.anySuperTypeConstructor { typeConstructor -> + simpleType.fastCorrespondingSupertypes(typeConstructor)?.any { superType -> + val isFunctional = superType.cast().isBuiltinFunctionalType(session) + if (isFunctional) + functionalSupertype = superType + isFunctional + } ?: false + } + functionalSupertype ?: error("Failed to find functional supertype for $simpleType") + } + } + } + + override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { + val classId = if (isSuspend) + StandardNames.getSuspendFunctionClassId(parametersNumber) + else StandardNames.getFunctionClassId(parametersNumber) + return session.firSymbolProvider.getClassLikeSymbolByFqName(classId)?.toLookupTag() + ?: error("Can't find Function type") + } + + override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { + val classId = if (isSuspend) + StandardNames.getKSuspendFunctionClassId(parametersNumber) + else StandardNames.getKFunctionClassId(parametersNumber) + return session.firSymbolProvider.getClassLikeSymbolByFqName(classId)?.toLookupTag() + ?: error("Can't find KFunction type") + } } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemUtilContext.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemUtilContext.kt index f97e4b45389..973bf0ce2f8 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemUtilContext.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemUtilContext.kt @@ -25,23 +25,16 @@ interface ConstraintSystemUtilContext { fun KotlinTypeMarker.refineType(): KotlinTypeMarker // PostponedArgumentInputTypesResolver - fun extractFunctionalTypeFromSupertypes(type: KotlinTypeMarker): KotlinTypeMarker - fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List - fun KotlinTypeMarker.isFunctionOrKFunctionTypeWithAnySuspendability(): Boolean - fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean fun createArgumentConstraintPosition(argument: T): ArgumentConstraintPosition fun createFixVariableConstraintPosition(variable: TypeVariableMarker, atom: T): FixVariableConstraintPosition fun extractParameterTypesFromDeclaration(declaration: PostponedAtomWithRevisableExpectedType): List? - fun KotlinTypeMarker.isExtensionFunctionType(): Boolean - fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker - fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker - fun isAnonymousFunction(argument: PostponedAtomWithRevisableExpectedType): Boolean + fun PostponedAtomWithRevisableExpectedType.isAnonymousFunction(): Boolean fun PostponedAtomWithRevisableExpectedType.isFunctionExpressionWithReceiver(): Boolean fun createTypeVariableForLambdaReturnType(): TypeVariableMarker fun createTypeVariableForLambdaParameterType(argument: PostponedAtomWithRevisableExpectedType, index: Int): TypeVariableMarker + fun createTypeVariableForCallableReferenceReturnType(): TypeVariableMarker fun createTypeVariableForCallableReferenceParameterType( argument: PostponedAtomWithRevisableExpectedType, index: Int ): TypeVariableMarker - fun createTypeVariableForCallableReferenceReturnType(): TypeVariableMarker } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt index 3ecd6b7e21c..f4b2269d5c5 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt @@ -38,7 +38,7 @@ class PostponedArgumentInputTypesResolver( variableDependencyProvider: TypeVariableDependencyInformationProvider ): List? { fun List.extractFunctionalTypes() = mapNotNull { constraint -> - TypeWithKind(resolutionTypeSystemContext.extractFunctionalTypeFromSupertypes(constraint.type), constraint.kind) + TypeWithKind(constraint.type.getFunctionalTypeFromSupertypes(), constraint.kind) } val typeVariableTypeConstructor = variable.typeVariable.freshTypeConstructor() @@ -216,7 +216,7 @@ class PostponedArgumentInputTypesResolver( parametersNumber: Int, isSuspend: Boolean, resultTypeResolver: ResultTypeResolver - ): TypeConstructorMarker = with(resolutionTypeSystemContext) { + ): TypeConstructorMarker { val expectedType = argument.expectedType ?: throw IllegalStateException("Postponed argument's expected type must not be null") @@ -263,7 +263,7 @@ class PostponedArgumentInputTypesResolver( * * TODO: regarding anonymous functions: see info about need for analysis in partial mode in `collectParameterTypesAndBuildNewExpectedTypes` */ - if (areAllParameterTypesSpecified && !isExtensionFunction && !isAnonymousFunction(argument)) + if (areAllParameterTypesSpecified && !isExtensionFunction && !argument.isAnonymousFunction()) return null val allParameterTypes = @@ -283,7 +283,6 @@ class PostponedArgumentInputTypesResolver( resultTypeResolver ) - val isExtensionFunctionType = parameterTypesInfo.isExtensionFunction val areParametersNumberInDeclarationAndConstraintsEqual = !parametersFromDeclaration.isNullOrEmpty() && !parametersFromConstraints.isNullOrEmpty() && parametersFromDeclaration.size == parametersFromConstraints.first().size @@ -295,7 +294,7 @@ class PostponedArgumentInputTypesResolver( * Example: `val x: String.() -> Int = id { x: String -> 42 }` */ val shouldDiscriminateExtensionFunctionAnnotation = - isExtensionFunctionType && areAllParameterTypesSpecified && areParametersNumberInDeclarationAndConstraintsEqual + isExtensionFunction && areAllParameterTypesSpecified && areParametersNumberInDeclarationAndConstraintsEqual /* * We need to add an extension function annotation for anonymous functions with an explicitly specified receiver @@ -344,7 +343,7 @@ class PostponedArgumentInputTypesResolver( * * TODO: investigate why we can't do it for anonymous functions in full mode always (see `diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt`) */ - if (completionMode == ConstraintSystemCompletionMode.PARTIAL && !isAnonymousFunction(argument)) + if (completionMode == ConstraintSystemCompletionMode.PARTIAL && !argument.isAnonymousFunction()) return@any false if (argument.revisedExpectedType != null) return@any false val parameterTypesInfo = @@ -402,10 +401,10 @@ class PostponedArgumentInputTypesResolver( topLevelType: KotlinTypeMarker, dependencyProvider: TypeVariableDependencyInformationProvider, resolvedAtomProvider: ResolvedAtomProvider - ): Boolean = with(resolutionTypeSystemContext) { + ): Boolean = with(c) { val expectedType = argument.run { safeAs()?.revisedExpectedType ?: expectedType } - if (expectedType != null && expectedType.isFunctionOrKFunctionTypeWithAnySuspendability()) { + if (expectedType != null && expectedType.isFunctionOrKFunctionWithAnySuspendability()) { val wasFixedSomeVariable = c.fixNextReadyVariableForParameterType( expectedType, postponedArguments, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ClassicConstraintSystemUtilContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ClassicConstraintSystemUtilContext.kt index 5deb915bfe4..76f469e8ff9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ClassicConstraintSystemUtilContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ClassicConstraintSystemUtilContext.kt @@ -51,26 +51,6 @@ class ClassicConstraintSystemUtilContext( return kotlinTypeRefiner.refineType(this) } - override fun extractFunctionalTypeFromSupertypes(type: KotlinTypeMarker): KotlinTypeMarker { - require(type is KotlinType) - return type.extractFunctionalTypeFromSupertypes() - } - - override fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List { - require(this is KotlinType) - return this.getPureArgumentsForFunctionalTypeOrSubtype() - } - - override fun KotlinTypeMarker.isFunctionOrKFunctionTypeWithAnySuspendability(): Boolean { - require(this is KotlinType) - return this.isFunctionOrKFunctionTypeWithAnySuspendability - } - - override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean { - require(this is KotlinType) - return this.isSuspendFunctionTypeOrSubtype - } - override fun createArgumentConstraintPosition(argument: T): ArgumentConstraintPosition { require(argument is ResolvedAtom) @Suppress("UNCHECKED_CAST") @@ -95,22 +75,9 @@ class ClassicConstraintSystemUtilContext( } } - override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean { - require(this is KotlinType) - return this.isExtensionFunctionType - } - - override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - return getFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor - } - - override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - return getKFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor - } - - override fun isAnonymousFunction(argument: PostponedAtomWithRevisableExpectedType): Boolean { - require(argument is ResolvedAtom) - return argument.atom is FunctionExpression + override fun PostponedAtomWithRevisableExpectedType.isAnonymousFunction(): Boolean { + require(this is ResolvedAtom) + return this.atom is FunctionExpression } override fun PostponedAtomWithRevisableExpectedType.isFunctionExpressionWithReceiver(): Boolean { 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 3c7fef38456..e28b8e07035 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 @@ -150,9 +150,9 @@ class KotlinConstraintSystemCompleter( c: ConstraintSystemCompletionContext, argument: PostponedAtomWithRevisableExpectedType, diagnosticsHolder: KotlinDiagnosticsHolder - ): Boolean = with(ctx) { + ): Boolean = with(c) { val revisedExpectedType: UnwrappedType = - argument.revisedExpectedType?.takeIf { it.isFunctionOrKFunctionTypeWithAnySuspendability() }?.cast() ?: return false + argument.revisedExpectedType?.takeIf { it.isFunctionOrKFunctionWithAnySuspendability() }?.cast() ?: return false when (argument) { is PostponedCallableReferenceAtom -> 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 592176ba67c..d2c8123f9eb 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 @@ -212,8 +212,7 @@ class CallableReferenceWithRevisedExpectedTypeAtom( class PostponedCallableReferenceAtom( eagerCallableReferenceAtom: EagerCallableReferenceAtom ) : AbstractPostponedCallableReferenceAtom(eagerCallableReferenceAtom.atom, eagerCallableReferenceAtom.expectedType), - PostponedCallableReferenceMarker, - PostponedAtomWithRevisableExpectedType + PostponedCallableReferenceMarker { override var revisedExpectedType: UnwrappedType? = null private set diff --git a/compiler/testData/codegen/box/closures/capturedVarsOptimization/capturedInInlineOnlyIndexedCAO.kt b/compiler/testData/codegen/box/closures/capturedVarsOptimization/capturedInInlineOnlyIndexedCAO.kt index 11d2983d00f..44e0531c7b7 100644 --- a/compiler/testData/codegen/box/closures/capturedVarsOptimization/capturedInInlineOnlyIndexedCAO.kt +++ b/compiler/testData/codegen/box/closures/capturedVarsOptimization/capturedInInlineOnlyIndexedCAO.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // WITH_RUNTIME class Host(var value: String) { diff --git a/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt b/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt index cd1e4daa3b0..ccddcecf6a6 100644 --- a/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt @@ -5,5 +5,5 @@ fun foo(x: Any, y: Int) = y fun main() { ::foo - val fooRef: (Int, Any) -> Unit = ::foo + val fooRef: (Int, Any) -> Unit = ::foo } diff --git a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt index dc35cde2de0..aec54f0d794 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt @@ -19,6 +19,6 @@ fun testFunctions() { fun testNestedCalls() { id(inferFromLambda { materialize() }) - id(inferFromLambda(fun() = materialize())) - id(inferFromLambda2(fun() = materialize())) + id(inferFromLambda(fun() = materialize())) + id(inferFromLambda2(fun() = materialize())) } diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt index e2d534ab09f..a5d809a3cd3 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -64,14 +64,14 @@ class A5: Function2 { fun main() { // 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 { 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 { it }, id1 { x: Inv -> TODO() }, id1 { x: Inv -> TODO() }) - select(id(id2 { it.inv() }), id(id { x: Int -> x })) + 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))) @@ -90,7 +90,7 @@ fun main() { takeDependentLambdas({ it; 10 }, { }) // Inferring lambda parameter types by anonymous function parameters - select({ it }, fun(x: Int) = 1) + 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 }) @@ -110,8 +110,8 @@ fun main() { 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 { it }) - val x11: (B) -> Unit = selectC(id { }, id { x -> x }, id { it }) + val x10: (Int) -> Unit = selectFloat(id { }, id { x -> }, id { ")!>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) /* @@ -121,7 +121,7 @@ fun main() { */ 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 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 @@ -130,7 +130,7 @@ fun main() { * 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 }) + 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 /* @@ -138,7 +138,7 @@ fun main() { * 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 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 @@ -147,8 +147,8 @@ fun main() { val x21: String.() -> Unit = select(")!>id(fun(x: String) {}), ")!>id(fun(x: String) {})) select(id Unit>(fun(x: String) {}), ")!>id(fun(x: String) {})) select(")!>id(fun String.(x: String) {}), ")!>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 -> 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 }) @@ -159,9 +159,9 @@ fun main() { 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() }) + 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 }) @@ -180,56 +180,56 @@ fun main() { takeLambdasWithInverselyDependentTypeParameters({ it }, { x: Number -> x }, { x: Int -> x }) // Inferring lambda parameter types by subtypes of functional type - ")!>select(A2(), { a, b, c -> a; b; c }) - ")!>select(A3(), { it }, { a -> a }) + ")!>select(A2(), { a, b, c -> a; b; c }) + ")!>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 }) + ")!>select(A3(), ")!>A3::foo1, { a -> a }, { it -> it }) // It's OK because `A3::foo2` is from companion of `A3` - ")!>select(A3(), ")!>A3::foo2, { a -> a }, { it -> it }) + ")!>select(A3(), ")!>A3::foo2, { a -> a }, { it -> it }) & java.io.Serializable>")!>select(A4(), { x: Number -> "" }) & java.io.Serializable>")!>select(A5(), { x: Number, y: Int -> "" }) - select(A2(), id { a, b, c -> a; b; c }) - ")!>select(id(A3()), { it }, { a -> a }) + ")!>select(A2(), id { a, b, c -> a; b; c }) + ")!>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 }) + ")!>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 }) - select(A4(), id { x: Number -> x }) - ")!>select(id(A5()), id { x: Number, y: Int -> x;y }) - ")!>select(id(A5()), id { x, y -> x;y }) + ")!>select(id(A3()), id(")!>A3::foo1), { a: Number -> a }) + ")!>select(id(A3()), id(")!>A3::foo1), id { a: Number -> a }) + ")!>select(A4(), id { x: Number -> x }) + >")!>select(id(A5()), id { x: Number, y: Int -> x;y }) + >")!>select(id(A5()), id { x, y -> x;y }) >")!>select(id(")!>A5()), id { x: Number, y: Int -> x;y }) - val x55: Function2 = select(id(A5()), id { x, y -> x;y; 1f }) + 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 -> "" }) - >")!>select({ x: Int -> 1 }, { x: Int, y: Number -> 1f }) - >")!>select(id { x: Int -> Inv(10) }, { x: String -> Inv("") }) + ")!>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 -> "" }) + >")!>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() }) + ")!>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()" }) // Anonymous functions - val x69: (C) -> Unit = selectB({ it }, { }, id(fun (x) { x })) + val x69: (C) -> Unit = selectB({ it }, { }, id(fun (x) { x })) select(id1(fun(it) { it.inv() }), id1 { x: Number -> TODO() }, id1(id2(::takeInt))) select(id(fun (it) { it }), id(id<(Int) -> Unit> { x: Number -> Unit })) select(id(fun (it) { it.inv() }), id<(Int) -> Unit> { }) val x70: (Int) -> Unit = selectNumber(id(fun (it) { }), id {}, id {}) val x71: String.() -> Unit = select(")!>id(fun String.() { }), ")!>id(fun(x: String) {})) val x72: String.() -> Unit = select(fun String.() { }, fun(x: String) {}) // must be error - select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { x;y }) + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { x;y }) select(id Unit>(fun (x, y) {}), { x: Int, y: String -> x }) // receiver of anonymous function must be specified explicitly select(id Unit>(fun Int.(y) {}), { x: Int, y: String -> x }) - ")!>select(A3(), fun (x) = "", { a -> a }) + ")!>select(A3(), fun (x) = "", { a -> a }) } diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt deleted file mode 100644 index 0c57ab8574b..00000000000 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt +++ /dev/null @@ -1,8 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER - -fun id(x: T) = x -fun select(vararg x: T) = x[0] - -val x1 = select(id { this }, fun Int.() = this) -val x2 = select(id { this + it.inv() }, fun Int.(x: Int) = this) -val x3 = select(id { this.length + it.inv() }, fun String.(x: Int) = length) diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt index 3fa8df88796..7a6ce4b2d89 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER fun id(x: T) = x diff --git a/compiler/testData/diagnostics/tests/inference/expectedTypeAdditionalTest.fir.kt b/compiler/testData/diagnostics/tests/inference/expectedTypeAdditionalTest.fir.kt index 1dac5d3aeb0..ac4946072b5 100644 --- a/compiler/testData/diagnostics/tests/inference/expectedTypeAdditionalTest.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/expectedTypeAdditionalTest.fir.kt @@ -7,7 +7,8 @@ fun foo() = foo() as T fun foo2(): T = TODO() -val test = foo2().plus("") as String +// TODO: "not enough information" should be reported on foo2() instead +val test = foo2().plus("") as String fun T.bar() = this val barTest = "".bar() as Number \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/kt32462.fir.kt b/compiler/testData/diagnostics/tests/inference/kt32462.fir.kt index 4ffa2eeff8a..64284609ab5 100644 --- a/compiler/testData/diagnostics/tests/inference/kt32462.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/kt32462.fir.kt @@ -22,6 +22,6 @@ fun test_1() { fun test_2() { select( A::toB, - A::toC + A::toC ) } diff --git a/compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt b/compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt new file mode 100644 index 00000000000..a365e67ebef --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt @@ -0,0 +1,15 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNREACHABLE_CODE + +interface Some { + fun method(): Unit +} + +fun elvis(nullable: S?, notNullable: S): S = TODO() + +fun Some.doWithPredicate(predicate: (R) -> Unit): R? = TODO() + +fun test(derived: Some) { + val expected: Some = derived.doWithPredicate { it.method() } ?: TODO() + val expected2: Some = elvis(derived.doWithPredicate { it.method() }, TODO()) +} diff --git a/compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.txt b/compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.txt new file mode 100644 index 00000000000..0038771c0e6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.txt @@ -0,0 +1,12 @@ +package + +public fun elvis(/*0*/ nullable: S?, /*1*/ notNullable: S): S +public fun test(/*0*/ derived: Some): kotlin.Unit +public fun Some.doWithPredicate(/*0*/ predicate: (R) -> kotlin.Unit): R? + +public interface Some { + 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 fun method(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt41394.fir.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt41394.fir.kt new file mode 100644 index 00000000000..50cc43d36a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt41394.fir.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER +// !LANGUAGE: +InferenceCompatibility + +fun foo(x: T, fn: (VR?, T) -> Unit) {} + +fun takeInt(x: Int) {} + +fun main(x: Int) { + foo(x) { prev: Int?, new -> takeInt(new) } // `new` is `Int` in OI, `Int?` in NI +} diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt index 8f6d0d7fc37..ba68e417ef0 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER // !LANGUAGE: +InferenceCompatibility diff --git a/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.fir.kt b/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.fir.kt deleted file mode 100644 index 157ae3b5566..00000000000 --- a/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.fir.kt +++ /dev/null @@ -1,20 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -DEPRECATION -EXPERIMENTAL_IS_NOT_ENABLED -UNUSED_VARIABLE -// WITH_RUNTIME - -import kotlin.experimental.ExperimentalTypeInference - -@UseExperimental(ExperimentalTypeInference::class) -fun combined( - check: () -> Unit, - @BuilderInference block: TestInterface.() -> Unit -): R = TODO() - -interface TestInterface { - fun emit(r: R) -} - -fun test() { - val ret = combined({ }) { - emit(1) - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.kt b/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.kt index 72bcb817bda..058d3959182 100644 --- a/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.kt +++ b/compiler/testData/diagnostics/tests/inference/simpleLambdaInCallWithAnotherLambdaWithBuilderInference.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER -DEPRECATION -EXPERIMENTAL_IS_NOT_ENABLED -UNUSED_VARIABLE // WITH_RUNTIME diff --git a/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.fir.kt b/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.fir.kt deleted file mode 100644 index c7a162d39fc..00000000000 --- a/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.fir.kt +++ /dev/null @@ -1,36 +0,0 @@ -// !WITH_NEW_INFERENCE -//If this test hangs, it means something is broken. -package a - -object A { - val iii = 42 -} - -//inappropriate but participating in resolve functions -fun foo(s: String, a: Any) = s + a -fun foo(a: Any, s: String) = s + a -fun foo(i: Int, j: Int) = i + j -fun foo(a: Any, i: Int) = "$a$i" -fun foo(f: (Int) -> Int, i: Int) = f(i) -fun foo(f: (String) -> Int, s: String) = f(s) -fun foo(f: (Any) -> Int, a: Any) = f(a) -fun foo(s: String, f: (String) -> Int) = f(s) -fun foo(a: Any, f: (Any) -> Int) = f(a) -//appropriate function -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) = - x1 + x2 + x3 + x4 + x5 + A.iii - )) - )) - )) - )) - )) -} diff --git a/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt b/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt index 67b4400b312..7244f734de2 100644 --- a/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt +++ b/compiler/testData/diagnostics/tests/resolve/resolveWithSpecifiedFunctionLiteralWithId.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !WITH_NEW_INFERENCE //If this test hangs, it means something is broken. package a diff --git a/compiler/testData/diagnostics/tests/resolve/specialConstructions/inferenceForElvis.fir.kt b/compiler/testData/diagnostics/tests/resolve/specialConstructions/inferenceForElvis.fir.kt index 06ba1f69025..e3f2ccf61b0 100644 --- a/compiler/testData/diagnostics/tests/resolve/specialConstructions/inferenceForElvis.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/specialConstructions/inferenceForElvis.fir.kt @@ -4,5 +4,5 @@ fun foo(f: (T) -> Unit): T? = null // T is used only as return type fun test() { val x = foo { it checkType { _() }} ?: "" // foo() is inferred as foo, which isn't very good - val y: Any = foo { it checkType { _() } } ?: "" // but for now it's fixed by specifying expected type + val y: Any = foo { it checkType { _() } } ?: "" // but for now it's fixed by specifying expected type } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index a26191251d0..83bf7f40210 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10454,6 +10454,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt"); } + @TestMetadata("lambdaParameterTypeInElvis.kt") + public void testLambdaParameterTypeInElvis() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt"); + } + @TestMetadata("listConstructor.kt") public void testListConstructor() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/listConstructor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 25aa047b7d7..fbf37f80c75 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10449,6 +10449,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt"); } + @TestMetadata("lambdaParameterTypeInElvis.kt") + public void testLambdaParameterTypeInElvis() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/lambdaParameterTypeInElvis.kt"); + } + @TestMetadata("listConstructor.kt") public void testListConstructor() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/listConstructor.kt"); diff --git a/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt b/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt index 608fbd6ba55..25c7dca454c 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/builtins/StandardNames.kt @@ -208,14 +208,20 @@ object StandardNames { return "Function$parameterCount" } + @JvmStatic + fun getFunctionClassId(parameterCount: Int): ClassId { + return ClassId(BUILT_INS_PACKAGE_FQ_NAME, Name.identifier(getFunctionName(parameterCount))) + } + @JvmStatic fun getKFunctionFqName(parameterCount: Int): FqNameUnsafe { return reflect(FunctionClassKind.KFunction.classNamePrefix + parameterCount) } @JvmStatic - fun getFunctionClassId(parameterCount: Int): ClassId { - return ClassId(BUILT_INS_PACKAGE_FQ_NAME, Name.identifier(getFunctionName(parameterCount))) + fun getKFunctionClassId(parameterCount: Int): ClassId { + val fqName = getKFunctionFqName(parameterCount) + return ClassId(fqName.parent().toSafe(), fqName.shortName()) } @JvmStatic @@ -228,6 +234,17 @@ object StandardNames { return ClassId(COROUTINES_PACKAGE_FQ_NAME_RELEASE, Name.identifier(getSuspendFunctionName(parameterCount))) } + @JvmStatic + fun getKSuspendFunctionName(parameterCount: Int): FqNameUnsafe { + return reflect(FunctionClassKind.KSuspendFunction.classNamePrefix + parameterCount) + } + + @JvmStatic + fun getKSuspendFunctionClassId(parameterCount: Int): ClassId { + val fqName = getKSuspendFunctionName(parameterCount) + return ClassId(fqName.parent().toSafe(), fqName.shortName()) + } + @JvmStatic fun isPrimitiveArray(arrayFqName: FqNameUnsafe): Boolean { return FqNames.arrayClassFqNameToPrimitiveType.get(arrayFqName) != null diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index c1f2dd1d9c5..1528abbfed3 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -193,6 +193,20 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun TypeVariableTypeConstructorMarker.isContainedInInvariantOrContravariantPositions(): Boolean fun KotlinTypeMarker.isSignedOrUnsignedNumberType(): Boolean + + fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean + + fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean + + fun KotlinTypeMarker.isExtensionFunctionType(): Boolean + + fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List + + fun KotlinTypeMarker.getFunctionalTypeFromSupertypes(): KotlinTypeMarker + + fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker + + fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker } 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 a3f031f2c44..0e1753d4d13 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -5,10 +5,8 @@ package org.jetbrains.kotlin.types.checker -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.builtins.StandardNames.FqNames -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 @@ -674,6 +672,39 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy } ?: error("Expected intersection type, found $firstCandidate") } + + override fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean { + require(this is KotlinType, this::errorMessage) + return this.isFunctionOrKFunctionTypeWithAnySuspendability + } + + override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean { + require(this is KotlinType, this::errorMessage) + return this.isSuspendFunctionTypeOrSubtype + } + + override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean { + require(this is KotlinType, this::errorMessage) + return this.isExtensionFunctionType + } + + override fun KotlinTypeMarker.extractArgumentsForFunctionalTypeOrSubtype(): List { + require(this is KotlinType, this::errorMessage) + return this.getPureArgumentsForFunctionalTypeOrSubtype() + } + + override fun KotlinTypeMarker.getFunctionalTypeFromSupertypes(): KotlinTypeMarker { + require(this is KotlinType) + return this.extractFunctionalTypeFromSupertypes() + } + + override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { + return getFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor + } + + override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { + return getKFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor + } } fun TypeVariance.convertVariance(): Variance {