FIR: allow fun T.() = ... as an instance of (T) -> ...

It was already done by the previous commit by mistake, but it broke if
there are other value parameters because the type of the first parameter
would be inferred to be same as the type of the receiver.
This commit is contained in:
pyos
2021-02-02 18:56:49 +01:00
committed by TeamCityServer
parent 0a25550fc2
commit 474d1d48f7
9 changed files with 37 additions and 16 deletions
@@ -477,6 +477,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<ConeKotlinType>("varargParameterType") parameter<ConeKotlinType>("varargParameterType")
} }
val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error<FirSourceElement, KtParameter>() val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error<FirSourceElement, KtParameter>()
val CANNOT_INFER_PARAMETER_TYPE by error<FirSourceElement, KtParameter>()
} }
val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") { val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") {
@@ -295,6 +295,7 @@ object FirErrors {
val MULTIPLE_VARARG_PARAMETERS by error0<FirSourceElement, KtParameter>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER) val MULTIPLE_VARARG_PARAMETERS by error0<FirSourceElement, KtParameter>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER)
val FORBIDDEN_VARARG_PARAMETER_TYPE by error1<FirSourceElement, KtParameter, ConeKotlinType>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER) val FORBIDDEN_VARARG_PARAMETER_TYPE by error1<FirSourceElement, KtParameter, ConeKotlinType>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER)
val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0<FirSourceElement, KtParameter>() val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0<FirSourceElement, KtParameter>()
val CANNOT_INFER_PARAMETER_TYPE by error0<FirSourceElement, KtParameter>()
// Fun interfaces // Fun interfaces
val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0<FirSourceElement, KtExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0<FirSourceElement, KtExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -49,6 +49,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_INFER_PARAMETER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_VAL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_VAL
@@ -685,6 +686,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(MULTIPLE_VARARG_PARAMETERS, "Multiple vararg-parameters are prohibited") map.put(MULTIPLE_VARARG_PARAMETERS, "Multiple vararg-parameters are prohibited")
map.put(FORBIDDEN_VARARG_PARAMETER_TYPE, "Forbidden vararg parameter type: {0}", RENDER_TYPE) map.put(FORBIDDEN_VARARG_PARAMETER_TYPE, "Forbidden vararg parameter type: {0}", RENDER_TYPE)
map.put(VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION, "A type annotation is required on a value parameter") map.put(VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION, "A type annotation is required on a value parameter")
map.put(CANNOT_INFER_PARAMETER_TYPE, "cannot infer a type for this parameter. Please specify it explicitly.")
// Fun interfaces // Fun interfaces
map.put(FUN_INTERFACE_CONSTRUCTOR_REFERENCE, "Functional interface constructor references are prohibited") map.put(FUN_INTERFACE_CONSTRUCTOR_REFERENCE, "Functional interface constructor references are prohibited")
@@ -176,6 +176,7 @@ private fun ConeSimpleDiagnostic.getFactory(): FirDiagnosticFactory0<FirSourceEl
DiagnosticKind.NotLoopLabel -> FirErrors.NOT_A_LOOP_LABEL DiagnosticKind.NotLoopLabel -> FirErrors.NOT_A_LOOP_LABEL
DiagnosticKind.VariableExpected -> FirErrors.VARIABLE_EXPECTED DiagnosticKind.VariableExpected -> FirErrors.VARIABLE_EXPECTED
DiagnosticKind.ValueParameterWithNoTypeAnnotation -> FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION DiagnosticKind.ValueParameterWithNoTypeAnnotation -> FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION
DiagnosticKind.CannotInferParameterType -> FirErrors.CANNOT_INFER_PARAMETER_TYPE
DiagnosticKind.UnknownCallableKind -> FirErrors.UNKNOWN_CALLABLE_KIND DiagnosticKind.UnknownCallableKind -> FirErrors.UNKNOWN_CALLABLE_KIND
DiagnosticKind.IllegalProjectionUsage -> FirErrors.ILLEGAL_PROJECTION_USAGE DiagnosticKind.IllegalProjectionUsage -> FirErrors.ILLEGAL_PROJECTION_USAGE
DiagnosticKind.MissingStdlibClass -> FirErrors.MISSING_STDLIB_CLASS DiagnosticKind.MissingStdlibClass -> FirErrors.MISSING_STDLIB_CLASS
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.Candidate
@@ -201,30 +203,25 @@ fun ConeKotlinType.isKClassType(): Boolean {
return classId == StandardClassIds.KClass return classId == StandardClassIds.KClass
} }
private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotlinType =
when (this) {
is ConeKotlinTypeProjection -> type
is ConeStarProjection -> default
}
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? { fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
return when (val projection = fullyExpandedType(session).typeArguments.first()) { return fullyExpandedType(session).typeArguments.first().typeOrDefault(session.builtinTypes.nothingType.type)
is ConeKotlinTypeProjection -> projection.type
is ConeStarProjection -> session.builtinTypes.nothingType.type
}
} }
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType { fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
require(this is ConeClassLikeType) require(this is ConeClassLikeType)
return when (val projection = fullyExpandedType(session).typeArguments.last()) { return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
is ConeKotlinTypeProjection -> projection.type
is ConeStarProjection -> session.builtinTypes.nullableAnyType.type
}
} }
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> { fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
require(this is ConeClassLikeType) require(this is ConeClassLikeType)
return fullyExpandedType(session).typeArguments.dropLast(1).map { return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
when (it) {
is ConeKotlinTypeProjection -> it.type
is ConeStarProjection -> session.builtinTypes.nothingType.type
}
}
} }
val FirAnonymousFunction.returnType: ConeKotlinType? get() = returnTypeRef.coneTypeSafe() val FirAnonymousFunction.returnType: ConeKotlinType? get() = returnTypeRef.coneTypeSafe()
@@ -261,7 +258,7 @@ fun extractLambdaInfoFromFunctionalType(
session.builtinTypes.unitType.type session.builtinTypes.unitType.type
else else
argument.returnType ?: expectedType.returnType(session) argument.returnType ?: expectedType.returnType(session)
// `fun (x: T) = ...` and `fun T.() = ...` are both instances of `T.() -> V`; `fun () = ...` is not. // `fun (x: T) = ...` and `fun T.() = ...` are both instances of `T.() -> V` and `(T) -> V`; `fun () = ...` is not.
// For lambdas, the existence of the receiver is always implied by the expected type, and a value parameter // For lambdas, the existence of the receiver is always implied by the expected type, and a value parameter
// can never fill its role. // can never fill its role.
val receiverType = if (argument.isLambda) expectedType.receiverType(session) else argument.receiverType val receiverType = if (argument.isLambda) expectedType.receiverType(session) else argument.receiverType
@@ -272,7 +269,8 @@ fun extractLambdaInfoFromFunctionalType(
expectedParameters // Infer existence of a parameter named `it` of an appropriate type. expectedParameters // Infer existence of a parameter named `it` of an appropriate type.
} else { } else {
argument.valueParameters.mapIndexed { index, parameter -> argument.valueParameters.mapIndexed { index, parameter ->
parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: session.builtinTypes.nothingType.type parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index)
?: ConeClassErrorType(ConeSimpleDiagnostic("Cannot infer type for parameter ${parameter.name}", DiagnosticKind.CannotInferParameterType))
} }
} }
@@ -27,6 +27,7 @@ enum class DiagnosticKind {
Java, Java,
SuperNotAllowed, SuperNotAllowed,
ValueParameterWithNoTypeAnnotation, ValueParameterWithNoTypeAnnotation,
CannotInferParameterType,
UnknownCallableKind, UnknownCallableKind,
IllegalProjectionUsage, IllegalProjectionUsage,
MissingStdlibClass, MissingStdlibClass,
@@ -1338,6 +1338,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.CANNOT_INFER_PARAMETER_TYPE) { firDiagnostic ->
CannotInferParameterTypeImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE) { firDiagnostic -> add(FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE) { firDiagnostic ->
FunInterfaceConstructorReferenceImpl( FunInterfaceConstructorReferenceImpl(
firDiagnostic as FirPsiDiagnostic<*>, firDiagnostic as FirPsiDiagnostic<*>,
@@ -949,6 +949,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ValueParameterWithNoTypeAnnotation::class override val diagnosticClass get() = ValueParameterWithNoTypeAnnotation::class
} }
abstract class CannotInferParameterType : KtFirDiagnostic<KtParameter>() {
override val diagnosticClass get() = CannotInferParameterType::class
}
abstract class FunInterfaceConstructorReference : KtFirDiagnostic<KtExpression>() { abstract class FunInterfaceConstructorReference : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = FunInterfaceConstructorReference::class override val diagnosticClass get() = FunInterfaceConstructorReference::class
} }
@@ -1529,6 +1529,13 @@ internal class ValueParameterWithNoTypeAnnotationImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
} }
internal class CannotInferParameterTypeImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.CannotInferParameterType(), KtAbstractFirDiagnostic<KtParameter> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class FunInterfaceConstructorReferenceImpl( internal class FunInterfaceConstructorReferenceImpl(
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken, override val token: ValidityToken,