[NI] Add checking @NotNull parameters for candidates
This commit is contained in:
+4
@@ -40,6 +40,10 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
|
|||||||
return StandardClassIds.Nothing(symbolProvider).constructType(emptyArray(), false)
|
return StandardClassIds.Nothing(symbolProvider).constructType(emptyArray(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun anyType(): SimpleTypeMarker {
|
||||||
|
return StandardClassIds.Any(symbolProvider).constructType(emptyArray(), false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
|
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
|
||||||
require(lowerBound is ConeKotlinType)
|
require(lowerBound is ConeKotlinType)
|
||||||
require(upperBound is ConeKotlinType)
|
require(upperBound is ConeKotlinType)
|
||||||
|
|||||||
+1
-1
@@ -135,7 +135,7 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
require(diagnostic is ArgumentTypeMismatchDiagnostic)
|
require(diagnostic is ArgumentTypeMismatchDiagnostic)
|
||||||
reportIfNonNull(callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()) {
|
reportIfNonNull(callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()) {
|
||||||
if (it.isNull()) {
|
if (it.isNull()) {
|
||||||
trace.report(NULL_FOR_NONNULL_TYPE.on(it, diagnostic.expectedType))
|
trace.reportDiagnosticOnce(NULL_FOR_NONNULL_TYPE.on(it, diagnostic.expectedType))
|
||||||
} else {
|
} else {
|
||||||
trace.report(TYPE_MISMATCH.on(it, diagnostic.expectedType, diagnostic.actualType))
|
trace.report(TYPE_MISMATCH.on(it, diagnostic.expectedType, diagnostic.actualType))
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosi
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ReceiverConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ReceiverConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.types.NotNullTypeVariable
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.checker.captureFromExpression
|
import org.jetbrains.kotlin.types.checker.captureFromExpression
|
||||||
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
|
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
|
||||||
@@ -81,6 +82,12 @@ private fun checkExpressionArgument(
|
|||||||
|
|
||||||
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
|
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
|
||||||
val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument)
|
val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument)
|
||||||
|
|
||||||
|
// Used only for arguments with @NotNull annotation
|
||||||
|
if (expectedType is NotNullTypeVariable && argumentType.isMarkedNullable) {
|
||||||
|
diagnosticsHolder.addDiagnostic(ArgumentTypeMismatchDiagnostic(expectedType, argumentType, expressionArgument))
|
||||||
|
}
|
||||||
|
|
||||||
if (expressionArgument.isSafeCall) {
|
if (expressionArgument.isSafeCall) {
|
||||||
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
|
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
|
||||||
diagnosticsHolder.addDiagnosticIfNotNull(
|
diagnosticsHolder.addDiagnosticIfNotNull(
|
||||||
|
|||||||
+1
-2
@@ -5,6 +5,5 @@ interface A<T : A<T?>?> {
|
|||||||
fun foo(): T?
|
fun foo(): T?
|
||||||
}
|
}
|
||||||
fun testA(a: A<*>) {
|
fun testA(a: A<*>) {
|
||||||
// in new inference here we have A<A<A<*>>>
|
a.foo() checkType { _<A<*>?>() }
|
||||||
a.foo() checkType { <!NI;DEBUG_INFO_UNRESOLVED_WITH_TARGET, NI;UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><A<*>?>() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ public interface J2 extends J {
|
|||||||
fun main() {
|
fun main() {
|
||||||
J <!NI;TYPE_MISMATCH!>{ <!EXPECTED_PARAMETER_TYPE_MISMATCH!>s: String<!> -> s}<!> // should be prohibited, because SAM value parameter has nullable type
|
J <!NI;TYPE_MISMATCH!>{ <!EXPECTED_PARAMETER_TYPE_MISMATCH!>s: String<!> -> s}<!> // should be prohibited, because SAM value parameter has nullable type
|
||||||
J { "" + it<!UNSAFE_CALL!>.<!>length }
|
J { "" + it<!UNSAFE_CALL!>.<!>length }
|
||||||
J { <!NI;NULL_FOR_NONNULL_TYPE, NULL_FOR_NONNULL_TYPE!>null<!> }
|
J { <!NULL_FOR_NONNULL_TYPE!>null<!> }
|
||||||
J { <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>it?.length?.toString()<!> }
|
J { <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>it?.length?.toString()<!> }
|
||||||
|
|
||||||
J2 <!NI;TYPE_MISMATCH!>{ <!EXPECTED_PARAMETER_TYPE_MISMATCH!>s: String<!> -> s}<!>
|
J2 <!NI;TYPE_MISMATCH!>{ <!EXPECTED_PARAMETER_TYPE_MISMATCH!>s: String<!> -> s}<!>
|
||||||
J2 { "" + it<!UNSAFE_CALL!>.<!>length }
|
J2 { "" + it<!UNSAFE_CALL!>.<!>length }
|
||||||
J2 { <!NI;NULL_FOR_NONNULL_TYPE, NULL_FOR_NONNULL_TYPE!>null<!> }
|
J2 { <!NULL_FOR_NONNULL_TYPE!>null<!> }
|
||||||
J2 { <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>it?.length?.toString()<!> }
|
J2 { <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>it?.length?.toString()<!> }
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+7
-5
@@ -11,13 +11,15 @@ public class A {
|
|||||||
// FILE: k.kt
|
// FILE: k.kt
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!OI;NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||||
|
|
||||||
A.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
A.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||||
A.bar<String?>(<!OI;NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
A.bar<String?>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||||
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!OI;NULL_FOR_NONNULL_TYPE!>null<!>, A.platformString())
|
A.bar<String?>("", "")
|
||||||
|
|
||||||
|
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!NULL_FOR_NONNULL_TYPE!>null<!>, A.platformString())
|
||||||
|
|
||||||
val x: String? = null
|
val x: String? = null
|
||||||
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!OI;TYPE_MISMATCH!>x<!>, "")
|
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!TYPE_MISMATCH!>x<!>, "")
|
||||||
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!OI;NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
A.<!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
// !LANGUAGE: +NewInference
|
||||||
|
|
||||||
|
// FILE: SmartFMap.java
|
||||||
|
|
||||||
|
public class SmartFMap<K, V> implements java.util.Map<K, V> {
|
||||||
|
public static < K, V> SmartFMap<K, V> emptyMap() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmartFMap < K, V> plus(@org.jetbrains.annotations.NotNull K key, V value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
class KotlinType
|
||||||
|
|
||||||
|
interface TypePredicate : (KotlinType) -> Boolean {
|
||||||
|
override fun invoke(typeToCheck: KotlinType): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any?> TypePredicate.expectedTypeFor(keys: Iterable<T>): Map<T, TypePredicate> =
|
||||||
|
keys.fold(SmartFMap.emptyMap<T, TypePredicate>()) { map, key ->
|
||||||
|
map.plus(key, this)
|
||||||
|
}
|
||||||
Vendored
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ T> TypePredicate.expectedTypeFor(/*0*/ keys: kotlin.collections.Iterable<T>): kotlin.collections.Map<T, TypePredicate>
|
||||||
|
|
||||||
|
public final class KotlinType {
|
||||||
|
public constructor KotlinType()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class SmartFMap</*0*/ K : kotlin.Any!, /*1*/ V : kotlin.Any!> : kotlin.collections.MutableMap<K!, V!> {
|
||||||
|
public constructor SmartFMap</*0*/ K : kotlin.Any!, /*1*/ V : kotlin.Any!>()
|
||||||
|
public abstract override /*1*/ /*fake_override*/ val entries: kotlin.collections.MutableSet<kotlin.collections.MutableMap.MutableEntry<K!, V!>>
|
||||||
|
public abstract override /*1*/ /*fake_override*/ val keys: kotlin.collections.MutableSet<K!>
|
||||||
|
public abstract override /*1*/ /*fake_override*/ val size: kotlin.Int
|
||||||
|
public abstract override /*1*/ /*fake_override*/ val values: kotlin.collections.MutableCollection<V!>
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun clear(): kotlin.Unit
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun containsKey(/*0*/ key: K!): kotlin.Boolean
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: V!): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: K!): V?
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
|
||||||
|
public open fun plus(/*0*/ @org.jetbrains.annotations.NotNull key: K, /*1*/ value: V!): SmartFMap<K!, V!>!
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun put(/*0*/ key: K!, /*1*/ value: V!): V?
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun putAll(/*0*/ from: kotlin.collections.Map<out K!, V!>): kotlin.Unit
|
||||||
|
public abstract override /*1*/ /*fake_override*/ fun remove(/*0*/ key: K!): V?
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public open fun </*0*/ K : kotlin.Any!, /*1*/ V : kotlin.Any!> emptyMap(): SmartFMap<K!, V!>!
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TypePredicate : (KotlinType) -> kotlin.Boolean {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public abstract override /*1*/ fun invoke(/*0*/ typeToCheck: KotlinType): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+5
@@ -2753,6 +2753,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAnnotation.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAnnotation.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("notNullAnnotation.kt")
|
||||||
|
public void testNotNullAnnotation() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("onlyInputTypesAndLowPriority.kt")
|
@TestMetadata("onlyInputTypesAndLowPriority.kt")
|
||||||
public void testOnlyInputTypesAndLowPriority() throws Exception {
|
public void testOnlyInputTypesAndLowPriority() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesAndLowPriority.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesAndLowPriority.kt");
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+5
@@ -2753,6 +2753,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAnnotation.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAnnotation.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("notNullAnnotation.kt")
|
||||||
|
public void testNotNullAnnotation() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("onlyInputTypesAndLowPriority.kt")
|
@TestMetadata("onlyInputTypesAndLowPriority.kt")
|
||||||
public void testOnlyInputTypesAndLowPriority() throws Exception {
|
public void testOnlyInputTypesAndLowPriority() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesAndLowPriority.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesAndLowPriority.kt");
|
||||||
|
|||||||
+1
-1
@@ -215,7 +215,7 @@ private object EnhancedTypeAnnotationDescriptor : AnnotationDescriptor {
|
|||||||
override fun toString() = "[EnhancedType]"
|
override fun toString() = "[EnhancedType]"
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NotNullTypeParameter(override val delegate: SimpleType) : CustomTypeVariable, DelegatingSimpleType() {
|
internal class NotNullTypeParameter(override val delegate: SimpleType) : NotNullTypeVariable, DelegatingSimpleType() {
|
||||||
|
|
||||||
override val isTypeVariable: Boolean
|
override val isTypeVariable: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ interface CustomTypeVariable {
|
|||||||
fun substitutionResult(replacement: KotlinType): KotlinType
|
fun substitutionResult(replacement: KotlinType): KotlinType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// That interface is needed to provide information about definitely not null
|
||||||
|
// type parameters (e.g. from @NotNull annotation) to type system
|
||||||
|
interface NotNullTypeVariable : CustomTypeVariable
|
||||||
|
|
||||||
fun KotlinType.isCustomTypeVariable(): Boolean = (unwrap() as? CustomTypeVariable)?.isTypeVariable ?: false
|
fun KotlinType.isCustomTypeVariable(): Boolean = (unwrap() as? CustomTypeVariable)?.isTypeVariable ?: false
|
||||||
fun KotlinType.getCustomTypeVariable(): CustomTypeVariable? =
|
fun KotlinType.getCustomTypeVariable(): CustomTypeVariable? =
|
||||||
(unwrap() as? CustomTypeVariable)?.let {
|
(unwrap() as? CustomTypeVariable)?.let {
|
||||||
|
|||||||
@@ -333,6 +333,10 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
|
|||||||
return builtIns.nothingType
|
return builtIns.nothingType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun anyType(): SimpleTypeMarker {
|
||||||
|
return builtIns.anyType
|
||||||
|
}
|
||||||
|
|
||||||
val builtIns: KotlinBuiltIns get() = throw UnsupportedOperationException("Not supported")
|
val builtIns: KotlinBuiltIns get() = throw UnsupportedOperationException("Not supported")
|
||||||
|
|
||||||
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
|
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ interface TypeSystemBuiltInsContext {
|
|||||||
fun nullableNothingType(): SimpleTypeMarker
|
fun nullableNothingType(): SimpleTypeMarker
|
||||||
fun nullableAnyType(): SimpleTypeMarker
|
fun nullableAnyType(): SimpleTypeMarker
|
||||||
fun nothingType(): SimpleTypeMarker
|
fun nothingType(): SimpleTypeMarker
|
||||||
|
fun anyType(): SimpleTypeMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TypeSystemTypeFactoryContext {
|
interface TypeSystemTypeFactoryContext {
|
||||||
|
|||||||
Reference in New Issue
Block a user