Support @EnhancedNullability in psi2ir

This commit is contained in:
Dmitry Petrov
2019-12-03 15:17:02 +03:00
parent 429bf78afa
commit c83f68151c
9 changed files with 149 additions and 6 deletions
@@ -1670,6 +1670,11 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
runTest("compiler/testData/ir/irText/types/asOnPlatformType.kt");
}
@TestMetadata("enhancedNullability.kt")
public void testEnhancedNullability() throws Exception {
runTest("compiler/testData/ir/irText/types/enhancedNullability.kt");
}
@TestMetadata("explicitEqualsAndCompareToCallsOnPlatformTypeReceiver.kt")
public void testExplicitEqualsAndCompareToCallsOnPlatformTypeReceiver() throws Exception {
runTest("compiler/testData/ir/irText/types/explicitEqualsAndCompareToCallsOnPlatformTypeReceiver.kt");
@@ -10,14 +10,17 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
@@ -27,6 +30,7 @@ import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : GeneratorExtensions() {
val classNameOverride = mutableMapOf<IrClass, JvmClassName>()
@@ -88,4 +92,24 @@ class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : Gene
override fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean =
descriptor.hasJvmFieldAnnotation()
override val enhancedNullability: EnhancedNullability
get() = JvmEnhancedNullability
open class JvmEnhancedNullability : EnhancedNullability() {
override fun hasEnhancedNullability(kotlinType: KotlinType): Boolean =
kotlinType.hasEnhancedNullability()
override fun stripEnhancedNullability(kotlinType: KotlinType): KotlinType =
if (kotlinType.hasEnhancedNullability())
kotlinType.replaceAnnotations(
FilteredAnnotations(kotlinType.annotations, true) {
it != JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION
}
)
else
kotlinType
companion object Instance : JvmEnhancedNullability()
}
}
@@ -30,4 +30,16 @@ open class GeneratorExtensions : StubGeneratorExtensions() {
}
open fun computeFieldVisibility(descriptor: PropertyDescriptor): Visibility? = null
open val enhancedNullability: EnhancedNullability
get() = EnhancedNullability
open class EnhancedNullability {
open fun hasEnhancedNullability(kotlinType: KotlinType): Boolean = false
open fun stripEnhancedNullability(kotlinType: KotlinType): KotlinType = kotlinType
companion object Instance : EnhancedNullability()
}
}
@@ -50,7 +50,7 @@ fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
context.irBuiltIns,
context.typeTranslator,
context.callToSubstitutedDescriptorMap,
context.extensions.samConversion
context.extensions
),
null
)
@@ -61,7 +61,7 @@ open class InsertImplicitCasts(
private val irBuiltIns: IrBuiltIns,
private val typeTranslator: TypeTranslator,
private val callToSubstitutedDescriptorMap: Map<IrMemberAccessExpression, CallableDescriptor>,
private val samConversion: GeneratorExtensions.SamConversion
private val generatorExtensions: GeneratorExtensions
) : IrElementTransformerVoid() {
private fun KotlinType.toIrType() = typeTranslator.translateType(this)
@@ -191,10 +191,13 @@ open class InsertImplicitCasts(
finallyExpression = finallyExpression?.coerceToUnit()
}
private fun KotlinType.getSubstitutedFunctionTypeForSamType() =
generatorExtensions.samConversion.getSubstitutedFunctionTypeForSamType(this)
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression =
when (expression.operator) {
IrTypeOperator.SAM_CONVERSION -> expression.transformPostfix {
argument = argument.cast(samConversion.getSubstitutedFunctionTypeForSamType(typeOperand.originalKotlinType!!))
argument = argument.cast(typeOperand.originalKotlinType!!.getSubstitutedFunctionTypeForSamType())
}
IrTypeOperator.IMPLICIT_CAST -> {
@@ -251,7 +254,8 @@ open class InsertImplicitCasts(
else
implicitCast(expectedType, IrTypeOperator.IMPLICIT_DYNAMIC_CAST)
valueType.isNullabilityFlexible() && valueType.containsNull() && !expectedType.containsNull() ->
(valueType.isNullabilityFlexible() && valueType.containsNull() || valueType.hasEnhancedNullability()) &&
!expectedType.containsNull() ->
implicitNonNull(valueType, expectedType)
KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType.makeNullable()) ->
@@ -267,8 +271,12 @@ open class InsertImplicitCasts(
}
}
private fun KotlinType.hasEnhancedNullability() =
generatorExtensions.enhancedNullability.hasEnhancedNullability(this)
private fun IrExpression.implicitNonNull(valueType: KotlinType, expectedType: KotlinType): IrExpression {
val nonNullValueType = valueType.upperIfFlexible().makeNotNullable()
val nonNullFlexibleType = valueType.upperIfFlexible().makeNotNullable()
val nonNullValueType = generatorExtensions.enhancedNullability.stripEnhancedNullability(nonNullFlexibleType)
return implicitCast(nonNullValueType, IrTypeOperator.IMPLICIT_NOTNULL).cast(expectedType)
}
@@ -1,7 +1,6 @@
// !API_VERSION: LATEST
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FILE: A.java
import org.jetbrains.annotations.NotNull;
@@ -0,0 +1,31 @@
FILE fqName:<root> fileName:/enhancedNullability.kt
FUN name:use visibility:public modality:FINAL <> (s:kotlin.String) returnType:kotlin.Unit
VALUE_PARAMETER name:s index:0 type:kotlin.String
BLOCK_BODY
FUN name:testUse visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun use (s: kotlin.String): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
s: CALL 'public open fun s (): kotlin.String [operator] declared in <root>.J' type=kotlin.String origin=null
FUN name:testLocalVal visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:local type:kotlin.String [val]
CALL 'public open fun s (): kotlin.String [operator] declared in <root>.J' type=kotlin.String origin=null
FUN name:testReturnValue visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun testReturnValue (): kotlin.String declared in <root>'
CALL 'public open fun s (): kotlin.String [operator] declared in <root>.J' type=kotlin.String origin=null
PROPERTY name:testGlobalVal visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:testGlobalVal type:kotlin.String visibility:private [final,static]
EXPRESSION_BODY
CALL 'public open fun s (): kotlin.String [operator] declared in <root>.J' type=kotlin.String origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-testGlobalVal> visibility:public modality:FINAL <> () returnType:kotlin.String
correspondingProperty: PROPERTY name:testGlobalVal visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-testGlobalVal> (): kotlin.String declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:testGlobalVal type:kotlin.String visibility:private [final,static]' type=kotlin.String origin=null
PROPERTY name:testGlobalValGetter visibility:public modality:FINAL [val]
FUN name:<get-testGlobalValGetter> visibility:public modality:FINAL <> () returnType:kotlin.String
correspondingProperty: PROPERTY name:testGlobalValGetter visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-testGlobalValGetter> (): kotlin.String declared in <root>'
CALL 'public open fun s (): kotlin.String [operator] declared in <root>.J' type=kotlin.String origin=null
@@ -0,0 +1,23 @@
// FILE: enhancedNullability.kt
fun use(s: String) {}
fun testUse() {
use(J.s())
}
fun testLocalVal() {
val local = J.s()
}
fun testReturnValue() = J.s()
val testGlobalVal = J.s()
val testGlobalValGetter get() = J.s()
// FILE: J.java
import org.jetbrains.annotations.*
public class J {
public static @NotNull String s() { return null; }
}
@@ -0,0 +1,36 @@
FILE fqName:<root> fileName:/enhancedNullability.kt
FUN name:use visibility:public modality:FINAL <> (s:kotlin.String) returnType:kotlin.Unit
VALUE_PARAMETER name:s index:0 type:kotlin.String
BLOCK_BODY
FUN name:testUse visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun use (s: kotlin.String): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
s: TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public open fun s (): kotlin.String declared in <root>.J' type=kotlin.String origin=null
FUN name:testLocalVal visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:local type:kotlin.String [val]
TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public open fun s (): kotlin.String declared in <root>.J' type=kotlin.String origin=null
FUN name:testReturnValue visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun testReturnValue (): kotlin.String declared in <root>'
TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public open fun s (): kotlin.String declared in <root>.J' type=kotlin.String origin=null
PROPERTY name:testGlobalVal visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:testGlobalVal type:kotlin.String visibility:private [final,static]
EXPRESSION_BODY
TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public open fun s (): kotlin.String declared in <root>.J' type=kotlin.String origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-testGlobalVal> visibility:public modality:FINAL <> () returnType:kotlin.String
correspondingProperty: PROPERTY name:testGlobalVal visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-testGlobalVal> (): kotlin.String declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:testGlobalVal type:kotlin.String visibility:private [final,static]' type=kotlin.String origin=null
PROPERTY name:testGlobalValGetter visibility:public modality:FINAL [val]
FUN name:<get-testGlobalValGetter> visibility:public modality:FINAL <> () returnType:kotlin.String
correspondingProperty: PROPERTY name:testGlobalValGetter visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-testGlobalValGetter> (): kotlin.String declared in <root>'
TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String
CALL 'public open fun s (): kotlin.String declared in <root>.J' type=kotlin.String origin=null
@@ -1670,6 +1670,11 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
runTest("compiler/testData/ir/irText/types/asOnPlatformType.kt");
}
@TestMetadata("enhancedNullability.kt")
public void testEnhancedNullability() throws Exception {
runTest("compiler/testData/ir/irText/types/enhancedNullability.kt");
}
@TestMetadata("explicitEqualsAndCompareToCallsOnPlatformTypeReceiver.kt")
public void testExplicitEqualsAndCompareToCallsOnPlatformTypeReceiver() throws Exception {
runTest("compiler/testData/ir/irText/types/explicitEqualsAndCompareToCallsOnPlatformTypeReceiver.kt");