diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java index ada24bc4a2e..264c5c67d69 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java @@ -20,7 +20,10 @@ import com.google.common.collect.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; -import com.intellij.psi.*; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiMethod; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -154,47 +157,52 @@ public class SignaturesPropagationData { private JavaDescriptorResolver.ValueParameterDescriptors modifyValueParametersAccordingToSuperMethods( @NotNull JavaDescriptorResolver.ValueParameterDescriptors parameters // descriptors built by parameters resolver ) { - // we are not processing receiver type specifically: - // if this function comes from Kotlin, then we don't need to do it, if it doesn't, then it can't have receiver + assert parameters.getReceiverType() == null : "Parameters before propagation have receiver type," + + " but propagation should be disabled for functions compiled from Kotlin in class: " + + DescriptorUtils.getFQName(containingClass); + JetType receiverType = null; List resultParameters = Lists.newArrayList(); + boolean shouldBeExtension = checkIfShouldBeExtension(); + for (ValueParameterDescriptor originalParam : parameters.getDescriptors()) { - final int index = originalParam.getIndex(); + final int originalIndex = originalParam.getIndex(); List typesFromSuperMethods = ContainerUtil.map(superFunctions, new Function() { @Override public TypeAndVariance fun(FunctionDescriptor superFunction) { + ReceiverParameterDescriptor receiver = superFunction.getReceiverParameter(); + int index = receiver != null ? originalIndex - 1 : originalIndex; + if (index == -1) { + assert receiver != null : "can't happen: index is -1, while function is not extension"; + return new TypeAndVariance(receiver.getType(), INVARIANT); + } return new TypeAndVariance(superFunction.getValueParameters().get(index).getType(), INVARIANT); } }); - VarargCheckResult varargCheckResult = - checkVarargInSuperFunctions(originalParam); + VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam); JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods, MEMBER_SIGNATURE_CONTRAVARIANT); - resultParameters.add(new ValueParameterDescriptorImpl( - originalParam.getContainingDeclaration(), - index, - originalParam.getAnnotations(), - originalParam.getName(), - altType, - originalParam.declaresDefaultValue(), - varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null - )); + if (shouldBeExtension && originalIndex == 0) { + receiverType = altType; + } + else { + resultParameters.add(new ValueParameterDescriptorImpl( + originalParam.getContainingDeclaration(), + shouldBeExtension ? originalIndex - 1 : originalIndex, + originalParam.getAnnotations(), + originalParam.getName(), + altType, + originalParam.declaresDefaultValue(), + varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null + )); + } } - JetType originalReceiverType = parameters.getReceiverType(); - if (originalReceiverType != null) { - JetType substituted = SignaturesUtil.createSubstitutorForTypeParameters(autoTypeParameterToModified) - .substitute(originalReceiverType, INVARIANT); - assert substituted != null; - return new JavaDescriptorResolver.ValueParameterDescriptors(substituted, resultParameters); - } - else { - return new JavaDescriptorResolver.ValueParameterDescriptors(null, resultParameters); - } + return new JavaDescriptorResolver.ValueParameterDescriptors(receiverType, resultParameters); } private static List getSuperFunctionsForMethod( @@ -270,7 +278,7 @@ public class SignaturesPropagationData { for (FunctionDescriptor fun : klass.getDefaultType().getMemberScope().getFunctions(functionName)) { CallableMemberDescriptor.Kind kind = fun.getKind(); if ((kind == CallableMemberDescriptor.Kind.DECLARATION || kind == CallableMemberDescriptor.Kind.DELEGATION) && - fun.getValueParameters().size() == parameterCount) { + fun.getValueParameters().size() + (fun.getReceiverParameter() != null ? 1 : 0) == parameterCount) { PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun); if (declaration instanceof PsiMethod) { result.put(fqName, Pair.create(fun, (PsiMethod) declaration)); @@ -295,12 +303,38 @@ public class SignaturesPropagationData { return null; } + private boolean checkIfShouldBeExtension() { + boolean someSupersExtension = false; + boolean someSupersNotExtension = false; + + for (FunctionDescriptor superFunction : superFunctions) { + if (superFunction.getReceiverParameter() != null) { + someSupersExtension = true; + } + else { + someSupersNotExtension = true; + } + } + + if (someSupersExtension) { + if (someSupersNotExtension) { + reportError("Incompatible super methods: some are extension functions, some are not"); + } + else { + return true; + } + } + return false; + } + @NotNull private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) { boolean someSupersVararg = false; boolean someSupersNotVararg = false; for (FunctionDescriptor superFunction : superFunctions) { - if (superFunction.getValueParameters().get(originalParam.getIndex()).getVarargElementType() != null) { + int originalIndex = originalParam.getIndex(); + int index = superFunction.getReceiverParameter() != null ? originalIndex - 1 : originalIndex; + if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) { someSupersVararg = true; } else { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java index 9e18fa32636..01f84197a25 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java @@ -151,7 +151,7 @@ public final class JavaFunctionResolver { List signatureErrors = Lists.newArrayList(); List superFunctions; - if (ownerDescriptor instanceof ClassDescriptor) { + if (ownerDescriptor instanceof ClassDescriptor && !method.getJetMethodAnnotation().isDefined()) { // don't propagate for Kotlin functions SignaturesPropagationData signaturesPropagationData = new SignaturesPropagationData( (ClassDescriptor) ownerDescriptor, returnType, valueParameterDescriptors, methodTypeParameters, method, trace); superFunctions = signaturesPropagationData.getSuperFunctions(); diff --git a/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot.txt b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot.txt new file mode 100644 index 00000000000..fd0efdb3f72 --- /dev/null +++ b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot.txt @@ -0,0 +1,18 @@ +package test + +public trait Sub : test.Super1, test.Super2 { + public abstract override /*1*/ fun bar(/*0*/ vararg p: jet.String /*jet.Array*/): jet.Unit + public abstract override /*1*/ fun foo(/*0*/ p: jet.String): jet.Unit + public abstract override /*1*/ /*fake_override*/ fun jet.Array.bar(): jet.Unit + public abstract override /*1*/ /*fake_override*/ fun jet.String.foo(): jet.Unit +} + +public trait Super1 { + public abstract fun jet.Array.bar(): jet.Unit + public abstract fun jet.String.foo(): jet.Unit +} + +public trait Super2 { + public abstract fun bar(/*0*/ vararg p: jet.String /*jet.Array*/): jet.Unit + public abstract fun foo(/*0*/ p: jet.String): jet.Unit +} diff --git a/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot/Sub.java b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot/Sub.java new file mode 100644 index 00000000000..f3b24148631 --- /dev/null +++ b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot/Sub.java @@ -0,0 +1,11 @@ +package test; + +import org.jetbrains.jet.jvm.compiler.annotation.ExpectLoadError; + +public interface Sub extends Super1, Super2 { + @ExpectLoadError("Incompatible super methods: some are extension functions, some are not") + void foo(String p); + + @ExpectLoadError("Incompatible super methods: some are extension functions, some are not|Incompatible super methods: some have vararg parameter, some have not") + void bar(String... p); +} diff --git a/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot/supers.kt b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot/supers.kt new file mode 100644 index 00000000000..8395f7c57a9 --- /dev/null +++ b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot/supers.kt @@ -0,0 +1,12 @@ +package test + +public trait Super1 { + public fun String.foo() + public fun Array.bar() +} + +public trait Super2 { + public fun foo(p: String) + public fun bar(vararg p: String) +} + diff --git a/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction.txt b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction.txt new file mode 100644 index 00000000000..c08879340ac --- /dev/null +++ b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction.txt @@ -0,0 +1,13 @@ +package test + +public open class Sub : test.Super { + public constructor Sub() + public open override /*1*/ fun jet.String.bar(/*0*/ param: jet.String): jet.String + public final override /*1*/ /*fake_override*/ fun jet.String.foo(): jet.Unit +} + +public open class Super { + public constructor Super() + public abstract fun jet.String.bar(/*0*/ p: jet.String): jet.Unit + public final fun jet.String.foo(): jet.Unit +} diff --git a/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction/Sub.java b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction/Sub.java new file mode 100644 index 00000000000..29aaf4e35f7 --- /dev/null +++ b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction/Sub.java @@ -0,0 +1,6 @@ +package test; + +public class Sub extends Super { + public String bar(String recv, String param) { + } +} diff --git a/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction/Super.kt b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction/Super.kt new file mode 100644 index 00000000000..0a8d5f24cd7 --- /dev/null +++ b/compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction/Super.kt @@ -0,0 +1,6 @@ +package test + +public open class Super { + public fun String.foo() = Unit.VALUE + public abstract fun String.bar(p: String) +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java index 3962e91a955..2c2435d95ae 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.ConfigurationKind; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.TestJdkKind; +import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; import org.jetbrains.jet.cli.jvm.compiler.CliLightClassGenerationSupport; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.config.CommonConfigurationKeys; @@ -136,6 +137,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { CompilerConfiguration configuration = JetTestUtils.compilerConfigurationForTests( ConfigurationKind.JDK_ONLY, TestJdkKind.MOCK_JDK, tmpdir); configuration.put(CommonConfigurationKeys.SOURCE_ROOTS_KEY, Arrays.asList(sourcesDir.getAbsolutePath())); + configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, new File("compiler/tests")); // for @ExpectLoadError annotation JetCoreEnvironment environment = new JetCoreEnvironment(getTestRootDisposable(), configuration); ModuleDescriptorImpl moduleDescriptor = AnalyzerFacadeForJVM.createJavaModule(""); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 09853f91ad9..faf788d6631 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -1367,6 +1367,16 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/DeepSubclassingKotlinInJava.txt"); } + @TestMetadata("InheritExtensionAndNot.txt") + public void testInheritExtensionAndNot() throws Exception { + doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot.txt"); + } + + @TestMetadata("InheritExtensionFunction.txt") + public void testInheritExtensionFunction() throws Exception { + doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction.txt"); + } + @TestMetadata("SubclassFromTraitImplementation.txt") public void testSubclassFromTraitImplementation() throws Exception { doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/SubclassFromTraitImplementation.txt");