[FIR] Implement IMPLICIT_NOTHING_*_TYPE diagnostics

This commit is contained in:
Dmitriy Novozhilov
2022-11-09 18:44:57 +02:00
committed by Space Team
parent 0e84bf2053
commit 1b42298025
18 changed files with 104 additions and 23 deletions
@@ -1927,6 +1927,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.IMPLICIT_NOTHING_RETURN_TYPE) { firDiagnostic ->
ImplicitNothingReturnTypeImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.IMPLICIT_NOTHING_PROPERTY_TYPE) { firDiagnostic ->
ImplicitNothingPropertyTypeImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.CYCLIC_GENERIC_UPPER_BOUND) { firDiagnostic ->
CyclicGenericUpperBoundImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -1371,6 +1371,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val isMismatchDueToNullability: Boolean
}
abstract class ImplicitNothingReturnType : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ImplicitNothingReturnType::class
}
abstract class ImplicitNothingPropertyType : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ImplicitNothingPropertyType::class
}
abstract class CyclicGenericUpperBound : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = CyclicGenericUpperBound::class
}
@@ -1648,6 +1648,16 @@ internal class ReturnTypeMismatchImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.ReturnTypeMismatch(), KtAbstractFirDiagnostic<KtExpression>
internal class ImplicitNothingReturnTypeImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.ImplicitNothingReturnType(), KtAbstractFirDiagnostic<PsiElement>
internal class ImplicitNothingPropertyTypeImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.ImplicitNothingPropertyType(), KtAbstractFirDiagnostic<PsiElement>
internal class CyclicGenericUpperBoundImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
@@ -21,4 +21,4 @@ open class Base<T>(val x: T)
class Derived : Base<Int>(10)
val xx = Derived().x + 1
val <!REDECLARATION!>t<!> = throw AssertionError("")
val <!IMPLICIT_NOTHING_PROPERTY_TYPE, REDECLARATION!>t<!> = throw AssertionError("")
@@ -653,6 +653,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<Boolean>("isMismatchDueToNullability")
}
val IMPLICIT_NOTHING_RETURN_TYPE by error<PsiElement>(PositioningStrategy.NAME_IDENTIFIER)
val IMPLICIT_NOTHING_PROPERTY_TYPE by error<PsiElement>(PositioningStrategy.NAME_IDENTIFIER)
val CYCLIC_GENERIC_UPPER_BOUND by error<PsiElement>()
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error<KtDeclaration>(PositioningStrategy.TYPE_PARAMETERS_LIST)
@@ -407,6 +407,8 @@ object FirErrors {
val TYPE_PARAMETERS_NOT_ALLOWED by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error0<KtTypeParameter>()
val RETURN_TYPE_MISMATCH by error4<KtExpression, ConeKotlinType, ConeKotlinType, FirFunction, Boolean>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
val IMPLICIT_NOTHING_RETURN_TYPE by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val IMPLICIT_NOTHING_PROPERTY_TYPE by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val CYCLIC_GENERIC_UPPER_BOUND by error0<PsiElement>()
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
@@ -37,6 +37,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val callableDeclarationCheckers: Set<FirCallableDeclarationChecker>
get() = setOf(
FirKClassWithIncorrectTypeArgumentChecker,
FirImplicitNothingReturnTypeChecker,
)
override val functionCheckers: Set<FirFunctionChecker>
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isNothing
object FirImplicitNothingReturnTypeChecker : FirCallableDeclarationChecker() {
override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirSimpleFunction && declaration !is FirProperty) return
if (declaration is FirProperty && declaration.isLocal) return
if (declaration.isOverride) return
if (declaration.symbol.hasExplicitReturnType) return
if (declaration.returnTypeRef.coneType.isNothing) {
val factory = when (declaration) {
is FirSimpleFunction -> FirErrors.IMPLICIT_NOTHING_RETURN_TYPE
is FirProperty -> FirErrors.IMPLICIT_NOTHING_PROPERTY_TYPE
else -> error("Should not be here")
}
reporter.reportOn(declaration.source, factory, context)
}
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
import org.jetbrains.kotlin.fir.types.isBoolean
import org.jetbrains.kotlin.fir.types.isNothing
import org.jetbrains.kotlin.fir.types.replaceArgumentsWithStarProjections
@@ -130,3 +131,8 @@ fun FirSimpleFunction.isTypedEqualsInInlineClass(session: FirSession): Boolean =
}
} ?: false
val FirCallableSymbol<*>.hasExplicitReturnType: Boolean
get() {
val returnTypeRef = resolvedReturnTypeRef
return returnTypeRef.delegatedTypeRef != null || returnTypeRef is FirImplicitUnitTypeRef
}
@@ -236,6 +236,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SUSPEND_F
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SUSPEND_PROPERTY_ACCESS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IMPLICIT_NOTHING_PROPERTY_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IMPLICIT_NOTHING_RETURN_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_FILE_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER
@@ -1220,6 +1222,9 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
NOT_RENDERED
)
map.put(IMPLICIT_NOTHING_RETURN_TYPE, "'Nothing' return type needs to be specified explicitly")
map.put(IMPLICIT_NOTHING_PROPERTY_TYPE, "'Nothing' property type needs to be specified explicitly");
map.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds")
map.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Type parameters must be placed before the name of the function")
@@ -136,7 +136,7 @@ fun blockNoReturnIfUnitInOneBranch(): Int {
fun nonBlockReturnIfEmptyIf(): Int = <!RETURN_TYPE_MISMATCH!>if (1 < 2) {} else {}<!>
fun nonBlockNoReturnIfUnitInOneBranch(): Int = <!RETURN_TYPE_MISMATCH!>if (1 < 2) {} else 2<!>
val a = <!RETURN_NOT_ALLOWED!>return<!> 1
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>a<!> = <!RETURN_NOT_ALLOWED!>return<!> 1
class A() {
}
@@ -30,13 +30,13 @@ fun testReturnFromAnonFun() =
return <!RETURN_TYPE_MISMATCH!>if (true) 42 else println()<!>
})
fun testReturn1() =
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>testReturn1<!>() =
run {
return <!RETURN_TYPE_MISMATCH!>if (true) 42
else println()<!>
}
fun testReturn2() =
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>testReturn2<!>() =
run {
return <!RETURN_TYPE_MISMATCH!>if (true) 42
else if (true) 42
@@ -1,10 +1,10 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNREACHABLE_CODE -UNUSED_PARAMETER -RETURN_NOT_ALLOWED
fun test1() = run {
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>test1<!>() = run {
return <!RETURN_TYPE_MISMATCH!>"OK"<!>
}
fun test2() = run {
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>test2<!>() = run {
fun local(): String {
return ""
}
@@ -14,7 +14,7 @@ fun test() {
val a : Nothing = <!RETURN_NOT_ALLOWED!>return<!> 1
val b = <!RETURN_NOT_ALLOWED!>return<!> 1
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>b<!> = <!RETURN_NOT_ALLOWED!>return<!> 1
val c = doSmth(if (true) 3 else <!RETURN_NOT_ALLOWED!>return<!>)
@@ -24,7 +24,7 @@ fun testResultOfLambda2() =
}
}
fun testReturn1() =
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>testReturn1<!>() =
run {
return <!RETURN_TYPE_MISMATCH!>when {
true -> 42
@@ -32,7 +32,7 @@ fun testReturn1() =
}<!>
}
fun testReturn2() =
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>testReturn2<!>() =
run {
return <!RETURN_TYPE_MISMATCH!>when {
true -> 42
@@ -80,4 +80,4 @@ val testUsage5: Any get() =
when {
true -> 42
else -> println()
}
}
+10 -10
View File
@@ -1,37 +1,37 @@
fun foo() = throw Exception()
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>foo<!>() = throw Exception()
fun bar() = null!!
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>bar<!>() = null!!
fun baz() = bar()
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>baz<!>() = bar()
fun gav(): Any = null!!
val x = null!!
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>x<!> = null!!
val y: Nothing = throw Exception()
fun check() {
// Error: KT-10449
fun local() = bar()
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>local<!>() = bar()
// Unreachable / unused, but not implicit Nothing
val x = null!!
}
fun nonLocalReturn() = run { <!RETURN_TYPE_MISMATCH!>return<!> }
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>nonLocalReturn<!>() = run { <!RETURN_TYPE_MISMATCH!>return<!> }
class Klass {
fun bar() = null!!
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>bar<!>() = null!!
val y = null!!
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>y<!> = null!!
init {
fun local() = bar()
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>local<!>() = bar()
// Should be unreachable: see KT-5311
val z = null!!
}
fun foo() {
fun local() = bar()
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>local<!>() = bar()
val x = y
}
@@ -1,6 +1,6 @@
// !CHECK_TYPE
val x get() = null
val y get() = null!!
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>y<!> get() = null!!
fun foo() {
x checkType { _<Nothing?>() }
@@ -4,8 +4,8 @@
// TESTCASE NUMBER: 1
// UNEXPECTED BEHAVIOUR
// ISSUES : KT-35545
fun case1(a: Boolean) = run { println("d"); return <!RETURN_TYPE_MISMATCH!>true<!> }
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>case1<!>(a: Boolean) = run { println("d"); return <!RETURN_TYPE_MISMATCH!>true<!> }
// TESTCASE NUMBER: 2
val case2
val <!IMPLICIT_NOTHING_PROPERTY_TYPE!>case2<!>
get() = run { println("d"); return <!RETURN_TYPE_MISMATCH!>true<!> }