Introduced test flag: JVM8_TARGET_WITH_DEFAULTS

This commit is contained in:
Mikhael Bogdanov
2017-01-11 13:44:53 +01:00
parent 7f8acbb759
commit 0a363fd1a5
49 changed files with 148 additions and 61 deletions
@@ -181,7 +181,7 @@ public class AsmUtil {
public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
return (functionDescriptor.getModality() == Modality.ABSTRACT ||
(isJvmInterface(functionDescriptor.getContainingDeclaration()) && !state.isJvm8Target()))
(isJvmInterface(functionDescriptor.getContainingDeclaration()) && !state.isJvm8TargetWithDefaults()))
&& !isStaticMethod(kind, functionDescriptor);
}
@@ -99,7 +99,7 @@ public class FunctionCodegen {
private final Function1<DeclarationDescriptor, Boolean> IS_PURE_INTERFACE_CHECKER = new Function1<DeclarationDescriptor, Boolean>() {
@Override
public Boolean invoke(DeclarationDescriptor descriptor) {
return JvmCodegenUtil.isAnnotationOrJvm6Interface(descriptor, state);
return JvmCodegenUtil.isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, state);
}
};
@@ -201,7 +201,7 @@ public class FunctionCodegen {
generateBridges(functionDescriptor);
if (isJvm8InterfaceMember(functionDescriptor, state) && contextKind != OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()) {
if (isJvm8InterfaceWithDefaultsMember(functionDescriptor, state) && contextKind != OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()) {
generateDelegateForDefaultImpl(functionDescriptor, origin.getElement());
}
@@ -419,7 +419,7 @@ public class FunctionCodegen {
generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext());
methodEnd = new Label();
}
else if (OwnerKind.DEFAULT_IMPLS == context.getContextKind() && isJvm8InterfaceMember(functionDescriptor, parentCodegen.state)) {
else if (OwnerKind.DEFAULT_IMPLS == context.getContextKind() && isJvm8InterfaceWithDefaultsMember(functionDescriptor, parentCodegen.state)) {
int flags = AsmUtil.getMethodAsmFlags(functionDescriptor, OwnerKind.DEFAULT_IMPLS, context.getState());
assert (flags & Opcodes.ACC_ABSTRACT) == 0 : "Interface method with body should be non-abstract" + functionDescriptor;
Type type = typeMapper.mapOwner(functionDescriptor);
@@ -724,7 +724,7 @@ public class FunctionCodegen {
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
if (descriptor instanceof ConstructorDescriptor) return;
if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
if (isAnnotationOrJvm6Interface(descriptor.getContainingDeclaration(), state)) return;
if (isAnnotationOrJvmInterfaceWithoutDefaults(descriptor.getContainingDeclaration(), state)) return;
// equals(Any?), hashCode(), toString() never need bridges
if (isMethodOfAny(descriptor)) return;
@@ -1089,7 +1089,7 @@ public class FunctionCodegen {
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor(), false);
}
else {
if (isJvm8InterfaceMember(descriptor, state)) {
if (isJvm8InterfaceWithDefaultsMember(descriptor, state)) {
iv.invokeinterface(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
}
else {
@@ -1257,6 +1257,6 @@ public class FunctionCodegen {
@NotNull GenerationState state
) {
assert isInterface(contextClass) : "'processInterface' method should be called only for interfaces, but: " + contextClass;
return isJvm8Interface(contextClass, state) ? kind != OwnerKind.DEFAULT_IMPLS : kind == OwnerKind.DEFAULT_IMPLS;
return JvmCodegenUtil.isJvm8InterfaceWithDefaults(contextClass, state) ? kind != OwnerKind.DEFAULT_IMPLS : kind == OwnerKind.DEFAULT_IMPLS;
}
}
@@ -233,7 +233,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override
protected void generateDefaultImplsIfNeeded() {
if (isInterface(descriptor) && !isLocal && (!isJvm8Interface(descriptor, state) || state.getGenerateDefaultImplsForJvm8())) {
if (isInterface(descriptor) && !isLocal && (!JvmCodegenUtil.isJvm8InterfaceWithDefaults(descriptor, state) || state.getGenerateDefaultImplsForJvm8())) {
Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor);
ClassBuilder defaultImplsBuilder =
state.getFactory().newVisitor(JvmDeclarationOriginKt.DefaultImpls(myClass.getPsiOrParent(), descriptor), defaultImplsType, myClass.getContainingKtFile());
@@ -1293,14 +1293,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateTraitMethods() {
if (isAnnotationOrJvm6Interface(descriptor, state)) return;
if (isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, state)) return;
List<FunctionDescriptor> restrictedInheritance = new ArrayList<FunctionDescriptor>();
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
FunctionDescriptor interfaceFun = entry.getKey();
//skip java 8 default methods
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !isJvm8InterfaceMember(interfaceFun, state)) {
if (state.isJvm8Target() && !JvmCodegenUtil.isJvm8Interface(interfaceFun.getContainingDeclaration(), state)) {
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !isJvm8InterfaceWithDefaultsMember(interfaceFun, state)) {
if (state.isJvm8TargetWithDefaults() && !JvmCodegenUtil.isJvm8InterfaceWithDefaults(interfaceFun.getContainingDeclaration(), state)) {
restrictedInheritance.add(interfaceFun);
}
else {
@@ -30,8 +30,6 @@ import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.RootContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
@@ -64,11 +62,11 @@ public class JvmCodegenUtil {
private JvmCodegenUtil() {
}
public static boolean isAnnotationOrJvm6Interface(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
return isAnnotationOrJvm6Interface(descriptor, state.isJvm8Target());
public static boolean isAnnotationOrJvmInterfaceWithoutDefaults(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
return isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, state.isJvm8Target(), state.isJvm8TargetWithDefaults());
}
public static boolean isAnnotationOrJvm6Interface(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target) {
private static boolean isAnnotationOrJvmInterfaceWithoutDefaults(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target, boolean isJvm8TargetWithDefaults) {
if (!isJvmInterface(descriptor)) {
return false;
}
@@ -80,23 +78,24 @@ public class JvmCodegenUtil {
KotlinJvmBinaryClass binaryClass = ((KotlinJvmBinarySourceElement) source).getBinaryClass();
assert binaryClass instanceof FileBasedKotlinClass :
"KotlinJvmBinaryClass should be subclass of FileBasedKotlinClass, but " + binaryClass;
return ((FileBasedKotlinClass) binaryClass).getClassVersion() == Opcodes.V1_6;
/*TODO need add some flags to compiled code*/
return true || ((FileBasedKotlinClass) binaryClass).getClassVersion() == Opcodes.V1_6;
}
}
return !isJvm8Target;
return !isJvm8TargetWithDefaults;
}
public static boolean isJvm8Interface(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
return isJvm8Interface(descriptor, state.isJvm8Target());
public static boolean isJvm8InterfaceWithDefaults(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
return isJvm8InterfaceWithDefaults(descriptor, state.isJvm8Target(), state.isJvm8TargetWithDefaults());
}
public static boolean isJvm8Interface(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target) {
return DescriptorUtils.isInterface(descriptor) && !isAnnotationOrJvm6Interface(descriptor, isJvm8Target);
public static boolean isJvm8InterfaceWithDefaults(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target, boolean isJvm8TargetWithDefaults) {
return DescriptorUtils.isInterface(descriptor) && !isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, isJvm8Target, isJvm8TargetWithDefaults);
}
public static boolean isJvm8InterfaceMember(@NotNull CallableMemberDescriptor descriptor, @NotNull GenerationState state) {
public static boolean isJvm8InterfaceWithDefaultsMember(@NotNull CallableMemberDescriptor descriptor, @NotNull GenerationState state) {
DeclarationDescriptor declaration = descriptor.getContainingDeclaration();
return isJvm8Interface(declaration, state);
return isJvm8InterfaceWithDefaults(declaration, state);
}
public static boolean isJvmInterface(DeclarationDescriptor descriptor) {
@@ -66,7 +66,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.*;
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceMember;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceWithDefaultsMember;
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
@@ -377,7 +377,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor();
if (context instanceof MethodContext) {
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
if (isInterface(functionDescriptor.getContainingDeclaration()) && !isJvm8InterfaceMember(functionDescriptor, state)) {
if (isInterface(functionDescriptor.getContainingDeclaration()) && !isJvm8InterfaceWithDefaultsMember(functionDescriptor, state)) {
return typeMapper.mapDefaultImpls(classDescriptor);
}
}
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper
class KotlinToJvmSignatureMapperImpl : KotlinToJvmSignatureMapper {
// We use empty BindingContext, because it is only used by KotlinTypeMapper for purposes irrelevant to the needs of this class
private val typeMapper = KotlinTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider,
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false)
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, false)
override fun mapToJvmMethodSignature(function: FunctionDescriptor) = typeMapper.mapAsmMethod(function)
}
@@ -63,7 +63,7 @@ class BuilderFactoryForDuplicateSignatureDiagnostics(
// Avoid errors when some classes are not loaded for some reason
private val typeMapper = KotlinTypeMapper(
bindingContext, ClassBuilderMode.LIGHT_CLASSES, fileClassesProvider, IncompatibleClassTracker.DoNothing, moduleName, false
bindingContext, ClassBuilderMode.LIGHT_CLASSES, fileClassesProvider, IncompatibleClassTracker.DoNothing, moduleName, false, false
)
private val reportDiagnosticsTasks = ArrayList<() -> Unit>()
@@ -125,6 +125,7 @@ class GenerationState @JvmOverloads constructor(
}
val isJvm8Target: Boolean = configuration.get(JVMConfigurationKeys.JVM_TARGET) == JvmTarget.JVM_1_8
val isJvm8TargetWithDefaults: Boolean = isJvm8Target && configuration.getBoolean(JVMConfigurationKeys.JVM8_TARGET_WITH_DEFAULTS)
val generateDefaultImplsForJvm8: Boolean = configuration.getBoolean(JVMConfigurationKeys.INTERFACE_COMPATIBILITY)
val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
@@ -134,7 +135,7 @@ class GenerationState @JvmOverloads constructor(
val bindingContext: BindingContext = bindingTrace.bindingContext
val typeMapper: KotlinTypeMapper = KotlinTypeMapper(
this.bindingContext, classBuilderMode, fileClassesProvider, IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
this.moduleName, isJvm8Target
this.moduleName, isJvm8Target, isJvm8TargetWithDefaults
)
val intrinsics: IntrinsicMethods = IntrinsicMethods()
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
@@ -98,6 +98,7 @@ public class KotlinTypeMapper {
private final IncompatibleClassTracker incompatibleClassTracker;
private final String moduleName;
private final boolean isJvm8Target;
private final boolean isJvm8TargetWithDefaults;
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
private final Function2<String, String, String> defaultClassNameFactory
@@ -153,7 +154,8 @@ public class KotlinTypeMapper {
@NotNull JvmFileClassesProvider fileClassesProvider,
@NotNull IncompatibleClassTracker incompatibleClassTracker,
@NotNull String moduleName,
boolean isJvm8Target
boolean isJvm8Target,
boolean isJvm8TargetWithDefaults
) {
this.bindingContext = bindingContext;
this.classBuilderMode = classBuilderMode;
@@ -161,6 +163,7 @@ public class KotlinTypeMapper {
this.incompatibleClassTracker = incompatibleClassTracker;
this.moduleName = moduleName;
this.isJvm8Target = isJvm8Target;
this.isJvm8TargetWithDefaults = isJvm8TargetWithDefaults;
}
@NotNull
@@ -682,7 +685,7 @@ public class KotlinTypeMapper {
descriptor = classCallable;
continue;
}
else if (isSuperCall && !isJvm8Target && !isInterface(descriptor.getContainingDeclaration())) {
else if (isSuperCall && !isJvm8TargetWithDefaults && !isInterface(descriptor.getContainingDeclaration())) {
//Don't unwrap fake overrides from class to interface cause substituted override would be implicitly generated for target 1.6
return descriptor;
}
@@ -738,12 +741,12 @@ public class KotlinTypeMapper {
baseMethodDescriptor = findBaseDeclaration(functionDescriptor).getOriginal();
ClassDescriptor ownerForDefault = (ClassDescriptor) baseMethodDescriptor.getContainingDeclaration();
ownerForDefaultImpl =
isJvmInterface(ownerForDefault) && !isJvm8Interface(ownerForDefault) ?
isJvmInterface(ownerForDefault) && !isJvm8InterfaceWithDefaults(ownerForDefault) ?
mapDefaultImpls(ownerForDefault) : mapClass(ownerForDefault);
if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) {
thisClass = mapClass(currentOwner);
if (declarationOwner instanceof JavaClassDescriptor || isJvm8Interface(declarationOwner)) {
if (declarationOwner instanceof JavaClassDescriptor || isJvm8InterfaceWithDefaults(declarationOwner)) {
invokeOpcode = INVOKESPECIAL;
signature = mapSignatureSkipGeneric(functionDescriptor);
owner = thisClass;
@@ -782,7 +785,6 @@ public class KotlinTypeMapper {
signature = mapSignatureSkipGeneric(functionToCall);
/*TODO: isInterfaceMember?*/
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor
? declarationOwner
: currentOwner;
@@ -828,8 +830,9 @@ public class KotlinTypeMapper {
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE );
}
private boolean isJvm8Interface(@NotNull ClassDescriptor ownerForDefault) {
return isJvmInterface(ownerForDefault) && JvmCodegenUtil.isJvm8Interface(ownerForDefault, isJvm8Target);
private boolean isJvm8InterfaceWithDefaults(@NotNull ClassDescriptor ownerForDefault) {
return isJvmInterface(ownerForDefault) &&
JvmCodegenUtil.isJvm8InterfaceWithDefaults(ownerForDefault, isJvm8Target, isJvm8TargetWithDefaults);
}
public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {