[FIR] Save warning-level enhanced types to an attribute

#KT-56989
This commit is contained in:
Kirill Rakhman
2023-09-20 15:31:42 +02:00
committed by Space Team
parent ef96912573
commit 1ecbc094ec
13 changed files with 105 additions and 48 deletions
@@ -24,7 +24,7 @@ KtFunctionSymbol:
receiverParameter: null
returnType: KtFlexibleType:
annotationsList: []
type: kotlin/String!
type: Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
@@ -3,12 +3,12 @@ FIR element: FirSimpleFunctionImpl
FIR source kind: KtRealSourceElementKind
FIR element rendered:
public final [ResolvedTo(BODY_RESOLVE)] fun test(): R|kotlin/String!| {
public final [ResolvedTo(BODY_RESOLVE)] fun test(): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!| {
^test R|/ClassWithExternalAnnotatedMembers.ClassWithExternalAnnotatedMembers|().R|/ClassWithExternalAnnotatedMembers.externalNotNullMethod|()
}
FIR FILE:
FILE: [ResolvedTo(IMPORTS)] usage.kt
public final [ResolvedTo(BODY_RESOLVE)] fun test(): R|kotlin/String!| {
public final [ResolvedTo(BODY_RESOLVE)] fun test(): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!| {
^test R|/ClassWithExternalAnnotatedMembers.ClassWithExternalAnnotatedMembers|().R|/ClassWithExternalAnnotatedMembers.externalNotNullMethod|()
}
@@ -5,7 +5,7 @@
public open class NonNullNever : R|kotlin/Any| {
@R|javax/annotation/Nonnull|(when = R|javax/annotation/meta/When.NEVER|) public open field field: R|kotlin/String?|
@R|MyNullable|() public open fun foo(@R|javax/annotation/Nonnull|(when = R|javax/annotation/meta/When.NEVER|) x: R|kotlin/String?|, @R|MyNullable|() y: R|kotlin/CharSequence!|): R|kotlin/String!|
@R|MyNullable|() public open fun foo(@R|javax/annotation/Nonnull|(when = R|javax/annotation/meta/When.NEVER|) x: R|kotlin/String?|, @R|MyNullable|() y: R|Enhanced for warning(kotlin/CharSequence?) kotlin/CharSequence!|): R|Enhanced for warning(kotlin/String?) kotlin/String!|
public constructor(): R|NonNullNever|
@@ -1,5 +1,5 @@
@R|FieldsAreNullable|() public open class A : R|kotlin/Any| {
public open field field: R|kotlin/String!|
public open field field: R|Enhanced for warning(kotlin/String?) kotlin/String!|
@R|javax/annotation/Nonnull|() public open field nonNullField: R|@EnhancedNullability kotlin/String|
@@ -1,5 +1,5 @@
@R|spr/NonNullApi|() public open class A : R|kotlin/Any| {
public open fun foo(x: R|kotlin/String!|, @R|spr/Nullable|() y: R|kotlin/CharSequence!|): R|kotlin/String!|
public open fun foo(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|spr/Nullable|() y: R|Enhanced for warning(kotlin/CharSequence?) kotlin/CharSequence!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|spr/ForceFlexibility|() public open fun bar(x: R|kotlin/String!|, @R|javax/annotation/Nonnull|() y: R|@EnhancedNullability kotlin/CharSequence|): R|kotlin/String!|
@@ -1,55 +1,55 @@
@R|NonNullApi|() public open class A : R|kotlin/Any| {
public open fun foo1(x: R|kotlin/String!|): R|kotlin/String!|
public open fun foo1(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun foo2(x: R|kotlin/String!|): R|kotlin/String!|
public open fun foo2(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun foo3(x: R|kotlin/String!|): R|kotlin/String!|
public open fun foo3(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|javax/annotation/Nullable|() public open fun bar1(@R|javax/annotation/Nullable|() x: R|kotlin/String?|): R|kotlin/String?|
@R|javax/annotation/Nullable|() public open fun bar2(@R|javax/annotation/Nullable|() x: R|kotlin/String?|): R|kotlin/String?|
public open fun baz(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|kotlin/String!|
public open fun baz(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public constructor(): R|A|
}
@R|NonNullApi|() public abstract interface AInt : R|kotlin/Any| {
public abstract fun foo1(x: R|kotlin/String!|): R|kotlin/CharSequence!|
public abstract fun foo1(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/CharSequence) kotlin/CharSequence!|
public abstract fun foo2(x: R|kotlin/String!|): R|kotlin/CharSequence!|
public abstract fun foo2(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/CharSequence) kotlin/CharSequence!|
public abstract fun foo3(x: R|kotlin/String!|): R|kotlin/CharSequence!|
public abstract fun foo3(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/CharSequence) kotlin/CharSequence!|
@R|javax/annotation/Nullable|() public abstract fun bar1(@R|javax/annotation/Nullable|() x: R|kotlin/String?|): R|kotlin/CharSequence?|
@R|javax/annotation/Nullable|() public abstract fun bar2(@R|javax/annotation/Nullable|() x: R|kotlin/String?|): R|kotlin/CharSequence?|
public abstract fun baz(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|kotlin/CharSequence!|
public abstract fun baz(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|Enhanced for warning(@EnhancedNullability kotlin/CharSequence) kotlin/CharSequence!|
}
@R|NullableApi|() public open class B : R|A|, R|AInt| {
public open fun foo1(x: R|kotlin/String!|): R|kotlin/String!|
public open fun foo1(x: R|Enhanced for warning(kotlin/String?) kotlin/String!|): R|Enhanced for warning(kotlin/String?) kotlin/String!|
@R|javax/annotation/Nonnull|() public open fun foo2(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|@EnhancedNullability kotlin/String|
public open fun bar1(x: R|kotlin/String?|): R|kotlin/String?|
public open fun baz(x: R|@EnhancedNullability kotlin/String|): R|kotlin/String!|
public open fun baz(x: R|@EnhancedNullability kotlin/String|): R|Enhanced for warning(kotlin/String?) kotlin/String!|
public constructor(): R|B|
}
@R|NonNullApi|() public open class C : R|A|, R|AInt| {
public open fun foo1(x: R|kotlin/String!|): R|kotlin/String!|
public open fun foo1(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun foo2(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|kotlin/String!|
public open fun foo2(@R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun bar1(x: R|kotlin/String?|): R|kotlin/String?|
@R|javax/annotation/Nullable|() public open fun bar2(@R|javax/annotation/Nullable|() x: R|kotlin/String?|): R|kotlin/String?|
public open fun baz(x: R|@EnhancedNullability kotlin/String|): R|kotlin/String!|
public open fun baz(x: R|@EnhancedNullability kotlin/String|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public constructor(): R|C|
@@ -1,24 +1,24 @@
@R|NonNullApi|() public open class A : R|kotlin/Any| {
public open field field: R|kotlin/String!|
public open field field: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun foo(x: R|kotlin/String!|, @R|javax/annotation/CheckForNull|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
public open fun foo(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|javax/annotation/CheckForNull|() y: R|kotlin/CharSequence?|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|NullableApi|() public open fun foobar(x: R|kotlin/String!|, @R|NonNullApi|() y: R|kotlin/CharSequence!|): R|kotlin/String!|
@R|NullableApi|() public open fun foobar(x: R|Enhanced for warning(kotlin/String?) kotlin/String!|, @R|NonNullApi|() y: R|Enhanced for warning(@EnhancedNullability kotlin/CharSequence) kotlin/CharSequence!|): R|Enhanced for warning(kotlin/String?) kotlin/String!|
public open fun bar(): R|kotlin/String!|
public open fun bar(): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|javax/annotation/Nullable|() public open fun baz(): R|ft<kotlin/collections/MutableList<kotlin/String!>?, kotlin/collections/List<kotlin/String!>?>|
public constructor(): R|A|
@R|NullableApi|() public open inner class B : R|kotlin/Any| {
public open field field: R|kotlin/String!|
public open field field: R|Enhanced for warning(kotlin/String?) kotlin/String!|
public open fun foo(x: R|kotlin/String!|, @R|javax/annotation/Nonnull|() y: R|@EnhancedNullability kotlin/CharSequence|): R|kotlin/String!|
public open fun foo(x: R|Enhanced for warning(kotlin/String?) kotlin/String!|, @R|javax/annotation/Nonnull|() y: R|@EnhancedNullability kotlin/CharSequence|): R|Enhanced for warning(kotlin/String?) kotlin/String!|
@R|NonNullApi|() public open fun foobar(x: R|kotlin/String!|, @R|NullableApi|() y: R|kotlin/CharSequence!|): R|kotlin/String!|
@R|NonNullApi|() public open fun foobar(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|NullableApi|() y: R|Enhanced for warning(kotlin/CharSequence?) kotlin/CharSequence!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun bar(): R|kotlin/String!|
public open fun bar(): R|Enhanced for warning(kotlin/String?) kotlin/String!|
@R|javax/annotation/Nullable|() public open fun baz(): R|ft<kotlin/collections/MutableList<kotlin/String!>?, kotlin/collections/List<kotlin/String!>?>|
@@ -26,13 +26,13 @@
}
@R|FieldsAreNullable|() public open inner class C : R|kotlin/Any| {
public open field field: R|kotlin/String!|
public open field field: R|Enhanced for warning(kotlin/String?) kotlin/String!|
public open fun foo(x: R|kotlin/String!|, @R|javax/annotation/Nullable|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
public open fun foo(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|javax/annotation/Nullable|() y: R|kotlin/CharSequence?|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|NullableApi|() public open fun foobar(x: R|kotlin/String!|, @R|javax/annotation/Nullable|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
@R|NullableApi|() public open fun foobar(x: R|Enhanced for warning(kotlin/String?) kotlin/String!|, @R|javax/annotation/Nullable|() y: R|kotlin/CharSequence?|): R|Enhanced for warning(kotlin/String?) kotlin/String!|
public open fun bar(): R|kotlin/String!|
public open fun bar(): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|javax/annotation/Nullable|() public open fun baz(): R|ft<kotlin/collections/MutableList<kotlin/String!>?, kotlin/collections/List<kotlin/String!>?>|
@@ -1,7 +1,7 @@
@R|javax/annotation/ParametersAreNonnullByDefault|() public open class A : R|kotlin/Any| {
@R|javax/annotation/Nullable|() public open field field: R|kotlin/String?|
public open fun foo(q: R|kotlin/String!|, @R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|, @R|javax/annotation/CheckForNull|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
public open fun foo(q: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|, @R|javax/annotation/CheckForNull|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
@R|javax/annotation/Nonnull|() public open fun bar(): R|@EnhancedNullability kotlin/String|
@@ -1,7 +1,7 @@
public open class A : R|kotlin/Any| {
@R|javax/annotation/Nullable|() public open field field: R|kotlin/String?|
public open fun foo(q: R|kotlin/String!|, @R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|, @R|javax/annotation/CheckForNull|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
public open fun foo(q: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|javax/annotation/Nonnull|() x: R|@EnhancedNullability kotlin/String|, @R|javax/annotation/CheckForNull|() y: R|kotlin/CharSequence?|): R|kotlin/String!|
@R|javax/annotation/Nonnull|() public open fun bar(): R|@EnhancedNullability kotlin/String|
@@ -1,11 +1,11 @@
@R|spr/NonNullApi|() public open class A : R|kotlin/Any| {
public open field field: R|kotlin/String!|
public open fun foo(x: R|kotlin/String!|, @R|spr/Nullable|() y: R|kotlin/CharSequence!|): R|kotlin/String!|
public open fun foo(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|spr/Nullable|() y: R|Enhanced for warning(kotlin/CharSequence?) kotlin/CharSequence!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun bar(): R|kotlin/String!|
public open fun bar(): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|spr/Nullable|() public open fun baz(): R|ft<kotlin/collections/MutableList<kotlin/String!>, kotlin/collections/List<kotlin/String!>?>|
@R|spr/Nullable|() public open fun baz(): R|ft<Enhanced for warning(kotlin/collections/MutableList<kotlin/String!>?) kotlin/collections/MutableList<kotlin/String!>, kotlin/collections/List<kotlin/String!>?>|
public constructor(): R|A|
@@ -1,11 +1,11 @@
public open class A : R|kotlin/Any| {
public open field field: R|kotlin/String!|
public open fun foo(x: R|kotlin/String!|, @R|spr/Nullable|() y: R|kotlin/CharSequence!|): R|kotlin/String!|
public open fun foo(x: R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|, @R|spr/Nullable|() y: R|Enhanced for warning(kotlin/CharSequence?) kotlin/CharSequence!|): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
public open fun bar(): R|kotlin/String!|
public open fun bar(): R|Enhanced for warning(@EnhancedNullability kotlin/String) kotlin/String!|
@R|spr/Nullable|() public open fun baz(): R|ft<kotlin/collections/MutableList<kotlin/String!>, kotlin/collections/List<kotlin/String!>?>|
@R|spr/Nullable|() public open fun baz(): R|ft<Enhanced for warning(kotlin/collections/MutableList<kotlin/String!>?) kotlin/collections/MutableList<kotlin/String!>, kotlin/collections/List<kotlin/String!>?>|
public constructor(): R|test/A|
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2023 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.fir.types.ConeAttributeWithConeType
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.renderForDebugging
import kotlin.reflect.KClass
class EnhancedTypeForWarningAttribute(
override val coneType: ConeKotlinType,
) : ConeAttributeWithConeType<EnhancedTypeForWarningAttribute>() {
override fun union(other: EnhancedTypeForWarningAttribute?): EnhancedTypeForWarningAttribute? = null
override fun intersect(other: EnhancedTypeForWarningAttribute?): EnhancedTypeForWarningAttribute? = null
override fun add(other: EnhancedTypeForWarningAttribute?): EnhancedTypeForWarningAttribute = other ?: this
override fun isSubtypeOf(other: EnhancedTypeForWarningAttribute?): Boolean = true
override fun toString(): String = "Enhanced for warning(${coneType.renderForDebugging()})"
override fun copyWith(newType: ConeKotlinType): EnhancedTypeForWarningAttribute = EnhancedTypeForWarningAttribute(newType)
override val key: KClass<out EnhancedTypeForWarningAttribute>
get() = EnhancedTypeForWarningAttribute::class
override val keepInInferredDeclarationType: Boolean
get() = true
}
val ConeAttributes.enhancedTypeForWarning: EnhancedTypeForWarningAttribute? by ConeAttributes.attributeAccessor<EnhancedTypeForWarningAttribute>()
val ConeKotlinType.enhancedTypeForWarning: ConeKotlinType?
get() = attributes.enhancedTypeForWarning?.coneType
@@ -40,14 +40,10 @@ private fun ConeKotlinType.enhanceConeKotlinType(
): ConeKotlinType? {
return when (this) {
is ConeFlexibleType -> {
// Currently, the warnings are left unsupported in K2 (see KT-57307)
// But modulo information for warnings, we reproduce the K1 behavior: if head type qualifier is for warnings, we totally ignore
// We reproduce the K1 behavior: if head type qualifier is for warnings, we totally ignore
// enhancement on its arguments, too (see JavaTypeEnhancement.enhancePossiblyFlexible).
// It's not totally correct, but tolerable since we would like to avoid excessive breaking changes and the warnings should be
// anyway reported.
// TODO: support not loosing information for warnings here, too
if (qualifiers(index).isNullabilityQualifierForWarning) return null
val lowerResult = lowerBound.enhanceInflexibleType(
session, TypeComponentPosition.FLEXIBLE_LOWER, qualifiers, index, subtreeSizes
)
@@ -96,9 +92,36 @@ private fun ConeSimpleKotlinType.enhanceInflexibleType(
val effectiveQualifiers = qualifiers(index)
val enhancedTag = lookupTag.enhanceMutability(effectiveQualifiers, position)
// TODO: implement warnings (see KT-57307)
val nullabilityFromQualifiers = effectiveQualifiers.nullability
.takeIf { shouldEnhance && !effectiveQualifiers.isNullabilityQualifierForWarning }
val nullabilityFromQualifiers = effectiveQualifiers.nullability.takeIf { shouldEnhance }
val enhanced = enhanceInflexibleType(
session,
qualifiers,
index,
subtreeSizes,
isFromDefinitelyNotNullType,
effectiveQualifiers.definitelyNotNull,
nullabilityFromQualifiers,
enhancedTag
)
return if (effectiveQualifiers.isNullabilityQualifierForWarning && enhanced != null) {
this.withAttributes(attributes.plus(EnhancedTypeForWarningAttribute(enhanced)))
} else {
enhanced
}
}
private fun ConeLookupTagBasedType.enhanceInflexibleType(
session: FirSession,
qualifiers: IndexedJavaTypeQualifiers,
index: Int,
subtreeSizes: List<Int>,
isFromDefinitelyNotNullType: Boolean,
isDefinitelyNotNull: Boolean,
nullabilityFromQualifiers: NullabilityQualifier?,
enhancedTag: ConeClassifierLookupTag,
): ConeSimpleKotlinType? {
val enhancedIsNullable = when (nullabilityFromQualifiers) {
NullabilityQualifier.NULLABLE -> true
NullabilityQualifier.NOT_NULL -> false
@@ -126,7 +149,7 @@ private fun ConeSimpleKotlinType.enhanceInflexibleType(
val mergedArguments = Array(typeArguments.size) { enhancedArguments[it] ?: typeArguments[it] }
val mergedAttributes = if (shouldAddAttribute) attributes + CompilerConeAttributes.EnhancedNullability else attributes
val enhancedType = enhancedTag.constructType(mergedArguments, enhancedIsNullable, mergedAttributes)
return if (effectiveQualifiers.definitelyNotNull || (isFromDefinitelyNotNullType && nullabilityFromQualifiers == null))
return if (isDefinitelyNotNull || (isFromDefinitelyNotNullType && nullabilityFromQualifiers == null))
ConeDefinitelyNotNullType.create(enhancedType, session.typeContext) ?: enhancedType
else
enhancedType