[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
This commit is contained in:
+6
@@ -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 {
|
||||
|
||||
+17
-27
@@ -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<KtContextReceiver> 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<KtType> 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)
|
||||
}
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+4
-4
@@ -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)
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
class A
|
||||
class B
|
||||
|
||||
typealias WithGeneric<T> = (T) -> String
|
||||
fun withGeneric(f: WithGeneric<Double>) {}
|
||||
|
||||
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<T> = suspend context(T, B) String.(Int, T) -> String
|
||||
fun withEverything(f: WithEverything<A>) {}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
class A
|
||||
|
||||
class B
|
||||
|
||||
typealias WithGeneric<T> = (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<T> = suspend context(T, B) String.(Int, T) -> String
|
||||
|
||||
fun withEverything(f: suspend context(A, B) String.(Int, A) -> String)
|
||||
|
||||
@@ -229,6 +229,14 @@ fun ConeKotlinType.findContributedInvokeSymbol(
|
||||
|
||||
// ---------------------------------------------- function type type argument extraction ----------------------------------------------
|
||||
|
||||
fun ConeKotlinType.contextReceiversTypes(session: FirSession): List<ConeKotlinType> {
|
||||
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<ConeKotlinType> {
|
||||
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<ConeKotlinType> {
|
||||
require(this is ConeClassLikeType)
|
||||
// TODO: add requirement
|
||||
|
||||
Reference in New Issue
Block a user