diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java index c11aebd4151..d6370045649 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java @@ -110,7 +110,7 @@ public class CallReceiver extends StackValue { return new AsmTypeAndKotlinType(typeMapper.mapType(classDescriptor), classDescriptor.getDefaultType()); } //noinspection ConstantConditions - return new AsmTypeAndKotlinType(callableMethod.getDispatchReceiverType(), null); + return new AsmTypeAndKotlinType(callableMethod.getDispatchReceiverType(), callableMethod.getDispatchReceiverKotlinType()); } // Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have @@ -147,7 +147,7 @@ public class CallReceiver extends StackValue { } return callableMethod != null ? - new AsmTypeAndKotlinType(callableMethod.getExtensionReceiverType(), null) : + new AsmTypeAndKotlinType(callableMethod.getExtensionReceiverType(), callableMethod.getExtensionReceiverKotlinType()) : new AsmTypeAndKotlinType(typeMapper.mapType(extensionReceiver.getType()), extensionReceiver.getType()); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/Callable.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/Callable.kt index 82bce227228..a6f3ab50718 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/Callable.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/Callable.kt @@ -1,22 +1,12 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2000-2018 JetBrains s.r.o. 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.codegen import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -25,8 +15,12 @@ interface Callable { val dispatchReceiverType: Type? + val dispatchReceiverKotlinType: KotlinType? + val extensionReceiverType: Type? + val extensionReceiverKotlinType: KotlinType? + val generateCalleeType: Type? val valueParameterTypes: List @@ -35,12 +29,14 @@ interface Callable { val returnType: Type + val returnKotlinType: KotlinType? + fun genInvokeInstruction(v: InstructionAdapter) fun isStaticCall(): Boolean fun invokeMethodWithArguments(resolvedCall: ResolvedCall<*>, receiver: StackValue, codegen: ExpressionCodegen): StackValue { - return StackValue.functionCall(returnType) { + return StackValue.functionCall(returnType, resolvedCall.resultingDescriptor.returnType) { codegen.invokeMethodWithArguments(this, resolvedCall, receiver) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt index 1d268a70200..9b50f7d30da 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2000-2018 JetBrains s.r.o. 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.codegen @@ -20,6 +9,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESPECIAL import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESTATIC @@ -35,8 +25,11 @@ class CallableMethod( private val signature: JvmMethodSignature, private val invokeOpcode: Int, override val dispatchReceiverType: Type?, + override val dispatchReceiverKotlinType: KotlinType?, override val extensionReceiverType: Type?, + override val extensionReceiverKotlinType: KotlinType?, override val generateCalleeType: Type?, + override val returnKotlinType: KotlinType?, private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode ) : Callable { fun getValueParameters(): List = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index c168ba9fe57..c710ecaed32 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -3879,7 +3879,7 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull public StackValue generateConstructorCall(@NotNull ResolvedCall resolvedCall, @NotNull Type objectType) { - return StackValue.functionCall(objectType, v -> { + return StackValue.functionCall(objectType, null, v -> { v.anew(objectType); v.dup(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 4544d39c2f4..df6981fb415 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -717,11 +717,15 @@ public abstract class StackValue { } public static StackValue operation(Type type, Function1 lambda) { - return new OperationStackValue(type, lambda); + return operation(type, null, lambda); } - public static StackValue functionCall(Type type, Function1 lambda) { - return new FunctionCallStackValue(type, lambda); + public static StackValue operation(Type type, KotlinType kotlinType, Function1 lambda) { + return new OperationStackValue(type, kotlinType, lambda); + } + + public static StackValue functionCall(Type type, KotlinType kotlinType, Function1 lambda) { + return new FunctionCallStackValue(type, kotlinType, lambda); } public static boolean couldSkipReceiverOnStaticCall(StackValue value) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt index 31dd0d77336..7cb72795238 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt @@ -60,7 +60,11 @@ class StackValueWithLeaveTask( } } -open class OperationStackValue(resultType: Type, val lambda: (v: InstructionAdapter) -> Unit) : StackValue(resultType) { +open class OperationStackValue( + resultType: Type, + resultKotlinType: KotlinType?, + val lambda: (v: InstructionAdapter) -> Unit +) : StackValue(resultType, resultKotlinType) { override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) { lambda(v) @@ -68,7 +72,11 @@ open class OperationStackValue(resultType: Type, val lambda: (v: InstructionAdap } } -class FunctionCallStackValue(resultType: Type, lambda: (v: InstructionAdapter) -> Unit) : OperationStackValue(resultType, lambda) +class FunctionCallStackValue( + resultType: Type, + resultKotlinType: KotlinType?, + lambda: (v: InstructionAdapter) -> Unit +) : OperationStackValue(resultType, resultKotlinType, lambda) fun ValueParameterDescriptor.findJavaDefaultArgumentValue(targetType: Type, typeMapper: KotlinTypeMapper): StackValue { val descriptorWithDefaultValue = DFS.dfs( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicCallable.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicCallable.kt index b74a3ee22bd..98aafcea689 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicCallable.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicCallable.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2000-2018 JetBrains s.r.o. 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.codegen.intrinsics @@ -19,6 +8,7 @@ package org.jetbrains.kotlin.codegen.intrinsics import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.Callable import org.jetbrains.kotlin.codegen.CallableMethod +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -52,6 +42,15 @@ open class IntrinsicCallable( override val parameterTypes: Array get() = throw UnsupportedOperationException() + override val dispatchReceiverKotlinType: KotlinType? + get() = null + + override val extensionReceiverKotlinType: KotlinType? + get() = null + + override val returnKotlinType: KotlinType? + get() = null + override fun isStaticCall() = false override val generateCalleeType: Type? diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 71d13569529..aa259473047 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -745,10 +745,11 @@ public class KotlinTypeMapper { if (descriptor instanceof ConstructorDescriptor) { JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal()); Type owner = mapOwner(descriptor); - String defaultImplDesc = mapDefaultMethod(descriptor.getOriginal(), OwnerKind.IMPLEMENTATION).getDescriptor(); + FunctionDescriptor originalDescriptor = descriptor.getOriginal(); + String defaultImplDesc = mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION).getDescriptor(); return new CallableMethod( owner, owner, defaultImplDesc, method, INVOKESPECIAL, - null, null, null, false + null, null, null, null, null, originalDescriptor.getReturnType(), false ); } @@ -764,11 +765,13 @@ public class KotlinTypeMapper { FunctionDescriptor functionDescriptor = findSuperDeclaration(descriptor.getOriginal(), superCall); JvmMethodSignature signature; + KotlinType returnKotlinType; Type owner; Type ownerForDefaultImpl; FunctionDescriptor baseMethodDescriptor; int invokeOpcode; Type thisClass; + KotlinType dispatchReceiverKotlinType; boolean isInterfaceMember = false; if (functionParent instanceof ClassDescriptor) { @@ -790,15 +793,19 @@ public class KotlinTypeMapper { if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) { thisClass = mapClass(currentOwner); + dispatchReceiverKotlinType = currentOwner.getDefaultType(); if (declarationOwner instanceof JavaClassDescriptor || isJvm8InterfaceWithDefaults(declarationOwner)) { invokeOpcode = INVOKESPECIAL; signature = mapSignatureSkipGeneric(functionDescriptor); + returnKotlinType = functionDescriptor.getReturnType(); owner = thisClass; isInterfaceMember = true; } else { invokeOpcode = INVOKESTATIC; - signature = mapSignatureSkipGeneric(descriptor.getOriginal(), OwnerKind.DEFAULT_IMPLS); + FunctionDescriptor originalDescriptor = descriptor.getOriginal(); + signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS); + returnKotlinType = originalDescriptor.getReturnType(); owner = mapDefaultImpls(currentOwner); } } @@ -834,41 +841,53 @@ public class KotlinTypeMapper { signature = isInsideInlineClass ? mapSignatureForInlineErasedClassSkipGeneric(functionToCall) : mapSignatureSkipGeneric(functionToCall); + returnKotlinType = functionToCall.getReturnType(); ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor ? declarationOwner : currentOwner; owner = isInsideInlineClass ? mapErasedInlineClass(receiver) : mapClass(receiver); thisClass = owner; + dispatchReceiverKotlinType = receiver.getDefaultType(); } } else { - signature = mapSignatureSkipGeneric(functionDescriptor.getOriginal()); + FunctionDescriptor originalDescriptor = functionDescriptor.getOriginal(); + signature = mapSignatureSkipGeneric(originalDescriptor); + returnKotlinType = originalDescriptor.getReturnType(); owner = mapOwner(functionDescriptor); ownerForDefaultImpl = owner; baseMethodDescriptor = functionDescriptor; if (functionParent instanceof PackageFragmentDescriptor) { invokeOpcode = INVOKESTATIC; thisClass = null; + dispatchReceiverKotlinType = null; } else if (functionDescriptor instanceof ConstructorDescriptor) { invokeOpcode = INVOKESPECIAL; thisClass = null; + dispatchReceiverKotlinType = null; } else { invokeOpcode = INVOKEVIRTUAL; thisClass = owner; + DeclarationDescriptor ownerDescriptor = functionDescriptor.getContainingDeclaration(); + dispatchReceiverKotlinType = ownerDescriptor instanceof ClassDescriptor ? + ((ClassDescriptor) ownerDescriptor).getDefaultType() : null; } } Type calleeType = isLocalFunction(functionDescriptor) ? owner : null; Type receiverParameterType; + KotlinType extensionReceiverKotlinType; ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getExtensionReceiverParameter(); if (receiverParameter != null) { - receiverParameterType = mapType(receiverParameter.getType()); + extensionReceiverKotlinType = receiverParameter.getType(); + receiverParameterType = mapType(extensionReceiverKotlinType); } else { + extensionReceiverKotlinType = null; receiverParameterType = null; } @@ -876,8 +895,9 @@ public class KotlinTypeMapper { return new CallableMethod( owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode, - thisClass, receiverParameterType, calleeType, - isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE ); + thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType, calleeType, returnKotlinType, + isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE + ); } private boolean isJvm8InterfaceWithDefaults(@NotNull ClassDescriptor ownerForDefault) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicCallable.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicCallable.kt index 21e1b14ed8f..89074e56240 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicCallable.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicCallable.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2000-2018 JetBrains s.r.o. 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.backend.jvm.intrinsics @@ -19,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.Callable import org.jetbrains.kotlin.codegen.CallableMethod +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import java.lang.UnsupportedOperationException @@ -53,6 +43,15 @@ open class IntrinsicCallable( override val parameterTypes: Array get() = throw UnsupportedOperationException() + override val dispatchReceiverKotlinType: KotlinType? + get() = null + + override val extensionReceiverKotlinType: KotlinType? + get() = null + + override val returnKotlinType: KotlinType? + get() = null + override fun isStaticCall() = false override val generateCalleeType: Type? diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt index fdb58a5e118..6f5b09d4bbe 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2000-2018 JetBrains s.r.o. 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.backend.jvm.intrinsics @@ -63,8 +52,12 @@ open class IrIntrinsicFunction( get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. override val dispatchReceiverType: Type? get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + override val dispatchReceiverKotlinType: KotlinType? + get() = null override val extensionReceiverType: Type? get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + override val extensionReceiverKotlinType: KotlinType? + get() = null override val generateCalleeType: Type? get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. override val valueParameterTypes: List @@ -73,6 +66,8 @@ open class IrIntrinsicFunction( get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. override val returnType: Type get() = signature.returnType + override val returnKotlinType: KotlinType? + get() = null override fun isStaticCall(): Boolean { return false diff --git a/compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt b/compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt new file mode 100644 index 00000000000..e2c1990450a --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt @@ -0,0 +1,35 @@ +// !LANGUAGE: +InlineClasses + +inline class Foo(val a: Int) { + fun member(): String = "" + + fun asResult() = a +} + +fun id(x: T): T = x +fun T.idExtension(): T = this + +fun Foo.extension() {} + + +fun test(f: Foo): String { + id(f) // box + id(f).idExtension() // box + + id(f).member() // box unbox + id(f).extension() // box unbox + + val a = id(f) // box unbox + val b = id(f).idExtension() // box unbox + + if (a.asResult() != 10) return "fail" + if (b.asResult() != 10) return "fail" + + return "OK" +} + +fun box(): String { + val f = Foo(10) + + return test(f) +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt new file mode 100644 index 00000000000..4cab3f88177 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt @@ -0,0 +1,28 @@ +// !LANGUAGE: +InlineClasses + +inline class Foo(val a: Int) { + fun member(): String = "" +} + +fun id(x: T): T = x +fun T.idExtension(): T = this + +fun Foo.extension() {} + + +fun test(f: Foo) { + id(f) // box + id(f).idExtension() // box + + id(f).member() // box unbox + id(f).extension() // box unbox + + val a = id(f) // box unbox + val b = id(f).idExtension() // box unbox +} + +// 6 INVOKESTATIC Foo\$Erased.box +// 4 INVOKEVIRTUAL Foo.unbox + +// 0 valueOf +// 0 intValue \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassesAfterSmartCasts.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassesAfterSmartCasts.kt new file mode 100644 index 00000000000..0f0218fe54e --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassesAfterSmartCasts.kt @@ -0,0 +1,28 @@ +// !LANGUAGE: +InlineClasses + +inline class Foo(val x: Int) { + fun member() {} +} + +fun Foo?.extensionOnNullable() {} + +fun test(f: Foo?) { + if (f != null) { + f.member() // unbox + } + + if (f != null) { + f.extensionOnNullable() + } + + if (f != null) { + val a = f + a.member() // unbox + } +} + +// 0 INVOKESTATIC Foo\$Erased.box +// 2 INVOKEVIRTUAL Foo.unbox + +// 0 valueOf +// 0 intValue \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 4f06cb164b2..7836bfa7a77 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1914,6 +1914,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("boxUnboxInlineClassFromMethodReturnType.kt") + public void testBoxUnboxInlineClassFromMethodReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt"); + doTest(fileName); + } + @TestMetadata("callMemberMethodsInsideInlineClass.kt") public void testCallMemberMethodsInsideInlineClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt"); @@ -1937,6 +1943,18 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingOnFunctionCall.kt"); doTest(fileName); } + + @TestMetadata("unboxInlineClassAfterSafeCall.kt") + public void testUnboxInlineClassAfterSafeCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterSafeCall.kt"); + doTest(fileName); + } + + @TestMetadata("unboxInlineClassesAfterSmartCasts.kt") + public void testUnboxInlineClassesAfterSmartCasts() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassesAfterSmartCasts.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/interfaces") diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AbstractAndroidExtensionsExpressionCodegenExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AbstractAndroidExtensionsExpressionCodegenExtension.kt index 3a32f0655ec..2630dfc09d8 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AbstractAndroidExtensionsExpressionCodegenExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AbstractAndroidExtensionsExpressionCodegenExtension.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2000-2018 JetBrains s.r.o. 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.android.synthetic.codegen @@ -20,8 +9,8 @@ import kotlinx.android.extensions.CacheImplementation import kotlinx.android.extensions.CacheImplementation.NO_CACHE import org.jetbrains.kotlin.android.synthetic.AndroidConst import org.jetbrains.kotlin.android.synthetic.codegen.AndroidContainerType.LAYOUT_CONTAINER -import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor +import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticFunction import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty import org.jetbrains.kotlin.codegen.* @@ -37,9 +26,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.org.objectweb.asm.Label -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SYNTHETIC +import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -96,13 +83,13 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC val containerOptions = ContainerOptionsProxy.create(container) if (!containerOptions.getCacheOrDefault(resolvedCall.call.calleeExpression).hasCache) { - return StackValue.functionCall(Type.VOID_TYPE) {} + return StackValue.functionCall(Type.VOID_TYPE, null) {} } if (containerOptions.containerType == AndroidContainerType.UNKNOWN) return null val actualReceiver = StackValue.receiver(resolvedCall, receiver, c.codegen, null) - return StackValue.functionCall(Type.VOID_TYPE) { + return StackValue.functionCall(Type.VOID_TYPE, null) { val bytecodeClassName = c.typeMapper.mapType(container).internalName actualReceiver.put(c.typeMapper.mapType(container), it)