Compare commits

...

5 Commits

Author SHA1 Message Date
Ilmir Usmanov
8ddcd78d83 IC Mangling: Use correct java field type if the type is inline class
in JVM_IR BE.
 #KT-26445
2020-12-11 12:29:35 +01:00
Ilmir Usmanov
cab14a559e IC Mangling: Use correct java field type if the type is inline class
in old JVM BE.
 #KT-26445
2020-12-11 12:29:34 +01:00
Ilmir Usmanov
9dc847cb4c IC Mangling: Change test since we pass boxed inline class to java method
#KT-28214
2020-12-11 12:29:34 +01:00
Ilmir Usmanov
b3e20adf6c IC Mangling: Do not mangle functions with inline classes from Java
in JVM_IR BE. Map types to boxed variants, when mapping signatures.
 #KT-26445
2020-12-11 12:29:25 +01:00
Ilmir Usmanov
681d6d5c16 IC Mangling: Do not mangle functions with inline classes from Java
in old JVM BE. Map types to boxed variants, when mapping signatures.
 #KT-26445
2020-12-11 12:29:13 +01:00
18 changed files with 301 additions and 11 deletions

View File

@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.load.java.DescriptorsJvmAbiUtil;
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
import org.jetbrains.kotlin.load.kotlin.DescriptorBasedTypeSignatureMappingKt;
import org.jetbrains.kotlin.load.kotlin.MethodSignatureMappingKt;
import org.jetbrains.kotlin.name.Name;
@@ -2404,9 +2405,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
fieldName = KotlinTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty);
}
KotlinType propertyType = propertyDescriptor.getOriginal().getType();
if (propertyDescriptor instanceof JavaPropertyDescriptor && InlineClassesUtilsKt.isInlineClassType(propertyType)) {
propertyType = TypeUtils.makeNullable(propertyType);
}
return StackValue.property(
propertyDescriptor, backingFieldOwner,
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyType),
isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall, skipLateinitAssertion,
isDelegatedProperty && forceField ? delegateType : null
);
@@ -4375,6 +4381,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Type exprType = expressionType(expr);
KotlinType exprKotlinType = kotlinType(expr);
if (exprKotlinType != null && InlineClassesUtilsKt.isInlineClassType(exprKotlinType) &&
FlexibleTypesKt.isNullabilityFlexible(exprKotlinType)) {
exprKotlinType = TypeUtils.makeNullable(exprKotlinType);
}
StackValue value;
if (compileTimeConstant != null) {
value = StackValue.constant(compileTimeConstant.getValue(), exprType, exprKotlinType);

View File

@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.load.java.descriptors.getImplClassNameForDeserialized
import org.jetbrains.kotlin.load.java.getJvmMethodNameIfSpecial
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
@@ -995,7 +996,8 @@ class KotlinTypeMapper @JvmOverloads constructor(
if ((isFunctionExpression(descriptor) || isFunctionLiteral(descriptor)) && returnType.isInlineClassType()) return true
return isJvmPrimitive(returnType) &&
getAllOverriddenDescriptors(descriptor).any { !isJvmPrimitive(it.returnType!!) }
getAllOverriddenDescriptors(descriptor).any { !isJvmPrimitive(it.returnType!!) } ||
returnType.isInlineClassType() && descriptor is JavaMethodDescriptor
}
private fun isJvmPrimitive(kotlinType: KotlinType) =
@@ -1061,7 +1063,11 @@ class KotlinTypeMapper @JvmOverloads constructor(
fun writeParameterType(sw: JvmSignatureWriter, type: KotlinType, callableDescriptor: CallableDescriptor?) {
if (sw.skipGenericSignature()) {
mapType(type, sw, TypeMappingMode.DEFAULT)
if (type.isInlineClassType() && callableDescriptor is JavaMethodDescriptor) {
mapType(type, sw, TypeMappingMode.GENERIC_ARGUMENT)
} else {
mapType(type, sw, TypeMappingMode.DEFAULT)
}
return
}

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
@@ -84,6 +85,7 @@ fun getManglingSuffixBasedOnKotlinSignature(
): String? {
if (descriptor !is FunctionDescriptor) return null
if (descriptor is ConstructorDescriptor) return null
if (descriptor is JavaMethodDescriptor) return null
if (InlineClassDescriptorResolver.isSynthesizedBoxOrUnboxMethod(descriptor)) return null
// Don't mangle functions with '@JvmName' annotation.

View File

@@ -15113,6 +15113,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractFirBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: ");
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("inlineClasInSignature.kt")
public void testInlineClasInSignature() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignature.kt");
}
@TestMetadata("inlineClasInSignatureNonNull.kt")
public void testInlineClasInSignatureNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNonNull.kt");
}
@TestMetadata("inlineClasInSignatureNullable.kt")
public void testInlineClasInSignatureNullable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNullable.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isFromJava
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
@@ -665,7 +666,8 @@ class ExpressionCodegen(
?: receiverType ?: typeMapper.mapClass(callee.parentAsClass)
val ownerName = ownerType.internalName
val fieldName = callee.name.asString()
val fieldType = callee.type.asmType
val calleeIrType = if (callee.isFromJava() && callee.type.isInlined()) callee.type.makeNullable() else callee.type
val fieldType = calleeIrType.asmType
return if (expression is IrSetField) {
val value = expression.value.accept(this, data)
// We only initialize enum entries with a subtype of `fieldType` and can avoid the CHECKCAST.

View File

@@ -195,7 +195,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
// See also: KotlinTypeMapper.forceBoxedReturnType
private fun forceBoxedReturnType(function: IrFunction): Boolean =
isBoxMethodForInlineClass(function) || forceFoxedReturnTypeOnOverride(function) || forceBoxedReturnTypeOnDefaultImplFun(function)
isBoxMethodForInlineClass(function) || forceFoxedReturnTypeOnOverride(function) || forceBoxedReturnTypeOnDefaultImplFun(function) ||
function.isFromJava() && function.returnType.isInlined()
private fun forceFoxedReturnTypeOnOverride(function: IrFunction) =
function is IrSimpleFunction &&
@@ -320,7 +321,11 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
private fun writeParameterType(sw: JvmSignatureWriter, type: IrType, declaration: IrDeclaration) {
if (sw.skipGenericSignature()) {
typeMapper.mapType(type, TypeMappingMode.DEFAULT, sw)
if (type.isInlined() && declaration.isFromJava()) {
typeMapper.mapType(type, TypeMappingMode.GENERIC_ARGUMENT, sw)
} else {
typeMapper.mapType(type, TypeMappingMode.DEFAULT, sw)
}
return
}

View File

@@ -81,7 +81,7 @@ class MemoizedInlineClassReplacements(
}
// Otherwise, mangle functions with mangled parameters, ignoring constructors
it is IrSimpleFunction && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) ->
it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) ->
if (it.dispatchReceiverParameter != null)
createMethodReplacement(it)
else

View File

@@ -0,0 +1,31 @@
// LANGUAGE: +InlineClasses
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: WithInlineClass.java
import kotlin.UInt;
public class WithInlineClass {
public static UInt UINT = null;
public static void acceptsUInt(UInt u) {
UINT = u;
}
public static UInt provideUInt() {
return UINT;
}
}
// FILE: box.kt
fun box(): String {
WithInlineClass.acceptsUInt(1u)
var res = WithInlineClass.provideUInt()
if (res != 1u) return "FAIL 1 $res"
WithInlineClass.UINT = 2u
res = WithInlineClass.UINT
if (res != 2u) return "FAIL 2 $res"
return "OK"
}

View File

@@ -0,0 +1,34 @@
// LANGUAGE: +InlineClasses
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: WithInlineClass.java
import kotlin.UInt;
import org.jetbrains.annotations.NotNull;
public class WithInlineClass {
@NotNull
public static UInt UINT = null;
public static void acceptsUInt(@NotNull UInt u) {
UINT = u;
}
@NotNull
public static UInt provideUInt() {
return UINT;
}
}
// FILE: box.kt
fun box(): String {
WithInlineClass.acceptsUInt(1u)
var res = WithInlineClass.provideUInt()
if (res != 1u) return "FAIL 1 $res"
WithInlineClass.UINT = 2u
res = WithInlineClass.UINT
if (res != 2u) return "FAIL 2 $res"
return "OK"
}

View File

@@ -0,0 +1,34 @@
// LANGUAGE: +InlineClasses
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: WithInlineClass.java
import kotlin.UInt;
import org.jetbrains.annotations.Nullable;
public class WithInlineClass {
@Nullable
public static UInt UINT = null;
public static void acceptsUInt(@Nullable UInt u) {
UINT = u;
}
@Nullable
public static UInt provideUInt() {
return UINT;
}
}
// FILE: box.kt
fun box(): String {
WithInlineClass.acceptsUInt(1u)
var res = WithInlineClass.provideUInt()
if (res != 1u) return "FAIL 1 $res"
WithInlineClass.UINT = 2u
res = WithInlineClass.UINT
if (res != 2u) return "FAIL 2 $res"
return "OK"
}

View File

@@ -15,8 +15,10 @@ fun box(): String {
val mh = MethodHandles.lookup().unreflect(::foo.javaMethod!!)
// TODO: it's unclear whether this should throw or not, see KT-28214.
val r1 = mh.invokeExact(Z("OK")) as String
if (r1 != "OK") return "Fail r1: $r1"
return mh.invokeExact("OK") as String
return try {
mh.invokeExact(Z("OK"))
"FAIL"
} catch (ignored: java.lang.invoke.WrongMethodTypeException) {
"OK"
}
}

View File

@@ -15113,6 +15113,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("inlineClasInSignature.kt")
public void testInlineClasInSignature() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignature.kt");
}
@TestMetadata("inlineClasInSignatureNonNull.kt")
public void testInlineClasInSignatureNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNonNull.kt");
}
@TestMetadata("inlineClasInSignatureNullable.kt")
public void testInlineClasInSignatureNullable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNullable.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -15113,6 +15113,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("inlineClasInSignature.kt")
public void testInlineClasInSignature() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignature.kt");
}
@TestMetadata("inlineClasInSignatureNonNull.kt")
public void testInlineClasInSignatureNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNonNull.kt");
}
@TestMetadata("inlineClasInSignatureNullable.kt")
public void testInlineClasInSignatureNullable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNullable.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -15113,6 +15113,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractIrBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("inlineClasInSignature.kt")
public void testInlineClasInSignature() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignature.kt");
}
@TestMetadata("inlineClasInSignatureNonNull.kt")
public void testInlineClasInSignatureNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNonNull.kt");
}
@TestMetadata("inlineClasInSignatureNullable.kt")
public void testInlineClasInSignatureNullable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/javaInterop/inlineClasInSignatureNullable.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -13073,6 +13073,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractIrJsCodegenBoxES6Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -13073,6 +13073,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -13138,6 +13138,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -7459,6 +7459,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/javaInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class JavaInterop extends AbstractIrCodegenBoxWasmTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
}
public void testAllFilesPresentInJavaInterop() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/javaInterop"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)