KT-3577 Stack overflow when resolving SAM adapter (from completion, show parameters, etc)

#KT-3577
This commit is contained in:
Evgeny Gerashchenko
2013-05-17 20:54:36 +04:00
parent 6f7d42185f
commit 5fc7c885bb
11 changed files with 174 additions and 40 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptorLite; import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptorLite;
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope; import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection; import java.util.Collection;
@@ -30,18 +31,16 @@ import java.util.Collection;
* @see org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor * @see org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor
*/ */
public class ClassDescriptorFromJvmBytecode extends MutableClassDescriptorLite { public class ClassDescriptorFromJvmBytecode extends MutableClassDescriptorLite {
private final boolean isSamInterface; private JetType functionTypeForSamInterface;
private JavaClassNonStaticMembersScope scopeForConstructorResolve; private JavaClassNonStaticMembersScope scopeForConstructorResolve;
public ClassDescriptorFromJvmBytecode( public ClassDescriptorFromJvmBytecode(
@NotNull DeclarationDescriptor containingDeclaration, @NotNull DeclarationDescriptor containingDeclaration,
@NotNull ClassKind kind, @NotNull ClassKind kind,
boolean isInner, boolean isInner
boolean isSamInterface
) { ) {
super(containingDeclaration, kind, isInner); super(containingDeclaration, kind, isInner);
this.isSamInterface = isSamInterface;
} }
@@ -62,7 +61,12 @@ public class ClassDescriptorFromJvmBytecode extends MutableClassDescriptorLite {
this.scopeForConstructorResolve = scopeForConstructorResolve; this.scopeForConstructorResolve = scopeForConstructorResolve;
} }
public boolean isSamInterface() { @Nullable
return isSamInterface; public JetType getFunctionTypeForSamInterface() {
return functionTypeForSamInterface;
}
public void setFunctionTypeForSamInterface(@NotNull JetType functionTypeForSamInterface) {
this.functionTypeForSamInterface = functionTypeForSamInterface;
} }
} }
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.java.provider;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiFormatUtil;
@@ -402,28 +403,37 @@ public final class MembersCache {
} }
public static boolean isSamInterface(@NotNull PsiClass psiClass) { public static boolean isSamInterface(@NotNull PsiClass psiClass) {
return getSamInterfaceMethod(psiClass) != null;
}
// Returns null if not SAM interface
@Nullable
public static PsiMethod getSamInterfaceMethod(@NotNull PsiClass psiClass) {
if (psiClass.hasModifierProperty(PsiModifier.PRIVATE)) { // TODO hacky
return null;
}
if (DescriptorResolverUtils.isKotlinClass(psiClass)) { if (DescriptorResolverUtils.isKotlinClass(psiClass)) {
return false; return null;
} }
String qualifiedName = psiClass.getQualifiedName(); String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName == null || qualifiedName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.getFqName() + ".")) { if (qualifiedName == null || qualifiedName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.getFqName() + ".")) {
return false; return null;
} }
if (!psiClass.isInterface() || psiClass.isAnnotationType()) { if (!psiClass.isInterface() || psiClass.isAnnotationType()) {
return false; return null;
} }
int foundAbstractMethods = 0; List<PsiMethod> methods = Lists.newArrayList();
for (PsiMethod method : psiClass.getAllMethods()) { for (PsiMethod method : psiClass.getAllMethods()) {
if (!isObjectMethod(method) && method.hasModifierProperty(PsiModifier.ABSTRACT)) { if (!isObjectMethod(method) && method.hasModifierProperty(PsiModifier.ABSTRACT)) {
foundAbstractMethods++; methods.add(method);
if (method.hasTypeParameters()) { if (method.hasTypeParameters()) {
return false; return null;
} }
} }
} }
return foundAbstractMethods == 1; return methods.size() == 1 ? methods.get(0) : null;
} }
private static abstract class RunOnce implements Runnable { private static abstract class RunOnce implements Runnable {
@@ -100,7 +100,7 @@ public final class JavaClassObjectResolver {
FqName fqName = new FqName(qualifiedName); FqName fqName = new FqName(qualifiedName);
ClassPsiDeclarationProvider classObjectData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(classObjectPsiClass); ClassPsiDeclarationProvider classObjectData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(classObjectPsiClass);
ClassDescriptorFromJvmBytecode classObjectDescriptor ClassDescriptorFromJvmBytecode classObjectDescriptor
= new ClassDescriptorFromJvmBytecode(containing, ClassKind.CLASS_OBJECT, false, false); = new ClassDescriptorFromJvmBytecode(containing, ClassKind.CLASS_OBJECT, false);
classObjectDescriptor.setSupertypes(supertypesResolver.getSupertypes(classObjectDescriptor, classObjectDescriptor.setSupertypes(supertypesResolver.getSupertypes(classObjectDescriptor,
new PsiClassWrapper(classObjectPsiClass), new PsiClassWrapper(classObjectPsiClass),
classObjectData, classObjectData,
@@ -129,7 +129,7 @@ public final class JavaClassObjectResolver {
) { ) {
FqNameUnsafe fqName = DescriptorResolverUtils.getFqNameForClassObject(psiClass); FqNameUnsafe fqName = DescriptorResolverUtils.getFqNameForClassObject(psiClass);
ClassDescriptorFromJvmBytecode classObjectDescriptor = ClassDescriptorFromJvmBytecode classObjectDescriptor =
new ClassDescriptorFromJvmBytecode(containing, ClassKind.CLASS_OBJECT, false, false); new ClassDescriptorFromJvmBytecode(containing, ClassKind.CLASS_OBJECT, false);
ClassPsiDeclarationProvider data = semanticServices.getPsiDeclarationProviderFactory().createSyntheticClassObjectClassData(psiClass); ClassPsiDeclarationProvider data = semanticServices.getPsiDeclarationProviderFactory().createSyntheticClassObjectClassData(psiClass);
setUpClassObjectDescriptor(classObjectDescriptor, containing, fqName, data, getClassObjectName(containing.getName().getName())); setUpClassObjectDescriptor(classObjectDescriptor, containing, fqName, data, getClassObjectName(containing.getName().getName()));
return classObjectDescriptor; return classObjectDescriptor;
@@ -20,6 +20,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifier;
import gnu.trove.THashMap; import gnu.trove.THashMap;
import gnu.trove.TObjectHashingStrategy; import gnu.trove.TObjectHashingStrategy;
@@ -33,8 +34,11 @@ import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation; import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation;
import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider; import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope; import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameBase; import org.jetbrains.jet.lang.resolve.name.FqNameBase;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
@@ -234,7 +238,7 @@ public final class JavaClassResolver {
ClassKind kind = getClassKind(psiClass, jetClassAnnotation); ClassKind kind = getClassKind(psiClass, jetClassAnnotation);
ClassPsiDeclarationProvider classData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(psiClass); ClassPsiDeclarationProvider classData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(psiClass);
ClassDescriptorFromJvmBytecode classDescriptor = new ClassDescriptorFromJvmBytecode( ClassDescriptorFromJvmBytecode classDescriptor = new ClassDescriptorFromJvmBytecode(
containingDeclaration, kind, isInnerClass(psiClass), MembersCache.isSamInterface(psiClass)); containingDeclaration, kind, isInnerClass(psiClass));
cache(javaClassToKotlinFqName(fqName), classDescriptor); cache(javaClassToKotlinFqName(fqName), classDescriptor);
classDescriptor.setName(Name.identifier(psiClass.getName())); classDescriptor.setName(Name.identifier(psiClass.getName()));
@@ -269,6 +273,13 @@ public final class JavaClassResolver {
trace.record(BindingContext.CLASS, psiClass, classDescriptor); trace.record(BindingContext.CLASS, psiClass, classDescriptor);
PsiMethod samInterfaceMethod = MembersCache.getSamInterfaceMethod(psiClass);
if (samInterfaceMethod != null) {
SimpleFunctionDescriptor abstractMethod = functionResolver.resolveFunctionMutely(
psiClass, new PsiMethodWrapper(samInterfaceMethod), classDescriptor);
classDescriptor.setFunctionTypeForSamInterface(SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod));
}
return classDescriptor; return classDescriptor;
} }
@@ -34,10 +34,7 @@ import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData; import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData;
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesPropagationData; import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesPropagationData;
import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider; import org.jetbrains.jet.lang.resolve.java.provider.*;
import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers;
import org.jetbrains.jet.lang.resolve.java.provider.PackagePsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
@@ -93,10 +90,18 @@ public final class JavaFunctionResolver {
this.annotationResolver = annotationResolver; this.annotationResolver = annotationResolver;
} }
@Nullable
SimpleFunctionDescriptor resolveFunctionMutely(
@NotNull PsiClass psiClass, PsiMethodWrapper method,
@NotNull ClassOrNamespaceDescriptor ownerDescriptor
) {
return resolveMethodToFunctionDescriptor(psiClass, method, DeclarationOrigin.JAVA, ownerDescriptor, false);
}
@Nullable @Nullable
private SimpleFunctionDescriptor resolveMethodToFunctionDescriptor( private SimpleFunctionDescriptor resolveMethodToFunctionDescriptor(
@NotNull PsiClass psiClass, PsiMethodWrapper method, @NotNull PsiClass psiClass, PsiMethodWrapper method,
@NotNull PsiDeclarationProvider scopeData, @NotNull ClassOrNamespaceDescriptor ownerDescriptor @NotNull DeclarationOrigin declarationOrigin, @NotNull ClassOrNamespaceDescriptor ownerDescriptor, boolean record
) { ) {
if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, method.getPsiMember())) { if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, method.getPsiMember())) {
return null; return null;
@@ -114,7 +119,7 @@ public final class JavaFunctionResolver {
PsiMethod psiMethod = method.getPsiMethod(); PsiMethod psiMethod = method.getPsiMethod();
PsiClass containingClass = psiMethod.getContainingClass(); PsiClass containingClass = psiMethod.getContainingClass();
if (scopeData.getDeclarationOrigin() == KOTLIN) { if (declarationOrigin == KOTLIN) {
// TODO: unless maybe class explicitly extends Object // TODO: unless maybe class explicitly extends Object
assert containingClass != null; assert containingClass != null;
String ownerClassName = containingClass.getQualifiedName(); String ownerClassName = containingClass.getQualifiedName();
@@ -189,11 +194,11 @@ public final class JavaFunctionResolver {
/*isInline = */ false /*isInline = */ false
); );
if (functionDescriptorImpl.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { if (functionDescriptorImpl.getKind() == CallableMemberDescriptor.Kind.DECLARATION && record) {
BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, psiMethod, functionDescriptorImpl); BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, psiMethod, functionDescriptorImpl);
} }
if (scopeData.getDeclarationOrigin() == JAVA) { if (declarationOrigin == JAVA && record) {
trace.record(BindingContext.IS_DECLARED_IN_JAVA, functionDescriptorImpl); trace.record(BindingContext.IS_DECLARED_IN_JAVA, functionDescriptorImpl);
} }
@@ -208,7 +213,9 @@ public final class JavaFunctionResolver {
checkFunctionsOverrideCorrectly(method, superFunctions, functionDescriptorImpl); checkFunctionsOverrideCorrectly(method, superFunctions, functionDescriptorImpl);
} }
else { else {
trace.record(BindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, functionDescriptorImpl, signatureErrors); if (record) {
trace.record(BindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, functionDescriptorImpl, signatureErrors);
}
} }
} }
@@ -267,7 +274,7 @@ public final class JavaFunctionResolver {
Set<SimpleFunctionDescriptor> functionsFromCurrent = Sets.newHashSet(); Set<SimpleFunctionDescriptor> functionsFromCurrent = Sets.newHashSet();
for (PsiMethodWrapper method : namedMembers.getMethods()) { for (PsiMethodWrapper method : namedMembers.getMethods()) {
SimpleFunctionDescriptor function = resolveMethodToFunctionDescriptor(psiClass, method, scopeData, owner); SimpleFunctionDescriptor function = resolveMethodToFunctionDescriptor(psiClass, method, scopeData.getDeclarationOrigin(), owner, true);
if (function != null) { if (function != null) {
functionsFromCurrent.add(function); functionsFromCurrent.add(function);
@@ -27,10 +27,7 @@ import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil; import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Arrays; import java.util.Arrays;
@@ -38,7 +35,10 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
public class SingleAbstractMethodUtils { public class SingleAbstractMethodUtils {
@NotNull @NotNull
private static List<CallableMemberDescriptor> getAbstractMembers(@NotNull JetType type) { private static List<CallableMemberDescriptor> getAbstractMembers(@NotNull JetType type) {
List<CallableMemberDescriptor> abstractMembers = Lists.newArrayList(); List<CallableMemberDescriptor> abstractMembers = Lists.newArrayList();
@@ -52,18 +52,67 @@ public class SingleAbstractMethodUtils {
return abstractMembers; return abstractMembers;
} }
@NotNull // TODO maybe do this in substitutor?
private static JetType fixProjections(@NotNull JetType functionType) {
//removes redundant projection kinds and detects conflicts
List<TypeProjection> arguments = Lists.newArrayList();
for (TypeParameterDescriptor typeParameter : functionType.getConstructor().getParameters()) {
Variance variance = typeParameter.getVariance();
TypeProjection argument = functionType.getArguments().get(typeParameter.getIndex());
Variance kind = argument.getProjectionKind();
if (kind != INVARIANT && variance != INVARIANT) {
if (kind == variance) {
arguments.add(new TypeProjection(argument.getType()));
}
else {
return null;
}
}
else {
arguments.add(argument);
}
}
ClassifierDescriptor classifier = functionType.getConstructor().getDeclarationDescriptor();
assert classifier instanceof ClassDescriptor : "Not class: " + classifier;
return new JetTypeImpl(
functionType.getAnnotations(),
functionType.getConstructor(),
functionType.isNullable(),
arguments,
((ClassDescriptor) classifier).getMemberScope(arguments)
);
}
@Nullable
private static JetType getFunctionTypeForSamType(@NotNull JetType samType) { private static JetType getFunctionTypeForSamType(@NotNull JetType samType) {
FunctionDescriptor function = getAbstractMethodOfSamType(samType); // e.g. samType == Comparator<String>?
ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor();
if (classifier instanceof ClassDescriptorFromJvmBytecode) {
// Function2<T, T, Int>
JetType functionTypeDefault = ((ClassDescriptorFromJvmBytecode) classifier).getFunctionTypeForSamInterface();
if (functionTypeDefault != null) {
// Function2<String, String, Int>?
JetType substitute = TypeSubstitutor.create(samType).substitute(functionTypeDefault, Variance.INVARIANT);
return substitute == null ? null : fixProjections(TypeUtils.makeNullableAsSpecified(substitute, samType.isNullable()));
}
}
return null;
}
@NotNull
public static JetType getFunctionTypeForAbstractMethod(@NotNull FunctionDescriptor function) {
JetType returnType = function.getReturnType(); JetType returnType = function.getReturnType();
assert returnType != null : "function is not initialized: " + function; assert returnType != null : "function is not initialized: " + function;
List<JetType> parameterTypes = Lists.newArrayList(); List<JetType> parameterTypes = Lists.newArrayList();
for (ValueParameterDescriptor parameter : function.getValueParameters()) { for (ValueParameterDescriptor parameter : function.getValueParameters()) {
parameterTypes.add(parameter.getType()); parameterTypes.add(parameter.getType());
} }
JetType functionType = KotlinBuiltIns.getInstance() return KotlinBuiltIns.getInstance().getFunctionType(
.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), null, parameterTypes, returnType); Collections.<AnnotationDescriptor>emptyList(), null, parameterTypes, returnType);
return TypeUtils.makeNullableAsSpecified(functionType, samType.isNullable());
} }
private static boolean isSamInterface(@NotNull ClassDescriptor klass) { private static boolean isSamInterface(@NotNull ClassDescriptor klass) {
@@ -98,6 +147,7 @@ public class SingleAbstractMethodUtils {
TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result); TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result);
JetType parameterTypeUnsubstituted = getFunctionTypeForSamType(samInterface.getDefaultType()); JetType parameterTypeUnsubstituted = getFunctionTypeForSamType(samInterface.getDefaultType());
assert parameterTypeUnsubstituted != null : "couldn't get function type for SAM type" + samInterface.getDefaultType();
JetType parameterType = typeParameters.substitutor.substitute(parameterTypeUnsubstituted, Variance.IN_VARIANCE); JetType parameterType = typeParameters.substitutor.substitute(parameterTypeUnsubstituted, Variance.IN_VARIANCE);
assert parameterType != null : "couldn't substitute type: " + parameterType + ", substitutor = " + typeParameters.substitutor; assert parameterType != null : "couldn't substitute type: " + parameterType + ", substitutor = " + typeParameters.substitutor;
ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl( ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
@@ -121,10 +171,7 @@ public class SingleAbstractMethodUtils {
} }
public static boolean isSamType(@NotNull JetType type) { public static boolean isSamType(@NotNull JetType type) {
ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor(); return getFunctionTypeForSamType(type) != null;
return classifier instanceof ClassDescriptorFromJvmBytecode &&
((ClassDescriptorFromJvmBytecode) classifier).isSamInterface() &&
getAbstractMembers(type).size() == 1; // Comparator<*> is not a SAM type, because substituted compare() method doesn't exist
} }
public static boolean isSamAdapterNecessary(@NotNull SimpleFunctionDescriptor fun) { public static boolean isSamAdapterNecessary(@NotNull SimpleFunctionDescriptor fun) {
@@ -155,7 +202,8 @@ public class SingleAbstractMethodUtils {
List<ValueParameterDescriptor> valueParameters = Lists.newArrayList(); List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
for (ValueParameterDescriptor originalParam : original.getValueParameters()) { for (ValueParameterDescriptor originalParam : original.getValueParameters()) {
JetType originalType = originalParam.getType(); JetType originalType = originalParam.getType();
JetType newTypeUnsubstituted = isSamType(originalType) ? getFunctionTypeForSamType(originalType) : originalType; JetType functionType = getFunctionTypeForSamType(originalType);
JetType newTypeUnsubstituted = functionType != null ? functionType : originalType;
JetType newType = typeParameters.substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE); JetType newType = typeParameters.substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE);
assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + typeParameters.substitutor; assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + typeParameters.substitutor;
@@ -0,0 +1,12 @@
package test;
public interface DeepSamLoop {
interface Foo {
void foo(Bar p);
}
interface Bar {
void foo(Foo p);
}
}
@@ -0,0 +1,19 @@
package test
public trait DeepSamLoop : java.lang.Object {
public trait Bar : java.lang.Object {
public abstract /*synthesized*/ fun foo(/*0*/ p0: ((test.DeepSamLoop.Bar?) -> jet.Unit)?): jet.Unit
public abstract fun foo(/*0*/ p0: test.DeepSamLoop.Foo?): jet.Unit
}
public trait Foo : java.lang.Object {
public abstract /*synthesized*/ fun foo(/*0*/ p0: ((test.DeepSamLoop.Foo?) -> jet.Unit)?): jet.Unit
public abstract fun foo(/*0*/ p0: test.DeepSamLoop.Bar?): jet.Unit
}
}
package DeepSamLoop {
public /*synthesized*/ fun Bar(/*0*/ function: (test.DeepSamLoop.Foo?) -> jet.Unit): test.DeepSamLoop.Bar
public /*synthesized*/ fun Foo(/*0*/ function: (test.DeepSamLoop.Bar?) -> jet.Unit): test.DeepSamLoop.Foo
}
@@ -0,0 +1,5 @@
package test;
public interface SelfAsParameter {
void foo(SelfAsParameter p);
}
@@ -0,0 +1,8 @@
package test
public /*synthesized*/ fun SelfAsParameter(/*0*/ function: (test.SelfAsParameter?) -> jet.Unit): test.SelfAsParameter
public trait SelfAsParameter : java.lang.Object {
public abstract /*synthesized*/ fun foo(/*0*/ p0: ((test.SelfAsParameter?) -> jet.Unit)?): jet.Unit
public abstract fun foo(/*0*/ p0: test.SelfAsParameter?): jet.Unit
}
@@ -1229,11 +1229,21 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Basic.java"); doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Basic.java");
} }
@TestMetadata("DeepSamLoop.java")
public void testDeepSamLoop() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/DeepSamLoop.java");
}
@TestMetadata("NonTrivialFunctionType.java") @TestMetadata("NonTrivialFunctionType.java")
public void testNonTrivialFunctionType() throws Exception { public void testNonTrivialFunctionType() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/NonTrivialFunctionType.java"); doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/NonTrivialFunctionType.java");
} }
@TestMetadata("SelfAsParameter.java")
public void testSelfAsParameter() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/SelfAsParameter.java");
}
@TestMetadata("SeveralSamParameters.java") @TestMetadata("SeveralSamParameters.java")
public void testSeveralSamParameters() throws Exception { public void testSeveralSamParameters() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/SeveralSamParameters.java"); doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/SeveralSamParameters.java");