FIR: use frontend-independent Java type qualifier computation
This commit is contained in:
-148
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.java.enhancement
|
||||
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaTypeConversionMode
|
||||
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
||||
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.load.java.AnnotationQualifierApplicabilityType
|
||||
import org.jetbrains.kotlin.load.java.JavaDefaultQualifiers
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.*
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal class EnhancementSignatureParts(
|
||||
private val typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
private val typeContainer: FirAnnotationContainer?,
|
||||
private val javaTypeParameterStack: JavaTypeParameterStack,
|
||||
private val current: FirJavaTypeRef,
|
||||
private val fromOverridden: Collection<FirTypeRef>,
|
||||
private val isCovariant: Boolean,
|
||||
private val context: FirJavaEnhancementContext,
|
||||
private val containerApplicabilityType: AnnotationQualifierApplicabilityType
|
||||
) {
|
||||
private val isForVarargParameter get() = typeContainer.safeAs<FirValueParameter>()?.isVararg == true
|
||||
|
||||
private fun ConeKotlinType.toFqNameUnsafe(): FqNameUnsafe? =
|
||||
((this as? ConeLookupTagBasedType)?.lookupTag as? ConeClassLikeLookupTag)?.classId?.asSingleFqName()?.toUnsafe()
|
||||
|
||||
internal fun enhance(
|
||||
session: FirSession,
|
||||
predefined: TypeEnhancementInfo? = null,
|
||||
forAnnotationMember: Boolean = false
|
||||
): FirResolvedTypeRef {
|
||||
val mode = if (forAnnotationMember) FirJavaTypeConversionMode.ANNOTATION_MEMBER else FirJavaTypeConversionMode.DEFAULT
|
||||
val typeWithoutEnhancement = current.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack, mode)
|
||||
val qualifiers = computeIndexedQualifiersForOverride(typeWithoutEnhancement, predefined)
|
||||
return buildResolvedTypeRef {
|
||||
type = typeWithoutEnhancement.enhance(session, qualifiers) ?: typeWithoutEnhancement
|
||||
annotations += current.annotations
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType?.toIndexed(context: FirJavaEnhancementContext): List<TypeAndDefaultQualifiers> {
|
||||
val list = ArrayList<TypeAndDefaultQualifiers>(1)
|
||||
|
||||
fun add(type: ConeKotlinType?) {
|
||||
// TODO: should use the context from parent type
|
||||
val annotations = type?.attributes?.customAnnotations.orEmpty()
|
||||
val c = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, annotations)
|
||||
list.add(TypeAndDefaultQualifiers(type, c.defaultTypeQualifiers?.get(AnnotationQualifierApplicabilityType.TYPE_USE)))
|
||||
type?.typeArguments?.forEach { add(it.type) }
|
||||
}
|
||||
|
||||
add(this)
|
||||
return list
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.extractQualifiers(): JavaTypeQualifiers {
|
||||
val lower = lowerBoundIfFlexible()
|
||||
val upper = upperBoundIfFlexible()
|
||||
val mapping = JavaToKotlinClassMap
|
||||
return JavaTypeQualifiers(
|
||||
when {
|
||||
lower.isMarkedNullable -> NullabilityQualifier.NULLABLE
|
||||
!upper.isMarkedNullable -> NullabilityQualifier.NOT_NULL
|
||||
else -> null
|
||||
},
|
||||
when {
|
||||
mapping.isReadOnly(lower.toFqNameUnsafe()) -> MutabilityQualifier.READ_ONLY
|
||||
mapping.isMutable(upper.toFqNameUnsafe()) -> MutabilityQualifier.MUTABLE
|
||||
else -> null
|
||||
},
|
||||
isNotNullTypeParameter = lower is ConeDefinitelyNotNullType
|
||||
)
|
||||
}
|
||||
|
||||
private fun composeAnnotations(first: List<FirAnnotationCall>, second: List<FirAnnotationCall>): List<FirAnnotationCall> {
|
||||
return when {
|
||||
first.isEmpty() -> second
|
||||
second.isEmpty() -> first
|
||||
else -> first + second
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypeAndDefaultQualifiers.extractQualifiersFromAnnotations(isHeadTypeConstructor: Boolean): JavaTypeQualifiers {
|
||||
val annotations = type?.attributes?.customAnnotations.orEmpty()
|
||||
val composedAnnotations =
|
||||
if (isHeadTypeConstructor && typeContainer != null)
|
||||
composeAnnotations(typeContainer.annotations, annotations)
|
||||
else
|
||||
annotations
|
||||
|
||||
val defaultTypeQualifier =
|
||||
if (isHeadTypeConstructor)
|
||||
context.defaultTypeQualifiers?.get(containerApplicabilityType)
|
||||
else
|
||||
defaultQualifiers
|
||||
|
||||
val nullabilityInfo = typeQualifierResolver.extractNullability(composedAnnotations)
|
||||
?: defaultTypeQualifier?.nullabilityQualifier
|
||||
|
||||
return JavaTypeQualifiers(
|
||||
nullabilityInfo?.qualifier,
|
||||
typeQualifierResolver.extractMutability(composedAnnotations),
|
||||
isNotNullTypeParameter = nullabilityInfo?.qualifier == NullabilityQualifier.NOT_NULL &&
|
||||
type?.lowerBoundIfFlexible() is ConeTypeParameterType,
|
||||
isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true
|
||||
)
|
||||
}
|
||||
|
||||
private fun computeIndexedQualifiersForOverride(current: ConeKotlinType?, predefined: TypeEnhancementInfo?): IndexedJavaTypeQualifiers {
|
||||
val indexedFromSupertypes =
|
||||
fromOverridden.map { it.toConeKotlinTypeProbablyFlexible(context.session, javaTypeParameterStack).toIndexed(context) }
|
||||
val indexedThisType = current.toIndexed(context)
|
||||
|
||||
// The covariant case may be hard, e.g. in the superclass the return may be Super<T>, but in the subclass it may be Derived, which
|
||||
// is declared to extend Super<T>, and propagating data here is highly non-trivial, so we only look at the head type constructor
|
||||
// (outermost type), unless the type in the subclass is interchangeable with the all the types in superclasses:
|
||||
// e.g. we have (Mutable)List<String!>! in the subclass and { List<String!>, (Mutable)List<String>! } from superclasses
|
||||
// Note that `this` is flexible here, so it's equal to it's bounds
|
||||
val onlyHeadTypeConstructor = isCovariant && fromOverridden.any { true /*equalTypes(it, this)*/ }
|
||||
|
||||
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
||||
val computedResult = Array(treeSize) { index ->
|
||||
val qualifiers = indexedThisType[index].extractQualifiersFromAnnotations(index == 0)
|
||||
val superQualifiers = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type?.extractQualifiers() }
|
||||
qualifiers.computeQualifiersForOverride(superQualifiers, index == 0 && isCovariant, index == 0 && isForVarargParameter)
|
||||
}
|
||||
return { index -> predefined?.map?.get(index) ?: computedResult.getOrNull(index) ?: JavaTypeQualifiers.NONE }
|
||||
}
|
||||
|
||||
private data class TypeAndDefaultQualifiers(
|
||||
val type: ConeKotlinType?, // null denotes '*' here
|
||||
val defaultQualifiers: JavaDefaultQualifiers?
|
||||
)
|
||||
}
|
||||
+95
-37
@@ -21,13 +21,17 @@ import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaTypeConversionMode
|
||||
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.load.java.AnnotationQualifierApplicabilityType
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.*
|
||||
@@ -35,6 +39,12 @@ import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.load.java.JavaTypeEnhancementState
|
||||
import org.jetbrains.kotlin.load.java.JavaTypeQualifiersByElementType
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemContext
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class FirSignatureEnhancement(
|
||||
@@ -170,7 +180,7 @@ class FirSignatureEnhancement(
|
||||
}
|
||||
return enhanceMethod(firMethod, original.callableId, name)
|
||||
}
|
||||
|
||||
|
||||
private fun enhanceMethod(
|
||||
firMethod: FirFunction,
|
||||
methodId: CallableId,
|
||||
@@ -309,14 +319,16 @@ class FirSignatureEnhancement(
|
||||
overriddenMembers: List<FirCallableDeclaration>,
|
||||
memberContext: FirJavaEnhancementContext
|
||||
): FirResolvedTypeRef {
|
||||
return ownerFunction.partsForValueParameter(
|
||||
return ownerFunction.enhanceValueParameter(
|
||||
typeQualifierResolver,
|
||||
overriddenMembers,
|
||||
// TODO: check me
|
||||
parameterContainer = ownerFunction,
|
||||
methodContext = memberContext,
|
||||
typeInSignature = TypeInSignature.Receiver
|
||||
).enhance(session)
|
||||
typeInSignature = TypeInSignature.Receiver,
|
||||
predefined = null,
|
||||
forAnnotationMember = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun enhanceValueParameterType(
|
||||
@@ -331,15 +343,13 @@ class FirSignatureEnhancement(
|
||||
if (ownerParameter.returnTypeRef is FirResolvedTypeRef) {
|
||||
return ownerParameter.returnTypeRef as FirResolvedTypeRef
|
||||
}
|
||||
return ownerFunction.partsForValueParameter(
|
||||
return ownerFunction.enhanceValueParameter(
|
||||
typeQualifierResolver,
|
||||
overriddenMembers,
|
||||
parameterContainer = ownerParameter,
|
||||
methodContext = memberContext,
|
||||
typeInSignature = TypeInSignature.ValueParameter(hasReceiver, index)
|
||||
).enhance(
|
||||
session,
|
||||
predefinedEnhancementInfo?.parametersInfo?.getOrNull(index),
|
||||
typeInSignature = TypeInSignature.ValueParameter(hasReceiver, index),
|
||||
predefined = predefinedEnhancementInfo?.parametersInfo?.getOrNull(index),
|
||||
forAnnotationMember = owner.classKind == ClassKind.ANNOTATION_CLASS
|
||||
)
|
||||
}
|
||||
@@ -350,7 +360,7 @@ class FirSignatureEnhancement(
|
||||
memberContext: FirJavaEnhancementContext,
|
||||
predefinedEnhancementInfo: PredefinedFunctionEnhancementInfo?
|
||||
): FirResolvedTypeRef {
|
||||
return owner.parts(
|
||||
return owner.enhance(
|
||||
typeQualifierResolver,
|
||||
overriddenMembers,
|
||||
typeContainer = owner, isCovariant = true,
|
||||
@@ -358,9 +368,9 @@ class FirSignatureEnhancement(
|
||||
containerApplicabilityType =
|
||||
if (owner is FirJavaField) AnnotationQualifierApplicabilityType.FIELD
|
||||
else AnnotationQualifierApplicabilityType.METHOD_RETURN_TYPE,
|
||||
typeInSignature = TypeInSignature.Return
|
||||
).enhance(
|
||||
session, predefinedEnhancementInfo?.returnTypeInfo, forAnnotationMember = this.owner.classKind == ClassKind.ANNOTATION_CLASS
|
||||
typeInSignature = TypeInSignature.Return,
|
||||
predefined = predefinedEnhancementInfo?.returnTypeInfo,
|
||||
forAnnotationMember = this.owner.classKind == ClassKind.ANNOTATION_CLASS
|
||||
)
|
||||
}
|
||||
|
||||
@@ -388,14 +398,16 @@ class FirSignatureEnhancement(
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirFunction.partsForValueParameter(
|
||||
private fun FirFunction.enhanceValueParameter(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
overriddenMembers: List<FirCallableDeclaration>,
|
||||
// TODO: investigate if it's really can be a null (check properties' with extension overrides in Java)
|
||||
parameterContainer: FirAnnotationContainer?,
|
||||
methodContext: FirJavaEnhancementContext,
|
||||
typeInSignature: TypeInSignature
|
||||
): EnhancementSignatureParts = (this as FirCallableDeclaration).parts(
|
||||
typeInSignature: TypeInSignature,
|
||||
predefined: TypeEnhancementInfo?,
|
||||
forAnnotationMember: Boolean
|
||||
): FirResolvedTypeRef = (this as FirCallableDeclaration).enhance(
|
||||
typeQualifierResolver,
|
||||
overriddenMembers,
|
||||
parameterContainer, false,
|
||||
@@ -403,33 +415,79 @@ class FirSignatureEnhancement(
|
||||
methodContext.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, it.annotations)
|
||||
} ?: methodContext,
|
||||
AnnotationQualifierApplicabilityType.VALUE_PARAMETER,
|
||||
typeInSignature
|
||||
typeInSignature,
|
||||
predefined,
|
||||
forAnnotationMember
|
||||
)
|
||||
|
||||
private fun FirCallableDeclaration.parts(
|
||||
private fun FirCallableDeclaration.enhance(
|
||||
typeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
overriddenMembers: List<FirCallableDeclaration>,
|
||||
typeContainer: FirAnnotationContainer?,
|
||||
isCovariant: Boolean,
|
||||
containerContext: FirJavaEnhancementContext,
|
||||
containerApplicabilityType: AnnotationQualifierApplicabilityType,
|
||||
typeInSignature: TypeInSignature
|
||||
): EnhancementSignatureParts {
|
||||
val typeRef = typeInSignature.getTypeRef(this)
|
||||
return EnhancementSignatureParts(
|
||||
typeQualifierResolver,
|
||||
typeContainer,
|
||||
javaTypeParameterStack,
|
||||
typeRef as FirJavaTypeRef,
|
||||
overriddenMembers.map {
|
||||
typeInSignature.getTypeRef(it)
|
||||
},
|
||||
isCovariant,
|
||||
// recompute default type qualifiers using type annotations
|
||||
containerContext.copyWithNewDefaultTypeQualifiers(
|
||||
typeQualifierResolver, typeRef.annotations
|
||||
),
|
||||
containerApplicabilityType
|
||||
typeInSignature: TypeInSignature,
|
||||
predefined: TypeEnhancementInfo?,
|
||||
forAnnotationMember: Boolean
|
||||
): FirResolvedTypeRef {
|
||||
val parts = EnhancementSignatureParts(
|
||||
session, typeQualifierResolver, typeContainer, isCovariant,
|
||||
containerApplicabilityType, containerContext.defaultTypeQualifiers
|
||||
)
|
||||
val typeRef = typeInSignature.getTypeRef(this)
|
||||
val mode = if (forAnnotationMember) FirJavaTypeConversionMode.ANNOTATION_MEMBER else FirJavaTypeConversionMode.DEFAULT
|
||||
val typeWithoutEnhancement = typeRef.toConeKotlinType(mode)
|
||||
val typesFromOverridden = overriddenMembers.map { typeInSignature.getTypeRef(it).toConeKotlinType(mode) }
|
||||
val qualifiers = with(parts) { typeWithoutEnhancement.computeIndexedQualifiers(typesFromOverridden, predefined) }
|
||||
return buildResolvedTypeRef {
|
||||
type = typeWithoutEnhancement.enhance(session, qualifiers) ?: typeWithoutEnhancement
|
||||
annotations += typeRef.annotations
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeRef.toConeKotlinType(mode: FirJavaTypeConversionMode): ConeKotlinType =
|
||||
toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack, mode)
|
||||
}
|
||||
|
||||
private class EnhancementSignatureParts(
|
||||
private val session: FirSession,
|
||||
override val annotationTypeQualifierResolver: FirAnnotationTypeQualifierResolver,
|
||||
private val typeContainer: FirAnnotationContainer?,
|
||||
override val isCovariant: Boolean,
|
||||
override val containerApplicabilityType: AnnotationQualifierApplicabilityType,
|
||||
override val containerDefaultTypeQualifiers: JavaTypeQualifiersByElementType?
|
||||
) : AbstractSignatureParts<FirAnnotationCall>() {
|
||||
override val enableImprovementsInStrictMode: Boolean
|
||||
get() = true
|
||||
|
||||
override val skipRawTypeArguments: Boolean
|
||||
get() = false
|
||||
|
||||
override val containerAnnotations: Iterable<FirAnnotationCall>
|
||||
get() = typeContainer?.annotations ?: emptyList()
|
||||
|
||||
override val containerIsVarargParameter: Boolean
|
||||
get() = typeContainer is FirValueParameter && typeContainer.isVararg
|
||||
|
||||
override val typeSystem: TypeSystemContext
|
||||
get() = session.typeContext
|
||||
|
||||
override val FirAnnotationCall.forceWarning: Boolean
|
||||
get() = false // TODO: force warnings on IDEA external annotations
|
||||
|
||||
override val KotlinTypeMarker.annotations: Iterable<FirAnnotationCall>
|
||||
get() = (this as ConeKotlinType).attributes.customAnnotations
|
||||
|
||||
override val KotlinTypeMarker.fqNameUnsafe: FqNameUnsafe?
|
||||
get() = ((this as? ConeLookupTagBasedType)?.lookupTag as? ConeClassLikeLookupTag)?.classId?.asSingleFqName()?.toUnsafe()
|
||||
|
||||
override val KotlinTypeMarker.enhancedForWarnings: KotlinTypeMarker?
|
||||
get() = null // TODO: implement enhancement for warnings
|
||||
|
||||
override fun KotlinTypeMarker.isEqual(other: KotlinTypeMarker): Boolean =
|
||||
AbstractTypeChecker.equalTypes(session.typeContext, this, other)
|
||||
|
||||
override val TypeParameterMarker.isFromJava: Boolean
|
||||
get() = (this as ConeTypeParameterLookupTag).symbol.fir.origin == FirDeclarationOrigin.Java
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.utils.extractRadix
|
||||
|
||||
typealias IndexedJavaTypeQualifiers = (Int) -> JavaTypeQualifiers
|
||||
|
||||
internal fun ConeKotlinType.enhance(session: FirSession, qualifiers: IndexedJavaTypeQualifiers): ConeKotlinType? =
|
||||
enhanceConeKotlinType(session, qualifiers, 0, mutableListOf<Int>().apply { computeSubtreeSizes(this) })
|
||||
|
||||
|
||||
+6
-10
@@ -15,23 +15,19 @@ public class Test {}
|
||||
|
||||
// FILE: main.kt
|
||||
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<Any?>, x: Test): Unit {
|
||||
// jspecify_nullness_mismatch
|
||||
a1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a1.foo(null)
|
||||
a1.foo(1)
|
||||
|
||||
// jspecify_nullness_mismatch
|
||||
a2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a2.foo(null)
|
||||
a2.foo(1)
|
||||
|
||||
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||
a1.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
// jspecify_nullness_mismatch
|
||||
a1.bar(x, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a1.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
|
||||
a1.bar(x, null)
|
||||
a1.bar(x, 1)
|
||||
|
||||
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||
a2.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
// jspecify_nullness_mismatch
|
||||
a2.bar(x, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a2.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
|
||||
a2.bar(x, null)
|
||||
a2.bar(x, 1)
|
||||
}
|
||||
|
||||
compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/strictMode/SelfType.fir.kt
Vendored
+3
-6
@@ -39,15 +39,12 @@ public class CKN extends C<@Nullable CK> {}
|
||||
// FILE: main.kt
|
||||
fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit {
|
||||
ak.foo(ak)
|
||||
// jspecify_nullness_mismatch
|
||||
ak.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
ak.foo(null)
|
||||
|
||||
// jspecify_nullness_mismatch
|
||||
akn.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
akn.foo(null)
|
||||
|
||||
bk.foo(bk)
|
||||
// jspecify_nullness_mismatch
|
||||
bk.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
bk.foo(null)
|
||||
|
||||
ck.foo(ck)
|
||||
ck.foo(null)
|
||||
|
||||
+2
-4
@@ -30,13 +30,11 @@ fun <T : Test> main(a1: A<Any?>, a2: A<Test>, b1: B<Any?>, b2: B<Test>, x: T): U
|
||||
a2.bar<T?>(null)
|
||||
a2.bar<T>(x)
|
||||
|
||||
// jspecify_nullness_mismatch
|
||||
b1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
b1.foo(null)
|
||||
b1.bar<T?>(null)
|
||||
b1.bar<T>(x)
|
||||
|
||||
// jspecify_nullness_mismatch
|
||||
b2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
b2.foo(null)
|
||||
b2.bar<T?>(null)
|
||||
b2.bar<T>(x)
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -14,5 +14,5 @@ public class Foo<T extends @Nullable Object> {
|
||||
|
||||
// FILE: main.kt
|
||||
fun test(): Foo<String> {
|
||||
return <!DEBUG_INFO_EXPRESSION_TYPE("Foo<kotlin.String>")!>Foo.create()<!>
|
||||
return <!DEBUG_INFO_EXPRESSION_TYPE("Foo<kotlin.String..kotlin.String?!>")!>Foo.create()<!>
|
||||
}
|
||||
|
||||
+6
-6
@@ -14,17 +14,17 @@ public class Test {}
|
||||
|
||||
// FILE: main.kt
|
||||
fun main(a1: NullnessUnspecifiedTypeParameter<Any>, a2: NullnessUnspecifiedTypeParameter<Any?>, x: Test): Unit {
|
||||
a1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a1.foo(null)
|
||||
a1.foo(1)
|
||||
|
||||
a2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a2.foo(null)
|
||||
a2.foo(1)
|
||||
|
||||
a1.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a1.bar(x, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a1.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
|
||||
a1.bar(x, null)
|
||||
a1.bar(x, 1)
|
||||
|
||||
a2.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a2.bar(x, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
a2.bar(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
|
||||
a2.bar(x, null)
|
||||
a2.bar(x, 1)
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -40,12 +40,12 @@ public class CKN extends C<@Nullable CK> {}
|
||||
// FILE: main.kt
|
||||
fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit {
|
||||
ak.foo(ak)
|
||||
ak.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
ak.foo(null)
|
||||
|
||||
akn.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>) // the corresponding warning/error is present on the Java side
|
||||
akn.foo(null) // the corresponding warning/error is present on the Java side
|
||||
|
||||
bk.foo(bk)
|
||||
bk.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
bk.foo(null)
|
||||
|
||||
ck.foo(ck)
|
||||
ck.foo(null)
|
||||
|
||||
+2
-2
@@ -29,11 +29,11 @@ fun <T : Test> main(a1: A<Any?>, a2: A<Test>, b1: B<Any?>, b2: B<Test>, x: T): U
|
||||
a2.bar<T?>(null)
|
||||
a2.bar<T>(x)
|
||||
|
||||
b1.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
b1.foo(null)
|
||||
b1.bar<T?>(null)
|
||||
b1.bar<T>(x)
|
||||
|
||||
b2.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
b2.foo(null)
|
||||
b2.bar<T?>(null)
|
||||
b2.bar<T>(x)
|
||||
}
|
||||
|
||||
+4
-4
@@ -51,15 +51,15 @@ fun <R> main(a: ReturnType<R>) {
|
||||
takeNotNullStringAndNotNullK(x3)
|
||||
takeNullableStringAndNotNullK(<!ARGUMENT_TYPE_MISMATCH!>x3<!>)
|
||||
|
||||
val x4 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<R!!>..kotlin.Array<out R!!>")!>a.foo4<!>
|
||||
val x4 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<R!!>..kotlin.Array<out R!!>?!")!>a.foo4<!>
|
||||
takeArrayOfNotNullString(<!ARGUMENT_TYPE_MISMATCH!>x4<!>)
|
||||
takeArrayOfNullableString(<!ARGUMENT_TYPE_MISMATCH!>x4<!>)
|
||||
takeArrayOfNotNullK(x4)
|
||||
takeArrayOfNullableK(<!ARGUMENT_TYPE_MISMATCH!>x4<!>)
|
||||
|
||||
val x5 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<kotlin.String?>?..kotlin.Array<out kotlin.String?>??")!>a.foo5()<!>
|
||||
val x5 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<kotlin.String?>..kotlin.Array<out kotlin.String?>?!")!>a.foo5()<!>
|
||||
takeArrayOfNotNullString(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableString(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableString(x5)
|
||||
takeArrayOfNotNullK(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableK(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableK(x5)
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -53,15 +53,15 @@ fun <R> main(a: ReturnTypeWithWarnings<R>) {
|
||||
takeNotNullStringAndNotNullK(x3)
|
||||
takeNullableStringAndNotNullK(<!ARGUMENT_TYPE_MISMATCH!>x3<!>)
|
||||
|
||||
val x4 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<R!!>..kotlin.Array<out R!!>")!>a.foo4<!>
|
||||
val x4 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<R!!>..kotlin.Array<out R!!>?!")!>a.foo4<!>
|
||||
takeArrayOfNotNullString(<!ARGUMENT_TYPE_MISMATCH!>x4<!>)
|
||||
takeArrayOfNullableString(<!ARGUMENT_TYPE_MISMATCH!>x4<!>)
|
||||
takeArrayOfNotNullK(x4)
|
||||
takeArrayOfNullableK(<!ARGUMENT_TYPE_MISMATCH!>x4<!>)
|
||||
|
||||
val x5 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<kotlin.String?>?..kotlin.Array<out kotlin.String?>??")!>a.foo5()<!>
|
||||
val x5 = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Array<kotlin.String?>..kotlin.Array<out kotlin.String?>?!")!>a.foo5()<!>
|
||||
takeArrayOfNotNullString(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableString(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableString(x5)
|
||||
takeArrayOfNotNullK(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableK(<!ARGUMENT_TYPE_MISMATCH!>x5<!>)
|
||||
takeArrayOfNullableK(x5)
|
||||
}
|
||||
|
||||
+5
-5
@@ -32,9 +32,9 @@ fun testDesugaredForInList() {
|
||||
|
||||
fun testForInArrayUnused(j: J) {
|
||||
{ // BLOCK
|
||||
val <iterator>: Iterator<@FlexibleNullability P?> = j.arrayOfNotNull().iterator()
|
||||
val <iterator>: Iterator<@EnhancedNullability P> = j.arrayOfNotNull().iterator()
|
||||
while (<iterator>.hasNext()) { // BLOCK
|
||||
val x: @FlexibleNullability P? = <iterator>.next()
|
||||
val x: P = <iterator>.next() /*!! P */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,11 @@ fun testForInListUse() {
|
||||
|
||||
fun testForInArrayUse(j: J) {
|
||||
{ // BLOCK
|
||||
val <iterator>: Iterator<@FlexibleNullability P?> = j.arrayOfNotNull().iterator()
|
||||
val <iterator>: Iterator<@EnhancedNullability P> = j.arrayOfNotNull().iterator()
|
||||
while (<iterator>.hasNext()) { // BLOCK
|
||||
val x: @FlexibleNullability P? = <iterator>.next()
|
||||
val x: P = <iterator>.next() /*!! P */
|
||||
{ // BLOCK
|
||||
use(s = x /*!! @FlexibleNullability P */)
|
||||
use(s = x)
|
||||
use(s = x)
|
||||
}
|
||||
}
|
||||
|
||||
+18
-17
@@ -54,17 +54,18 @@ FILE fqName:<root> fileName:/enhancedNullabilityInForLoop.kt
|
||||
VALUE_PARAMETER name:j index:0 type:<root>.J
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=FOR_LOOP
|
||||
VAR FOR_LOOP_ITERATOR name:tmp_2 type:kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> [val]
|
||||
CALL 'public final fun iterator (): kotlin.collections.Iterator<T of kotlin.Array> [operator] declared in kotlin.Array' type=kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> origin=null
|
||||
$this: CALL 'public open fun arrayOfNotNull (): @[EnhancedNullability] kotlin.Array<out @[FlexibleNullability] <root>.P?> declared in <root>.J' type=@[EnhancedNullability] kotlin.Array<out @[FlexibleNullability] <root>.P?> origin=null
|
||||
VAR FOR_LOOP_ITERATOR name:tmp_2 type:kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> [val]
|
||||
CALL 'public final fun iterator (): kotlin.collections.Iterator<T of kotlin.Array> [operator] declared in kotlin.Array' type=kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> origin=null
|
||||
$this: CALL 'public open fun arrayOfNotNull (): @[EnhancedNullability] kotlin.Array<out @[EnhancedNullability] <root>.P> declared in <root>.J' type=@[EnhancedNullability] kotlin.Array<out @[EnhancedNullability] <root>.P> origin=null
|
||||
$this: GET_VAR 'j: <root>.J declared in <root>.testForInArrayUnused' type=<root>.J origin=null
|
||||
WHILE label=null origin=FOR_LOOP_INNER_WHILE
|
||||
condition: CALL 'public abstract fun hasNext (): kotlin.Boolean [operator] declared in kotlin.collections.Iterator' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT
|
||||
$this: GET_VAR 'val tmp_2: kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> [val] declared in <root>.testForInArrayUnused' type=kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> origin=null
|
||||
$this: GET_VAR 'val tmp_2: kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> [val] declared in <root>.testForInArrayUnused' type=kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> origin=null
|
||||
body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE
|
||||
VAR FOR_LOOP_VARIABLE name:x type:@[FlexibleNullability] <root>.P? [val]
|
||||
CALL 'public abstract fun next (): T of kotlin.collections.Iterator [operator] declared in kotlin.collections.Iterator' type=@[FlexibleNullability] <root>.P? origin=FOR_LOOP_NEXT
|
||||
$this: GET_VAR 'val tmp_2: kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> [val] declared in <root>.testForInArrayUnused' type=kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> origin=null
|
||||
VAR FOR_LOOP_VARIABLE name:x type:<root>.P [val]
|
||||
TYPE_OP type=<root>.P origin=IMPLICIT_NOTNULL typeOperand=<root>.P
|
||||
CALL 'public abstract fun next (): T of kotlin.collections.Iterator [operator] declared in kotlin.collections.Iterator' type=@[EnhancedNullability] <root>.P origin=FOR_LOOP_NEXT
|
||||
$this: GET_VAR 'val tmp_2: kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> [val] declared in <root>.testForInArrayUnused' type=kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> origin=null
|
||||
FUN name:testForInListUse visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=FOR_LOOP
|
||||
@@ -88,23 +89,23 @@ FILE fqName:<root> fileName:/enhancedNullabilityInForLoop.kt
|
||||
VALUE_PARAMETER name:j index:0 type:<root>.J
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=FOR_LOOP
|
||||
VAR FOR_LOOP_ITERATOR name:tmp_4 type:kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> [val]
|
||||
CALL 'public final fun iterator (): kotlin.collections.Iterator<T of kotlin.Array> [operator] declared in kotlin.Array' type=kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> origin=null
|
||||
$this: CALL 'public open fun arrayOfNotNull (): @[EnhancedNullability] kotlin.Array<out @[FlexibleNullability] <root>.P?> declared in <root>.J' type=@[EnhancedNullability] kotlin.Array<out @[FlexibleNullability] <root>.P?> origin=null
|
||||
VAR FOR_LOOP_ITERATOR name:tmp_4 type:kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> [val]
|
||||
CALL 'public final fun iterator (): kotlin.collections.Iterator<T of kotlin.Array> [operator] declared in kotlin.Array' type=kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> origin=null
|
||||
$this: CALL 'public open fun arrayOfNotNull (): @[EnhancedNullability] kotlin.Array<out @[EnhancedNullability] <root>.P> declared in <root>.J' type=@[EnhancedNullability] kotlin.Array<out @[EnhancedNullability] <root>.P> origin=null
|
||||
$this: GET_VAR 'j: <root>.J declared in <root>.testForInArrayUse' type=<root>.J origin=null
|
||||
WHILE label=null origin=FOR_LOOP_INNER_WHILE
|
||||
condition: CALL 'public abstract fun hasNext (): kotlin.Boolean [operator] declared in kotlin.collections.Iterator' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT
|
||||
$this: GET_VAR 'val tmp_4: kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> [val] declared in <root>.testForInArrayUse' type=kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> origin=null
|
||||
$this: GET_VAR 'val tmp_4: kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> [val] declared in <root>.testForInArrayUse' type=kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> origin=null
|
||||
body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE
|
||||
VAR FOR_LOOP_VARIABLE name:x type:@[FlexibleNullability] <root>.P? [val]
|
||||
CALL 'public abstract fun next (): T of kotlin.collections.Iterator [operator] declared in kotlin.collections.Iterator' type=@[FlexibleNullability] <root>.P? origin=FOR_LOOP_NEXT
|
||||
$this: GET_VAR 'val tmp_4: kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> [val] declared in <root>.testForInArrayUse' type=kotlin.collections.Iterator<@[FlexibleNullability] <root>.P?> origin=null
|
||||
VAR FOR_LOOP_VARIABLE name:x type:<root>.P [val]
|
||||
TYPE_OP type=<root>.P origin=IMPLICIT_NOTNULL typeOperand=<root>.P
|
||||
CALL 'public abstract fun next (): T of kotlin.collections.Iterator [operator] declared in kotlin.collections.Iterator' type=@[EnhancedNullability] <root>.P origin=FOR_LOOP_NEXT
|
||||
$this: GET_VAR 'val tmp_4: kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> [val] declared in <root>.testForInArrayUse' type=kotlin.collections.Iterator<@[EnhancedNullability] <root>.P> origin=null
|
||||
BLOCK type=kotlin.Unit origin=null
|
||||
CALL 'public final fun use (s: <root>.P): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
s: TYPE_OP type=@[FlexibleNullability] <root>.P origin=IMPLICIT_NOTNULL typeOperand=@[FlexibleNullability] <root>.P
|
||||
GET_VAR 'val x: @[FlexibleNullability] <root>.P? [val] declared in <root>.testForInArrayUse' type=@[FlexibleNullability] <root>.P? origin=null
|
||||
s: GET_VAR 'val x: <root>.P [val] declared in <root>.testForInArrayUse' type=<root>.P origin=null
|
||||
CALL 'public open fun use (s: @[EnhancedNullability] <root>.P): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=null
|
||||
s: GET_VAR 'val x: @[FlexibleNullability] <root>.P? [val] declared in <root>.testForInArrayUse' type=@[FlexibleNullability] <root>.P? origin=null
|
||||
s: GET_VAR 'val x: <root>.P [val] declared in <root>.testForInArrayUse' type=<root>.P origin=null
|
||||
CLASS INTERFACE name:K modality:ABSTRACT visibility:public superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.K
|
||||
FUN name:arrayOfNotNull visibility:public modality:ABSTRACT <> ($this:<root>.K) returnType:kotlin.Array<<root>.P>
|
||||
|
||||
Reference in New Issue
Block a user