From 474d1d48f74cb8cfcbcd3fb2d65837df0ecea8f2 Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 2 Feb 2021 18:56:49 +0100 Subject: [PATCH] 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. --- .../diagnostics/FirDiagnosticsList.kt | 1 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../diagnostics/FirDefaultErrorMessages.kt | 2 ++ .../coneDiagnosticToFirDiagnostic.kt | 1 + .../fir/resolve/inference/InferenceUtils.kt | 30 +++++++++---------- .../fir/diagnostics/ConeSimpleDiagnostic.kt | 1 + .../diagnostics/KtFirDataClassConverters.kt | 6 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 +++++ 9 files changed, 37 insertions(+), 16 deletions(-) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 84598acf2a0..4d2f1b8604e 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -477,6 +477,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { parameter("varargParameterType") } val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error() + val CANNOT_INFER_PARAMETER_TYPE by error() } val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index de3d6770fe3..1682362fa1a 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -295,6 +295,7 @@ object FirErrors { val MULTIPLE_VARARG_PARAMETERS by error0(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER) val FORBIDDEN_VARARG_PARAMETER_TYPE by error1(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER) val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0() + val CANNOT_INFER_PARAMETER_TYPE by error0() // Fun interfaces val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index e990e6555e8..588e85c9a99 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -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") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 80af52209c4..9f02fffc467 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -176,6 +176,7 @@ private fun ConeSimpleDiagnostic.getFactory(): FirDiagnosticFactory0 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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt index bff94a0be79..c95a158e7d5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt @@ -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 { 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)) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt index 203bbfb263b..09984b6c3b8 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt @@ -27,6 +27,7 @@ enum class DiagnosticKind { Java, SuperNotAllowed, ValueParameterWithNoTypeAnnotation, + CannotInferParameterType, UnknownCallableKind, IllegalProjectionUsage, MissingStdlibClass, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 7c59608da7e..8b71e08e929 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -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<*>, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 747ba79e83c..2c4587defe9 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -949,6 +949,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ValueParameterWithNoTypeAnnotation::class } + abstract class CannotInferParameterType : KtFirDiagnostic() { + override val diagnosticClass get() = CannotInferParameterType::class + } + abstract class FunInterfaceConstructorReference : KtFirDiagnostic() { override val diagnosticClass get() = FunInterfaceConstructorReference::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 00ac575bc0a..fc81f8051d2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -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 { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class FunInterfaceConstructorReferenceImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken,