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")
}
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") {
@@ -295,6 +295,7 @@ object FirErrors {
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 VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0<FirSourceElement, KtParameter>()
val CANNOT_INFER_PARAMETER_TYPE by error0<FirSourceElement, KtParameter>()
// Fun interfaces
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_TO_ANNOTATION_CONSTRUCTOR
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.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT
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(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(CANNOT_INFER_PARAMETER_TYPE, "cannot infer a type for this parameter. Please specify it explicitly.")
// Fun interfaces
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.VariableExpected -> FirErrors.VARIABLE_EXPECTED
DiagnosticKind.ValueParameterWithNoTypeAnnotation -> FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION
DiagnosticKind.CannotInferParameterType -> FirErrors.CANNOT_INFER_PARAMETER_TYPE
DiagnosticKind.UnknownCallableKind -> FirErrors.UNKNOWN_CALLABLE_KIND
DiagnosticKind.IllegalProjectionUsage -> FirErrors.ILLEGAL_PROJECTION_USAGE
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.declarations.FirAnonymousFunction
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.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
@@ -201,30 +203,25 @@ fun ConeKotlinType.isKClassType(): Boolean {
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? {
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
return when (val projection = fullyExpandedType(session).typeArguments.first()) {
is ConeKotlinTypeProjection -> projection.type
is ConeStarProjection -> session.builtinTypes.nothingType.type
}
return fullyExpandedType(session).typeArguments.first().typeOrDefault(session.builtinTypes.nothingType.type)
}
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
require(this is ConeClassLikeType)
return when (val projection = fullyExpandedType(session).typeArguments.last()) {
is ConeKotlinTypeProjection -> projection.type
is ConeStarProjection -> session.builtinTypes.nullableAnyType.type
}
return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
}
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
require(this is ConeClassLikeType)
return fullyExpandedType(session).typeArguments.dropLast(1).map {
when (it) {
is ConeKotlinTypeProjection -> it.type
is ConeStarProjection -> session.builtinTypes.nothingType.type
}
}
return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
}
val FirAnonymousFunction.returnType: ConeKotlinType? get() = returnTypeRef.coneTypeSafe()
@@ -261,7 +258,7 @@ fun extractLambdaInfoFromFunctionalType(
session.builtinTypes.unitType.type
else
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
// can never fill its role.
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.
} else {
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,
SuperNotAllowed,
ValueParameterWithNoTypeAnnotation,
CannotInferParameterType,
UnknownCallableKind,
IllegalProjectionUsage,
MissingStdlibClass,
@@ -1338,6 +1338,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.CANNOT_INFER_PARAMETER_TYPE) { firDiagnostic ->
CannotInferParameterTypeImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE) { firDiagnostic ->
FunInterfaceConstructorReferenceImpl(
firDiagnostic as FirPsiDiagnostic<*>,
@@ -949,6 +949,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ValueParameterWithNoTypeAnnotation::class
}
abstract class CannotInferParameterType : KtFirDiagnostic<KtParameter>() {
override val diagnosticClass get() = CannotInferParameterType::class
}
abstract class FunInterfaceConstructorReference : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = FunInterfaceConstructorReference::class
}
@@ -1529,6 +1529,13 @@ internal class ValueParameterWithNoTypeAnnotationImpl(
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(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,