FIR: Support type aliases to function types in resolution
This commit is contained in:
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.inferenceContext
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.withNullability
|
||||
@@ -19,11 +21,13 @@ import org.jetbrains.kotlin.fir.returnExpressions
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirILTTypeRefPlaceHolder
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
|
||||
fun Candidate.resolveArgumentExpression(
|
||||
@@ -299,14 +303,14 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
|
||||
argument: FirExpression,
|
||||
candidateExpectedType: ConeKotlinType
|
||||
): ConeKotlinType? {
|
||||
if (candidateExpectedType.isBuiltinFunctionalType) return null
|
||||
if (candidateExpectedType.isBuiltinFunctionalType(session)) return null
|
||||
// TODO: if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null
|
||||
val firNamedFunction = symbol.fir as? FirSimpleFunction ?: return null
|
||||
if (!samResolver.shouldRunSamConversionForFunction(firNamedFunction)) return null
|
||||
|
||||
val argumentIsFunctional = when ((argument as? FirWrappedArgumentExpression)?.expression ?: argument) {
|
||||
is FirAnonymousFunction, is FirCallableReferenceAccess -> true
|
||||
else -> argument.typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType == true
|
||||
else -> argument.typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true
|
||||
}
|
||||
if (!argumentIsFunctional) return null
|
||||
|
||||
@@ -335,3 +339,19 @@ internal fun FirExpression.getExpectedType(
|
||||
private fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
|
||||
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!")
|
||||
}
|
||||
|
||||
fun FirTypeRef.isExtensionFunctionType(session: FirSession): Boolean {
|
||||
if (annotations.any(FirAnnotationCall::isExtensionFunctionAnnotationCall)) return true
|
||||
|
||||
if (this !is FirResolvedTypeRef) return false
|
||||
val type = type as? ConeClassLikeType ?: return false
|
||||
if (type.fullyExpandedType(session) === type) return false
|
||||
|
||||
val typeAlias = type.lookupTag
|
||||
.toSymbol(session)
|
||||
?.safeAs<FirTypeAliasSymbol>()?.fir ?: return false
|
||||
|
||||
if (typeAlias.expandedTypeRef.annotations.any(FirAnnotationCall::isExtensionFunctionAnnotationCall)) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
+77
-60
@@ -5,11 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
@@ -31,8 +33,8 @@ fun Candidate.preprocessLambdaArgument(
|
||||
}
|
||||
|
||||
val resolvedArgument =
|
||||
extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument)
|
||||
?: extraLambdaInfo(expectedType, expectedTypeRef, argument, csBuilder)
|
||||
extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument, bodyResolveComponents.session)
|
||||
?: extraLambdaInfo(expectedType, expectedTypeRef, argument, csBuilder, bodyResolveComponents.session)
|
||||
|
||||
if (expectedType != null) {
|
||||
// TODO: add SAM conversion processing
|
||||
@@ -53,51 +55,45 @@ fun Candidate.preprocessCallableReference(
|
||||
expectedType: ConeKotlinType
|
||||
) {
|
||||
val lhs = bodyResolveComponents.doubleColonExpressionResolver.resolveDoubleColonLHS(argument)
|
||||
postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs)
|
||||
postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs, bodyResolveComponents.session)
|
||||
}
|
||||
|
||||
val ConeKotlinType.isBuiltinFunctionalType: Boolean
|
||||
get() {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> this.lookupTag.classId.asString().startsWith("kotlin/Function")
|
||||
else -> false
|
||||
}
|
||||
fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> fullyExpandedType(session).lookupTag.classId.asString().startsWith("kotlin/Function")
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val ConeKotlinType.isSuspendFunctionType: Boolean
|
||||
get() {
|
||||
val type = this
|
||||
return when (type) {
|
||||
is ConeClassLikeType -> {
|
||||
val classId = type.lookupTag.classId
|
||||
classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
|
||||
}
|
||||
else -> false
|
||||
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
||||
return when (val type = this) {
|
||||
is ConeClassLikeType -> {
|
||||
val classId = type.fullyExpandedType(session).lookupTag.classId
|
||||
classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef): ConeKotlinType? {
|
||||
if (expectedTypeRef.isExtensionFunctionType()) {
|
||||
return (this.typeArguments.first() as ConeTypedProjection).type
|
||||
fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef, session: FirSession): ConeKotlinType? {
|
||||
if (isBuiltinFunctionalType(session) && expectedTypeRef.isExtensionFunctionType(session)) {
|
||||
return ((this as ConeClassLikeType).fullyExpandedType(session).typeArguments.first() as ConeTypedProjection).type
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val ConeKotlinType.returnType: ConeKotlinType?
|
||||
get() {
|
||||
require(this is ConeClassLikeType)
|
||||
val projection = typeArguments.last()
|
||||
return (projection as? ConeTypedProjection)?.type
|
||||
}
|
||||
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType? {
|
||||
require(this is ConeClassLikeType)
|
||||
val projection = fullyExpandedType(session).typeArguments.last()
|
||||
return (projection as? ConeTypedProjection)?.type
|
||||
}
|
||||
|
||||
val ConeKotlinType.valueParameterTypes: List<ConeKotlinType?>
|
||||
get() {
|
||||
require(this is ConeClassLikeType)
|
||||
return typeArguments.dropLast(1).map {
|
||||
(it as? ConeTypedProjection)?.type
|
||||
}
|
||||
private fun ConeKotlinType.valueParameterTypes(session: FirSession): List<ConeKotlinType?> {
|
||||
require(this is ConeClassLikeType)
|
||||
return fullyExpandedType(session).typeArguments.dropLast(1).map {
|
||||
(it as? ConeTypedProjection)?.type
|
||||
}
|
||||
}
|
||||
|
||||
private val FirAnonymousFunction.returnType get() = returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
private val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeSafe<ConeKotlinType>()
|
||||
@@ -107,13 +103,15 @@ private fun extraLambdaInfo(
|
||||
expectedType: ConeKotlinType?,
|
||||
expectedTypeRef: FirTypeRef,
|
||||
argument: FirAnonymousFunction,
|
||||
csBuilder: ConstraintSystemBuilder
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
session: FirSession
|
||||
): ResolvedLambdaAtom {
|
||||
// val builtIns = csBuilder.builtIns
|
||||
val isSuspend = expectedType?.isSuspendFunctionType ?: false
|
||||
val isSuspend = expectedType?.isSuspendFunctionType(session) ?: false
|
||||
|
||||
val isFunctionSupertype =
|
||||
expectedType != null && expectedType.lowerBoundIfFlexible().isBuiltinFunctionalType//isNotNullOrNullableFunctionSupertype(expectedType)
|
||||
expectedType != null && expectedType.lowerBoundIfFlexible()
|
||||
.isBuiltinFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType)
|
||||
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
|
||||
|
||||
val typeVariable = TypeVariableForLambdaReturnType(argument, "_L")
|
||||
@@ -124,7 +122,8 @@ private fun extraLambdaInfo(
|
||||
?: expectedType?.typeArguments?.singleOrNull()?.safeAs<ConeTypedProjection>()?.type?.takeIf { isFunctionSupertype }
|
||||
?: typeVariable.defaultType
|
||||
|
||||
val nothingType = argument.session.builtinTypes.nothingType.type //StandardClassIds.Nothing(argument.session.firSymbolProvider).constructType(emptyArray(), false)
|
||||
val nothingType = argument.session.builtinTypes.nothingType
|
||||
.type //StandardClassIds.Nothing(argument.session.firSymbolProvider).constructType(emptyArray(), false)
|
||||
val parameters = argument.valueParameters?.map {
|
||||
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType
|
||||
} ?: emptyList()
|
||||
@@ -138,20 +137,23 @@ private fun extraLambdaInfo(
|
||||
internal fun extractLambdaInfoFromFunctionalType(
|
||||
expectedType: ConeKotlinType?,
|
||||
expectedTypeRef: FirTypeRef,
|
||||
argument: FirAnonymousFunction
|
||||
argument: FirAnonymousFunction,
|
||||
session: FirSession
|
||||
): ResolvedLambdaAtom? {
|
||||
if (expectedType == null) return null
|
||||
if (expectedType is ConeFlexibleType) return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument)
|
||||
if (!expectedType.isBuiltinFunctionalType) return null
|
||||
if (expectedType is ConeFlexibleType) {
|
||||
return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument, session)
|
||||
}
|
||||
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
||||
|
||||
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
|
||||
val receiverType = argumentAsFunctionExpression.receiverType ?: expectedType.receiverType(expectedTypeRef)
|
||||
val returnType = argumentAsFunctionExpression.returnType ?: expectedType.returnType ?: return null
|
||||
val parameters = extractLambdaParameters(expectedType, argument, expectedTypeRef.isExtensionFunctionType())
|
||||
val receiverType = argumentAsFunctionExpression.receiverType ?: expectedType.receiverType(expectedTypeRef, session)
|
||||
val returnType = argumentAsFunctionExpression.returnType ?: expectedType.returnType(session) ?: return null
|
||||
val parameters = extractLambdaParameters(expectedType, argument, expectedTypeRef.isExtensionFunctionType(session), session)
|
||||
|
||||
return ResolvedLambdaAtom(
|
||||
argument,
|
||||
expectedType.isSuspendFunctionType,
|
||||
expectedType.isSuspendFunctionType(session),
|
||||
receiverType,
|
||||
parameters,
|
||||
returnType,
|
||||
@@ -159,12 +161,16 @@ internal fun extractLambdaInfoFromFunctionalType(
|
||||
)
|
||||
}
|
||||
|
||||
private fun extractLambdaParameters(expectedType: ConeKotlinType, argument: FirAnonymousFunction, expectedTypeIsExtensionFunctionType: Boolean): List<ConeKotlinType> {
|
||||
private fun extractLambdaParameters(
|
||||
expectedType: ConeKotlinType,
|
||||
argument: FirAnonymousFunction,
|
||||
expectedTypeIsExtensionFunctionType: Boolean,
|
||||
session: FirSession
|
||||
): List<ConeKotlinType> {
|
||||
val parameters = argument.valueParameters
|
||||
val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType)
|
||||
|
||||
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type //StandardClassIds.Any(argument.session.firSymbolProvider).constructType(emptyArray(), true)
|
||||
val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType, session)
|
||||
|
||||
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type
|
||||
if (parameters.isEmpty()) {
|
||||
return expectedParameters.map { it?.type ?: nullableAnyType }
|
||||
}
|
||||
@@ -175,8 +181,11 @@ private fun extractLambdaParameters(expectedType: ConeKotlinType, argument: FirA
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.extractParametersForFunctionalType(isExtensionFunctionType: Boolean): List<ConeKotlinType?> {
|
||||
return valueParameterTypes.let {
|
||||
private fun ConeKotlinType.extractParametersForFunctionalType(
|
||||
isExtensionFunctionType: Boolean,
|
||||
session: FirSession
|
||||
): List<ConeKotlinType?> {
|
||||
return valueParameterTypes(session).let {
|
||||
if (isExtensionFunctionType) {
|
||||
it.drop(1)
|
||||
} else {
|
||||
@@ -217,7 +226,8 @@ class ResolvedLambdaAtom(
|
||||
class ResolvedCallableReferenceAtom(
|
||||
val reference: FirCallableReferenceAccess,
|
||||
val expectedType: ConeKotlinType?,
|
||||
val lhs: DoubleColonLHS?
|
||||
val lhs: DoubleColonLHS?,
|
||||
private val session: FirSession
|
||||
) : PostponedResolvedAtomMarker {
|
||||
override var analyzed: Boolean = false
|
||||
var postponed: Boolean = false
|
||||
@@ -227,23 +237,27 @@ class ResolvedCallableReferenceAtom(
|
||||
override val inputTypes: Collection<ConeKotlinType>
|
||||
get() {
|
||||
if (!postponed) return emptyList()
|
||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.inputTypes ?: listOfNotNull(expectedType)
|
||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.inputTypes
|
||||
?: listOfNotNull(expectedType)
|
||||
}
|
||||
override val outputType: ConeKotlinType?
|
||||
get() {
|
||||
if (!postponed) return null
|
||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.outputType
|
||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.outputType
|
||||
}
|
||||
}
|
||||
|
||||
private data class InputOutputTypes(val inputTypes: List<ConeKotlinType>, val outputType: ConeKotlinType)
|
||||
|
||||
private fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: ConeKotlinType?): InputOutputTypes? {
|
||||
private fun extractInputOutputTypesFromCallableReferenceExpectedType(
|
||||
expectedType: ConeKotlinType?,
|
||||
session: FirSession
|
||||
): InputOutputTypes? {
|
||||
if (expectedType == null) return null
|
||||
|
||||
return when {
|
||||
expectedType.isBuiltinFunctionalType || expectedType.isSuspendFunctionType ->
|
||||
extractInputOutputTypesFromFunctionType(expectedType)
|
||||
expectedType.isBuiltinFunctionalType(session) || expectedType.isSuspendFunctionType(session) ->
|
||||
extractInputOutputTypesFromFunctionType(expectedType, session)
|
||||
|
||||
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
|
||||
// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap())
|
||||
@@ -267,9 +281,12 @@ private fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedTyp
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractInputOutputTypesFromFunctionType(functionType: ConeKotlinType): InputOutputTypes {
|
||||
private fun extractInputOutputTypesFromFunctionType(
|
||||
functionType: ConeKotlinType,
|
||||
session: FirSession
|
||||
): InputOutputTypes {
|
||||
val receiver = null// TODO: functionType.receiverType()
|
||||
val parameters = functionType.valueParameterTypes.map {
|
||||
val parameters = functionType.valueParameterTypes(session).map {
|
||||
it ?: ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(),
|
||||
isNullable = false
|
||||
@@ -277,7 +294,7 @@ private fun extractInputOutputTypesFromFunctionType(functionType: ConeKotlinType
|
||||
}
|
||||
|
||||
val inputTypes = /*listOfNotNull(receiver) +*/ parameters
|
||||
val outputType = functionType.returnType ?: ConeClassLikeTypeImpl(
|
||||
val outputType = functionType.returnType(session) ?: ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(),
|
||||
isNullable = true
|
||||
)
|
||||
|
||||
@@ -99,8 +99,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
||||
val receiverType = (callable.receiverTypeRef as FirResolvedTypeRef?)?.type
|
||||
if (receiverType != null) return receiverType
|
||||
val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null
|
||||
if (!returnTypeRef.isExtensionFunctionType()) return null
|
||||
return (returnTypeRef.type.typeArguments.firstOrNull() as? ConeTypedProjection)?.type
|
||||
return returnTypeRef.type.receiverType(returnTypeRef, bodyResolveComponents.session)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -168,7 +168,7 @@ class TowerResolveManager internal constructor(private val towerResolver: FirTow
|
||||
for (invokeReceiverCandidate in invokeReceiverCollector.bestCandidates()) {
|
||||
|
||||
val symbol = invokeReceiverCandidate.symbol as FirCallableSymbol<*>
|
||||
val isExtensionFunctionType = symbol.fir.returnTypeRef.isExtensionFunctionType()
|
||||
val isExtensionFunctionType = symbol.fir.returnTypeRef.isExtensionFunctionType(towerResolver.components.session)
|
||||
if (invokeBuiltinExtensionMode && !isExtensionFunctionType) {
|
||||
continue
|
||||
}
|
||||
@@ -303,4 +303,4 @@ class TowerResolveManager internal constructor(private val towerResolver: FirTow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.returnType
|
||||
import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substituteOrNull
|
||||
@@ -187,7 +188,8 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
result = when (result) {
|
||||
is FirIntegerOperatorCall -> {
|
||||
val expectedType = data?.getExpectedType(functionCall)
|
||||
resultType = typeRef.resolvedTypeFromPrototype(typeRef.coneTypeUnsafe<ConeIntegerLiteralType>().getApproximatedType(expectedType))
|
||||
resultType =
|
||||
typeRef.resolvedTypeFromPrototype(typeRef.coneTypeUnsafe<ConeIntegerLiteralType>().getApproximatedType(expectedType))
|
||||
result.transformArguments(this, expectedType?.toExpectedType()).transformSingle(integerApproximator, expectedType)
|
||||
}
|
||||
else -> {
|
||||
@@ -238,9 +240,9 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
|
||||
private fun Candidate.createArgumentsMapping(): ExpectedArgumentType? {
|
||||
return argumentMapping?.map { (argument, valueParameter) ->
|
||||
val expectedType = valueParameter.returnTypeRef.substitute(this)
|
||||
argument.unwrapArgument() to expectedType
|
||||
}
|
||||
val expectedType = valueParameter.returnTypeRef.substitute(this)
|
||||
argument.unwrapArgument() to expectedType
|
||||
}
|
||||
?.toMap()?.toExpectedType()
|
||||
}
|
||||
|
||||
@@ -248,7 +250,8 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
delegatedConstructorCall: FirDelegatedConstructorCall,
|
||||
data: ExpectedArgumentType?
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
val calleeReference = delegatedConstructorCall.calleeReference as? FirNamedReferenceWithCandidate ?: return delegatedConstructorCall.compose()
|
||||
val calleeReference =
|
||||
delegatedConstructorCall.calleeReference as? FirNamedReferenceWithCandidate ?: return delegatedConstructorCall.compose()
|
||||
|
||||
val result = delegatedConstructorCall.transformArguments(this, calleeReference.candidate.createArgumentsMapping())
|
||||
return result.transformCalleeReference(
|
||||
@@ -276,8 +279,8 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
data: ExpectedArgumentType?
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
val expectedReturnType = data?.getExpectedType(anonymousFunction)
|
||||
?.takeIf { it.isBuiltinFunctionalType }
|
||||
?.let { it.typeArguments.last() as? ConeClassLikeType }
|
||||
?.takeIf { it.isBuiltinFunctionalType(session) }
|
||||
?.returnType(session) as? ConeClassLikeType
|
||||
|
||||
val initialType = anonymousFunction.returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||
if (initialType != null) {
|
||||
@@ -373,4 +376,4 @@ private fun ConeKotlinType.approximateIfPossible(expectedType: ConeKotlinType?)
|
||||
getApproximatedType(expectedType)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -416,7 +416,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
|
||||
val expectedTypeRef = (data as? ResolutionMode.WithExpectedType)?.expectedTypeRef ?: FirImplicitTypeRefImpl(null)
|
||||
val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let {
|
||||
extractLambdaInfoFromFunctionalType(
|
||||
it.type, it, anonymousFunction
|
||||
it.type, it, anonymousFunction, session
|
||||
)
|
||||
}
|
||||
var af = anonymousFunction
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
private typealias A = String.(Int) -> Int
|
||||
|
||||
private fun b(a: A) {
|
||||
"b".a(1)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
b {
|
||||
length + it
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
FILE: functionTypeAlias.kt
|
||||
private final typealias A = R|kotlin/String.(kotlin/Int) -> kotlin/Int|
|
||||
private final fun b(a: R|A|): R|kotlin/Unit| {
|
||||
R|<local>/a|.R|FakeOverride<kotlin/Function2.invoke: R|kotlin/Int|>|(String(b), Int(1))
|
||||
}
|
||||
public final fun main(): R|kotlin/Unit| {
|
||||
R|/b|(<L> = b@fun R|kotlin/String|.<anonymous>(it: R|kotlin/Int|): R|kotlin/Int| {
|
||||
this@R|special/anonymous|.R|kotlin/String.length|.R|kotlin/Int.plus|(R|<local>/it|)
|
||||
}
|
||||
)
|
||||
}
|
||||
+5
@@ -128,6 +128,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/resolve/testData/resolve/ft.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionTypeAlias.kt")
|
||||
public void testFunctionTypeAlias() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/functionTypeAlias.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionTypes.kt")
|
||||
public void testFunctionTypes() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/functionTypes.kt");
|
||||
|
||||
Generated
+5
@@ -128,6 +128,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/resolve/testData/resolve/ft.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionTypeAlias.kt")
|
||||
public void testFunctionTypeAlias() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/functionTypeAlias.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionTypes.kt")
|
||||
public void testFunctionTypes() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/functionTypes.kt");
|
||||
|
||||
@@ -769,7 +769,9 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
annotations.renderAnnotations()
|
||||
print("R|")
|
||||
val coneType = resolvedTypeRef.type
|
||||
print(coneType.renderFunctionType(kind, resolvedTypeRef.isExtensionFunctionType()))
|
||||
print(coneType.renderFunctionType(kind, resolvedTypeRef.annotations.any {
|
||||
it.isExtensionFunctionAnnotationCall
|
||||
}))
|
||||
print("|")
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstKind
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
@@ -38,12 +39,6 @@ val FirFunctionTypeRef.parametersCount: Int
|
||||
|
||||
const val EXTENSION_FUNCTION_ANNOTATION = "kotlin/ExtensionFunctionType"
|
||||
|
||||
fun FirTypeRef.isExtensionFunctionType(): Boolean {
|
||||
return annotations.any {
|
||||
it.isExtensionFunctionAnnotationCall
|
||||
}
|
||||
}
|
||||
|
||||
val FirAnnotationCall.isExtensionFunctionAnnotationCall: Boolean
|
||||
get() = (this as? FirAnnotationCall)?.let {
|
||||
(it.annotationTypeRef as? FirResolvedTypeRef)?.let {
|
||||
@@ -64,4 +59,4 @@ fun ConeClassLikeType.toConstKind(): FirConstKind<*>? = when (lookupTag.classId)
|
||||
StandardClassIds.Int -> FirConstKind.Int
|
||||
StandardClassIds.Long -> FirConstKind.Long
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -16,9 +16,9 @@ fun buildB() {
|
||||
val a2 = applyRestrictions2()
|
||||
val a3 = applyRestrictions3("foo")
|
||||
|
||||
B.Builder().<!UNRESOLVED_REFERENCE!>a1<!>()
|
||||
B.Builder().<!UNRESOLVED_REFERENCE!>a2<!>()
|
||||
B.Builder().<!UNRESOLVED_REFERENCE!>a3<!>()
|
||||
B.Builder().a1()
|
||||
B.Builder().a2()
|
||||
B.Builder().a3()
|
||||
}
|
||||
|
||||
// additional example from #KT-34820
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@ fun buildB() {
|
||||
val a2 = applyRestrictions2()
|
||||
val a3 = applyRestrictions3("foo")
|
||||
|
||||
B.Builder().<!UNRESOLVED_REFERENCE!>a1<!>()
|
||||
B.Builder().<!UNRESOLVED_REFERENCE!>a2<!>()
|
||||
B.Builder().<!UNRESOLVED_REFERENCE!>a3<!>()
|
||||
B.Builder().a1()
|
||||
B.Builder().a2()
|
||||
B.Builder().a3()
|
||||
}
|
||||
|
||||
+15
-15
@@ -36,13 +36,13 @@ class W4(val f: L2) {
|
||||
}
|
||||
|
||||
fun test1() { // to extension lambda 0
|
||||
val w10 = <!INAPPLICABLE_CANDIDATE!>W1<!> { this } // oi+ ni+
|
||||
val w10 = W1 { this } // oi+ ni+
|
||||
val i10: E0 = id { this } // o1- ni+
|
||||
val j10 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { this } // oi+ ni+
|
||||
val f10 = W1(fun Int.(): Int = this) // oi+ ni+
|
||||
val g10: E0 = id(fun Int.(): Int = this) // oi+ ni+
|
||||
|
||||
val w11 = W1 { i: Int -> i } // oi- ni-
|
||||
val w11 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i: Int -> i } // oi- ni-
|
||||
val i11: E0 = id { i: Int -> i } // o1+ ni+
|
||||
val w12 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni-
|
||||
val i12: E0 = id { i -> i } // oi- ni-
|
||||
@@ -53,23 +53,23 @@ fun test1() { // to extension lambda 0
|
||||
// val i13: E0 = id { it } // this or it: oi- ni-
|
||||
// val j13 = id<E0> { it } // this or it: oi- ni-
|
||||
|
||||
val o14 = <!INAPPLICABLE_CANDIDATE!>W1<!> { -> 0 } // oi+ ni+
|
||||
val o14 = W1 { -> 0 } // oi+ ni+
|
||||
}
|
||||
|
||||
fun test2() { // to extension lambda 1
|
||||
val w20 = <!INAPPLICABLE_CANDIDATE!>W2<!> { this + <!UNRESOLVED_REFERENCE!>it<!>.<!UNRESOLVED_REFERENCE!>length<!> } // oi+ ni+
|
||||
val w20 = W2 { this + it.length } // oi+ ni+
|
||||
val i20: E1 = id { this + <!UNRESOLVED_REFERENCE!>it<!>.<!UNRESOLVED_REFERENCE!>length<!> } // oi- ni+
|
||||
val w21 = <!INAPPLICABLE_CANDIDATE!>W2<!> { this } // oi+ ni+
|
||||
val w21 = W2 { this } // oi+ ni+
|
||||
val i21: E1 = id { this } // oi- ni+
|
||||
val f21 = <!INAPPLICABLE_CANDIDATE!>W2<!>(fun Int.(String): Int = this) // oi+ ni+
|
||||
val f21 = W2(fun Int.(String): Int = this) // oi+ ni+
|
||||
val g21: E1 = id(fun Int.(String): Int = this) // oi+ ni+
|
||||
val w22 = <!INAPPLICABLE_CANDIDATE!>W2<!> { s -> this + s.<!UNRESOLVED_REFERENCE!>length<!> } // oi+ ni+
|
||||
val w22 = W2 { s -> this + s.length } // oi+ ni+
|
||||
val i22: E1 = id { s -> this + s.<!UNRESOLVED_REFERENCE!>length<!> } // oi+ ni+
|
||||
val w23 = <!INAPPLICABLE_CANDIDATE!>W2<!> { s -> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi+ ni+
|
||||
val w23 = W2 { s -> s.length } // oi+ ni+
|
||||
val i23: E1 = id { s -> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi+ ni+
|
||||
val w24 = <!INAPPLICABLE_CANDIDATE!>W2<!> { s: String -> this + s.length } // oi+ ni+
|
||||
val w24 = W2 { s: String -> this + s.length } // oi+ ni+
|
||||
// val i24: E1 = id { s: String -> this + s.length } //oi- ni-
|
||||
val w25 = <!INAPPLICABLE_CANDIDATE!>W2<!> { s: String -> s.length } // oi+ ni+
|
||||
val w25 = W2 { s: String -> s.length } // oi+ ni+
|
||||
// val i25: E1 = id { s: String -> s.length } // oi- ni-
|
||||
|
||||
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)
|
||||
@@ -80,7 +80,7 @@ fun test2() { // to extension lambda 1
|
||||
|
||||
val w28 = <!INAPPLICABLE_CANDIDATE!>W2<!> { i: Int, s -> i <!AMBIGUITY!>+<!> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi- ni-
|
||||
val i28: E1 = id { i: Int, s -> i <!AMBIGUITY!>+<!> s.<!UNRESOLVED_REFERENCE!>length<!> } // oi- ni-
|
||||
val w29 = W2 { i: Int, s: String -> i + s.length } // oi- ni-
|
||||
val w29 = <!INAPPLICABLE_CANDIDATE!>W2<!> { i: Int, s: String -> i + s.length } // oi- ni-
|
||||
val i29: E1 = id { i: Int, s: String -> i + s.length } // oi+ ni+
|
||||
|
||||
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)
|
||||
@@ -89,9 +89,9 @@ fun test2() { // to extension lambda 1
|
||||
}
|
||||
|
||||
fun test3() { // to non-extension lambda 1
|
||||
val w30 = <!INAPPLICABLE_CANDIDATE!>W3<!> { i -> i } // oi+ ni+
|
||||
val w30 = W3 { i -> i } // oi+ ni+
|
||||
val i30: L1 = id { i -> i } // oi+ ni+
|
||||
val w31 = <!INAPPLICABLE_CANDIDATE!>W3<!> { <!UNRESOLVED_REFERENCE!>it<!> } // oi+ ni+
|
||||
val w31 = W3 { it } // oi+ ni+
|
||||
val i31: L1 = id { <!UNRESOLVED_REFERENCE!>it<!> } // oi- ni+
|
||||
val j31 = <!INAPPLICABLE_CANDIDATE!>id<!><L1> { <!UNRESOLVED_REFERENCE!>it<!> } // oi+ ni+
|
||||
|
||||
@@ -100,7 +100,7 @@ fun test3() { // to non-extension lambda 1
|
||||
// val i32: L1 = id { this } // this or it: oi- ni-
|
||||
// val j32 = id<L1> { this } // this or it: oi- ni-
|
||||
|
||||
val w33 = W3(fun Int.(): Int = this) // oi- ni+
|
||||
val w33 = <!INAPPLICABLE_CANDIDATE!>W3<!>(fun Int.(): Int = this) // oi- ni+
|
||||
val i33: L1 = id(fun Int.(): Int = this) // oi+ ni+
|
||||
|
||||
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)
|
||||
@@ -108,7 +108,7 @@ fun test3() { // to non-extension lambda 1
|
||||
}
|
||||
|
||||
fun test4() { // to non-extension lambda 2
|
||||
val w30 = <!INAPPLICABLE_CANDIDATE!>W4<!> { i, s -> i } // oi+ ni+
|
||||
val w30 = W4 { i, s -> i } // oi+ ni+
|
||||
val i30: L2 = id { i, s -> i } // oi+ ni+
|
||||
|
||||
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)
|
||||
|
||||
Reference in New Issue
Block a user