diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 895e4287589..ba272cd368b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2264,7 +2264,7 @@ public class ExpressionCodegen extends KtVisitor impleme receiver = StackValue.receiverWithoutReceiverArgument(receiver); } - return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver); + return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver, resolvedCall); } if (descriptor instanceof ClassDescriptor) { @@ -2411,7 +2411,7 @@ public class ExpressionCodegen extends KtVisitor impleme @Nullable ClassDescriptor superCallTarget, @NotNull StackValue receiver ) { - return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver); + return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver, null); } private CodegenContext getBackingFieldContext( @@ -2434,7 +2434,8 @@ public class ExpressionCodegen extends KtVisitor impleme boolean syntheticBackingField, @Nullable ClassDescriptor superCallTarget, boolean skipAccessorsForPrivateFieldInOuterClass, - StackValue receiver + @NotNull StackValue receiver, + @Nullable ResolvedCall resolvedCall ) { if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) { return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver); @@ -2530,13 +2531,13 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.property(propertyDescriptor, backingFieldOwner, typeMapper.mapType( isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()), - isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver); + isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall); } @NotNull private StackValue.Property intermediateValueForSyntheticExtensionProperty( @NotNull SyntheticJavaPropertyDescriptor propertyDescriptor, - StackValue receiver + @NotNull StackValue receiver ) { Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType()); CallableMethod callableGetter = @@ -2544,7 +2545,7 @@ public class ExpressionCodegen extends KtVisitor impleme FunctionDescriptor setMethod = propertyDescriptor.getSetMethod(); CallableMethod callableSetter = setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null; - return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, state, receiver); + return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, receiver, this, null); } @Override @@ -2831,8 +2832,12 @@ public class ExpressionCodegen extends KtVisitor impleme return getOrCreateCallGenerator(descriptor, function, null, true); } - @NotNull CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall resolvedCall) { + return getOrCreateCallGenerator(resolvedCall, resolvedCall.getResultingDescriptor()); + } + + @NotNull + CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall resolvedCall, @NotNull CallableDescriptor descriptor) { Map typeArguments = resolvedCall.getTypeArguments(); TypeParameterMappings mappings = new TypeParameterMappings(); for (Map.Entry entry : typeArguments.entrySet()) { @@ -2858,8 +2863,7 @@ public class ExpressionCodegen extends KtVisitor impleme ); } } - return getOrCreateCallGenerator( - resolvedCall.getResultingDescriptor(), resolvedCall.getCall().getCallElement(), mappings, false); + return getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement(), mappings, false); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index 8df801d3ebb..d2381c3fc5d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -391,7 +391,8 @@ public abstract class MemberCodegen { } public boolean isInlineMethodContext() { - return InlineUtil.isInline(getContextDescriptor()); + return InlineUtil.isInline(getFunctionDescriptor()); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index e5a3ceedd11..0c89e612733 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -46,7 +46,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes; 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.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.types.expressions.DoubleColonLHS; import org.jetbrains.kotlin.types.expressions.LabelResolver; import org.jetbrains.org.objectweb.asm.Label; @@ -211,8 +211,8 @@ public class InlineCodegen extends CallGenerator { : jvmSignature.getAsmMethod(); MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod); - - if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(functionDescriptor instanceof DeserializedSimpleFunctionDescriptor)) { + final CallableMemberDescriptor directMember = JvmCodegenUtil.getDirectMember(functionDescriptor); + if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(directMember instanceof DeserializedCallableMemberDescriptor)) { return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod); } @@ -220,7 +220,7 @@ public class InlineCodegen extends CallGenerator { state.getInlineCache().getMethodNodeById(), methodId, new Function0() { @Override public SMAPAndMethodNode invoke() { - SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(functionDescriptor, state, asmMethod); + SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod); if (result == null) { throw new IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor); } @@ -245,13 +245,13 @@ public class InlineCodegen extends CallGenerator { @Nullable private static SMAPAndMethodNode doCreateMethodNodeFromCompiled( - @NotNull FunctionDescriptor functionDescriptor, + @NotNull CallableMemberDescriptor callableDescriptor, @NotNull final GenerationState state, @NotNull Method asmMethod ) { KotlinTypeMapper typeMapper = state.getTypeMapper(); - if (isBuiltInArrayIntrinsic(functionDescriptor)) { + if (isBuiltInArrayIntrinsic(callableDescriptor)) { ClassId classId = IntrinsicArrayConstructorsKt.getClassId(); byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, new Function0() { @Override @@ -263,10 +263,10 @@ public class InlineCodegen extends CallGenerator { return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId, state); } - assert functionDescriptor instanceof DeserializedSimpleFunctionDescriptor : "Not a deserialized function: " + functionDescriptor; + assert callableDescriptor instanceof DeserializedCallableMemberDescriptor : "Not a deserialized function or proper: " + callableDescriptor; KotlinTypeMapper.ContainingClassesInfo containingClasses = - typeMapper.getContainingClassesForDeserializedCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor); + typeMapper.getContainingClassesForDeserializedCallable((DeserializedCallableMemberDescriptor) callableDescriptor); final ClassId containerId = containingClasses.getImplClassId(); @@ -292,7 +292,7 @@ public class InlineCodegen extends CallGenerator { @NotNull private static SMAPAndMethodNode doCreateMethodNodeFromSource( - @NotNull FunctionDescriptor functionDescriptor, + @NotNull FunctionDescriptor callableDescriptor, @NotNull JvmMethodSignature jvmSignature, @NotNull ExpressionCodegen codegen, @NotNull CodegenContext context, @@ -300,16 +300,16 @@ public class InlineCodegen extends CallGenerator { @NotNull GenerationState state, @NotNull Method asmMethod ) { - PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); + PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor); - if (!(element instanceof KtNamedFunction)) { - throw new IllegalStateException("Couldn't find declaration for function " + functionDescriptor); + if (!(element instanceof KtNamedFunction || element instanceof KtPropertyAccessor)) { + throw new IllegalStateException("Couldn't find declaration for function " + callableDescriptor); } - KtNamedFunction inliningFunction = (KtNamedFunction) element; + KtDeclarationWithBody inliningFunction = (KtDeclarationWithBody) element; MethodNode node = new MethodNode( InlineCodegenUtil.API, - getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0), + getMethodAsmFlags(callableDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0), asmMethod.getName(), asmMethod.getDescriptor(), null, null @@ -319,23 +319,26 @@ public class InlineCodegen extends CallGenerator { MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); CodegenContext parentContext = context.getParentContext(); assert parentContext != null : "Context has no parent: " + context; - MethodContext methodContext = parentContext.intoFunction(functionDescriptor); + MethodContext methodContext = parentContext.intoFunction(callableDescriptor); SMAP smap; if (callDefault) { - Type implementationOwner = state.getTypeMapper().mapImplementationOwner(functionDescriptor); + Type implementationOwner = state.getTypeMapper().mapImplementationOwner(callableDescriptor); FakeMemberCodegen parentCodegen = new FakeMemberCodegen( codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(), implementationOwner.getInternalName() ); + if (!(element instanceof KtNamedFunction)) { + throw new IllegalStateException("Propertiy accessors with default parameters not supported " + callableDescriptor); + } FunctionCodegen.generateDefaultImplBody( - methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, - inliningFunction, parentCodegen, asmMethod + methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, + (KtNamedFunction) inliningFunction, parentCodegen, asmMethod ); smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); } else { - smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen); + smap = generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen); } maxCalcAdapter.visitMaxs(-1, -1); maxCalcAdapter.visitEnd(); @@ -343,11 +346,11 @@ public class InlineCodegen extends CallGenerator { return new SMAPAndMethodNode(node, smap); } - private static boolean isBuiltInArrayIntrinsic(@NotNull FunctionDescriptor functionDescriptor) { - if (functionDescriptor instanceof FictitiousArrayConstructor) return true; - String name = functionDescriptor.getName().asString(); + private static boolean isBuiltInArrayIntrinsic(@NotNull CallableMemberDescriptor callableDescriptor) { + if (callableDescriptor instanceof FictitiousArrayConstructor) return true; + String name = callableDescriptor.getName().asString(); return (name.equals("arrayOf") || name.equals("emptyArray")) && - functionDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment; + callableDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment; } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt index a9180663778..c020dae941a 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt @@ -22,6 +22,8 @@ import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.jvm.BitEncoding +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmMethodSignature import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil fun inlineFunctionsJvmNames(header: KotlinClassHeader): Set { @@ -31,12 +33,14 @@ fun inlineFunctionsJvmNames(header: KotlinClassHeader): Set { return when (header.kind) { KotlinClassHeader.Kind.CLASS -> { val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(BitEncoding.decodeBytes(annotationData), strings) - inlineFunctionsJvmNames(classProto.functionList, nameResolver, classProto.typeTable) + inlineFunctionsJvmNames(classProto.functionList, nameResolver, classProto.typeTable) + + inlineAccessorsJvmNames(classProto.propertyList, nameResolver) } KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> { val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(BitEncoding.decodeBytes(annotationData), strings) - inlineFunctionsJvmNames(packageProto.functionList, nameResolver, packageProto.typeTable) + inlineFunctionsJvmNames(packageProto.functionList, nameResolver, packageProto.typeTable) + + inlineAccessorsJvmNames(packageProto.propertyList, nameResolver) } else -> emptySet() } @@ -50,3 +54,27 @@ private fun inlineFunctionsJvmNames(functions: List, nameReso } return jvmNames.toSet() } + +private fun inlineAccessorsJvmNames(properties: List, nameResolver: NameResolver): Set { + val propertiesWithInlineAccessors = properties.filter { proto -> + proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.getterFlags) || + proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.setterFlags) + } + val inlineAccessors = arrayListOf() + propertiesWithInlineAccessors.forEach { proto -> + if (proto.hasExtension(JvmProtoBuf.propertySignature)) { + val signature = proto.getExtension(JvmProtoBuf.propertySignature) + if (proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.getterFlags)) { + inlineAccessors.add(signature.getter) + } + + if (proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.setterFlags)) { + inlineAccessors.add(signature.setter) + } + } + } + + return inlineAccessors.mapNotNull { + nameResolver.getString(it.name) + nameResolver.getString(it.desc) + }.toSet() +} diff --git a/compiler/testData/codegen/boxInline/property/simple.kt b/compiler/testData/codegen/boxInline/property/simple.kt new file mode 100644 index 00000000000..c8a6f4dff07 --- /dev/null +++ b/compiler/testData/codegen/boxInline/property/simple.kt @@ -0,0 +1,25 @@ +// FILE: 1.kt +package test + +var value: Int = 0 + +inline var z: Int + get() = ++value + set(p: Int) { value = p } + +// FILE: 2.kt +import test.* + +fun box(): String { + val v = z + if (value != 1) return "fail 1: $value" + + z = v + 2 + + if (value != 3) return "fail 2: $value" + var p = z + + if (value != 4) return "fail 3: $value" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/property/simpleExtension.kt b/compiler/testData/codegen/boxInline/property/simpleExtension.kt new file mode 100644 index 00000000000..5a9db92386c --- /dev/null +++ b/compiler/testData/codegen/boxInline/property/simpleExtension.kt @@ -0,0 +1,25 @@ +// FILE: 1.kt +package test + +var value: Int = 0 + +inline var Int.z: Int + get() = this + ++value + set(p: Int) { value = p + this} + +// FILE: 2.kt +import test.* + +fun box(): String { + val v = 11.z + if (v != 12) return "fail 1: $v" + + 11.z = v + 2 + + if (value != 25) return "fail 2: $value" + var p = 11.z + + if (p != 37) return "fail 3: $p" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inline/property/simple.kt b/compiler/testData/codegen/bytecodeText/inline/property/simple.kt new file mode 100644 index 00000000000..e64ed8103bd --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inline/property/simple.kt @@ -0,0 +1,24 @@ +package test + +var value: Int = 0 + +inline var z: Int + get() = ++value + set(p: Int) { value = p } + +fun box(): String { + val v = z + if (value != 1) return "fail 1: $value" + + z = v + 2 + + if (value != 3) return "fail 2: $value" + var p = z + + if (value != 4) return "fail 3: $value" + + return "OK1" +} + +// 0 SimpleKt.getZ +// 0 SimpleKt.setZ \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 9816b8fbc95..9a982eb3b3b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -1514,6 +1514,27 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo } } + @TestMetadata("compiler/testData/codegen/boxInline/property") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Property extends AbstractBlackBoxInlineCodegenTest { + public void testAllFilesPresentInProperty() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/property"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simple.kt"); + doTest(fileName); + } + + @TestMetadata("simpleExtension.kt") + public void testSimpleExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simpleExtension.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/reified") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 2b468bd97e3..f530c5d533c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1008,6 +1008,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/whenMappingOnCallSite.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/bytecodeText/inline/property") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Property extends AbstractBytecodeTextTest { + public void testAllFilesPresentInProperty() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline/property"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/property/simple.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/bytecodeText/interfaces") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 564ea379a61..ca0f47d7a67 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1514,6 +1514,27 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi } } + @TestMetadata("compiler/testData/codegen/boxInline/property") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Property extends AbstractCompileKotlinAgainstInlineKotlinTest { + public void testAllFilesPresentInProperty() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/property"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simple.kt"); + doTest(fileName); + } + + @TestMetadata("simpleExtension.kt") + public void testSimpleExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simpleExtension.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/reified") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)