From 4da03f75f9b79d36a62bb125a7ae6c3660aad04f Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Wed, 21 Nov 2012 20:39:37 +0400 Subject: [PATCH] Supported simplest case of signatures propagation in value parameter position. #KT-2776 in progress --- .../SignaturesPropagation.java | 66 ++++++++++++++++--- .../java/resolver/JavaFunctionResolver.java | 6 +- .../parameter/InheritNullability.java | 14 ++++ .../parameter/InheritNullability.kt | 12 ++++ .../parameter/InheritNullability.txt | 10 +++ .../parameter/NotNullToNullable.java | 18 +++++ .../parameter/NotNullToNullable.kt | 12 ++++ .../parameter/NotNullToNullable.txt | 10 +++ .../parameter/NullableToNotNull.java | 17 +++++ .../parameter/NullableToNotNull.kt | 12 ++++ .../parameter/NullableToNotNull.txt | 10 +++ ...oSuperclassesInconsistentGenericTypes.java | 2 +- .../jvm/compiler/AbstractLoadJavaTest.java | 4 +- .../jvm/compiler/LoadJavaTestGenerated.java | 26 +++++++- ...esolveNamespaceComparingTestGenerated.java | 26 +++++++- 15 files changed, 229 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.java create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.kt create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.txt create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.java create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.kt create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.txt create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.java create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.kt create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.txt diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java index 96567b9b6bc..f201225e223 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagation.java @@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.CollectionClassMapping; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -51,7 +52,44 @@ public class SignaturesPropagation { } }); - return modifyReturnTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, true, reportError); + return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, true, reportError); + } + + public static JavaDescriptorResolver.ValueParameterDescriptors modifyValueParametersAccordingToSuperMethods( + @NotNull JavaDescriptorResolver.ValueParameterDescriptors parameters, // descriptors built by parameters resolver + @NotNull List superFunctions, + @NotNull Function1 reportError + ) { + // 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 + + List resultParameters = Lists.newArrayList(); + + for (final ValueParameterDescriptor originalParam : parameters.getDescriptors()) { + final int index = originalParam.getIndex(); + List typesFromSuperMethods = ContainerUtil.map(superFunctions, + new Function() { + @Override + public JetType fun(FunctionDescriptor superFunction) { + return superFunction.getValueParameters().get(index).getType(); + } + }); + + JetType altType = modifyTypeAccordingToSuperMethods(originalParam.getType(), typesFromSuperMethods, false, reportError); + + resultParameters.add(new ValueParameterDescriptorImpl( + originalParam.getContainingDeclaration(), + index, + originalParam.getAnnotations(), + originalParam.getName(), + originalParam.isVar(), + altType, + originalParam.declaresDefaultValue(), + originalParam.getVarargElementType() + )); + } + + return new JavaDescriptorResolver.ValueParameterDescriptors(parameters.getReceiverType(), resultParameters); } public static List getSuperFunctionsForMethod( @@ -91,7 +129,7 @@ public class SignaturesPropagation { @NotNull - private static JetType modifyReturnTypeAccordingToSuperMethods( + private static JetType modifyTypeAccordingToSuperMethods( @NotNull JetType autoType, @NotNull List typesFromSuper, boolean covariantPosition, @@ -101,10 +139,10 @@ public class SignaturesPropagation { return autoType; } - boolean resultNullable = returnTypeMustBeNullable(autoType, typesFromSuper, covariantPosition, reportError); - List resultArguments = getTypeArgsOfReturnType(autoType, typesFromSuper, reportError); + boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, covariantPosition, reportError); + List resultArguments = getTypeArgsOfType(autoType, typesFromSuper, reportError); JetScope resultScope; - ClassifierDescriptor classifierDescriptor = getReturnTypeClassifier(autoType, typesFromSuper); + ClassifierDescriptor classifierDescriptor = modifyTypeClassifier(autoType, typesFromSuper); if (classifierDescriptor instanceof ClassDescriptor) { resultScope = ((ClassDescriptor) classifierDescriptor).getMemberScope(resultArguments); } @@ -120,7 +158,7 @@ public class SignaturesPropagation { } @NotNull - private static List getTypeArgsOfReturnType( + private static List getTypeArgsOfType( @NotNull JetType autoType, @NotNull List typesFromSuper, @NotNull Function1 reportError @@ -150,7 +188,7 @@ public class SignaturesPropagation { List argTypesFromSuper = getTypes(projectionsFromSuper); boolean covariantPosition = effectiveProjectionKind == TypeCheckingProcedure.EnrichedProjectionKind.OUT; - JetType type = modifyReturnTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, covariantPosition, reportError); + JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, covariantPosition, reportError); Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper, reportError); resultArguments.add(new TypeProjection(projectionKind, type)); @@ -253,7 +291,7 @@ public class SignaturesPropagation { return parameterToArgumentsFromSuper; } - private static boolean returnTypeMustBeNullable( + private static boolean typeMustBeNullable( @NotNull JetType autoType, @NotNull List typesFromSuper, boolean covariantPosition, @@ -279,17 +317,25 @@ public class SignaturesPropagation { return false; } else { - reportError.invoke("Incompatible return types in super types: " + typesFromSuper); + reportError.invoke("Incompatible types in superclasses: " + typesFromSuper); } } assert someSupersNotNull || someSupersNullable; // we have at least one type, which is either not-null or nullable + // This check may seem like voodoo magic, but it's not. + // We want to handle case when parameter of super method is nullable, but parameter of sub method claims to be not null: + // of course, it is an error in annotations, and parameter of sub method should be nullable. + if (!covariantPosition && someSupersNullable && !autoType.isNullable()) { + reportError.invoke("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + autoType); + return true; + } + return someSupersNullable && autoType.isNullable(); } @NotNull - private static ClassifierDescriptor getReturnTypeClassifier(@NotNull JetType autoType, @NotNull List typesFromSuper) { + private static ClassifierDescriptor modifyTypeClassifier(@NotNull JetType autoType, @NotNull List typesFromSuper) { ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor(); if (!(classifier instanceof ClassDescriptor)) { assert classifier != null : "no declaration descriptor for type " + autoType; 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 3e56699bcc3..7b399e263ed 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 @@ -144,13 +144,15 @@ public final class JavaFunctionResolver { List superFunctions = SignaturesPropagation.getSuperFunctionsForMethod(method, trace); - returnType = SignaturesPropagation.modifyReturnTypeAccordingToSuperMethods(returnType, superFunctions, new Function1() { + Function1 reportError = new Function1() { @Override public Void invoke(String error) { signatureErrors.add(error); return null; } - }); + }; + returnType = SignaturesPropagation.modifyReturnTypeAccordingToSuperMethods(returnType, superFunctions, reportError); + valueParameterDescriptors = SignaturesPropagation.modifyValueParametersAccordingToSuperMethods(valueParameterDescriptors, superFunctions, reportError); // TODO consider better place for this check AlternativeMethodSignatureData alternativeMethodSignatureData = diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.java b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.java new file mode 100644 index 00000000000..5f53c7f1061 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.java @@ -0,0 +1,14 @@ +package test; + +import org.jetbrains.annotations.NotNull; + +public interface InheritNullability { + + public interface Super { + void foo(@NotNull String p); + } + + public interface Sub extends Super { + void foo(String p); + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.kt b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.kt new file mode 100644 index 00000000000..05f53fba688 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.kt @@ -0,0 +1,12 @@ +package test + +public trait InheritNullability: Object { + + public trait Super: Object { + public fun foo(p0: String) + } + + public trait Sub: Super { + override fun foo(p0: String) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.txt b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.txt new file mode 100644 index 00000000000..7eb781db180 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.txt @@ -0,0 +1,10 @@ +namespace test + +public abstract trait test.InheritNullability : java.lang.Object { + public abstract trait test.InheritNullability.Sub : test.InheritNullability.Super { + public abstract override /*1*/ fun foo(/*0*/ p0: jet.String): jet.Tuple0 + } + public abstract trait test.InheritNullability.Super : java.lang.Object { + public abstract fun foo(/*0*/ p0: jet.String): jet.Tuple0 + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.java b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.java new file mode 100644 index 00000000000..cda3691ccba --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.java @@ -0,0 +1,18 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import jet.runtime.typeinfo.KotlinSignature; +import org.jetbrains.jet.jvm.compiler.annotation.ExpectLoadError; + +public interface NotNullToNullable { + + public interface Super { + void foo(@NotNull String p); + } + + public interface Sub extends Super { + @ExpectLoadError("Auto type 'jet.String' is not-null, while type in alternative signature is nullable: 'String?'") + @KotlinSignature("fun foo(p: String?)") + void foo(String p); + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.kt b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.kt new file mode 100644 index 00000000000..84859cbafee --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.kt @@ -0,0 +1,12 @@ +package test + +public trait NotNullToNullable: Object { + + public trait Super: Object { + public fun foo(p0: String) + } + + public trait Sub: Super { + override fun foo(p0: String) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.txt b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.txt new file mode 100644 index 00000000000..5a98f5b659a --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.txt @@ -0,0 +1,10 @@ +namespace test + +public abstract trait test.NotNullToNullable : java.lang.Object { + public abstract trait test.NotNullToNullable.Sub : test.NotNullToNullable.Super { + public abstract override /*1*/ fun foo(/*0*/ p0: jet.String): jet.Tuple0 + } + public abstract trait test.NotNullToNullable.Super : java.lang.Object { + public abstract fun foo(/*0*/ p0: jet.String): jet.Tuple0 + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.java b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.java new file mode 100644 index 00000000000..9efe500dd14 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.java @@ -0,0 +1,17 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import jet.runtime.typeinfo.KotlinSignature; +import org.jetbrains.jet.jvm.compiler.annotation.ExpectLoadError; + +public interface NullableToNotNull { + + public interface Super { + void foo(String p); + } + + public interface Sub extends Super { + @ExpectLoadError("In superclass type is nullable: [String?], in subclass it is not: String") + void foo(@NotNull String p); + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.kt b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.kt new file mode 100644 index 00000000000..1836c6fc813 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.kt @@ -0,0 +1,12 @@ +package test + +public trait NullableToNotNull: Object { + + public trait Super: Object { + public fun foo(p0: String?) + } + + public trait Sub: Super { + override fun foo(p0: String?) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.txt b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.txt new file mode 100644 index 00000000000..8a1f8b8a61e --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.txt @@ -0,0 +1,10 @@ +namespace test + +public abstract trait test.NullableToNotNull : java.lang.Object { + public abstract trait test.NullableToNotNull.Sub : test.NullableToNotNull.Super { + public abstract override /*1*/ fun foo(/*0*/ p0: jet.String?): jet.Tuple0 + } + public abstract trait test.NullableToNotNull.Super : java.lang.Object { + public abstract fun foo(/*0*/ p0: jet.String?): jet.Tuple0 + } +} diff --git a/compiler/testData/loadJavaCustom/kotlinSignature/TwoSuperclassesInconsistentGenericTypes.java b/compiler/testData/loadJavaCustom/kotlinSignature/TwoSuperclassesInconsistentGenericTypes.java index ab9d77ac1b7..18448457a65 100644 --- a/compiler/testData/loadJavaCustom/kotlinSignature/TwoSuperclassesInconsistentGenericTypes.java +++ b/compiler/testData/loadJavaCustom/kotlinSignature/TwoSuperclassesInconsistentGenericTypes.java @@ -16,7 +16,7 @@ public interface TwoSuperclassesInconsistentGenericTypes { } public class Sub implements TwoSuperclassesInconsistentGenericTypes, Other { - @ExpectLoadError("Incompatible return types in super types: [String?, String]") + @ExpectLoadError("Incompatible types in superclasses: [String?, String]") public List foo() { throw new UnsupportedOperationException(); } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java index 749e4d2be80..8738662d208 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java @@ -50,7 +50,9 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { Arrays.asList(javaFile, ExpectedLoadErrorsUtil.ANNOTATION_SOURCE_FILE), tmpdir, myTestRootDisposable, ConfigurationKind.JDK_AND_ANNOTATIONS); NamespaceDescriptor nsb = nsbAndBindingContext.first; - ExpectedLoadErrorsUtil.checkForLoadErrors(nsb, nsbAndBindingContext.second); + + compareNamespaces(nsa, nsb, DONT_INCLUDE_METHODS_OF_OBJECT, txtFile); + ExpectedLoadErrorsUtil.checkForLoadErrors(nsb, nsbAndBindingContext.second); } } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 0d335c6bb46..54375cf9f95 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -439,12 +439,35 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { } @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation") - @InnerTestClasses({Propagation.Return.class}) + @InnerTestClasses({Propagation.Parameter.class, Propagation.Return.class}) public static class Propagation extends AbstractLoadJavaTest { public void testAllFilesPresentInPropagation() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation"), "java", true); } + @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation/parameter") + public static class Parameter extends AbstractLoadJavaTest { + public void testAllFilesPresentInParameter() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation/parameter"), "java", true); + } + + @TestMetadata("InheritNullability.java") + public void testInheritNullability() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.java"); + } + + @TestMetadata("NotNullToNullable.java") + public void testNotNullToNullable() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.java"); + } + + @TestMetadata("NullableToNotNull.java") + public void testNullableToNotNull() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.java"); + } + + } + @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation/return") public static class Return extends AbstractLoadJavaTest { @TestMetadata("AddNotNullJavaSubtype.java") @@ -576,6 +599,7 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { public static Test innerSuite() { TestSuite suite = new TestSuite("Propagation"); suite.addTestSuite(Propagation.class); + suite.addTestSuite(Parameter.class); suite.addTestSuite(Return.class); return suite; } diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java index 888e087d8e8..815d1af71fb 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -1329,12 +1329,35 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso } @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation") - @InnerTestClasses({Propagation.Return.class}) + @InnerTestClasses({Propagation.Parameter.class, Propagation.Return.class}) public static class Propagation extends AbstractLazyResolveNamespaceComparingTest { public void testAllFilesPresentInPropagation() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation"), "kt", true); } + @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation/parameter") + public static class Parameter extends AbstractLazyResolveNamespaceComparingTest { + public void testAllFilesPresentInParameter() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation/parameter"), "kt", true); + } + + @TestMetadata("InheritNullability.kt") + public void testInheritNullability() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/parameter/InheritNullability.kt"); + } + + @TestMetadata("NotNullToNullable.kt") + public void testNotNullToNullable() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/parameter/NotNullToNullable.kt"); + } + + @TestMetadata("NullableToNotNull.kt") + public void testNullableToNotNull() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/parameter/NullableToNotNull.kt"); + } + + } + @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation/return") public static class Return extends AbstractLazyResolveNamespaceComparingTest { @TestMetadata("AddNotNullJavaSubtype.kt") @@ -1466,6 +1489,7 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso public static Test innerSuite() { TestSuite suite = new TestSuite("Propagation"); suite.addTestSuite(Propagation.class); + suite.addTestSuite(Parameter.class); suite.addTestSuite(Return.class); return suite; }