From ac8d5a0ea806bf34a329f3303e192a3201361ec4 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Wed, 8 Feb 2023 21:41:28 +0100 Subject: [PATCH] [Analysis API] KTIJ-24527 Properly handle typealiased functional types Use expanded ConeTypes to get correct parameters and return types Also, fix the order of rendering modifiers in `KtFunctionalTypeRenderer` ^KTIJ-24527 Fixed --- ...ysisSourceModuleRendererTestGenerated.java | 6 +++ .../api/fir/types/KtFirFunctionalType.kt | 44 +++++++------------ ...ysisSourceModuleRendererTestGenerated.java | 6 +++ ...ysisSourceModuleRendererTestGenerated.java | 6 +++ ...ysisSourceModuleRendererTestGenerated.java | 6 +++ .../renderers/KtFunctionalTypeRenderer.kt | 8 ++-- .../functionalTypeAliases.kt | 17 +++++++ .../functionalTypeAliases.rendered | 24 ++++++++++ .../kotlin/fir/types/FunctionalTypeUtils.kt | 19 ++++++++ 9 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt create mode 100644 analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.rendered diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/symbolDeclarationRenderer/Fe10IdeNormalAnalysisSourceModuleRendererTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/symbolDeclarationRenderer/Fe10IdeNormalAnalysisSourceModuleRendererTestGenerated.java index b8c33c958cf..a8f10029690 100644 --- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/symbolDeclarationRenderer/Fe10IdeNormalAnalysisSourceModuleRendererTestGenerated.java +++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/symbolDeclarationRenderer/Fe10IdeNormalAnalysisSourceModuleRendererTestGenerated.java @@ -124,6 +124,12 @@ public class Fe10IdeNormalAnalysisSourceModuleRendererTestGenerated extends Abst runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionTypes.kt"); } + @Test + @TestMetadata("functionalTypeAliases.kt") + public void testFunctionalTypeAliases() throws Exception { + runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt"); + } + @Test @TestMetadata("genericFunctions.kt") public void testGenericFunctions() throws Exception { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt index e84864bf2b0..a3b1c22ed76 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt @@ -55,46 +55,36 @@ internal class KtFirFunctionalType( override val isReflectType: Boolean get() = withValidityAssertion { coneType.functionTypeKind(builder.rootSession)?.isReflectType == true } - override val arity: Int - get() = withValidityAssertion { - if (coneType.isExtensionFunctionType) coneType.typeArguments.size - 2 - else coneType.typeArguments.size - 1 - } + override val arity: Int get() = withValidityAssertion { parameterTypes.size } @OptIn(KtAnalysisApiInternals::class) override val contextReceivers: List by cached { - ownTypeArguments.subList(0, coneType.contextReceiversNumberForFunctionType).map { typeProjection -> - // Context receivers in function types may not have labels, hence the `null` label. - KtContextReceiverImpl((typeProjection as KtTypeArgumentWithVariance).type, _label = null, token) - } + coneType.contextReceiversTypes(builder.rootSession) + .map { + // Context receivers in function types may not have labels, hence the `null` label. + KtContextReceiverImpl(it.buildKtType(), _label = null, token) + } } - override val hasContextReceivers: Boolean get() = withValidityAssertion { coneType.hasContextReceivers } + override val hasContextReceivers: Boolean get() = withValidityAssertion { contextReceivers.isNotEmpty() } - override val receiverType: KtType? - get() = withValidityAssertion { - if (coneType.isExtensionFunctionType) { - // The extension receiver type follows any context receiver types. - (ownTypeArguments[coneType.contextReceiversNumberForFunctionType] as KtTypeArgumentWithVariance).type - } else null - } + override val receiverType: KtType? by cached { + coneType.receiverType(builder.rootSession)?.buildKtType() + } - override val hasReceiver: Boolean - get() = withValidityAssertion { - coneType.receiverType(builder.rootSession) != null - } + override val hasReceiver: Boolean get() = withValidityAssertion { receiverType != null } override val parameterTypes: List by cached { - // Parameter types follow context and extension receiver types. - val firstIndex = coneType.contextReceiversNumberForFunctionType + (if (coneType.isExtensionFunctionType) 1 else 0) - val parameterTypeArgs = ownTypeArguments.subList(firstIndex, ownTypeArguments.lastIndex) - parameterTypeArgs.map { (it as KtTypeArgumentWithVariance).type } + coneType.valueParameterTypesWithoutReceivers(builder.rootSession).map { it.buildKtType() } } - override val returnType: KtType - get() = withValidityAssertion { (ownTypeArguments.last() as KtTypeArgumentWithVariance).type } + override val returnType: KtType by cached { + coneType.returnType(builder.rootSession).buildKtType() + } override fun asStringForDebugging(): String = withValidityAssertion { coneType.renderForDebugging() } override fun equals(other: Any?) = typeEquals(other) override fun hashCode() = typeHashcode() + + private fun ConeKotlinType.buildKtType(): KtType = builder.typeBuilder.buildKtType(this) } diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeDependentAnalysisSourceModuleRendererTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeDependentAnalysisSourceModuleRendererTestGenerated.java index 09b742e1e87..a73c685d14f 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeDependentAnalysisSourceModuleRendererTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeDependentAnalysisSourceModuleRendererTestGenerated.java @@ -124,6 +124,12 @@ public class FirIdeDependentAnalysisSourceModuleRendererTestGenerated extends Ab runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionTypes.kt"); } + @Test + @TestMetadata("functionalTypeAliases.kt") + public void testFunctionalTypeAliases() throws Exception { + runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt"); + } + @Test @TestMetadata("genericFunctions.kt") public void testGenericFunctions() throws Exception { diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeNormalAnalysisSourceModuleRendererTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeNormalAnalysisSourceModuleRendererTestGenerated.java index 7e8a157d44c..6f52bc5f712 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeNormalAnalysisSourceModuleRendererTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirIdeNormalAnalysisSourceModuleRendererTestGenerated.java @@ -124,6 +124,12 @@ public class FirIdeNormalAnalysisSourceModuleRendererTestGenerated extends Abstr runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionTypes.kt"); } + @Test + @TestMetadata("functionalTypeAliases.kt") + public void testFunctionalTypeAliases() throws Exception { + runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt"); + } + @Test @TestMetadata("genericFunctions.kt") public void testGenericFunctions() throws Exception { diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirStandaloneNormalAnalysisSourceModuleRendererTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirStandaloneNormalAnalysisSourceModuleRendererTestGenerated.java index a8867fff815..9543c70fb05 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirStandaloneNormalAnalysisSourceModuleRendererTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/symbolDeclarationRenderer/FirStandaloneNormalAnalysisSourceModuleRendererTestGenerated.java @@ -124,6 +124,12 @@ public class FirStandaloneNormalAnalysisSourceModuleRendererTestGenerated extend runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionTypes.kt"); } + @Test + @TestMetadata("functionalTypeAliases.kt") + public void testFunctionalTypeAliases() throws Exception { + runTest("analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt"); + } + @Test @TestMetadata("genericFunctions.kt") public void testGenericFunctions() throws Exception { diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/types/renderers/KtFunctionalTypeRenderer.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/types/renderers/KtFunctionalTypeRenderer.kt index d2e650b2eb8..31abaf6082c 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/types/renderers/KtFunctionalTypeRenderer.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/types/renderers/KtFunctionalTypeRenderer.kt @@ -25,13 +25,13 @@ public interface KtFunctionalTypeRenderer { if (annotationsRendered || type.nullability == KtTypeNullability.NULLABLE) append("(") " ".separated( { - if (type.hasContextReceivers) { - contextReceiversRenderer.renderContextReceivers(type, printer) + if (type.isSuspend) { + keywordRenderer.renderKeyword(KtTokens.SUSPEND_KEYWORD, type, printer) } }, { - if (type.isSuspend) { - keywordRenderer.renderKeyword(KtTokens.SUSPEND_KEYWORD, type, printer) + if (type.hasContextReceivers) { + contextReceiversRenderer.renderContextReceivers(type, printer) } }, { diff --git a/analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt b/analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt new file mode 100644 index 00000000000..025f8aa36a5 --- /dev/null +++ b/analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.kt @@ -0,0 +1,17 @@ +class A +class B + +typealias WithGeneric = (T) -> String +fun withGeneric(f: WithGeneric) {} + +typealias WithReceiver = String.() -> Unit +fun withReceiver(f: WithReceiver) {} + +typealias WithContextReceiver = context(String) () -> Unit +fun withContextReceiver(f: WithContextReceiver) {} + +typealias WithSuspend = suspend (String) -> Int +fun withContextReceiver(f: WithSuspend) {} + +typealias WithEverything = suspend context(T, B) String.(Int, T) -> String +fun withEverything(f: WithEverything) {} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.rendered b/analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.rendered new file mode 100644 index 00000000000..d330bb9aeeb --- /dev/null +++ b/analysis/analysis-api/testData/components/symbolDeclarationRenderer/renderDeclaration/functionalTypeAliases.rendered @@ -0,0 +1,24 @@ +class A + +class B + +typealias WithGeneric = (T) -> String + +fun withGeneric(f: (Double) -> String) + +typealias WithReceiver = String.() -> Unit + +fun withReceiver(f: String.() -> Unit) + +typealias WithContextReceiver = context(String) () -> Unit + +fun withContextReceiver(f: context(String) () -> Unit) + +typealias WithSuspend = suspend (String) -> Int + +fun withContextReceiver(f: suspend (String) -> Int) + +typealias WithEverything = suspend context(T, B) String.(Int, T) -> String + +fun withEverything(f: suspend context(A, B) String.(Int, A) -> String) + diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt index 88598164da0..278593ada71 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt @@ -229,6 +229,14 @@ fun ConeKotlinType.findContributedInvokeSymbol( // ---------------------------------------------- function type type argument extraction ---------------------------------------------- +fun ConeKotlinType.contextReceiversTypes(session: FirSession): List { + if (!isSomeFunctionType(session)) return emptyList() + return fullyExpandedType(session).let { expanded -> + val contextReceivers = expanded.typeArguments.take(expanded.contextReceiversNumberForFunctionType) + contextReceivers.map { it.typeOrDefault(session.builtinTypes.nothingType.type) } + } +} + fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? { if (!isSomeFunctionType(session) || !isExtensionFunctionType(session)) return null return fullyExpandedType(session).let { expanded -> @@ -242,6 +250,17 @@ fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType { return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type) } +fun ConeKotlinType.valueParameterTypesWithoutReceivers(session: FirSession): List { + require(this is ConeClassLikeType) + // TODO: add requirement + val expandedType = fullyExpandedType(session) + + val receiversNumber = expandedType.contextReceiversNumberForFunctionType + if (expandedType.isExtensionFunctionType) 1 else 0 + val valueParameters = expandedType.typeArguments.drop(receiversNumber).dropLast(1) + + return valueParameters.map { it.typeOrDefault(session.builtinTypes.nothingType.type) } +} + fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List { require(this is ConeClassLikeType) // TODO: add requirement