Initial version of codegen for inline classes
This commit is contained in:
@@ -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) {
|
||||
|
||||
+7
-15
@@ -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)
|
||||
|
||||
+18
@@ -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
|
||||
+30
@@ -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)
|
||||
|
||||
+6
@@ -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
|
||||
Reference in New Issue
Block a user