Rewrite bridge generation to Kotlin, make it abstract
This commit is contained in:
@@ -7,8 +7,8 @@
|
|||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
<orderEntry type="module" module-name="util" />
|
||||||
<orderEntry type="library" name="intellij-core" level="project" />
|
<orderEntry type="module" module-name="frontend" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.jet.codegen.bridges
|
||||||
|
|
||||||
|
import org.jetbrains.jet.utils.DFS
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
public trait FunctionHandle {
|
||||||
|
val isDeclaration: Boolean
|
||||||
|
val isAbstract: Boolean
|
||||||
|
|
||||||
|
fun getOverridden(): Iterable<FunctionHandle>
|
||||||
|
}
|
||||||
|
|
||||||
|
public data class Bridge<Signature>(
|
||||||
|
public val from: Signature,
|
||||||
|
public val to: Signature
|
||||||
|
) {
|
||||||
|
override fun toString() = "$from -> $to"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public fun <Function : FunctionHandle, Signature> generateBridges(
|
||||||
|
function: Function,
|
||||||
|
signature: (Function) -> Signature
|
||||||
|
): Set<Bridge<Signature>> {
|
||||||
|
// If it's an abstract function, no bridges are needed: when an implementation will appear in some concrete subclass, all necessary
|
||||||
|
// bridges will be generated there
|
||||||
|
if (function.isAbstract) return setOf()
|
||||||
|
|
||||||
|
val fake = !function.isDeclaration
|
||||||
|
|
||||||
|
// If it's a concrete fake override and all of its super-functions are concrete, then every possible bridge is already generated
|
||||||
|
// into some of the super-classes and will be inherited in this class
|
||||||
|
if (fake && function.getOverridden().none { it.isAbstract }) return setOf()
|
||||||
|
|
||||||
|
val implementation = findConcreteSuperDeclaration(function)
|
||||||
|
|
||||||
|
val bridgesToGenerate = findAllReachableDeclarations(function).mapTo(HashSet<Signature>(), signature)
|
||||||
|
|
||||||
|
if (fake) {
|
||||||
|
// If it's a concrete fake override, some of the bridges may be inherited from the super-classes. Specifically, bridges for all
|
||||||
|
// declarations that are reachable from all concrete immediate super-functions of the given function. Note that all such bridges are
|
||||||
|
// guaranteed to delegate to the same implementation as bridges for the given function, that's why it's safe to inherit them
|
||||||
|
[suppress("UNCHECKED_CAST")]
|
||||||
|
for (overridden in function.getOverridden() as Iterable<Function>) {
|
||||||
|
if (!overridden.isAbstract) {
|
||||||
|
bridgesToGenerate.removeAll(findAllReachableDeclarations(overridden).map(signature))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val method = signature(implementation)
|
||||||
|
bridgesToGenerate.remove(method)
|
||||||
|
return bridgesToGenerate.map { Bridge(it, method) }.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <Function : FunctionHandle> findAllReachableDeclarations(function: Function): MutableSet<Function> {
|
||||||
|
val collector = object : DFS.NodeHandlerWithListResult<Function, Function>() {
|
||||||
|
override fun afterChildren(current: Function?) {
|
||||||
|
if (current != null && current.isDeclaration) {
|
||||||
|
result.add(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[suppress("UNCHECKED_CAST")]
|
||||||
|
DFS.dfs(listOf(function), { it!!.getOverridden() as Iterable<Function> }, collector)
|
||||||
|
return HashSet(collector.result())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a concrete function, finds an implementation (a concrete declaration) of this function in the supertypes.
|
||||||
|
* The implementation is guaranteed to exist because if it wouldn't, the given function would've been abstract
|
||||||
|
*/
|
||||||
|
private fun <Function : FunctionHandle> findConcreteSuperDeclaration(function: Function): Function {
|
||||||
|
require(!function.isAbstract, "Only concrete functions have implementations: $function")
|
||||||
|
|
||||||
|
if (function.isDeclaration) return function
|
||||||
|
|
||||||
|
// To find an implementation of a concrete fake override, we should find among all its super-functions such function that:
|
||||||
|
// 1) it's a concrete declaration
|
||||||
|
// 2) it's not reachable from any other declaration reachable from the given function
|
||||||
|
// The compiler guarantees that there will be exactly one such function.
|
||||||
|
// The following algorithm is used: first, we find all declarations reachable from the given function. Then for each such declaration
|
||||||
|
// we remove from that result all declarations reachable from it. The result is now guaranteed to have exactly one concrete declaration
|
||||||
|
// (and possibly some abstract declarations, which don't matter)
|
||||||
|
|
||||||
|
val result = findAllReachableDeclarations(function)
|
||||||
|
val toRemove = HashSet<Function>()
|
||||||
|
for (declaration in result) {
|
||||||
|
val reachable = findAllReachableDeclarations(declaration)
|
||||||
|
reachable.remove(declaration)
|
||||||
|
toRemove.addAll(reachable)
|
||||||
|
}
|
||||||
|
result.removeAll(toRemove)
|
||||||
|
|
||||||
|
val concreteRelevantDeclarations = result.filter { !it.isAbstract }
|
||||||
|
if (concreteRelevantDeclarations.size != 1) {
|
||||||
|
error("Concrete fake override $function should have exactly one concrete super-declaration: $concreteRelevantDeclarations")
|
||||||
|
}
|
||||||
|
|
||||||
|
return concreteRelevantDeclarations[0]
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.jet.codegen.bridges
|
||||||
|
|
||||||
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.jet.lang.descriptors.Modality
|
||||||
|
|
||||||
|
public fun <Signature> generateBridgesForFunctionDescriptor(
|
||||||
|
descriptor: FunctionDescriptor,
|
||||||
|
signature: (FunctionDescriptor) -> Signature
|
||||||
|
): Set<Bridge<Signature>> {
|
||||||
|
return generateBridges(DescriptorBasedFunctionHandle(descriptor), { signature(it.descriptor) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescriptor) : FunctionHandle {
|
||||||
|
override val isDeclaration: Boolean = descriptor.getKind().isReal()
|
||||||
|
override val isAbstract: Boolean = descriptor.getModality() == Modality.ABSTRACT
|
||||||
|
|
||||||
|
override fun getOverridden(): Iterable<FunctionHandle> {
|
||||||
|
return descriptor.getOverriddenDescriptors().map { DescriptorBasedFunctionHandle(it.getOriginal()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,8 +18,6 @@ package org.jetbrains.jet.codegen;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
import org.jetbrains.jet.codegen.context.ClassContext;
|
import org.jetbrains.jet.codegen.context.ClassContext;
|
||||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
@@ -29,13 +27,15 @@ import org.jetbrains.jet.lang.psi.*;
|
|||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC;
|
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.RETURN;
|
import static org.jetbrains.org.objectweb.asm.Opcodes.RETURN;
|
||||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
|
||||||
|
|
||||||
public abstract class ClassBodyCodegen extends MemberCodegen {
|
public abstract class ClassBodyCodegen extends MemberCodegen {
|
||||||
protected final JetClassOrObject myClass;
|
protected final JetClassOrObject myClass;
|
||||||
@@ -104,7 +104,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
|
|||||||
if (memberDescriptor instanceof FunctionDescriptor) {
|
if (memberDescriptor instanceof FunctionDescriptor) {
|
||||||
FunctionDescriptor member = (FunctionDescriptor) memberDescriptor;
|
FunctionDescriptor member = (FunctionDescriptor) memberDescriptor;
|
||||||
if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
functionCodegen.generateBridgesForFakeOverride(member);
|
functionCodegen.generateBridges(member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,11 @@ import com.intellij.util.ArrayUtil;
|
|||||||
import com.intellij.util.Function;
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import kotlin.Function1;
|
import kotlin.Function1;
|
||||||
import kotlin.KotlinPackage;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||||
|
import org.jetbrains.jet.codegen.bridges.Bridge;
|
||||||
|
import org.jetbrains.jet.codegen.bridges.BridgesPackage;
|
||||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||||
import org.jetbrains.jet.codegen.context.MethodContext;
|
import org.jetbrains.jet.codegen.context.MethodContext;
|
||||||
import org.jetbrains.jet.codegen.context.PackageFacadeContext;
|
import org.jetbrains.jet.codegen.context.PackageFacadeContext;
|
||||||
@@ -45,7 +46,6 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
|||||||
import org.jetbrains.jet.lang.resolve.constants.JavaClassValue;
|
import org.jetbrains.jet.lang.resolve.constants.JavaClassValue;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.utils.DFS;
|
|
||||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.Label;
|
import org.jetbrains.org.objectweb.asm.Label;
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
@@ -56,7 +56,10 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
|||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||||
import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
|
import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
|
||||||
@@ -417,108 +420,31 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
return bytecode;
|
return bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateBridges(@NotNull FunctionDescriptor descriptor) {
|
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
|
||||||
if (descriptor instanceof ConstructorDescriptor) return;
|
if (descriptor instanceof ConstructorDescriptor) return;
|
||||||
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
|
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
|
||||||
if (isTrait(descriptor.getContainingDeclaration())) return;
|
if (isTrait(descriptor.getContainingDeclaration())) return;
|
||||||
|
|
||||||
Set<Method> bridgesToGenerate = findAllReachableDeclarations(descriptor);
|
Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor(
|
||||||
|
descriptor,
|
||||||
Method method = typeMapper.mapSignature(descriptor).getAsmMethod();
|
new Function1<FunctionDescriptor, Method>() {
|
||||||
bridgesToGenerate.remove(method);
|
@Override
|
||||||
|
public Method invoke(FunctionDescriptor descriptor) {
|
||||||
|
return typeMapper.mapSignature(descriptor).getAsmMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!bridgesToGenerate.isEmpty()) {
|
if (!bridgesToGenerate.isEmpty()) {
|
||||||
PsiElement origin = callableDescriptorToDeclaration(bindingContext, descriptor);
|
PsiElement origin = descriptor.getKind().isReal()
|
||||||
for (Method bridge : bridgesToGenerate) {
|
? callableDescriptorToDeclaration(bindingContext, descriptor)
|
||||||
generateBridge(origin, bridge, method);
|
: null;
|
||||||
|
for (Bridge<Method> bridge : bridgesToGenerate) {
|
||||||
|
generateBridge(origin, bridge.getFrom(), bridge.getTo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateBridgesForFakeOverride(@NotNull FunctionDescriptor descriptor) {
|
|
||||||
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
|
|
||||||
|
|
||||||
// If it's an abstract fake override, no bridges are needed: when an implementation will appear in some subclass, all necessary
|
|
||||||
// bridges will be generated there
|
|
||||||
if (descriptor.getModality() == Modality.ABSTRACT) return;
|
|
||||||
|
|
||||||
// If it's a concrete fake override and all of its super-functions are non-abstract, then every possible bridge is already generated
|
|
||||||
// into some of the super-classes and will be inherited in this class
|
|
||||||
if (!hasAbstractSuperFunction(descriptor)) return;
|
|
||||||
|
|
||||||
FunctionDescriptor implementation = findNonAbstractDeclaration(descriptor);
|
|
||||||
|
|
||||||
Set<Method> bridgesToGenerate = findAllReachableDeclarations(descriptor);
|
|
||||||
// TODO: remove also all declarations reachable from all reachable non-abstract fake overrides in classes
|
|
||||||
bridgesToGenerate.removeAll(findAllReachableDeclarations(implementation));
|
|
||||||
|
|
||||||
Method method = typeMapper.mapSignature(implementation).getAsmMethod();
|
|
||||||
for (Method bridge : bridgesToGenerate) {
|
|
||||||
generateBridge(null, bridge, method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasAbstractSuperFunction(@NotNull FunctionDescriptor descriptor) {
|
|
||||||
for (FunctionDescriptor overridden : descriptor.getOverriddenDescriptors()) {
|
|
||||||
if (overridden.getOriginal().getModality() == Modality.ABSTRACT) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Set<Method> findAllReachableDeclarations(@NotNull FunctionDescriptor descriptor) {
|
|
||||||
DFS.Neighbors<FunctionDescriptor> neighbors = new DFS.Neighbors<FunctionDescriptor>() {
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Iterable<FunctionDescriptor> getNeighbors(FunctionDescriptor current) {
|
|
||||||
return KotlinPackage.map(current.getOverriddenDescriptors(), new Function1<FunctionDescriptor, FunctionDescriptor>() {
|
|
||||||
@Override
|
|
||||||
public FunctionDescriptor invoke(FunctionDescriptor descriptor) {
|
|
||||||
return descriptor.getOriginal();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
DFS.NodeHandlerWithListResult<FunctionDescriptor, Method> collector =
|
|
||||||
new DFS.NodeHandlerWithListResult<FunctionDescriptor, Method>() {
|
|
||||||
@Override
|
|
||||||
public void afterChildren(FunctionDescriptor current) {
|
|
||||||
if (current.getKind().isReal()) {
|
|
||||||
result.add(typeMapper.mapSignature(current).getAsmMethod());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
DFS.dfs(Collections.singleton(descriptor), neighbors, collector);
|
|
||||||
return new HashSet<Method>(collector.result());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a non-abstract function of any kind, finds an implementation (a non-abstract non-fake-override) of this function
|
|
||||||
* in the supertypes. The implementation is guaranteed to exist because if it wouldn't, the given function would've been abstract.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
private static FunctionDescriptor findNonAbstractDeclaration(@NotNull FunctionDescriptor descriptor) {
|
|
||||||
if (descriptor.getModality() == Modality.ABSTRACT) {
|
|
||||||
throw new IllegalArgumentException("Only non-abstract functions have implementations: " + descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor.getKind().isReal()) {
|
|
||||||
return descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (FunctionDescriptor overriddenSubstituted : descriptor.getOverriddenDescriptors()) {
|
|
||||||
FunctionDescriptor overridden = overriddenSubstituted.getOriginal();
|
|
||||||
if (overridden.getModality() != Modality.ABSTRACT) {
|
|
||||||
return findNonAbstractDeclaration(overridden);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException("No non-abstract declaration found for non-abstract function: " +
|
|
||||||
descriptor + "\nOverridden: " + descriptor.getOverriddenDescriptors());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
|
private static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
|
||||||
AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
|
AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
|
||||||
@@ -767,23 +693,6 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean differentMethods(Method method, Method overridden) {
|
|
||||||
if (!method.getReturnType().equals(overridden.getReturnType())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Type[] methodArgumentTypes = method.getArgumentTypes();
|
|
||||||
Type[] overriddenArgumentTypes = overridden.getArgumentTypes();
|
|
||||||
if (methodArgumentTypes.length != overriddenArgumentTypes.length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (int i = 0; i != methodArgumentTypes.length; ++i) {
|
|
||||||
if (!methodArgumentTypes[i].equals(overriddenArgumentTypes[i])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateBridge(@Nullable PsiElement origin, @NotNull Method bridge, @NotNull Method delegateTo) {
|
private void generateBridge(@Nullable PsiElement origin, @NotNull Method bridge, @NotNull Method delegateTo) {
|
||||||
int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
|
int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
open class A {
|
||||||
|
open fun foo(): Any = "A"
|
||||||
|
}
|
||||||
|
|
||||||
|
trait B : A
|
||||||
|
|
||||||
|
open class C : A() {
|
||||||
|
override fun foo(): Int = 222
|
||||||
|
}
|
||||||
|
|
||||||
|
trait D {
|
||||||
|
fun foo(): Number
|
||||||
|
}
|
||||||
|
|
||||||
|
class E : B, C(), D
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val e = E()
|
||||||
|
if (e.foo() != 222) return "Fail 1"
|
||||||
|
if ((e : D).foo() != 222) return "Fail 2"
|
||||||
|
if ((e : C).foo() != 222) return "Fail 3"
|
||||||
|
if ((e : B).foo() != 222) return "Fail 4"
|
||||||
|
if ((e : A).foo() != 222) return "Fail 5"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,563 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.jet.codegen
|
||||||
|
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.jet.codegen.bridges.*
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import java.util.HashSet
|
||||||
|
import org.jetbrains.jet.utils.DFS
|
||||||
|
|
||||||
|
class BridgeTest : TestCase() {
|
||||||
|
private class Fun(val text: String) : FunctionHandle {
|
||||||
|
override val isDeclaration: Boolean get() = text[1] == 'D'
|
||||||
|
override val isAbstract: Boolean get() = text[0] == '-'
|
||||||
|
|
||||||
|
val signature: Char get() = text[2]
|
||||||
|
|
||||||
|
val overriddenFunctions: MutableList<Fun> = arrayListOf()
|
||||||
|
override fun getOverridden() = overriddenFunctions
|
||||||
|
|
||||||
|
override fun toString() = text
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Meth(val function: Fun) {
|
||||||
|
override fun equals(other: Any?) = other is Meth && other.function.signature == function.signature
|
||||||
|
override fun hashCode() = function.signature.hashCode()
|
||||||
|
override fun toString() = function.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun v(text: String): Fun {
|
||||||
|
assert(text.length == 3, "Function vertex representation should consist of 3 characters: $text")
|
||||||
|
assert(text[0] in setOf('-', '+'), "First character should be '-' for abstract functions or '+' for concrete ones: $text")
|
||||||
|
assert(text[1] in setOf('D', 'F'), "Second character should be 'D' for declarations or 'F' for fake overrides: $text")
|
||||||
|
assert(text[2].isDigit(),
|
||||||
|
"Third character should be a number that represents a signature (same numbers mean the same method signatures)")
|
||||||
|
return Fun(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bridge(from: Fun, to: Fun): Bridge<Meth> = Bridge(Meth(from), Meth(to))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a graph out of the given pairs of vertices. First vertex should be a function in the derived class,
|
||||||
|
* second -- the corresponding overridden function in a superclass.
|
||||||
|
*
|
||||||
|
* Checks that the graph satisfies the following conditions:
|
||||||
|
* 1. Each fake override should have a super-declaration
|
||||||
|
* 2. Each concrete fake override should have exactly one concrete super-declaration. More accurately, for each concrete
|
||||||
|
* fake override F there is a concrete declaration D in supertypes such that every other concrete super-declaration of F
|
||||||
|
* is either reachable from D or is reachable from any abstract super-declaration of F (or both). This condition is effectively
|
||||||
|
* equivalent to the compiler guarantee that each class inherits not more than one implementation of each function.
|
||||||
|
*
|
||||||
|
* NOTE: abstract fake overrides CAN have concrete super-declarations! (traits with required classes)
|
||||||
|
*
|
||||||
|
* NOTE 2: the graph validation procedure probably doesn't cover all the possible cases compared to the analogous code in the compiler.
|
||||||
|
* There may be bugs here and they should be fixed accordingly.
|
||||||
|
*/
|
||||||
|
private fun graph(vararg edges: Pair<Fun, Fun>) {
|
||||||
|
for ((from, to) in edges) {
|
||||||
|
from.overriddenFunctions.add(to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findAllReachableDeclarations(from: Fun): MutableSet<Fun> {
|
||||||
|
val handler = object : DFS.NodeHandlerWithListResult<Fun, Fun>() {
|
||||||
|
override fun afterChildren(current: Fun?) {
|
||||||
|
if (current!!.isDeclaration) {
|
||||||
|
result.add(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DFS.dfs(listOf(from), { it!!.getOverridden() }, handler)
|
||||||
|
val result = HashSet(handler.result())
|
||||||
|
result.remove(from)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
val vertices = edges.flatMapTo(HashSet<Fun>()) { pair -> listOf(pair.first, pair.second) }
|
||||||
|
|
||||||
|
for (vertex in vertices) {
|
||||||
|
val directConcreteSuperFunctions = vertex.overriddenFunctions.filter { !it.isAbstract }
|
||||||
|
assert(directConcreteSuperFunctions.size <= 1,
|
||||||
|
"Incorrect test data: function $vertex has more than one direct concrete super-function: ${vertex.overriddenFunctions}\n" +
|
||||||
|
"This is not allowed because only classes can contain implementations (concrete functions), and having more than one " +
|
||||||
|
"concrete super-function means having more than one superclass, which is prohibited in Kotlin")
|
||||||
|
|
||||||
|
if (vertex.isDeclaration) continue
|
||||||
|
|
||||||
|
val superDeclarations = findAllReachableDeclarations(vertex)
|
||||||
|
assert(!superDeclarations.isEmpty(), "Incorrect test data: fake override vertex $vertex has no super-declarations")
|
||||||
|
|
||||||
|
// Remove all declarations inherited by other declarations
|
||||||
|
val toRemove = HashSet<Fun>()
|
||||||
|
for (superDeclaration in superDeclarations) {
|
||||||
|
toRemove.addAll(findAllReachableDeclarations(superDeclaration))
|
||||||
|
}
|
||||||
|
superDeclarations.removeAll(toRemove)
|
||||||
|
val concreteDeclarations = superDeclarations.filter { !it.isAbstract }
|
||||||
|
|
||||||
|
if (!vertex.isAbstract) {
|
||||||
|
assert(!concreteDeclarations.isEmpty(),
|
||||||
|
"Incorrect test data: concrete fake override vertex $vertex has no concrete super-declarations")
|
||||||
|
assert(concreteDeclarations.size == 1,
|
||||||
|
"Incorrect test data: concrete fake override vertex $vertex has more than one concrete super-declaration: " +
|
||||||
|
"$concreteDeclarations")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doTest(function: Fun, expectedBridges: Set<Bridge<Meth>>) {
|
||||||
|
val actualBridges = generateBridges(function, ::Meth)
|
||||||
|
assert(actualBridges.firstOrNull { it.from == it.to } == null,
|
||||||
|
"A bridge invoking itself was generated, which makes no sense, since it will result in StackOverflowError once called" +
|
||||||
|
": $actualBridges")
|
||||||
|
assertEquals(expectedBridges, actualBridges, "Expected and actual bridge sets differ for function $function")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Simple tests with no bridges
|
||||||
|
|
||||||
|
fun testOneVertexAbstract() {
|
||||||
|
val a = v("-D1")
|
||||||
|
graph()
|
||||||
|
doTest(a, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testOneVertexConcrete() {
|
||||||
|
val a = v("+D1")
|
||||||
|
graph()
|
||||||
|
doTest(a, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleFakeOverrideSameSignature() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+F1")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleFakeOverrideDifferentSignature() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+F2")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleDeclarationSameSignature() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+D1")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleAbstractDeclarationSameSignature() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D1")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleAbstractDeclarationOverridesConcreteSameSignature() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D1")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple tests where declaration "a" is inherited by declaration "b" with a different signature.
|
||||||
|
// Note that we don't generate bridges near abstract declarations in contrast to javac
|
||||||
|
|
||||||
|
fun testSimpleConcreteDeclarationDifferentSignature() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(b, setOf(bridge(a, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleAbstractDeclarationDifferentSignature() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleAbstractDeclarationOverridesConcreteDifferentSignature() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(b, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleConcreteDeclarationOverridesAbstractDifferentSignature() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
graph(b to a)
|
||||||
|
doTest(b, setOf(bridge(a, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple tests where declaration overrides declaration through a fake override in the super class, with a different signature
|
||||||
|
|
||||||
|
fun testSimpleConcreteDeclarationOverridesConcreteThroughFakeOverride() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+F2")
|
||||||
|
val c = v("+D3")
|
||||||
|
graph(b to a, c to b)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf(bridge(a, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleConcreteDeclarationOverridesAbstractThroughFakeOverride() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-F2")
|
||||||
|
val c = v("+D3")
|
||||||
|
graph(b to a, c to b)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf(bridge(a, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleAbstractDeclarationOverridesConcreteThroughFakeOverride() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+F2")
|
||||||
|
val c = v("-D3")
|
||||||
|
graph(b to a, c to b)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleAbstractDeclarationOverridesAbstractThroughFakeOverride() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-F2")
|
||||||
|
val c = v("-D3")
|
||||||
|
graph(b to a, c to b)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declaration "c" overrides two declarations "a" and "b"
|
||||||
|
|
||||||
|
fun testAbstractDeclarationOverridesTwoAbstractDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAbstractDeclarationOverridesAbstractAndConcreteDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testConcreteDeclarationOverridesTwoAbstractDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("+D3")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf(bridge(a, c), bridge(b, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testConcreteDeclarationOverridesAbstractAndConcreteDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+D3")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf(bridge(a, c), bridge(b, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declaration "c" overrides declaration "a" and declaration "b", which in turn overrides "a".
|
||||||
|
// We still need to generate both bridges near "c" to avoid several consecutive bridges in a call stack
|
||||||
|
|
||||||
|
fun testConcreteDeclarationOverridesTwoInheritingDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+D3")
|
||||||
|
graph(c to a, c to b, b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf(bridge(a, b)))
|
||||||
|
doTest(c, setOf(bridge(a, c), bridge(b, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testConcreteDeclarationOverridesAbstractDeclarationOverridingConcrete() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("+D3")
|
||||||
|
graph(c to a, c to b, b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf(bridge(a, c), bridge(b, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diamonds where the sink (vertex "d") is a declaration: bridges from all super-declarations to "d" should be present
|
||||||
|
|
||||||
|
fun testDiamondAbstractDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("-D4")
|
||||||
|
graph(b to a, c to a, d to b, d to c)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf())
|
||||||
|
doTest(d, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testDiamondMixedDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("+D4")
|
||||||
|
graph(b to a, c to a, d to b, d to c)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf(bridge(a, b)))
|
||||||
|
doTest(c, setOf())
|
||||||
|
doTest(d, setOf(bridge(a, d), bridge(b, d), bridge(c, d)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testDiamondAbstractFakeOverridesInTheMiddle() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-F2")
|
||||||
|
val c = v("-F3")
|
||||||
|
val d = v("+D4")
|
||||||
|
graph(b to a, c to a, d to b, d to c)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf())
|
||||||
|
doTest(d, setOf(bridge(a, d)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake override "c" overrides declarations "a" and "b": a bridge is needed if signatures are different and there's an implementation
|
||||||
|
|
||||||
|
fun testAbstractFakeOverride() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("-F3")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideSameSuperDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D1")
|
||||||
|
val c = v("+F2")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideAbstractAndConcreteDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+F3")
|
||||||
|
graph(c to a, c to b)
|
||||||
|
doTest(c, setOf(bridge(a, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideInheritingDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+F3")
|
||||||
|
graph(c to a, c to b, b to a)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf(bridge(a, b)))
|
||||||
|
// Here bridge a->b is not needed in c, it's already present in b
|
||||||
|
doTest(c, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diamonds where the sink (vertex "d") is a fake override
|
||||||
|
|
||||||
|
fun testDiamondFakeOverrideAbstractFakeAndConcrete() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-F2")
|
||||||
|
val c = v("+D3")
|
||||||
|
val d = v("+F4")
|
||||||
|
graph(b to a, c to a, d to b, d to c)
|
||||||
|
doTest(c, setOf(bridge(a, c)))
|
||||||
|
doTest(d, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testDiamondFakeOverrideAbstractAndConcrete() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("+D3")
|
||||||
|
val d = v("+F4")
|
||||||
|
graph(b to a, c to a, d to b, d to c)
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf(bridge(a, c)))
|
||||||
|
doTest(d, setOf(bridge(b, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testDiamondFakeOverrideAbstractOverridesConcrete() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("+F4")
|
||||||
|
graph(b to a, c to a, d to b, d to c)
|
||||||
|
doTest(b, setOf(bridge(a, b)))
|
||||||
|
doTest(c, setOf())
|
||||||
|
doTest(d, setOf(bridge(c, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// More complex tests where a fake override inherits several declarations
|
||||||
|
|
||||||
|
fun testFakeOverrideInheritingDeclarationsAndAbstract() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("+D3")
|
||||||
|
val e = v("+F4")
|
||||||
|
graph(e to a, e to b, e to c, c to b)
|
||||||
|
doTest(a, setOf())
|
||||||
|
doTest(b, setOf())
|
||||||
|
doTest(c, setOf(bridge(b, c)))
|
||||||
|
doTest(e, setOf(bridge(a, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideManyDeclarations() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("-D4")
|
||||||
|
val e = v("+F5")
|
||||||
|
graph(e to a, e to b, e to c, e to d)
|
||||||
|
doTest(e, setOf(bridge(a, b), bridge(c, b), bridge(d, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideTwoDeclarationsThroughFakeOverrides() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("+F2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("-F4")
|
||||||
|
val e = v("+F5")
|
||||||
|
graph(b to a, d to c, e to b, e to d)
|
||||||
|
doTest(e, setOf(bridge(c, a)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideMisleadingImplementation() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("+D4")
|
||||||
|
val e = v("+F5")
|
||||||
|
val f = v("+F6")
|
||||||
|
graph(c to a, e to d, f to b, f to c, f to e)
|
||||||
|
doTest(e, setOf())
|
||||||
|
// Although "a" is a concrete declaration, it's overridden with abstract in "c" and all bridges should delegate to "d" instead
|
||||||
|
doTest(f, setOf(bridge(a, d), bridge(b, d), bridge(c, d)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake override overrides another fake override (or declaration) with some bridges already present there
|
||||||
|
|
||||||
|
fun testFakeOverrideInheritsBridgeFromFakeOverride() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+F3")
|
||||||
|
val d = v("+F4")
|
||||||
|
graph(c to a, c to b, d to c)
|
||||||
|
doTest(c, setOf(bridge(a, b)))
|
||||||
|
doTest(d, setOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideInheritsBridgesAndAbstract() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+F3")
|
||||||
|
val d = v("-D4")
|
||||||
|
val e = v("+F5")
|
||||||
|
graph(c to a, c to b, e to c, e to d)
|
||||||
|
doTest(c, setOf(bridge(a, b)))
|
||||||
|
// It's important that "e" shouldn't have "a->b" bridge, because it's inherited from "c"
|
||||||
|
doTest(e, setOf(bridge(d, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideInheritsBridgeFromDeclaration() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("+F3")
|
||||||
|
val d = v("+D4")
|
||||||
|
val e = v("-D5")
|
||||||
|
val f = v("+F6")
|
||||||
|
graph(c to a, c to b, d to c, f to d, f to e)
|
||||||
|
doTest(c, setOf(bridge(b, a)))
|
||||||
|
doTest(d, setOf(bridge(a, d), bridge(b, d)))
|
||||||
|
doTest(f, setOf(bridge(e, d)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideDiamondWithExtraAbstract() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-F2")
|
||||||
|
val c = v("+D3")
|
||||||
|
val d = v("-D4")
|
||||||
|
val e = v("+F5")
|
||||||
|
graph(b to a, c to a, e to b, e to c, e to d)
|
||||||
|
doTest(c, setOf(bridge(a, c)))
|
||||||
|
// It's important that implementation of "e" is "c", not "a", so a bridge "d->c" should exist
|
||||||
|
doTest(e, setOf(bridge(d, c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testLongTreeOfFakeOverrideBridgeInheritance() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("-D3")
|
||||||
|
val d = v("+F4")
|
||||||
|
val e = v("-D5")
|
||||||
|
val f = v("-D6")
|
||||||
|
val g = v("+F7")
|
||||||
|
val h = v("-D8")
|
||||||
|
val i = v("-D9")
|
||||||
|
val j = v("+F0")
|
||||||
|
graph(d to a, d to b, d to c,
|
||||||
|
g to d, g to e, g to f,
|
||||||
|
j to g, j to h, j to i)
|
||||||
|
doTest(d, setOf(bridge(b, a), bridge(c, a)))
|
||||||
|
doTest(g, setOf(bridge(e, a), bridge(f, a)))
|
||||||
|
doTest(j, setOf(bridge(h, a), bridge(i, a)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideShouldNotInheritBridgeFromAbstractDeclaration() {
|
||||||
|
val a = v("-D1")
|
||||||
|
val b = v("+D2")
|
||||||
|
val c = v("+F3")
|
||||||
|
val d = v("-D4")
|
||||||
|
val e = v("+D5")
|
||||||
|
val f = v("+F6")
|
||||||
|
graph(c to a, c to b, d to c, f to d, f to e)
|
||||||
|
doTest(c, setOf(bridge(a, b)))
|
||||||
|
// Although "f" has a concrete fake override "c" in its hierarchy, we should NOT silently inherit a bridge from it,
|
||||||
|
// because it corresponds to another implementation ("b"). Instead a bunch of new bridges should be generated, delegating to "e"
|
||||||
|
doTest(f, setOf(bridge(a, e), bridge(b, e), bridge(d, e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFakeOverrideShouldNotInheritBridgeFromAbstractFakeOverride() {
|
||||||
|
val a = v("+D1")
|
||||||
|
val b = v("-D2")
|
||||||
|
val c = v("-F3")
|
||||||
|
val d = v("+F4")
|
||||||
|
graph(c to a, c to b, d to a, d to c)
|
||||||
|
doTest(c, setOf())
|
||||||
|
doTest(d, setOf(bridge(b, a)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -285,6 +285,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/bridges"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/bridges"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("complexMultiInheritance.kt")
|
||||||
|
public void testComplexMultiInheritance() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/bridges/complexMultiInheritance.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("delegation.kt")
|
@TestMetadata("delegation.kt")
|
||||||
public void testDelegation() throws Exception {
|
public void testDelegation() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/bridges/delegation.kt");
|
doTest("compiler/testData/codegen/box/bridges/delegation.kt");
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.utils;
|
package org.jetbrains.jet.utils;
|
||||||
|
|
||||||
|
import kotlin.jvm.KotlinSignature;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -87,6 +88,7 @@ public class DFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public interface Neighbors<N> {
|
public interface Neighbors<N> {
|
||||||
|
@KotlinSignature("fun getNeighbors(current: N?): Iterable<N>")
|
||||||
@NotNull
|
@NotNull
|
||||||
Iterable<N> getNeighbors(N current);
|
Iterable<N> getNeighbors(N current);
|
||||||
}
|
}
|
||||||
@@ -123,9 +125,11 @@ public class DFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class NodeHandlerWithListResult<N, R> extends AbstractNodeHandler<N, List<R>> {
|
public static abstract class NodeHandlerWithListResult<N, R> extends AbstractNodeHandler<N, List<R>> {
|
||||||
|
@NotNull
|
||||||
protected final LinkedList<R> result = new LinkedList<R>();
|
protected final LinkedList<R> result = new LinkedList<R>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NotNull
|
||||||
public List<R> result() {
|
public List<R> result() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user