FIR: Support type aliases to function types in resolution

This commit is contained in:
Denis Zharkov
2020-02-05 15:23:02 +03:00
parent 7249d2f889
commit 6f6281a3f3
15 changed files with 172 additions and 104 deletions
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.inferenceContext import org.jetbrains.kotlin.fir.inferenceContext
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference 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.firUnsafe
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolve.withNullability 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.FirILTTypeRefPlaceHolder
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall 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.fir.types.*
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun Candidate.resolveArgumentExpression( fun Candidate.resolveArgumentExpression(
@@ -299,14 +303,14 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
argument: FirExpression, argument: FirExpression,
candidateExpectedType: ConeKotlinType candidateExpectedType: ConeKotlinType
): ConeKotlinType? { ): ConeKotlinType? {
if (candidateExpectedType.isBuiltinFunctionalType) return null if (candidateExpectedType.isBuiltinFunctionalType(session)) return null
// TODO: if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null // TODO: if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null
val firNamedFunction = symbol.fir as? FirSimpleFunction ?: return null val firNamedFunction = symbol.fir as? FirSimpleFunction ?: return null
if (!samResolver.shouldRunSamConversionForFunction(firNamedFunction)) return null if (!samResolver.shouldRunSamConversionForFunction(firNamedFunction)) return null
val argumentIsFunctional = when ((argument as? FirWrappedArgumentExpression)?.expression ?: argument) { val argumentIsFunctional = when ((argument as? FirWrappedArgumentExpression)?.expression ?: argument) {
is FirAnonymousFunction, is FirCallableReferenceAccess -> true is FirAnonymousFunction, is FirCallableReferenceAccess -> true
else -> argument.typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType == true else -> argument.typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true
} }
if (!argumentIsFunctional) return null if (!argumentIsFunctional) return null
@@ -335,3 +339,19 @@ internal fun FirExpression.getExpectedType(
private fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType { private fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!") 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
}
@@ -5,11 +5,13 @@
package org.jetbrains.kotlin.fir.resolve.calls 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.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
import org.jetbrains.kotlin.fir.resolve.createFunctionalType 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.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -31,8 +33,8 @@ fun Candidate.preprocessLambdaArgument(
} }
val resolvedArgument = val resolvedArgument =
extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument) extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument, bodyResolveComponents.session)
?: extraLambdaInfo(expectedType, expectedTypeRef, argument, csBuilder) ?: extraLambdaInfo(expectedType, expectedTypeRef, argument, csBuilder, bodyResolveComponents.session)
if (expectedType != null) { if (expectedType != null) {
// TODO: add SAM conversion processing // TODO: add SAM conversion processing
@@ -53,51 +55,45 @@ fun Candidate.preprocessCallableReference(
expectedType: ConeKotlinType expectedType: ConeKotlinType
) { ) {
val lhs = bodyResolveComponents.doubleColonExpressionResolver.resolveDoubleColonLHS(argument) val lhs = bodyResolveComponents.doubleColonExpressionResolver.resolveDoubleColonLHS(argument)
postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs) postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs, bodyResolveComponents.session)
} }
val ConeKotlinType.isBuiltinFunctionalType: Boolean fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
get() { return when (this) {
return when (this) { is ConeClassLikeType -> fullyExpandedType(session).lookupTag.classId.asString().startsWith("kotlin/Function")
is ConeClassLikeType -> this.lookupTag.classId.asString().startsWith("kotlin/Function") else -> false
else -> false
}
} }
}
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
private val ConeKotlinType.isSuspendFunctionType: Boolean return when (val type = this) {
get() { is ConeClassLikeType -> {
val type = this val classId = type.fullyExpandedType(session).lookupTag.classId
return when (type) { classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
is ConeClassLikeType -> {
val classId = type.lookupTag.classId
classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
}
else -> false
} }
else -> false
} }
}
private fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef): ConeKotlinType? { fun ConeKotlinType.receiverType(expectedTypeRef: FirTypeRef, session: FirSession): ConeKotlinType? {
if (expectedTypeRef.isExtensionFunctionType()) { if (isBuiltinFunctionalType(session) && expectedTypeRef.isExtensionFunctionType(session)) {
return (this.typeArguments.first() as ConeTypedProjection).type return ((this as ConeClassLikeType).fullyExpandedType(session).typeArguments.first() as ConeTypedProjection).type
} }
return null return null
} }
val ConeKotlinType.returnType: ConeKotlinType? fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType? {
get() { require(this is ConeClassLikeType)
require(this is ConeClassLikeType) val projection = fullyExpandedType(session).typeArguments.last()
val projection = typeArguments.last() return (projection as? ConeTypedProjection)?.type
return (projection as? ConeTypedProjection)?.type }
}
val ConeKotlinType.valueParameterTypes: List<ConeKotlinType?> private fun ConeKotlinType.valueParameterTypes(session: FirSession): List<ConeKotlinType?> {
get() { require(this is ConeClassLikeType)
require(this is ConeClassLikeType) return fullyExpandedType(session).typeArguments.dropLast(1).map {
return typeArguments.dropLast(1).map { (it as? ConeTypedProjection)?.type
(it as? ConeTypedProjection)?.type
}
} }
}
private val FirAnonymousFunction.returnType get() = returnTypeRef.coneTypeSafe<ConeKotlinType>() private val FirAnonymousFunction.returnType get() = returnTypeRef.coneTypeSafe<ConeKotlinType>()
private val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeSafe<ConeKotlinType>() private val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeSafe<ConeKotlinType>()
@@ -107,13 +103,15 @@ private fun extraLambdaInfo(
expectedType: ConeKotlinType?, expectedType: ConeKotlinType?,
expectedTypeRef: FirTypeRef, expectedTypeRef: FirTypeRef,
argument: FirAnonymousFunction, argument: FirAnonymousFunction,
csBuilder: ConstraintSystemBuilder csBuilder: ConstraintSystemBuilder,
session: FirSession
): ResolvedLambdaAtom { ): ResolvedLambdaAtom {
// val builtIns = csBuilder.builtIns // val builtIns = csBuilder.builtIns
val isSuspend = expectedType?.isSuspendFunctionType ?: false val isSuspend = expectedType?.isSuspendFunctionType(session) ?: false
val isFunctionSupertype = val isFunctionSupertype =
expectedType != null && expectedType.lowerBoundIfFlexible().isBuiltinFunctionalType//isNotNullOrNullableFunctionSupertype(expectedType) expectedType != null && expectedType.lowerBoundIfFlexible()
.isBuiltinFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType)
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>() val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
val typeVariable = TypeVariableForLambdaReturnType(argument, "_L") val typeVariable = TypeVariableForLambdaReturnType(argument, "_L")
@@ -124,7 +122,8 @@ private fun extraLambdaInfo(
?: expectedType?.typeArguments?.singleOrNull()?.safeAs<ConeTypedProjection>()?.type?.takeIf { isFunctionSupertype } ?: expectedType?.typeArguments?.singleOrNull()?.safeAs<ConeTypedProjection>()?.type?.takeIf { isFunctionSupertype }
?: typeVariable.defaultType ?: 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 { val parameters = argument.valueParameters?.map {
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType
} ?: emptyList() } ?: emptyList()
@@ -138,20 +137,23 @@ private fun extraLambdaInfo(
internal fun extractLambdaInfoFromFunctionalType( internal fun extractLambdaInfoFromFunctionalType(
expectedType: ConeKotlinType?, expectedType: ConeKotlinType?,
expectedTypeRef: FirTypeRef, expectedTypeRef: FirTypeRef,
argument: FirAnonymousFunction argument: FirAnonymousFunction,
session: FirSession
): ResolvedLambdaAtom? { ): ResolvedLambdaAtom? {
if (expectedType == null) return null if (expectedType == null) return null
if (expectedType is ConeFlexibleType) return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument) if (expectedType is ConeFlexibleType) {
if (!expectedType.isBuiltinFunctionalType) return null return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument, session)
}
if (!expectedType.isBuiltinFunctionalType(session)) return null
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>() val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
val receiverType = argumentAsFunctionExpression.receiverType ?: expectedType.receiverType(expectedTypeRef) val receiverType = argumentAsFunctionExpression.receiverType ?: expectedType.receiverType(expectedTypeRef, session)
val returnType = argumentAsFunctionExpression.returnType ?: expectedType.returnType ?: return null val returnType = argumentAsFunctionExpression.returnType ?: expectedType.returnType(session) ?: return null
val parameters = extractLambdaParameters(expectedType, argument, expectedTypeRef.isExtensionFunctionType()) val parameters = extractLambdaParameters(expectedType, argument, expectedTypeRef.isExtensionFunctionType(session), session)
return ResolvedLambdaAtom( return ResolvedLambdaAtom(
argument, argument,
expectedType.isSuspendFunctionType, expectedType.isSuspendFunctionType(session),
receiverType, receiverType,
parameters, parameters,
returnType, 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 parameters = argument.valueParameters
val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType) val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType, session)
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type //StandardClassIds.Any(argument.session.firSymbolProvider).constructType(emptyArray(), true)
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type
if (parameters.isEmpty()) { if (parameters.isEmpty()) {
return expectedParameters.map { it?.type ?: nullableAnyType } 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?> { private fun ConeKotlinType.extractParametersForFunctionalType(
return valueParameterTypes.let { isExtensionFunctionType: Boolean,
session: FirSession
): List<ConeKotlinType?> {
return valueParameterTypes(session).let {
if (isExtensionFunctionType) { if (isExtensionFunctionType) {
it.drop(1) it.drop(1)
} else { } else {
@@ -217,7 +226,8 @@ class ResolvedLambdaAtom(
class ResolvedCallableReferenceAtom( class ResolvedCallableReferenceAtom(
val reference: FirCallableReferenceAccess, val reference: FirCallableReferenceAccess,
val expectedType: ConeKotlinType?, val expectedType: ConeKotlinType?,
val lhs: DoubleColonLHS? val lhs: DoubleColonLHS?,
private val session: FirSession
) : PostponedResolvedAtomMarker { ) : PostponedResolvedAtomMarker {
override var analyzed: Boolean = false override var analyzed: Boolean = false
var postponed: Boolean = false var postponed: Boolean = false
@@ -227,23 +237,27 @@ class ResolvedCallableReferenceAtom(
override val inputTypes: Collection<ConeKotlinType> override val inputTypes: Collection<ConeKotlinType>
get() { get() {
if (!postponed) return emptyList() if (!postponed) return emptyList()
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.inputTypes ?: listOfNotNull(expectedType) return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session)?.inputTypes
?: listOfNotNull(expectedType)
} }
override val outputType: ConeKotlinType? override val outputType: ConeKotlinType?
get() { get() {
if (!postponed) return null 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 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 if (expectedType == null) return null
return when { return when {
expectedType.isBuiltinFunctionalType || expectedType.isSuspendFunctionType -> expectedType.isBuiltinFunctionalType(session) || expectedType.isSuspendFunctionType(session) ->
extractInputOutputTypesFromFunctionType(expectedType) extractInputOutputTypesFromFunctionType(expectedType, session)
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) -> // ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap()) // 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 receiver = null// TODO: functionType.receiverType()
val parameters = functionType.valueParameterTypes.map { val parameters = functionType.valueParameterTypes(session).map {
it ?: ConeClassLikeTypeImpl( it ?: ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(), ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(),
isNullable = false isNullable = false
@@ -277,7 +294,7 @@ private fun extractInputOutputTypesFromFunctionType(functionType: ConeKotlinType
} }
val inputTypes = /*listOfNotNull(receiver) +*/ parameters val inputTypes = /*listOfNotNull(receiver) +*/ parameters
val outputType = functionType.returnType ?: ConeClassLikeTypeImpl( val outputType = functionType.returnType(session) ?: ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(), ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(),
isNullable = true isNullable = true
) )
@@ -99,8 +99,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
val receiverType = (callable.receiverTypeRef as FirResolvedTypeRef?)?.type val receiverType = (callable.receiverTypeRef as FirResolvedTypeRef?)?.type
if (receiverType != null) return receiverType if (receiverType != null) return receiverType
val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null
if (!returnTypeRef.isExtensionFunctionType()) return null return returnTypeRef.type.receiverType(returnTypeRef, bodyResolveComponents.session)
return (returnTypeRef.type.typeArguments.firstOrNull() as? ConeTypedProjection)?.type
} }
} }
@@ -168,7 +168,7 @@ class TowerResolveManager internal constructor(private val towerResolver: FirTow
for (invokeReceiverCandidate in invokeReceiverCollector.bestCandidates()) { for (invokeReceiverCandidate in invokeReceiverCollector.bestCandidates()) {
val symbol = invokeReceiverCandidate.symbol as FirCallableSymbol<*> val symbol = invokeReceiverCandidate.symbol as FirCallableSymbol<*>
val isExtensionFunctionType = symbol.fir.returnTypeRef.isExtensionFunctionType() val isExtensionFunctionType = symbol.fir.returnTypeRef.isExtensionFunctionType(towerResolver.components.session)
if (invokeBuiltinExtensionMode && !isExtensionFunctionType) { if (invokeBuiltinExtensionMode && !isExtensionFunctionType) {
continue continue
} }
@@ -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.Candidate
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
import org.jetbrains.kotlin.fir.resolve.calls.isBuiltinFunctionalType 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.constructFunctionalTypeRef
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substituteOrNull import org.jetbrains.kotlin.fir.resolve.substitution.substituteOrNull
@@ -187,7 +188,8 @@ class FirCallCompletionResultsWriterTransformer(
result = when (result) { result = when (result) {
is FirIntegerOperatorCall -> { is FirIntegerOperatorCall -> {
val expectedType = data?.getExpectedType(functionCall) 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) result.transformArguments(this, expectedType?.toExpectedType()).transformSingle(integerApproximator, expectedType)
} }
else -> { else -> {
@@ -238,9 +240,9 @@ class FirCallCompletionResultsWriterTransformer(
private fun Candidate.createArgumentsMapping(): ExpectedArgumentType? { private fun Candidate.createArgumentsMapping(): ExpectedArgumentType? {
return argumentMapping?.map { (argument, valueParameter) -> return argumentMapping?.map { (argument, valueParameter) ->
val expectedType = valueParameter.returnTypeRef.substitute(this) val expectedType = valueParameter.returnTypeRef.substitute(this)
argument.unwrapArgument() to expectedType argument.unwrapArgument() to expectedType
} }
?.toMap()?.toExpectedType() ?.toMap()?.toExpectedType()
} }
@@ -248,7 +250,8 @@ class FirCallCompletionResultsWriterTransformer(
delegatedConstructorCall: FirDelegatedConstructorCall, delegatedConstructorCall: FirDelegatedConstructorCall,
data: ExpectedArgumentType? data: ExpectedArgumentType?
): CompositeTransformResult<FirStatement> { ): 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()) val result = delegatedConstructorCall.transformArguments(this, calleeReference.candidate.createArgumentsMapping())
return result.transformCalleeReference( return result.transformCalleeReference(
@@ -276,8 +279,8 @@ class FirCallCompletionResultsWriterTransformer(
data: ExpectedArgumentType? data: ExpectedArgumentType?
): CompositeTransformResult<FirStatement> { ): CompositeTransformResult<FirStatement> {
val expectedReturnType = data?.getExpectedType(anonymousFunction) val expectedReturnType = data?.getExpectedType(anonymousFunction)
?.takeIf { it.isBuiltinFunctionalType } ?.takeIf { it.isBuiltinFunctionalType(session) }
?.let { it.typeArguments.last() as? ConeClassLikeType } ?.returnType(session) as? ConeClassLikeType
val initialType = anonymousFunction.returnTypeRef.coneTypeSafe<ConeKotlinType>() val initialType = anonymousFunction.returnTypeRef.coneTypeSafe<ConeKotlinType>()
if (initialType != null) { if (initialType != null) {
@@ -416,7 +416,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
val expectedTypeRef = (data as? ResolutionMode.WithExpectedType)?.expectedTypeRef ?: FirImplicitTypeRefImpl(null) val expectedTypeRef = (data as? ResolutionMode.WithExpectedType)?.expectedTypeRef ?: FirImplicitTypeRefImpl(null)
val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let { val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let {
extractLambdaInfoFromFunctionalType( extractLambdaInfoFromFunctionalType(
it.type, it, anonymousFunction it.type, it, anonymousFunction, session
) )
} }
var af = anonymousFunction 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|)
}
)
}
@@ -128,6 +128,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/resolve/ft.kt"); 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") @TestMetadata("functionTypes.kt")
public void testFunctionTypes() throws Exception { public void testFunctionTypes() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/functionTypes.kt"); runTest("compiler/fir/resolve/testData/resolve/functionTypes.kt");
@@ -128,6 +128,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/resolve/testData/resolve/ft.kt"); 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") @TestMetadata("functionTypes.kt")
public void testFunctionTypes() throws Exception { public void testFunctionTypes() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/functionTypes.kt"); runTest("compiler/fir/resolve/testData/resolve/functionTypes.kt");
@@ -769,7 +769,9 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
annotations.renderAnnotations() annotations.renderAnnotations()
print("R|") print("R|")
val coneType = resolvedTypeRef.type val coneType = resolvedTypeRef.type
print(coneType.renderFunctionType(kind, resolvedTypeRef.isExtensionFunctionType())) print(coneType.renderFunctionType(kind, resolvedTypeRef.annotations.any {
it.isExtensionFunctionAnnotationCall
}))
print("|") print("|")
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.types 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.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirConstKind import org.jetbrains.kotlin.fir.expressions.FirConstKind
import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.StandardClassIds
@@ -38,12 +39,6 @@ val FirFunctionTypeRef.parametersCount: Int
const val EXTENSION_FUNCTION_ANNOTATION = "kotlin/ExtensionFunctionType" const val EXTENSION_FUNCTION_ANNOTATION = "kotlin/ExtensionFunctionType"
fun FirTypeRef.isExtensionFunctionType(): Boolean {
return annotations.any {
it.isExtensionFunctionAnnotationCall
}
}
val FirAnnotationCall.isExtensionFunctionAnnotationCall: Boolean val FirAnnotationCall.isExtensionFunctionAnnotationCall: Boolean
get() = (this as? FirAnnotationCall)?.let { get() = (this as? FirAnnotationCall)?.let {
(it.annotationTypeRef as? FirResolvedTypeRef)?.let { (it.annotationTypeRef as? FirResolvedTypeRef)?.let {
@@ -16,9 +16,9 @@ fun buildB() {
val a2 = applyRestrictions2() val a2 = applyRestrictions2()
val a3 = applyRestrictions3("foo") val a3 = applyRestrictions3("foo")
B.Builder().<!UNRESOLVED_REFERENCE!>a1<!>() B.Builder().a1()
B.Builder().<!UNRESOLVED_REFERENCE!>a2<!>() B.Builder().a2()
B.Builder().<!UNRESOLVED_REFERENCE!>a3<!>() B.Builder().a3()
} }
// additional example from #KT-34820 // additional example from #KT-34820
@@ -16,7 +16,7 @@ fun buildB() {
val a2 = applyRestrictions2() val a2 = applyRestrictions2()
val a3 = applyRestrictions3("foo") val a3 = applyRestrictions3("foo")
B.Builder().<!UNRESOLVED_REFERENCE!>a1<!>() B.Builder().a1()
B.Builder().<!UNRESOLVED_REFERENCE!>a2<!>() B.Builder().a2()
B.Builder().<!UNRESOLVED_REFERENCE!>a3<!>() B.Builder().a3()
} }
@@ -36,13 +36,13 @@ class W4(val f: L2) {
} }
fun test1() { // to extension lambda 0 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 i10: E0 = id { this } // o1- ni+
val j10 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { this } // oi+ ni+ val j10 = <!INAPPLICABLE_CANDIDATE!>id<!><E0> { this } // oi+ ni+
val f10 = W1(fun Int.(): Int = this) // oi+ ni+ val f10 = W1(fun Int.(): Int = this) // oi+ ni+
val g10: E0 = id(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 i11: E0 = id { i: Int -> i } // o1+ ni+
val w12 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni- val w12 = <!INAPPLICABLE_CANDIDATE!>W1<!> { i -> i } // oi- ni-
val i12: E0 = id { 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 i13: E0 = id { it } // this or it: oi- ni-
// val j13 = id<E0> { 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 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 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 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 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 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 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 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- // val i25: E1 = id { s: String -> s.length } // oi- ni-
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) // 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 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 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+ 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) // 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 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 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 i31: L1 = id { <!UNRESOLVED_REFERENCE!>it<!> } // oi- ni+
val j31 = <!INAPPLICABLE_CANDIDATE!>id<!><L1> { <!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 i32: L1 = id { this } // this or it: oi- ni-
// val j32 = id<L1> { 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+ val i33: L1 = id(fun Int.(): Int = this) // oi+ ni+
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) // 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 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+ val i30: L2 = id { i, s -> i } // oi+ ni+
// yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above)