diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 7d9fd09d72f..fece669dec5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -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; @@ -197,7 +186,7 @@ public class AsmUtil { } public static boolean isStaticKind(OwnerKind kind) { - return kind == OwnerKind.PACKAGE || kind == OwnerKind.DEFAULT_IMPLS; + return kind == OwnerKind.PACKAGE || kind == OwnerKind.DEFAULT_IMPLS || kind == OwnerKind.ERASED_INLINE_CLASS; } public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java index 63efb709bae..dc4fdbe0fa8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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; @@ -22,6 +11,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; @@ -96,13 +86,16 @@ public class CallReceiver extends StackValue { return Type.VOID_TYPE; } + DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (callableMethod != null) { + if (InlineClassesUtilsKt.isInlineClass(container)) { + return typeMapper.mapType((ClassDescriptor) container); + } return callableMethod.getDispatchReceiverType(); } // Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have // all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver. - DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (container instanceof ClassDescriptor) { return typeMapper.mapClass((ClassDescriptor) container); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java index 50618dc020d..9d62b3a83ad 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java @@ -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; @@ -91,6 +80,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen? +) : ClassBodyCodegen(aClass, context, v, state, parentCodegen) { + override fun generateDeclaration() { + v.defineClass( + myClass.psiOrParent, state.classFileVersion, Opcodes.ACC_FINAL or Opcodes.ACC_STATIC or Opcodes.ACC_PUBLIC, + typeMapper.mapErasedInlineClass(descriptor).internalName, + null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY + ) + v.visitSource(myClass.containingKtFile.name, null) + } + + override fun generateKotlinMetadataAnnotation() { + writeSyntheticClassMetadata(v, state) + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 80396eed99e..7c1d37ee4b8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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; @@ -1667,6 +1656,12 @@ public class ExpressionCodegen extends KtVisitor impleme if (descriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + // `this` is represented as first parameter of function in erased inline class + if (contextKind() == OwnerKind.ERASED_INLINE_CLASS) { + Type underlyingRepresentationType = typeMapper.mapType(propertyDescriptor.getType()); + return StackValue.local(0, underlyingRepresentationType); + } + Collection codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject()); if (!codegenExtensions.isEmpty() && resolvedCall != null) { ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(this, typeMapper, v); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 8f3ae9054c8..a0cdbe7cbb7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt; import org.jetbrains.kotlin.resolve.constants.ArrayValue; import org.jetbrains.kotlin.resolve.constants.ConstantValue; @@ -172,7 +173,8 @@ public class FunctionCodegen { @NotNull FunctionGenerationStrategy strategy ) { OwnerKind contextKind = methodContext.getContextKind(); - if (isInterface(functionDescriptor.getContainingDeclaration()) && + DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); + if (isInterface(containingDeclaration) && functionDescriptor.getVisibility() == Visibilities.PRIVATE && !processInterfaceMember(functionDescriptor, contextKind, state)) { return; @@ -230,21 +232,55 @@ public class FunctionCodegen { boolean isOpenSuspendInClass = functionDescriptor.isSuspend() && functionDescriptor.getModality() != Modality.ABSTRACT && isOverridable(functionDescriptor) && - !isInterface(functionDescriptor.getContainingDeclaration()) && - !(functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) && + !isInterface(containingDeclaration) && + !(containingDeclaration instanceof PackageFragmentDescriptor) && origin.getOriginKind() != JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL; + boolean isMethodInInlineClassWrapper = + isClass(containingDeclaration) && + ((ClassDescriptor) containingDeclaration).isInline() && + contextKind != OwnerKind.ERASED_INLINE_CLASS && + functionDescriptor instanceof SimpleFunctionDescriptor; + if (isOpenSuspendInClass) { generateOpenMethodInSuspendClass( origin, functionDescriptor, methodContext, strategy, mv, jvmSignature, asmMethod, flags, staticInCompanionObject ); } + else if (isMethodInInlineClassWrapper) { + generateMethodInsideInlineClassWrapper(origin, functionDescriptor, (ClassDescriptor) containingDeclaration, mv); + } else { generateMethodBody( origin, functionDescriptor, methodContext, strategy, mv, jvmSignature, staticInCompanionObject ); } + } + private void generateMethodInsideInlineClassWrapper( + @NotNull JvmDeclarationOrigin origin, + @NotNull FunctionDescriptor functionDescriptor, + ClassDescriptor containingDeclaration, + MethodVisitor mv + ) { + mv.visitCode(); + + Type inlineErasedType = typeMapper.mapErasedInlineClass(containingDeclaration); + Method erasedMethodImpl = typeMapper.mapAsmMethod(functionDescriptor.getOriginal(), OwnerKind.ERASED_INLINE_CLASS); + + Type fieldOwnerType = typeMapper.mapClass(containingDeclaration); + + ValueParameterDescriptor valueRepresentation = InlineClassesUtilsKt.underlyingRepresentation(containingDeclaration); + if (valueRepresentation == null) return; + + Type fieldType = typeMapper.mapType(valueRepresentation); + + generateDelegateToStaticErasedVersion( + mv, erasedMethodImpl, inlineErasedType.getInternalName(), + fieldOwnerType, valueRepresentation.getName().asString(), fieldType + ); + + endVisit(mv, null, origin.getElement()); } private void generateOpenMethodInSuspendClass( @@ -792,6 +828,35 @@ public class FunctionCodegen { iv.areturn(asmMethod.getReturnType()); } + private static void generateDelegateToStaticErasedVersion( + @NotNull MethodVisitor mv, + @NotNull Method erasedStaticAsmMethod, + @NotNull String classToDelegateTo, + @NotNull Type fieldOwnerType, + @NotNull String fieldName, + @NotNull Type fieldType + ) { + InstructionAdapter iv = new InstructionAdapter(mv); + Type[] argTypes = erasedStaticAsmMethod.getArgumentTypes(); + + Label label = new Label(); + iv.visitLabel(label); + iv.visitLineNumber(1, label); + + iv.load(0, AsmTypes.OBJECT_TYPE); + iv.visitFieldInsn(Opcodes.GETFIELD, fieldOwnerType.getInternalName(), fieldName, fieldType.getDescriptor()); + + int k = 1; + for (int i = 1; i < argTypes.length; i++) { + Type argType = argTypes[i]; + iv.load(k, argType); + k += argType.getSize(); + } + + iv.invokestatic(classToDelegateTo, erasedStaticAsmMethod.getName(), erasedStaticAsmMethod.getDescriptor(), false); + iv.areturn(erasedStaticAsmMethod.getReturnType()); + } + private static void generateDelegateToStaticMethodBody( boolean isStatic, @NotNull MethodVisitor mv, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index ec95dad43ae..6de8cd34231 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -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.codegen; @@ -243,6 +232,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + @Override + protected void generateErasedInlineClassIfNeeded() { + if (!(myClass instanceof KtClass)) return; + if (!descriptor.isInline()) return; + + Type erasedInlineClassType = state.getTypeMapper().mapErasedInlineClass(descriptor); + ClassBuilder builder = state.getFactory().newVisitor( + JvmDeclarationOriginKt.ErasedInlineClassOrigin(myClass.getPsiOrParent(), descriptor), + erasedInlineClassType, + myClass.getContainingKtFile() + ); + + CodegenContext parentContext = context.getParentContext(); + assert parentContext != null : "Parent context of inline class declaration should not be null"; + + ClassContext erasedInlineClassContext = parentContext.intoWrapperForErasedInlineClass(descriptor, state); + new ErasedInlineClassBodyCodegen((KtClass) myClass, erasedInlineClassContext, builder, state, this).generate(); + } + @Override protected void generateKotlinMetadataAnnotation() { generateKotlinClassMetadataAnnotation(descriptor, false); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/OwnerKind.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/OwnerKind.kt index c217dce50d6..3791ea86c03 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/OwnerKind.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/OwnerKind.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 @@ -24,7 +13,8 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor enum class OwnerKind { PACKAGE, IMPLEMENTATION, - DEFAULT_IMPLS; + DEFAULT_IMPLS, + ERASED_INLINE_CLASS; companion object { fun getMemberOwnerKind(descriptor: DeclarationDescriptor): OwnerKind = when (descriptor) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index f927a24b8c6..3114d3ce665 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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; @@ -240,9 +229,11 @@ public class PropertyCodegen { } private static boolean areAccessorsNeededForPrimaryConstructorProperty( - @NotNull PropertyDescriptor descriptor + @NotNull PropertyDescriptor descriptor, + @NotNull OwnerKind kind ) { if (hasJvmFieldAnnotation(descriptor)) return false; + if (kind == OwnerKind.ERASED_INLINE_CLASS) return false; return !Visibilities.isPrivate(descriptor.getVisibility()); } @@ -250,7 +241,7 @@ public class PropertyCodegen { public void generatePrimaryConstructorProperty(@NotNull KtParameter p, @NotNull PropertyDescriptor descriptor) { genBackingFieldAndAnnotations(p, descriptor, true); - if (areAccessorsNeededForPrimaryConstructorProperty(descriptor)) { + if (areAccessorsNeededForPrimaryConstructorProperty(descriptor, context.getContextKind())) { generateGetter(p, descriptor, null); generateSetter(p, descriptor, null); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java index 16296614fda..2d64a3c3966 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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.context; @@ -349,6 +338,10 @@ public abstract class CodegenContext { return new ClosureContext(typeMapper, jvmViewOfSuspendLambda, this, localLookup, originalSuspendLambdaDescriptor); } + public ClassContext intoWrapperForErasedInlineClass(ClassDescriptor descriptor, GenerationState state) { + return new ClassContext(state.getTypeMapper(), descriptor, OwnerKind.ERASED_INLINE_CLASS, this, null); + } + @Nullable public CodegenContext getParentContext() { return parentContext; 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 b19bfa36421..1123563b3ad 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -402,6 +402,10 @@ public class KotlinTypeMapper { return mapType(descriptor.getReturnType()); } + public Type mapErasedInlineClass(@NotNull ClassDescriptor descriptor) { + return Type.getObjectType(mapClass(descriptor).getInternalName() + JvmAbi.ERASED_INLINE_CLASS_SUFFIX); + } + @NotNull public JvmMethodGenericSignature mapAnnotationParameterSignature(@NotNull PropertyDescriptor descriptor) { JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD); @@ -728,10 +732,13 @@ public class KotlinTypeMapper { } } else { + boolean isInsideInlineClass = currentOwner.isInline(); + boolean isStaticInvocation = (isStaticDeclaration(functionDescriptor) && !(functionDescriptor instanceof ImportedFromObjectCallableDescriptor)) || isStaticAccessor(functionDescriptor) || - CodegenUtilKt.isJvmStaticInObjectOrClassOrInterface(functionDescriptor); + CodegenUtilKt.isJvmStaticInObjectOrClassOrInterface(functionDescriptor) || + isInsideInlineClass; if (isStaticInvocation) { invokeOpcode = INVOKESTATIC; isInterfaceMember = currentIsInterface && currentOwner instanceof JavaClassDescriptor; @@ -753,12 +760,14 @@ public class KotlinTypeMapper { ? overriddenSpecialBuiltinFunction.getOriginal() : functionDescriptor.getOriginal(); - signature = mapSignatureSkipGeneric(functionToCall); + signature = isInsideInlineClass + ? mapSignatureForInlineErasedClassSkipGeneric(functionToCall) + : mapSignatureSkipGeneric(functionToCall); ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor ? declarationOwner : currentOwner; - owner = mapClass(receiver); + owner = isInsideInlineClass ? mapErasedInlineClass(receiver) : mapClass(receiver); thisClass = owner; } } @@ -972,6 +981,10 @@ public class KotlinTypeMapper { return mapSignatureSkipGeneric(f, OwnerKind.IMPLEMENTATION); } + public JvmMethodSignature mapSignatureForInlineErasedClassSkipGeneric(@NotNull FunctionDescriptor f) { + return mapSignatureSkipGeneric(f, OwnerKind.ERASED_INLINE_CLASS); + } + @NotNull public JvmMethodSignature mapSignatureSkipGeneric(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind) { return mapSignature(f, kind, true); @@ -1067,6 +1080,10 @@ public class KotlinTypeMapper { writeFormalTypeParameters(CollectionsKt.plus(receiverTypeAndTypeParameters.getTypeParameters(), directMember.getTypeParameters()), sw); thisIfNeeded = receiverTypeAndTypeParameters.getReceiverType(); } + else if (OwnerKind.ERASED_INLINE_CLASS == kind) { + ClassDescriptor classDescriptor = (ClassDescriptor) directMember.getContainingDeclaration(); + thisIfNeeded = classDescriptor.getDefaultType(); + } else { writeFormalTypeParameters(directMember.getTypeParameters(), sw); if (isAccessor(f) && f.getDispatchReceiverParameter() != null) { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt index f97181fcc40..036646f94e1 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt @@ -1,24 +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.resolve.jvm.diagnostics import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtPureElement import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils @@ -41,7 +29,8 @@ enum class JvmDeclarationOriginKind { MULTIFILE_CLASS_PART, SYNTHETIC, // this means that there's no proper descriptor for this jvm declaration, COLLECTION_STUB, - AUGMENTED_BUILTIN_API + AUGMENTED_BUILTIN_API, + ERASED_INLINE_CLASS } class JvmDeclarationOrigin( @@ -91,3 +80,6 @@ fun Synthetic(element: PsiElement?, descriptor: CallableMemberDescriptor): JvmDe val CollectionStub = JvmDeclarationOrigin(COLLECTION_STUB, null, null) fun AugmentedBuiltInApi(descriptor: CallableDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(AUGMENTED_BUILTIN_API, null, descriptor) + +fun ErasedInlineClassOrigin(element: PsiElement?, descriptor: ClassDescriptor): JvmDeclarationOrigin = + JvmDeclarationOrigin(ERASED_INLINE_CLASS, element, descriptor) diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt new file mode 100644 index 00000000000..1877ca24a7e --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: +InlineClasses + +inline class Foo(val x: Int) { + fun empty() {} + fun withParam(a: String) {} + fun withInlineClassParam(f: Foo) {} + + fun test() { + empty() + withParam("hello") + withInlineClassParam(this) + } +} + +// 2 INVOKESTATIC Foo\$Erased.empty \(I\)V +// 2 INVOKESTATIC Foo\$Erased.withParam \(ILjava/lang/String;\)V +// 2 INVOKESTATIC Foo\$Erased.withInlineClassParam \(II\)V +// 0 INVOKEVIRTUAL \ No newline at end of file diff --git a/compiler/testData/writeSignature/inlineClasses/basicInlineClassDeclarationCodegen.kt b/compiler/testData/writeSignature/inlineClasses/basicInlineClassDeclarationCodegen.kt new file mode 100644 index 00000000000..695f6a72d3f --- /dev/null +++ b/compiler/testData/writeSignature/inlineClasses/basicInlineClassDeclarationCodegen.kt @@ -0,0 +1,30 @@ +// !LANGUAGE: +InlineClasses + +inline class Foo(val x: Int) { + fun empty() {} + fun param(y: String) {} + fun Any.extension() {} + fun Any.extensionAndParam(y: Double) {} + + fun withInlineClassType(c: Foo) {} +} + +// method: Foo$Erased::empty +// jvm signature: (I)V +// generic signature: null + +// method: Foo$Erased::param +// jvm signature: (ILjava/lang/String;)V +// generic signature: null + +// method: Foo$Erased::extension +// jvm signature: (ILjava/lang/Object;)V +// generic signature: null + +// method: Foo$Erased::extensionAndParam +// jvm signature: (ILjava/lang/Object;D)V +// generic signature: null + +// method: Foo$Erased::withInlineClassType +// jvm signature: (II)V +// generic signature: null diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index b9dd203bbc9..35bf7e425de 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1885,6 +1885,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/inlineClasses") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClasses extends AbstractBytecodeTextTest { + public void testAllFilesPresentInInlineClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("callMemberMethodsInsideInlineClass.kt") + public void testCallMemberMethodsInsideInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/interfaces") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java index 7626b5ee613..029a56857f8 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java @@ -558,6 +558,12 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeSignature/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("basicInlineClassDeclarationCodegen.kt") + public void testBasicInlineClassDeclarationCodegen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/inlineClasses/basicInlineClassDeclarationCodegen.kt"); + doTest(fileName); + } + @TestMetadata("nullableInlineClassType.kt") public void testNullableInlineClassType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/inlineClasses/nullableInlineClassType.kt"); diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java index 7e930a8fd85..c1f0847b766 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.java @@ -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.load.java; @@ -32,6 +21,7 @@ import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; public final class JvmAbi { public static final String DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls"; + public static final String ERASED_INLINE_CLASS_NAME = "Erased"; /** * Warning: use DEFAULT_IMPLS_CLASS_NAME and TypeMappingConfiguration.innerClassNameFactory when possible. @@ -62,6 +52,8 @@ public final class JvmAbi { public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT = "$i$a$"; public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION = "$i$f$"; + public static final String ERASED_INLINE_CLASS_SUFFIX = "$" + ERASED_INLINE_CLASS_NAME; + @NotNull public static String getSyntheticMethodNameForAnnotatedProperty(@NotNull Name propertyName) { return propertyName.asString() + ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX; diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt index b3da887af88..26b523a8baf 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt @@ -6,9 +6,12 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor fun ClassDescriptor.underlyingRepresentation(): ValueParameterDescriptor? { if (!isInline) return null return unsubstitutedPrimaryConstructor?.valueParameters?.singleOrNull() } + +fun DeclarationDescriptor.isInlineClass() = this is ClassDescriptor && this.isInline \ No newline at end of file