Initial version of codegen for inline classes

This commit is contained in:
Mikhail Zarechenskiy
2018-01-29 13:06:12 +03:00
parent fbc02dee58
commit 928a342ace
18 changed files with 266 additions and 148 deletions
@@ -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) {
@@ -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);
}
@@ -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<KtPureClassOrObject
generatePrimaryConstructorProperties();
generateConstructors();
generateDefaultImplsIfNeeded();
generateErasedInlineClassIfNeeded();
}
// Generate _declared_ companions
@@ -150,13 +140,11 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) myClass);
}
protected void generateConstructors() {
protected void generateConstructors() {}
}
protected void generateDefaultImplsIfNeeded() {}
protected void generateDefaultImplsIfNeeded() {
}
protected void generateErasedInlineClassIfNeeded() {}
private static boolean shouldProcessFirst(KtDeclaration declaration) {
return !(declaration instanceof KtProperty || declaration instanceof KtNamedFunction);
@@ -0,0 +1,33 @@
/*
* 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 com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.org.objectweb.asm.Opcodes
class ErasedInlineClassBodyCodegen(
aClass: KtClass,
context: ClassContext,
v: ClassBuilder,
state: GenerationState,
parentCodegen: 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)
}
}
@@ -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<StackValue, StackValue> 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<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
if (!codegenExtensions.isEmpty() && resolvedCall != null) {
ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(this, typeMapper, v);
@@ -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,
@@ -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);
@@ -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) {
@@ -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);
}
@@ -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<T extends DeclarationDescriptor> {
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;
@@ -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) {
@@ -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)
@@ -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
@@ -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
@@ -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)
@@ -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");
@@ -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;
@@ -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