Generate delegation body for default interface methods, calculate proper abstractness for them
This commit is contained in:
committed by
Mikhael Bogdanov
parent
fc8058848f
commit
01aa89b1ea
@@ -168,9 +168,9 @@ public class AsmUtil {
|
||||
return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes));
|
||||
}
|
||||
|
||||
public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
|
||||
return (functionDescriptor.getModality() == Modality.ABSTRACT
|
||||
|| isJvmInterface(functionDescriptor.getContainingDeclaration()))
|
||||
public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
|
||||
return (functionDescriptor.getModality() == Modality.ABSTRACT ||
|
||||
(isJvmInterface(functionDescriptor.getContainingDeclaration()) && !state.isJvm8Target()))
|
||||
&& !isStaticMethod(kind, functionDescriptor);
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ public class AsmUtil {
|
||||
return kind == OwnerKind.PACKAGE || kind == OwnerKind.DEFAULT_IMPLS;
|
||||
}
|
||||
|
||||
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
|
||||
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
|
||||
int flags = getCommonCallableFlags(functionDescriptor);
|
||||
|
||||
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
|
||||
@@ -214,7 +214,7 @@ public class AsmUtil {
|
||||
flags |= ACC_STATIC;
|
||||
}
|
||||
|
||||
if (isAbstractMethod(functionDescriptor, kind)) {
|
||||
if (isAbstractMethod(functionDescriptor, kind, state)) {
|
||||
flags |= ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,10 +63,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
@@ -163,7 +160,7 @@ public class FunctionCodegen {
|
||||
JvmMethodGenericSignature jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, contextKind);
|
||||
Method asmMethod = jvmSignature.getAsmMethod();
|
||||
|
||||
int flags = getMethodAsmFlags(functionDescriptor, contextKind);
|
||||
int flags = getMethodAsmFlags(functionDescriptor, contextKind, state);
|
||||
|
||||
if (origin.getOriginKind() == JvmDeclarationOriginKind.SAM_DELEGATION) {
|
||||
flags |= ACC_SYNTHETIC;
|
||||
@@ -198,7 +195,7 @@ public class FunctionCodegen {
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
}
|
||||
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL || isAbstractMethod(functionDescriptor, contextKind)) {
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL || isAbstractMethod(functionDescriptor, contextKind, state)) {
|
||||
generateLocalVariableTable(
|
||||
mv,
|
||||
jvmSignature,
|
||||
@@ -356,6 +353,15 @@ public class FunctionCodegen {
|
||||
generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext());
|
||||
methodEnd = new Label();
|
||||
}
|
||||
else if (OwnerKind.IMPLEMENTATION == context.getContextKind() &&
|
||||
JvmCodegenUtil.isJvmInterface(functionDescriptor.getContainingDeclaration())) {
|
||||
int flags = AsmUtil.getMethodAsmFlags(functionDescriptor, OwnerKind.IMPLEMENTATION, context.getState());
|
||||
assert (flags & Opcodes.ACC_ABSTRACT) == 0 : "Interface method with body should be non-abstract" + functionDescriptor;
|
||||
Type type = typeMapper.mapDefaultImpls((ClassDescriptor) functionDescriptor.getContainingDeclaration());
|
||||
Method asmMethod = typeMapper.mapAsmMethod(functionDescriptor, OwnerKind.DEFAULT_IMPLS);
|
||||
generateDelegateToMethodBody(true, mv, asmMethod, type.getInternalName());
|
||||
methodEnd = new Label();
|
||||
}
|
||||
else {
|
||||
FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(),
|
||||
functionDescriptor));
|
||||
@@ -600,7 +606,7 @@ public class FunctionCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
|
||||
if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION, state)) {
|
||||
CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor);
|
||||
assert overridden != null;
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
|
||||
MethodNode node = new MethodNode(
|
||||
InlineCodegenUtil.API,
|
||||
getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
|
||||
getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0),
|
||||
asmMethod.getName(),
|
||||
asmMethod.getDescriptor(),
|
||||
null, null
|
||||
@@ -474,7 +474,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
JvmMethodSignature jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(descriptor);
|
||||
Method asmMethod = jvmMethodSignature.getAsmMethod();
|
||||
MethodNode methodNode = new MethodNode(
|
||||
InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()),
|
||||
InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind(), state),
|
||||
asmMethod.getName(), asmMethod.getDescriptor(), null, null
|
||||
);
|
||||
|
||||
@@ -678,7 +678,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
|
||||
@Override
|
||||
public void putHiddenParams() {
|
||||
if ((getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == 0) {
|
||||
if ((getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) & Opcodes.ACC_STATIC) == 0) {
|
||||
invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
|
||||
interface Test {
|
||||
fun test(): String {
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun testAbstract(): String
|
||||
}
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: Test, test
|
||||
// FLAGS: ACC_PUBLIC
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: Test, testAbstract
|
||||
// FLAGS: ACC_PUBLIC, ACC_ABSTRACT
|
||||
@@ -0,0 +1,15 @@
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
|
||||
interface Test {
|
||||
fun a() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TESTED_OBJECT_KIND: class
|
||||
// TESTED_OBJECTS: Test$DefaultImpls
|
||||
// FLAGS: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
|
||||
|
||||
|
||||
// TESTED_OBJECT_KIND: class
|
||||
// TESTED_OBJECTS: Test
|
||||
// FLAGS: ACC_PUBLIC, ACC_ABSTRACT, ACC_INTERFACE
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.flags;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("compiler/testData/codegen/java8/writeFlags")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
|
||||
public void testAllFilesPresentInWriteFlags() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/writeFlags"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("defaultMethod.kt")
|
||||
public void testDefaultMethod() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/writeFlags/defaultMethod.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceAndDefaultImpls.kt")
|
||||
public void testInterfaceAndDefaultImpls() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/writeFlags/interfaceAndDefaultImpls.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user