[FIR] Add DNN checks
Merge-request: KT-MR-7000 Merged-by: Nikolay Lunyak <lunyak.kolya@mail.ru>
This commit is contained in:
+18
@@ -2015,6 +2015,24 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INCORRECT_LEFT_COMPONENT_OF_INTERSECTION) { firDiagnostic ->
|
||||
IncorrectLeftComponentOfIntersectionImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION) { firDiagnostic ->
|
||||
IncorrectRightComponentOfIntersectionImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NULLABLE_ON_DEFINITELY_NOT_NULLABLE) { firDiagnostic ->
|
||||
NullableOnDefinitelyNotNullableImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
||||
ExtensionInClassReferenceNotAllowedImpl(
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a),
|
||||
|
||||
+12
@@ -1435,6 +1435,18 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val causingTypes: String
|
||||
}
|
||||
|
||||
abstract class IncorrectLeftComponentOfIntersection : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = IncorrectLeftComponentOfIntersection::class
|
||||
}
|
||||
|
||||
abstract class IncorrectRightComponentOfIntersection : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = IncorrectRightComponentOfIntersection::class
|
||||
}
|
||||
|
||||
abstract class NullableOnDefinitelyNotNullable : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = NullableOnDefinitelyNotNullable::class
|
||||
}
|
||||
|
||||
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
||||
abstract val referencedDeclaration: KtCallableSymbol
|
||||
|
||||
+15
@@ -1722,6 +1722,21 @@ internal class InferredTypeVariableIntoPossibleEmptyIntersectionImpl(
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.InferredTypeVariableIntoPossibleEmptyIntersection(), KtAbstractFirDiagnostic<PsiElement>
|
||||
|
||||
internal class IncorrectLeftComponentOfIntersectionImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.IncorrectLeftComponentOfIntersection(), KtAbstractFirDiagnostic<KtTypeReference>
|
||||
|
||||
internal class IncorrectRightComponentOfIntersectionImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.IncorrectRightComponentOfIntersection(), KtAbstractFirDiagnostic<KtTypeReference>
|
||||
|
||||
internal class NullableOnDefinitelyNotNullableImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.NullableOnDefinitelyNotNullable(), KtAbstractFirDiagnostic<KtTypeReference>
|
||||
|
||||
internal class ExtensionInClassReferenceNotAllowedImpl(
|
||||
override val referencedDeclaration: KtCallableSymbol,
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
|
||||
+4
@@ -705,6 +705,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<String>("description")
|
||||
parameter<String>("causingTypes")
|
||||
}
|
||||
|
||||
val INCORRECT_LEFT_COMPONENT_OF_INTERSECTION by error<KtTypeReference>()
|
||||
val INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION by error<KtTypeReference>()
|
||||
val NULLABLE_ON_DEFINITELY_NOT_NULLABLE by error<KtTypeReference>()
|
||||
}
|
||||
|
||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||
|
||||
@@ -417,6 +417,9 @@ object FirErrors {
|
||||
val PLATFORM_CLASS_MAPPED_TO_KOTLIN by warning1<PsiElement, FqName>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION by error4<PsiElement, String, Collection<ConeKotlinType>, String, String>()
|
||||
val INFERRED_TYPE_VARIABLE_INTO_POSSIBLE_EMPTY_INTERSECTION by warning4<PsiElement, String, Collection<ConeKotlinType>, String, String>()
|
||||
val INCORRECT_LEFT_COMPONENT_OF_INTERSECTION by error0<KtTypeReference>()
|
||||
val INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION by error0<KtTypeReference>()
|
||||
val NULLABLE_ON_DEFINITELY_NOT_NULLABLE by error0<KtTypeReference>()
|
||||
|
||||
// Reflection
|
||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<KtExpression, FirCallableSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ object CommonTypeCheckers : TypeCheckers() {
|
||||
FirTypeAnnotationChecker,
|
||||
FirSuspendModifierChecker,
|
||||
FirDeprecatedTypeChecker,
|
||||
FirOptInUsageTypeRefChecker
|
||||
FirOptInUsageTypeRefChecker,
|
||||
FirDefinitelyNotNullableChecker,
|
||||
)
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.type
|
||||
|
||||
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.types.*
|
||||
|
||||
object FirDefinitelyNotNullableChecker : FirTypeRefChecker() {
|
||||
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val intersection = (typeRef as? FirResolvedTypeRef)?.delegatedTypeRef as? FirIntersectionTypeRef ?: return
|
||||
|
||||
if (intersection.isMarkedNullable) {
|
||||
reporter.reportOn(intersection.source, FirErrors.NULLABLE_ON_DEFINITELY_NOT_NULLABLE, context)
|
||||
}
|
||||
|
||||
if (!intersection.isLeftValidForDefinitelyNotNullable) {
|
||||
reporter.reportOn(intersection.leftType.source, FirErrors.INCORRECT_LEFT_COMPONENT_OF_INTERSECTION, context)
|
||||
}
|
||||
|
||||
if (!intersection.isRightValidForDefinitelyNotNullable) {
|
||||
reporter.reportOn(intersection.rightType.source, FirErrors.INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -252,6 +252,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCONSISTENT_TYPE_PARAMETER_BOUNDS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCONSISTENT_TYPE_PARAMETER_VALUES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCORRECT_CHARACTER_LITERAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCORRECT_LEFT_COMPONENT_OF_INTERSECTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_UNSUCCESSFUL_FORK
|
||||
@@ -359,6 +361,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_THIS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_TYPE_ARGUMENTS_ON_RHS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_VALUE_FOR_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_INLINE_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_ON_DEFINITELY_NOT_NULLABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_IN_CLASS_LITERAL_LHS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER
|
||||
@@ -982,6 +985,18 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
TO_STRING,
|
||||
TO_STRING
|
||||
)
|
||||
map.put(
|
||||
NULLABLE_ON_DEFINITELY_NOT_NULLABLE,
|
||||
"'!!' type cannot be marked as nullable"
|
||||
)
|
||||
map.put(
|
||||
INCORRECT_LEFT_COMPONENT_OF_INTERSECTION,
|
||||
"Intersection types are only supported for definitely non-nullable types: left part should be a type parameter with nullable bounds"
|
||||
)
|
||||
map.put(
|
||||
INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION,
|
||||
"Intersection types are only supported for definitely non-nullable types: right part should be non-nullable Any"
|
||||
)
|
||||
|
||||
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING, NOT_RENDERED)
|
||||
map.put(THROWABLE_TYPE_MISMATCH, "Throwable type mismatch: actual type is {0}", TO_STRING, NOT_RENDERED)
|
||||
|
||||
+1
@@ -128,6 +128,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
||||
is ConeLocalVariableNoTypeOrInitializer -> runIf(variable.isLocalMember) {
|
||||
FirErrors.VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.createOn(source)
|
||||
}
|
||||
is ConeForbiddenIntersection -> null // reported in FirDefinitelyNotNullableChecker
|
||||
|
||||
is ConeUnderscoreIsReserved -> FirErrors.UNDERSCORE_IS_RESERVED.createOn(this.source)
|
||||
is ConeUnderscoreUsageWithoutBackticks -> FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.createOn(this.source)
|
||||
|
||||
+2
-5
@@ -523,14 +523,11 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
||||
is FirDynamicTypeRef -> ConeDynamicType.create(session) to null
|
||||
is FirIntersectionTypeRef -> {
|
||||
val leftType = typeRef.leftType.coneType
|
||||
val rightType = typeRef.rightType.coneType
|
||||
|
||||
if (rightType.isAny && leftType is ConeTypeParameterType) {
|
||||
if (leftType is ConeTypeParameterType) {
|
||||
ConeDefinitelyNotNullType(leftType) to null
|
||||
} else {
|
||||
ConeErrorType(ConeUnsupported("Intersection types are not supported yet", typeRef.source)) to null
|
||||
ConeErrorType(ConeForbiddenIntersection) to null
|
||||
}
|
||||
|
||||
}
|
||||
else -> error(typeRef.render())
|
||||
}
|
||||
|
||||
+4
@@ -237,3 +237,7 @@ class ConeAmbiguousAlteredAssign(val altererNames: List<String?>) : ConeDiagnost
|
||||
override val reason: String
|
||||
get() = "Assign altered by multiple extensions"
|
||||
}
|
||||
|
||||
object ConeForbiddenIntersection : ConeDiagnostic {
|
||||
override val reason: String get() = "Such an intersection type is not allowed"
|
||||
}
|
||||
|
||||
@@ -191,3 +191,7 @@ val ConeKotlinType.canBeNull: Boolean
|
||||
}
|
||||
}
|
||||
|
||||
val FirIntersectionTypeRef.isLeftValidForDefinitelyNotNullable
|
||||
get() = leftType.coneType.let { it is ConeTypeParameterType && it.canBeNull && !it.isMarkedNullable }
|
||||
|
||||
val FirIntersectionTypeRef.isRightValidForDefinitelyNotNullable get() = rightType.coneType.isAny
|
||||
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun main(x: Collection<String>) {
|
||||
if (x is List<!SYNTAX!><!> <!SYNTAX!><!SYNTAX!><!>& Any)<!> {}
|
||||
|
||||
val w: <!UNSUPPORTED!><!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>List<!> & Any<!> = null!!
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun main(x: Collection<String>) {
|
||||
|
||||
+10
-10
@@ -1,18 +1,18 @@
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun <T : Any> foo(x: T & Any, y: <!UNSUPPORTED!>List<<!UNSUPPORTED!>String & Any<!>> & Any<!>) {}
|
||||
fun <T : Any> foo(x: <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>T<!> & Any, y: <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>List<<!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>String<!> & Any><!> & Any) {}
|
||||
|
||||
fun <F> bar1(x: F? & Any) {}
|
||||
fun <F> bar2(x: <!UNSUPPORTED!>F & Any?<!>) {}
|
||||
fun <F> bar3(x: (F?) & Any) {}
|
||||
fun <F> bar4(x: (F & Any)?) {}
|
||||
fun <F> bar1(x: <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>F?<!> & Any) {}
|
||||
fun <F> bar2(x: F & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!>Any?<!>) {}
|
||||
fun <F> bar3(x: <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>(F?)<!> & Any) {}
|
||||
fun <F> bar4(x: <!NULLABLE_ON_DEFINITELY_NOT_NULLABLE!>(F & Any)?<!>) {}
|
||||
|
||||
fun <F> bar5(x: <!UNSUPPORTED!>F & String<!>) {}
|
||||
fun <F> bar5(x: F & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!>String<!>) {}
|
||||
|
||||
fun <F> bar6(x: <!UNSUPPORTED!>F & (F & Any)<!>) {}
|
||||
fun <F> bar7(x: <!UNSUPPORTED!>(F & Any) & Any<!>) {}
|
||||
fun <F> bar6(x: F & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!>(F & Any)<!>) {}
|
||||
fun <F> bar7(x: <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>(F & Any)<!> & Any) {}
|
||||
fun <F> bar8(x: (F & Any).() -> Unit) {}
|
||||
fun <F> (F & Any).bar9(x: () -> Unit) {}
|
||||
|
||||
fun <F> bar10(x: <!UNSUPPORTED!>F & <!UNSUPPORTED!>Any & String<!><!>) {}
|
||||
fun <F> bar11(x: <!UNSUPPORTED!>Double & <!UNSUPPORTED!>Any & String<!><!>) {}
|
||||
fun <F> bar10(x: F & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!><!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>Any<!> & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!>String<!><!>) {}
|
||||
fun <F> bar11(x: <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>Double<!> & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!><!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>Any<!> & <!INCORRECT_RIGHT_COMPONENT_OF_INTERSECTION!>String<!><!>) {}
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
|
||||
fun <T : Comparable<T & Any>> sort1() {}
|
||||
fun <T : Comparable<<!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>T<!> & Any>> sort1() {}
|
||||
fun <T : Comparable<T & Any>?> sort2() {}
|
||||
|
||||
class A1<K : Comparable<K & Any>>
|
||||
class A1<K : Comparable<<!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>K<!> & Any>>
|
||||
class A2<K : Comparable<K & Any>?>
|
||||
|
||||
fun <R : T & Any, T> bar() {}
|
||||
|
||||
fun <<!CYCLIC_GENERIC_UPPER_BOUND!>E : E & Any<!>> baz() {}
|
||||
fun <<!CYCLIC_GENERIC_UPPER_BOUND!>E : <!INCORRECT_LEFT_COMPONENT_OF_INTERSECTION!>E<!> & Any<!>> baz() {}
|
||||
|
||||
Reference in New Issue
Block a user