[FIR] Add DNN checks

Merge-request: KT-MR-7000
Merged-by: Nikolay Lunyak <lunyak.kolya@mail.ru>
This commit is contained in:
Nikolay Lunyak
2022-09-01 14:25:07 +00:00
committed by Space
parent bb2bee74cf
commit 3d9c77efa8
16 changed files with 124 additions and 26 deletions
@@ -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)
@@ -12,6 +12,7 @@ object CommonTypeCheckers : TypeCheckers() {
FirTypeAnnotationChecker,
FirSuspendModifierChecker,
FirDeprecatedTypeChecker,
FirOptInUsageTypeRefChecker
FirOptInUsageTypeRefChecker,
FirDefinitelyNotNullableChecker,
)
}
@@ -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)
}
}
}
@@ -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)
@@ -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)
@@ -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())
}
@@ -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