[FIR] Implement NULL_FOR_NONNULL_TYPE diagnostics, fix tests
This commit is contained in:
+1
-1
@@ -26,6 +26,6 @@ open class B<V> : A<Any, V>() {
|
||||
|
||||
fun test_1(b: B<Int>, x: Int, inv: Inv<Int>) {
|
||||
b.take(x)
|
||||
b.take(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
b.take(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
b.takeInv(inv)
|
||||
}
|
||||
|
||||
+3
-1
@@ -222,6 +222,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
|
||||
val NULL_FOR_NONNULL_TYPE by error<PsiElement> { }
|
||||
|
||||
val INAPPLICABLE_LATEINIT_MODIFIER by error<KtModifierListOwner>(PositioningStrategy.LATEINIT_MODIFIER) {
|
||||
parameter<String>("reason")
|
||||
}
|
||||
@@ -336,7 +338,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error<KtTypeParameterList>()
|
||||
|
||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning<KtTypeParameter>()
|
||||
|
||||
|
||||
val DYNAMIC_UPPER_BOUND by error<KtTypeReference>()
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ object FirErrors {
|
||||
val NONE_APPLICABLE by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val INAPPLICABLE_CANDIDATE by error1<PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ARGUMENT_TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
val NULL_FOR_NONNULL_TYPE by error0<PsiElement>()
|
||||
val INAPPLICABLE_LATEINIT_MODIFIER by error1<KtModifierListOwner, String>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
|
||||
val VARARG_OUTSIDE_PARENTHESES by error0<KtExpression>()
|
||||
val NAMED_ARGUMENTS_NOT_ALLOWED by error1<KtValueArgument, ForbiddenNamedArgumentsTarget>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
|
||||
|
||||
+7
-1
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isComponentCall
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
@@ -43,7 +45,11 @@ object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
||||
// TODO: remove after fix of KT-45989
|
||||
return
|
||||
}
|
||||
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
|
||||
if (initializer.isNullLiteral && propertyType.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(initializer.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
} else {
|
||||
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isNullLiteral
|
||||
|
||||
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val rValue = expression.rValue
|
||||
if (rValue.isNullLiteral) {
|
||||
val leftType = ((expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol)?.fir?.returnTypeRef
|
||||
if (leftType?.coneType?.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -8,15 +8,15 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULL_FOR_NONNULL_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
|
||||
object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||
override fun check(expression: FirReturnExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -33,7 +33,11 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||
|
||||
if (!isSubtypeForTypeMismatch(typeContext, subtype = returnExpressionType, supertype = functionReturnType)) {
|
||||
val returnExpressionSource = resultExpression.source ?: return
|
||||
reporter.report(RETURN_TYPE_MISMATCH.on(returnExpressionSource, functionReturnType, returnExpressionType), context)
|
||||
if (resultExpression.isNullLiteral && functionReturnType.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(resultExpression.source, NULL_FOR_NONNULL_TYPE, context)
|
||||
} else {
|
||||
reporter.report(RETURN_TYPE_MISMATCH.on(returnExpressionSource, functionReturnType, returnExpressionType), context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -142,6 +142,9 @@ private fun mapInapplicableCandidateError(
|
||||
rootCause.expectedType,
|
||||
rootCause.actualType
|
||||
)
|
||||
is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.on(
|
||||
rootCause.argument.source ?: source
|
||||
)
|
||||
is NonVarargSpread -> FirErrors.NON_VARARG_SPREAD.on(rootCause.argument.source?.getChild(KtTokens.MUL, depth = 1)!!)
|
||||
is ArgumentPassedTwice -> FirErrors.ARGUMENT_PASSED_TWICE.on(rootCause.argument.source)
|
||||
is TooManyArguments -> FirErrors.TOO_MANY_ARGUMENTS.on(rootCause.argument.source ?: source, rootCause.function)
|
||||
|
||||
+3
-2
@@ -30,7 +30,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirTypeParameterInQualifiedAccessChecker,
|
||||
FirSealedClassConstructorCallChecker,
|
||||
FirUninitializedEnumChecker,
|
||||
FirFunInterfaceConstructorReferenceChecker,
|
||||
FirFunInterfaceConstructorReferenceChecker,
|
||||
)
|
||||
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
@@ -46,7 +46,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
|
||||
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
|
||||
get() = setOf(
|
||||
FirValReassignmentViaBackingFieldChecker
|
||||
FirValReassignmentViaBackingFieldChecker,
|
||||
FirAssignmentTypeMismatchChecker
|
||||
)
|
||||
|
||||
override val whenExpressionCheckers: Set<FirWhenExpressionChecker>
|
||||
|
||||
@@ -353,6 +353,10 @@ private fun checkApplicabilityForArgumentType(
|
||||
}
|
||||
}
|
||||
|
||||
if (argument.isNullLiteral && actualExpectedType.nullability == ConeNullability.NOT_NULL) {
|
||||
return NullForNotNullType(argument)
|
||||
}
|
||||
|
||||
fun tryGetConeTypeThatCompatibleWithKtType(type: ConeKotlinType): ConeKotlinType {
|
||||
if (type is ConeTypeVariableType) {
|
||||
val originalTypeParameter =
|
||||
@@ -374,7 +378,6 @@ private fun checkApplicabilityForArgumentType(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
if (isReceiver && isDispatch) {
|
||||
if (!expectedType.isNullable && argumentType.isMarkedNullable) {
|
||||
sink.reportDiagnostic(InapplicableWrongReceiver(expectedType, argumentType))
|
||||
|
||||
+4
@@ -92,3 +92,7 @@ class ArgumentTypeMismatch(
|
||||
val actualType: ConeKotlinType,
|
||||
val argument: FirExpression
|
||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||
|
||||
class NullForNotNullType(
|
||||
val argument: FirExpression
|
||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
@@ -41,6 +43,7 @@ val FirTypeRef.isArrayType: Boolean
|
||||
get() =
|
||||
isBuiltinType(StandardClassIds.Array, false) ||
|
||||
StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) }
|
||||
val FirExpression.isNullLiteral: Boolean get() = this is FirConstExpression<*> && this.value == null && this.source != null
|
||||
|
||||
private val FirTypeRef.classLikeTypeOrNull: ConeClassLikeType?
|
||||
get() = when (this) {
|
||||
|
||||
@@ -30,7 +30,7 @@ fun foo(expr: StringBuilder): Int {
|
||||
|
||||
fun unitShort() : Unit = Unit
|
||||
fun unitShortConv() : Unit = <!RETURN_TYPE_MISMATCH!>1<!>
|
||||
fun unitShortNull() : Unit = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
fun unitShortNull() : Unit = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
|
||||
fun intEmpty() : Int {}
|
||||
fun intShortInfer() = 1
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ fun <T> test(x: T) {
|
||||
|
||||
baz<Int?, String?>(null, null, ::foo)
|
||||
|
||||
baz<Int, String?>(<!ARGUMENT_TYPE_MISMATCH!>null<!>, null, ::foo)
|
||||
baz<Int?, String>(null, <!ARGUMENT_TYPE_MISMATCH!>null<!>, ::foo)
|
||||
baz<Int, String?>(<!NULL_FOR_NONNULL_TYPE!>null<!>, null, ::foo)
|
||||
baz<Int?, String>(null, <!NULL_FOR_NONNULL_TYPE!>null<!>, ::foo)
|
||||
baz(null, "", ::foo)
|
||||
baz(1, null, ::foo)
|
||||
baz(null, null, ::foo)
|
||||
|
||||
@@ -13,7 +13,7 @@ fun test2() = run {
|
||||
|
||||
inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> = null!!
|
||||
fun test3(a: List<String>, b: List<Int>) = a.map {
|
||||
if (it.length == 3) return <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
if (it.length == 3) return <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
if (it.length == 4) return <!RETURN_TYPE_MISMATCH!>""<!>
|
||||
if (it.length == 4) return <!RETURN_TYPE_MISMATCH!>5<!>
|
||||
if (it.length == 4) return b
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fun <T> foo(x: T, y: T!!) = x!!
|
||||
|
||||
fun main() {
|
||||
foo<String>("", "").length
|
||||
foo<String>("", <!ARGUMENT_TYPE_MISMATCH!>null<!>).length
|
||||
foo<String>("", <!NULL_FOR_NONNULL_TYPE!>null<!>).length
|
||||
foo<String?>(null, "").length
|
||||
foo<String?>(null, null).length
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fun <T> foo(x: T, y: T!!): T!! = x ?: y
|
||||
|
||||
fun main() {
|
||||
foo<String>("", "").length
|
||||
foo<String>("", <!ARGUMENT_TYPE_MISMATCH!>null<!>).length
|
||||
foo<String>("", <!NULL_FOR_NONNULL_TYPE!>null<!>).length
|
||||
foo<String?>(null, "")<!UNSAFE_CALL!>.<!>length
|
||||
foo<String?>(null, null)<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
val foo: Any?
|
||||
}
|
||||
|
||||
interface C: A {
|
||||
override val foo: String?
|
||||
}
|
||||
interface B: A {
|
||||
override var foo: String
|
||||
}
|
||||
|
||||
fun <T> test(a: T) where T : B, T : C {
|
||||
a.foo = ""
|
||||
a.foo = null
|
||||
|
||||
a.foo.checkType { _<String>() }
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface A {
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
fun <E> bar(x: E) {}
|
||||
|
||||
fun <T> foo(): T {
|
||||
val x1: T = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
val x2: T? = null
|
||||
|
||||
bar<T>(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
bar<T?>(null)
|
||||
|
||||
return <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
}
|
||||
|
||||
fun <T> baz(): T? = null
|
||||
|
||||
fun <T> foobar(): T = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
|
||||
class A<F> {
|
||||
fun xyz(x: F) {}
|
||||
|
||||
fun foo(): F {
|
||||
val x1: F = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
val x2: F? = null
|
||||
|
||||
xyz(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
bar<F?>(null)
|
||||
|
||||
return <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
}
|
||||
|
||||
fun baz(): F? = null
|
||||
|
||||
fun foobar(): F = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
fun <E> bar(x: E) {}
|
||||
|
||||
+1
-1
@@ -9,6 +9,6 @@ interface Tr<T> {
|
||||
fun test(t: Tr<*>) {
|
||||
t.v = null!!
|
||||
t.v = ""
|
||||
t.v = null
|
||||
t.v = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
t.v checkType { _<Any?>() }
|
||||
}
|
||||
@@ -8,7 +8,7 @@ fun <T> bar(a: T, b: Map<T, String>) = b.get(a)
|
||||
|
||||
fun test(a: Int) {
|
||||
foo(a, null)
|
||||
bar(a, <!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
bar(a, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
}
|
||||
fun test1(a: Int) {
|
||||
foo(a, throw Exception())
|
||||
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
public class A {}
|
||||
|
||||
// FILE: X.java
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class X<T> {
|
||||
@NotNull T fooN() {return null;}
|
||||
void barN(@NotNull T a) {}
|
||||
}
|
||||
|
||||
// FILE: Y.java
|
||||
public class Y extends X<String> {
|
||||
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun main() {
|
||||
checkSubtype<Any>(Y().fooN())
|
||||
Y().barN(<!ARGUMENT_TYPE_MISMATCH!>null<!>);
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
public class A {}
|
||||
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
public class A {}
|
||||
|
||||
// FILE: X.java
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class X<T> {
|
||||
@NotNull T fooN() {return null;}
|
||||
void barN(@NotNull T a) {}
|
||||
}
|
||||
|
||||
// FILE: Y.java
|
||||
public class Y extends X<A> {
|
||||
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun main() {
|
||||
checkSubtype<Any>(Y().fooN())
|
||||
Y().barN(<!ARGUMENT_TYPE_MISMATCH!>null<!>);
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
public class A {}
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ public class SpecializedMap extends AbstractSpecializedMap {
|
||||
// FILE: main.kt
|
||||
fun foo(x: SpecializedMap) {
|
||||
x.containsKey(1)
|
||||
x.containsKey(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
x.containsKey(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
x.<!OVERLOAD_RESOLUTION_AMBIGUITY!>get<!>(2)
|
||||
x.<!NONE_APPLICABLE!>get<!>(null)
|
||||
|
||||
@@ -20,5 +20,5 @@ class In<in F> {
|
||||
|
||||
fun test() {
|
||||
A.foo().x() checkType { _<Any?>() }
|
||||
A.bar().y(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
A.bar().y(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// FILE: p/J.java
|
||||
|
||||
package p;
|
||||
|
||||
public class J {
|
||||
public void _int(int s) {}
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
import p.*
|
||||
|
||||
fun test() {
|
||||
J()._int(1)
|
||||
J()._int(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: p/J.java
|
||||
|
||||
package p;
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// FILE: A.java
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class A<T> {
|
||||
public static A<String> create() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void bar(@NotNull T x) {
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
A.create().bar(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
A.create().bar("")
|
||||
|
||||
A<String>().bar(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
A<String?>().bar(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
A<String?>().bar("")
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: A.java
|
||||
|
||||
import java.util.*;
|
||||
|
||||
+3
-3
@@ -33,9 +33,9 @@ class C2 : A<String?>() {
|
||||
}
|
||||
|
||||
fun test() {
|
||||
B1().bar(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
B2().bar(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
B1().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
B2().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
C1().bar(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
C1().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -22,6 +22,6 @@ val doubleList: List<Double?> = null!!
|
||||
|
||||
fun main() {
|
||||
Test.rawField.foo("", <!ARGUMENT_TYPE_MISMATCH!>doubleList<!>)
|
||||
Test.rawField.foo(<!ARGUMENT_TYPE_MISMATCH!>null<!>, <!ARGUMENT_TYPE_MISMATCH!>doubleList<!>)
|
||||
Test.DerivedRawA().foo(<!ARGUMENT_TYPE_MISMATCH!>null<!>, <!ARGUMENT_TYPE_MISMATCH!>doubleList<!>)
|
||||
Test.rawField.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!ARGUMENT_TYPE_MISMATCH!>doubleList<!>)
|
||||
Test.DerivedRawA().foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!ARGUMENT_TYPE_MISMATCH!>doubleList<!>)
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ interface B: A {
|
||||
fun test(a: A) {
|
||||
if (a is B && a is C) {
|
||||
a.foo = ""
|
||||
a.foo = null
|
||||
a.foo = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
|
||||
a.foo.checkType { _<String>() }
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -23,8 +23,8 @@ fun foo(k: KotlinClass) {
|
||||
|
||||
k.setSomething4("")
|
||||
k.something4 += ""
|
||||
k.setSomething4(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
k.something4 = null
|
||||
k.setSomething4(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
k.something4 = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
|
||||
useString(k.getSomething5())
|
||||
useString(k.something5)
|
||||
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// FILE: KotlinFile.kt
|
||||
fun foo(javaInterface: JavaInterface) {
|
||||
javaInterface.doIt(<!ARGUMENT_TYPE_MISMATCH!>null<!>) { }
|
||||
javaInterface.doIt("", <!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
}
|
||||
|
||||
// FILE: JavaInterface.java
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
public interface JavaInterface {
|
||||
void doIt(@NotNull String s, @NotNull Runnable runnable);
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !WITH_NEW_INFERENCE
|
||||
// FILE: KotlinFile.kt
|
||||
fun foo(javaInterface: JavaInterface) {
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ abstract class MyIt7 : Iterator<String> {
|
||||
|
||||
|
||||
fun foo(x: Iterator<String>, y: Iterator<String?>) {
|
||||
x.forEachRemaining(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
x.forEachRemaining(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
x.forEachRemaining { it -> it.length }
|
||||
x.forEachRemaining { it -> it?.length }
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class KotlinMap2 : java.util.AbstractMap<String, Int>() {
|
||||
fun foo(x: MutableMap<String, Int>, y: java.util.HashMap<String, Int>, z: java.util.AbstractMap<String, Int>) {
|
||||
x.remove("", 1)
|
||||
x.remove("", <!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
x.remove("", <!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
x.remove("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
y.remove("", 1)
|
||||
y.remove("", <!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
|
||||
Vendored
+1
-1
@@ -21,7 +21,7 @@ class Pair<X, Y>(val x: X, val y: Y)
|
||||
typealias PL<T> = Pair<T, List<T>>
|
||||
typealias PN<T> = Pair<T, Num<T>>
|
||||
|
||||
val test5 = PL(1, <!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
val test5 = PL(1, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
|
||||
class Foo<T>(val p: Pair<T, T>)
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// NI_EXPECTED_FILE
|
||||
|
||||
object ObjectWithInvoke {
|
||||
operator fun invoke() = this
|
||||
}
|
||||
|
||||
class ClassWithCompanionObjectWithInvoke {
|
||||
companion object {
|
||||
operator fun invoke(x: Any) = x
|
||||
}
|
||||
}
|
||||
|
||||
typealias WI = ObjectWithInvoke
|
||||
|
||||
typealias CWI = ClassWithCompanionObjectWithInvoke
|
||||
|
||||
val test1 = WI()
|
||||
val test2 = WI(<!TOO_MANY_ARGUMENTS!>null<!>)
|
||||
|
||||
val test3 = CWI()
|
||||
val test4 = CWI("")
|
||||
val test5 = CWI(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
val test5a = ClassWithCompanionObjectWithInvoke(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !WITH_NEW_INFERENCE
|
||||
// NI_EXPECTED_FILE
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
fun <E> myBuildList(@BuilderInference builderAction: MutableList<E>.() -> Unit) {
|
||||
ArrayList<E>().builderAction()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun main() {
|
||||
val newList1 = myBuildList {
|
||||
addAll(
|
||||
listOf(1).map { Foo(<!ARGUMENT_TYPE_MISMATCH!>null<!>) }
|
||||
)
|
||||
}
|
||||
|
||||
val newList2 = buildList {
|
||||
addAll(listOf(1,2,3).map{ Foo(<!ARGUMENT_TYPE_MISMATCH!>null<!>) })
|
||||
}
|
||||
}
|
||||
|
||||
class Foo(val notNullProp: String)
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
|
||||
@@ -7,4 +7,4 @@ fun foo(c : Collection<String>) = {
|
||||
}
|
||||
|
||||
fun bar() : String? = null
|
||||
fun zoo(s : String) : Boolean = true
|
||||
fun zoo(s : String) : Boolean = true
|
||||
|
||||
Vendored
+8
-8
@@ -4,44 +4,44 @@
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1() {
|
||||
val x: Int = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
val x: Int = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 2
|
||||
fun case_2() {
|
||||
val x: Any = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
val x: Any = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 3
|
||||
fun case_3() {
|
||||
val x: Nothing = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
val x: Nothing = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 4
|
||||
fun case_4() {
|
||||
var x: Int = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
var x: Int = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 5
|
||||
fun case_5() {
|
||||
var x: Any = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
var x: Any = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 6
|
||||
fun case_6() {
|
||||
var x: Nothing = <!INITIALIZER_TYPE_MISMATCH!>null<!>
|
||||
var x: Nothing = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 7
|
||||
fun case_7() {
|
||||
val x: Int
|
||||
x = null
|
||||
x = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 8
|
||||
fun case_8() {
|
||||
var x: Int = 10
|
||||
x = null
|
||||
x = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
|
||||
Vendored
+4
-4
@@ -43,7 +43,7 @@ class Case8 {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(): Any = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||
fun case_9(): Any = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
|
||||
// TESTCASE NUMBER: 10
|
||||
fun case_10(x: Int, y: Boolean): Any = <!RETURN_TYPE_MISMATCH!>if (y) x else null<!>
|
||||
@@ -57,10 +57,10 @@ class Case12 {
|
||||
var y: Any
|
||||
var z: Any
|
||||
init {
|
||||
x = null
|
||||
y = null
|
||||
x = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
y = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
z = 10
|
||||
z = null
|
||||
z = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import kotlin.contracts.*
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(): Boolean? {
|
||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returnsNotNull() implies (<!ARGUMENT_TYPE_MISMATCH!>null<!>)<!> }
|
||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returnsNotNull() implies (<!NULL_FOR_NONNULL_TYPE!>null<!>)<!> }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -739,6 +739,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NULL_FOR_NONNULL_TYPE) { firDiagnostic ->
|
||||
NullForNonnullTypeImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INAPPLICABLE_LATEINIT_MODIFIER) { firDiagnostic ->
|
||||
InapplicableLateinitModifierImpl(
|
||||
firDiagnostic.a,
|
||||
|
||||
+4
@@ -532,6 +532,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val actualType: KtType
|
||||
}
|
||||
|
||||
abstract class NullForNonnullType : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = NullForNonnullType::class
|
||||
}
|
||||
|
||||
abstract class InapplicableLateinitModifier : KtFirDiagnostic<KtModifierListOwner>() {
|
||||
override val diagnosticClass get() = InapplicableLateinitModifier::class
|
||||
abstract val reason: String
|
||||
|
||||
+7
@@ -851,6 +851,13 @@ internal class ArgumentTypeMismatchImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NullForNonnullTypeImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NullForNonnullType(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class InapplicableLateinitModifierImpl(
|
||||
override val reason: String,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ fun foo(expr: StringBuilder): Int {
|
||||
|
||||
fun unitShort() : Unit = Unit
|
||||
fun unitShortConv() : Unit = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Unit, actual kotlin/Int">1</error>
|
||||
fun unitShortNull() : Unit = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Unit, actual kotlin/Nothing?">null</error>
|
||||
fun unitShortNull() : Unit = <error descr="[NULL_FOR_NONNULL_TYPE] ">null</error>
|
||||
|
||||
fun intEmpty() : Int {}
|
||||
fun intShortInfer() = 1
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ package test
|
||||
|
||||
annotation class A(val value: String)
|
||||
|
||||
@A(<error descr="[ARGUMENT_TYPE_MISMATCH] Argument type mismatch: actual type is kotlin/Nothing? but kotlin/String was expected">null</error>)
|
||||
@A(<error descr="[NULL_FOR_NONNULL_TYPE] ">null</error>)
|
||||
fun foo() {}
|
||||
|
||||
@A(<error descr="[ARGUMENT_TYPE_MISMATCH] Argument type mismatch: actual type is kotlin/Nothing? but kotlin/String was expected">null</error>)
|
||||
@A(<error descr="[NULL_FOR_NONNULL_TYPE] ">null</error>)
|
||||
class B
|
||||
|
||||
Reference in New Issue
Block a user