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,