From c83f68151c09391129b3b6950d9704d28030f1ec Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 3 Dec 2019 15:17:02 +0300 Subject: [PATCH] Support @EnhancedNullability in psi2ir --- .../kotlin/fir/Fir2IrTextTestGenerated.java | 5 +++ .../backend/jvm/JvmGeneratorExtensions.kt | 24 +++++++++++++ .../psi2ir/generators/GeneratorExtensions.kt | 12 +++++++ .../transformations/InsertImplicitCasts.kt | 18 +++++++--- .../javaNullCheckThrowsNpe_1_4.kt | 1 - .../irText/types/enhancedNullability.fir.txt | 31 ++++++++++++++++ .../ir/irText/types/enhancedNullability.kt | 23 ++++++++++++ .../ir/irText/types/enhancedNullability.txt | 36 +++++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 5 +++ 9 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/ir/irText/types/enhancedNullability.fir.txt create mode 100644 compiler/testData/ir/irText/types/enhancedNullability.kt create mode 100644 compiler/testData/ir/irText/types/enhancedNullability.txt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java index fcaa91b7935..0b155e6fc09 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java @@ -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"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt index 4386d8102bd..d0720f4d2be 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.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() @@ -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() + } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt index 31010ba2cc2..22d4b2c7954 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt @@ -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() + } + } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt index 4ad58124c07..a4a3b2c2bde 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt @@ -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, - 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) } diff --git a/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsNpe_1_4.kt b/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsNpe_1_4.kt index 53a26871f42..afc82eb35da 100644 --- a/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsNpe_1_4.kt +++ b/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsNpe_1_4.kt @@ -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; diff --git a/compiler/testData/ir/irText/types/enhancedNullability.fir.txt b/compiler/testData/ir/irText/types/enhancedNullability.fir.txt new file mode 100644 index 00000000000..986052738d6 --- /dev/null +++ b/compiler/testData/ir/irText/types/enhancedNullability.fir.txt @@ -0,0 +1,31 @@ +FILE fqName: 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 ' type=kotlin.Unit origin=null + s: CALL 'public open fun s (): kotlin.String [operator] declared in .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 .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 ' + CALL 'public open fun s (): kotlin.String [operator] declared in .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 .J' type=kotlin.String origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: 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 (): kotlin.String declared in ' + 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: 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 (): kotlin.String declared in ' + CALL 'public open fun s (): kotlin.String [operator] declared in .J' type=kotlin.String origin=null diff --git a/compiler/testData/ir/irText/types/enhancedNullability.kt b/compiler/testData/ir/irText/types/enhancedNullability.kt new file mode 100644 index 00000000000..b0e32bc5d94 --- /dev/null +++ b/compiler/testData/ir/irText/types/enhancedNullability.kt @@ -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; } +} diff --git a/compiler/testData/ir/irText/types/enhancedNullability.txt b/compiler/testData/ir/irText/types/enhancedNullability.txt new file mode 100644 index 00000000000..0f43c87601e --- /dev/null +++ b/compiler/testData/ir/irText/types/enhancedNullability.txt @@ -0,0 +1,36 @@ +FILE fqName: 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 ' 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 .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 .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 ' + TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String + CALL 'public open fun s (): kotlin.String declared in .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 .J' type=kotlin.String origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: 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 (): kotlin.String declared in ' + 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: 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 (): kotlin.String declared in ' + TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String + CALL 'public open fun s (): kotlin.String declared in .J' type=kotlin.String origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 6c633f247ed..e1ff3bfbb18 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -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");