FIR2IR: add implicit NOT_NULL cast if needed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
eeda48e63e
commit
46cc01602e
+2
-2
@@ -5,8 +5,8 @@ FILE: jvm.kt
|
||||
}
|
||||
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval x: R|kotlin/String| = this@R|/User|.R|/Annotated.foo|(String(123))
|
||||
lval y: R|kotlin/String| = this@R|/User|.R|/Annotated.foo|(Null(null))
|
||||
lval x: R|@EnhancedNullability kotlin/String| = this@R|/User|.R|/Annotated.foo|(String(123))
|
||||
lval y: R|@EnhancedNullability kotlin/String| = this@R|/User|.R|/Annotated.foo|(Null(null))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,18 @@ object CompilerConeAttributes {
|
||||
override fun toString(): String = "@NoInfer"
|
||||
}
|
||||
|
||||
object EnhancedNullability : ConeAttribute<EnhancedNullability>() {
|
||||
val ANNOTATION_CLASS_ID = ClassId(FqName("kotlin.jvm.internal"), Name.identifier("EnhancedNullability"))
|
||||
|
||||
override fun union(other: EnhancedNullability?): EnhancedNullability? = other
|
||||
override fun intersect(other: EnhancedNullability?): EnhancedNullability? = this
|
||||
override fun isSubtypeOf(other: EnhancedNullability?): Boolean = true
|
||||
|
||||
override val key: KClass<out EnhancedNullability> = EnhancedNullability::class
|
||||
|
||||
override fun toString(): String = "@EnhancedNullability"
|
||||
}
|
||||
|
||||
object ExtensionFunctionType : ConeAttribute<ExtensionFunctionType>() {
|
||||
val ANNOTATION_CLASS_ID = ClassId(FqName("kotlin"), Name.identifier("ExtensionFunctionType"))
|
||||
|
||||
@@ -62,8 +74,12 @@ object CompilerConeAttributes {
|
||||
|
||||
val ConeAttributes.exact: CompilerConeAttributes.Exact? by ConeAttributes.attributeAccessor<CompilerConeAttributes.Exact>()
|
||||
val ConeAttributes.noInfer: CompilerConeAttributes.NoInfer? by ConeAttributes.attributeAccessor<CompilerConeAttributes.NoInfer>()
|
||||
val ConeAttributes.enhancedNullability: CompilerConeAttributes.EnhancedNullability? by ConeAttributes.attributeAccessor<CompilerConeAttributes.EnhancedNullability>()
|
||||
val ConeAttributes.extensionFunctionType: CompilerConeAttributes.ExtensionFunctionType? by ConeAttributes.attributeAccessor<CompilerConeAttributes.ExtensionFunctionType>()
|
||||
val ConeAttributes.unsafeVarianceType: CompilerConeAttributes.UnsafeVariance? by ConeAttributes.attributeAccessor<CompilerConeAttributes.UnsafeVariance>()
|
||||
|
||||
val ConeKotlinType.hasEnhancedNullability: Boolean
|
||||
get() = attributes.enhancedNullability != null
|
||||
|
||||
val ConeKotlinType.isExtensionFunctionType: Boolean
|
||||
get() = attributes.extensionFunctionType != null
|
||||
|
||||
@@ -87,8 +87,9 @@ class Fir2IrTypeConverter(
|
||||
firSymbol.toSymbol(session, classifierStorage, typeContext)
|
||||
}
|
||||
val typeAnnotations: MutableList<IrConstructorCall> =
|
||||
if (attributes.extensionFunctionType == null) mutableListOf()
|
||||
if (!isExtensionFunctionType) mutableListOf()
|
||||
else mutableListOf(builtIns.extensionFunctionTypeAnnotationConstructorCall())
|
||||
// TODO: Need to convert @EnhancedNullability ?
|
||||
typeAnnotations += with(annotationGenerator) { annotations.toIrAnnotations() }
|
||||
IrSimpleTypeImpl(
|
||||
irSymbol, !typeContext.definitelyNotNull && this.isMarkedNullable,
|
||||
|
||||
@@ -542,7 +542,25 @@ class Fir2IrVisitor(
|
||||
expression.accept(this, null) as IrExpression
|
||||
}
|
||||
}
|
||||
}.insertImplicitNotNullCastIfNeeded(expression)
|
||||
}
|
||||
|
||||
private fun IrExpression.insertImplicitNotNullCastIfNeeded(expression: FirExpression): IrExpression {
|
||||
if (this is IrTypeOperatorCall && this.operator == IrTypeOperator.IMPLICIT_NOTNULL) {
|
||||
return this
|
||||
}
|
||||
// TODO: Other conditions to check?
|
||||
if (expression.typeRef.coneTypeSafe<ConeKotlinType>()?.hasEnhancedNullability != true) {
|
||||
return this
|
||||
}
|
||||
return IrTypeOperatorCallImpl(
|
||||
this.startOffset,
|
||||
this.endOffset,
|
||||
this.type,
|
||||
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||
this.type,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertToIrReceiverExpression(
|
||||
|
||||
@@ -61,10 +61,11 @@ internal val JavaClass.classKind: ClassKind
|
||||
|
||||
internal fun ClassId.toConeKotlinType(
|
||||
typeArguments: Array<ConeTypeProjection>,
|
||||
isNullable: Boolean
|
||||
isNullable: Boolean,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeLookupTagBasedType {
|
||||
val lookupTag = ConeClassLikeLookupTagImpl(this)
|
||||
return ConeClassLikeTypeImpl(lookupTag, typeArguments, isNullable)
|
||||
return ConeClassLikeTypeImpl(lookupTag, typeArguments, isNullable, attributes)
|
||||
}
|
||||
|
||||
internal fun FirTypeRef.toConeKotlinTypeProbablyFlexible(
|
||||
@@ -110,11 +111,17 @@ internal fun JavaType?.toConeKotlinTypeWithoutEnhancement(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
forAnnotationValueParameter: Boolean = false,
|
||||
isForSupertypes: Boolean = false
|
||||
isForSupertypes: Boolean = false,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeKotlinType {
|
||||
return when (this) {
|
||||
is JavaClassifierType -> {
|
||||
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forAnnotationValueParameter = forAnnotationValueParameter)
|
||||
toConeKotlinTypeWithoutEnhancement(
|
||||
session,
|
||||
javaTypeParameterStack,
|
||||
forAnnotationValueParameter = forAnnotationValueParameter,
|
||||
attributes = attributes
|
||||
)
|
||||
}
|
||||
is JavaPrimitiveType -> {
|
||||
val primitiveType = type
|
||||
@@ -124,14 +131,26 @@ internal fun JavaType?.toConeKotlinTypeWithoutEnhancement(
|
||||
}
|
||||
|
||||
val classId = StandardClassIds.byName(kotlinPrimitiveName)
|
||||
classId.toConeKotlinType(emptyArray(), isNullable = false)
|
||||
classId.toConeKotlinType(emptyArray(), isNullable = false, attributes)
|
||||
}
|
||||
is JavaArrayType -> {
|
||||
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forAnnotationValueParameter, isForSupertypes)
|
||||
}
|
||||
is JavaWildcardType -> bound?.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, isForSupertypes = isForSupertypes) ?: run {
|
||||
StandardClassIds.Any.toConeFlexibleType(emptyArray())
|
||||
toConeKotlinTypeWithoutEnhancement(
|
||||
session,
|
||||
javaTypeParameterStack,
|
||||
forAnnotationValueParameter,
|
||||
isForSupertypes,
|
||||
attributes = attributes
|
||||
)
|
||||
}
|
||||
is JavaWildcardType ->
|
||||
bound?.toConeKotlinTypeWithoutEnhancement(
|
||||
session,
|
||||
javaTypeParameterStack,
|
||||
isForSupertypes = isForSupertypes,
|
||||
attributes = attributes
|
||||
) ?: run {
|
||||
StandardClassIds.Any.toConeFlexibleType(emptyArray())
|
||||
}
|
||||
null -> {
|
||||
StandardClassIds.Any.toConeFlexibleType(emptyArray())
|
||||
}
|
||||
@@ -143,7 +162,8 @@ private fun JavaArrayType.toConeKotlinTypeWithoutEnhancement(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
forAnnotationValueParameter: Boolean = false,
|
||||
isForSupertypes: Boolean
|
||||
isForSupertypes: Boolean,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeKotlinType {
|
||||
val componentType = componentType
|
||||
return if (componentType !is JavaPrimitiveType) {
|
||||
@@ -152,11 +172,12 @@ private fun JavaArrayType.toConeKotlinTypeWithoutEnhancement(
|
||||
session, javaTypeParameterStack, forAnnotationValueParameter, isForSupertypes
|
||||
)
|
||||
if (forAnnotationValueParameter) {
|
||||
classId.constructClassLikeType(arrayOf(argumentType), isNullable = false)
|
||||
classId.constructClassLikeType(arrayOf(argumentType), isNullable = false, attributes = attributes)
|
||||
} else {
|
||||
classId.toConeFlexibleType(
|
||||
arrayOf(argumentType),
|
||||
typeArgumentsForUpper = arrayOf(ConeKotlinTypeProjectionOut(argumentType))
|
||||
typeArgumentsForUpper = arrayOf(ConeKotlinTypeProjectionOut(argumentType)),
|
||||
attributes = attributes
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -164,19 +185,20 @@ private fun JavaArrayType.toConeKotlinTypeWithoutEnhancement(
|
||||
val classId = StandardClassIds.byName(javaComponentName + "Array")
|
||||
|
||||
if (forAnnotationValueParameter) {
|
||||
classId.constructClassLikeType(emptyArray(), isNullable = false)
|
||||
classId.constructClassLikeType(emptyArray(), isNullable = false, attributes = attributes)
|
||||
} else {
|
||||
classId.toConeFlexibleType(emptyArray())
|
||||
classId.toConeFlexibleType(emptyArray(), attributes = attributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassId.toConeFlexibleType(
|
||||
typeArguments: Array<ConeTypeProjection>,
|
||||
typeArgumentsForUpper: Array<ConeTypeProjection> = typeArguments
|
||||
typeArgumentsForUpper: Array<ConeTypeProjection> = typeArguments,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
) = ConeFlexibleType(
|
||||
toConeKotlinType(typeArguments, isNullable = false),
|
||||
toConeKotlinType(typeArgumentsForUpper, isNullable = true)
|
||||
toConeKotlinType(typeArguments, isNullable = false, attributes),
|
||||
toConeKotlinType(typeArgumentsForUpper, isNullable = true, attributes)
|
||||
)
|
||||
|
||||
private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
@@ -184,7 +206,8 @@ private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
forTypeParameterBounds: Boolean = false,
|
||||
isForSupertypes: Boolean = false,
|
||||
forAnnotationValueParameter: Boolean = false
|
||||
forAnnotationValueParameter: Boolean = false,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeKotlinType {
|
||||
val lowerBound = toConeKotlinTypeForFlexibleBound(
|
||||
session,
|
||||
@@ -192,7 +215,8 @@ private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
isLowerBound = true,
|
||||
forTypeParameterBounds,
|
||||
isForSupertypes,
|
||||
forAnnotationValueParameter = forAnnotationValueParameter
|
||||
forAnnotationValueParameter = forAnnotationValueParameter,
|
||||
attributes = attributes
|
||||
)
|
||||
if (forAnnotationValueParameter) {
|
||||
return lowerBound
|
||||
@@ -205,7 +229,8 @@ private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
forTypeParameterBounds,
|
||||
isForSupertypes,
|
||||
lowerBound,
|
||||
forAnnotationValueParameter = forAnnotationValueParameter
|
||||
forAnnotationValueParameter = forAnnotationValueParameter,
|
||||
attributes = attributes
|
||||
)
|
||||
|
||||
return if (isRaw) ConeRawType(lowerBound, upperBound) else ConeFlexibleType(lowerBound, upperBound)
|
||||
@@ -308,7 +333,8 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
|
||||
forTypeParameterBounds: Boolean,
|
||||
isForSupertypes: Boolean,
|
||||
lowerBound: ConeLookupTagBasedType? = null,
|
||||
forAnnotationValueParameter: Boolean = false
|
||||
forAnnotationValueParameter: Boolean = false,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeLookupTagBasedType {
|
||||
return when (val classifier = classifier) {
|
||||
is JavaClass -> {
|
||||
@@ -357,7 +383,7 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
|
||||
}
|
||||
|
||||
lookupTag.constructClassType(
|
||||
mappedTypeArguments.toTypedArray(), isNullable = !isLowerBound
|
||||
mappedTypeArguments.toTypedArray(), isNullable = !isLowerBound, attributes
|
||||
)
|
||||
}
|
||||
is JavaTypeParameter -> {
|
||||
|
||||
+9
-2
@@ -42,6 +42,8 @@ internal class EnhancementSignatureParts(
|
||||
) {
|
||||
private val isForVarargParameter get() = typeContainer.safeAs<FirValueParameter>()?.isVararg == true
|
||||
|
||||
private val attributesCache = mutableMapOf<FirTypeRef?, ConeAttributes>().withDefault { ConeAttributes.Empty }
|
||||
|
||||
private fun ConeKotlinType.toFqNameUnsafe(): FqNameUnsafe? =
|
||||
((this as? ConeLookupTagBasedType)?.lookupTag as? ConeClassLikeLookupTag)?.classId?.asSingleFqName()?.toUnsafe()
|
||||
|
||||
@@ -62,7 +64,8 @@ internal class EnhancementSignatureParts(
|
||||
val typeWithoutEnhancement = current.type.toConeKotlinTypeWithoutEnhancement(
|
||||
session,
|
||||
javaTypeParameterStack,
|
||||
forAnnotationValueParameter
|
||||
forAnnotationValueParameter,
|
||||
attributes = attributesCache.getValue(current)
|
||||
)
|
||||
val containsFunctionN = typeWithoutEnhancement.contains {
|
||||
if (it is ConeClassErrorType) false
|
||||
@@ -204,7 +207,11 @@ internal class EnhancementSignatureParts(
|
||||
else
|
||||
defaultQualifiersForType
|
||||
|
||||
val nullabilityInfo = composedAnnotation.extractNullability(typeQualifierResolver, javaTypeEnhancementState)
|
||||
val nullabilityInfo = composedAnnotation.extractNullability(typeQualifierResolver, javaTypeEnhancementState).also {
|
||||
if (it?.qualifier == NullabilityQualifier.NOT_NULL) {
|
||||
attributesCache[this] = composedAnnotation.computeTypeAttributesForJavaType()
|
||||
}
|
||||
}
|
||||
?: defaultTypeQualifier?.nullabilityQualifier?.let { nullability ->
|
||||
NullabilityQualifierWithMigrationStatus(
|
||||
nullability.qualifier,
|
||||
|
||||
@@ -13,14 +13,11 @@ import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
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.java.JavaTypeParameterStack
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||
@@ -327,3 +324,11 @@ internal fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaul
|
||||
private val DEFAULT_VALUE_ID = ClassId.topLevel(DEFAULT_VALUE_FQ_NAME)
|
||||
private val DEFAULT_NULL_ID = ClassId.topLevel(DEFAULT_NULL_FQ_NAME)
|
||||
|
||||
internal fun List<FirAnnotationCall>.computeTypeAttributesForJavaType(): ConeAttributes =
|
||||
computeTypeAttributes { classId ->
|
||||
when (classId) {
|
||||
CompilerConeAttributes.EnhancedNullability.ANNOTATION_CLASS_ID -> add(CompilerConeAttributes.EnhancedNullability)
|
||||
// TODO: Need to handle others too? E.g., COMPATQUAL_NONNULL_ANNOTATION_ID
|
||||
in NOT_NULL_ANNOTATION_IDS -> add(CompilerConeAttributes.EnhancedNullability)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ private fun FirAnnotationCall.extractNullabilityTypeFromArgument(): NullabilityQ
|
||||
}
|
||||
|
||||
private val NULLABLE_ANNOTATION_IDS = NULLABLE_ANNOTATIONS.map { ClassId.topLevel(it) }
|
||||
private val NOT_NULL_ANNOTATION_IDS = NOT_NULL_ANNOTATIONS.map { ClassId.topLevel(it) }
|
||||
val NOT_NULL_ANNOTATION_IDS = NOT_NULL_ANNOTATIONS.map { ClassId.topLevel(it) }
|
||||
private val JAVAX_NONNULL_ANNOTATION_ID = ClassId.topLevel(JAVAX_NONNULL_ANNOTATION)
|
||||
private val COMPATQUAL_NULLABLE_ANNOTATION_ID = ClassId.topLevel(COMPATQUAL_NULLABLE_ANNOTATION)
|
||||
private val COMPATQUAL_NONNULL_ANNOTATION_ID = ClassId.topLevel(COMPATQUAL_NONNULL_ANNOTATION)
|
||||
|
||||
@@ -87,16 +87,19 @@ fun ConeClassLikeType.toConstKind(): FirConstKind<*>? = when (lookupTag.classId)
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun List<FirAnnotationCall>.computeTypeAttributes(): ConeAttributes {
|
||||
fun List<FirAnnotationCall>.computeTypeAttributes(
|
||||
additionalProcessor: MutableList<ConeAttribute<*>>.(ClassId) -> Unit = {}
|
||||
): ConeAttributes {
|
||||
if (this.isEmpty()) return ConeAttributes.Empty
|
||||
val attributes = mutableListOf<ConeAttribute<*>>()
|
||||
for (annotation in this) {
|
||||
val type = annotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>() ?: continue
|
||||
when (type.lookupTag.classId) {
|
||||
when (val classId = type.lookupTag.classId) {
|
||||
CompilerConeAttributes.Exact.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.Exact
|
||||
CompilerConeAttributes.NoInfer.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.NoInfer
|
||||
CompilerConeAttributes.ExtensionFunctionType.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.ExtensionFunctionType
|
||||
CompilerConeAttributes.UnsafeVariance.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.UnsafeVariance
|
||||
else -> additionalProcessor.invoke(attributes, classId)
|
||||
}
|
||||
}
|
||||
return ConeAttributes.create(attributes)
|
||||
|
||||
@@ -27,14 +27,16 @@ fun ConeClassifierLookupTag.constructType(
|
||||
fun ConeClassLikeLookupTag.constructClassType(
|
||||
typeArguments: Array<out ConeTypeProjection>,
|
||||
isNullable: Boolean,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeClassLikeType {
|
||||
return ConeClassLikeTypeImpl(this, typeArguments, isNullable)
|
||||
return ConeClassLikeTypeImpl(this, typeArguments, isNullable, attributes)
|
||||
}
|
||||
|
||||
fun ClassId.constructClassLikeType(
|
||||
typeArguments: Array<out ConeTypeProjection>,
|
||||
isNullable: Boolean,
|
||||
attributes: ConeAttributes = ConeAttributes.Empty
|
||||
): ConeClassLikeType {
|
||||
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), typeArguments, isNullable)
|
||||
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), typeArguments, isNullable, attributes)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user