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 cb030dad67f..906fbc5455b 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 @@ -34,16 +34,13 @@ import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers; import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import javax.inject.Inject; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.JAVA; import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.KOTLIN; @@ -136,7 +133,6 @@ public final class JavaFunctionResolver { .resolveParameterDescriptors(functionDescriptorImpl, method.getParameters(), methodTypeVariableResolver); JetType returnType = makeReturnType(returnPsiType, method, methodTypeVariableResolver); - Set typesFromSuperMethods = Sets.newHashSet(); for (HierarchicalMethodSignature superSignature : method.getPsiMethod().getHierarchicalMethodSignature().getSuperSignatures()) { DeclarationDescriptor superFun = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, superSignature.getMethod()); @@ -144,11 +140,8 @@ public final class JavaFunctionResolver { typesFromSuperMethods.add(((FunctionDescriptor) superFun).getReturnType()); } } - typesFromSuperMethods.add(returnType); - JetType intersectionType = TypeUtils.intersect(JetTypeChecker.INSTANCE, typesFromSuperMethods); - if (intersectionType != null && intersectionType.getConstructor().getDeclarationDescriptor() != null) { - returnType = intersectionType; - } + + returnType = modifyReturnTypeAccordingToSuperMethods(returnType, typesFromSuperMethods, true); // TODO consider better place for this check AlternativeMethodSignatureData alternativeMethodSignatureData = @@ -293,6 +286,92 @@ public final class JavaFunctionResolver { return r; } + @NotNull + private static JetType modifyReturnTypeAccordingToSuperMethods( + @NotNull JetType autoType, + @NotNull Collection typesFromSuper, + boolean covariantPosition + ) { + if (ErrorUtils.isErrorType(autoType)) { + return autoType; + } + + boolean resultNullable = returnTypeMustBeNullable(autoType, typesFromSuper, covariantPosition); + List resultArguments = getTypeArgsOfReturnType(autoType, typesFromSuper); + JetScope resultScope; + ClassifierDescriptor classifierDescriptor = autoType.getConstructor().getDeclarationDescriptor(); + if (classifierDescriptor instanceof ClassDescriptor) { + resultScope = ((ClassDescriptor) classifierDescriptor).getMemberScope(resultArguments); + } + else { + resultScope = autoType.getMemberScope(); + } + + return new JetTypeImpl(autoType.getAnnotations(), + autoType.getConstructor(), + resultNullable, + resultArguments, + resultScope); + } + + @NotNull + private static List getTypeArgsOfReturnType(@NotNull JetType autoType, Collection typesFromSuper) { + TypeConstructor typeConstructor = autoType.getConstructor(); + List autoTypeArguments = autoType.getArguments(); + + // If class is changed, then we can't say anything about type arguments + for (JetType typeFromSuper : typesFromSuper) { + if (!TypeUtils.equalClasses(autoType, typeFromSuper)) { + return autoTypeArguments; + } + } + + List resultArguments = Lists.newArrayList(); + for (int i = 0; i < autoTypeArguments.size(); i++) { + TypeProjection argument = autoTypeArguments.get(i); + JetType argType = argument.getType(); + Variance varianceInClass = typeConstructor.getParameters().get(i).getVariance(); + + List argTypesFromSuper = Lists.newArrayList(); + for (JetType typeFromSuper : typesFromSuper) { + argTypesFromSuper.add(typeFromSuper.getArguments().get(i).getType()); + } + + JetType type = modifyReturnTypeAccordingToSuperMethods(argType, argTypesFromSuper, varianceInClass == Variance.OUT_VARIANCE); + resultArguments.add(new TypeProjection(argument.getProjectionKind(), type)); + } + return resultArguments; + } + + private static boolean returnTypeMustBeNullable(JetType autoType, Collection typesFromSuper, boolean covariantPosition) { + boolean someSupersNullable = false; + boolean someSupersNotNull = false; + for (JetType typeFromSuper : typesFromSuper) { + if (typeFromSuper.isNullable()) { + someSupersNullable = true; + } + else { + someSupersNotNull = true; + } + } + if (someSupersNotNull && someSupersNullable) { + //noinspection IfStatementWithIdenticalBranches + if (covariantPosition) { + return false; + } + else { + // TODO error! + return true; + } + } + + if (!someSupersNotNull && !someSupersNullable) { // no types from super + return autoType.isNullable(); + } + + return someSupersNullable && autoType.isNullable(); + } + private static boolean isEnumSpecialMethod(@NotNull FunctionDescriptor functionDescriptor) { List methodTypeParameters = functionDescriptor.getValueParameters(); String methodName = functionDescriptor.getName().getName(); diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.java b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.java new file mode 100644 index 00000000000..a6c1f6a14a9 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.java @@ -0,0 +1,20 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +import jet.runtime.typeinfo.KotlinSignature; + +public class AddNullabilitySameGenericType1 { + @KotlinSignature("fun foo(): MutableList") + public List foo() { + throw new UnsupportedOperationException(); + } + + public class Sub extends AddNullabilitySameGenericType1 { + @KotlinSignature("fun foo(): MutableList") + public List foo() { + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.kt b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.kt new file mode 100644 index 00000000000..d33cca238e4 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.kt @@ -0,0 +1,11 @@ +package test + +import org.jetbrains.annotations.NotNull + +public open class AddNullabilitySameGenericType1 : java.lang.Object() { + public open fun foo(): MutableList = throw UnsupportedOperationException() + + public open class Sub: AddNullabilitySameGenericType1() { + override fun foo(): MutableList = throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.txt b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.txt new file mode 100644 index 00000000000..480d73ed66d --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.txt @@ -0,0 +1,10 @@ +namespace test + +public open class test.AddNullabilitySameGenericType1 : java.lang.Object { + public final /*constructor*/ fun (): test.AddNullabilitySameGenericType1 + public open fun foo(): jet.MutableList + public open class test.AddNullabilitySameGenericType1.Sub : test.AddNullabilitySameGenericType1 { + public final /*constructor*/ fun (): test.AddNullabilitySameGenericType1.Sub + public open override /*1*/ fun foo(): jet.MutableList + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.java b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.java new file mode 100644 index 00000000000..3ab85d8f6d5 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.java @@ -0,0 +1,20 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +import jet.runtime.typeinfo.KotlinSignature; + +public class AddNullabilitySameGenericType2 { + @KotlinSignature("fun foo(): MutableList") + public List foo() { + throw new UnsupportedOperationException(); + } + + public class Sub extends AddNullabilitySameGenericType2 { + @KotlinSignature("fun foo(): MutableList?") + public List foo() { + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.kt b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.kt new file mode 100644 index 00000000000..217e1005060 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.kt @@ -0,0 +1,11 @@ +package test + +import org.jetbrains.annotations.NotNull + +public open class AddNullabilitySameGenericType2 : java.lang.Object() { + public open fun foo(): MutableList = throw UnsupportedOperationException() + + public open class Sub: AddNullabilitySameGenericType2() { + override fun foo(): MutableList = throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.txt b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.txt new file mode 100644 index 00000000000..0d32f70c5c8 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.txt @@ -0,0 +1,10 @@ +namespace test + +public open class test.AddNullabilitySameGenericType2 : java.lang.Object { + public final /*constructor*/ fun (): test.AddNullabilitySameGenericType2 + public open fun foo(): jet.MutableList + public open class test.AddNullabilitySameGenericType2.Sub : test.AddNullabilitySameGenericType2 { + public final /*constructor*/ fun (): test.AddNullabilitySameGenericType2.Sub + public open override /*1*/ fun foo(): jet.MutableList + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.java b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.java new file mode 100644 index 00000000000..8c4d0f1e27f --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.java @@ -0,0 +1,19 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +import jet.runtime.typeinfo.KotlinSignature; + +public class InheritNullabilitySameGenericType { + @KotlinSignature("fun foo(): MutableList") + public List foo() { + throw new UnsupportedOperationException(); + } + + public class Sub extends InheritNullabilitySameGenericType { + public List foo() { + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.kt b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.kt new file mode 100644 index 00000000000..8dbc0607ad9 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.kt @@ -0,0 +1,11 @@ +package test + +import org.jetbrains.annotations.NotNull + +public open class InheritNullabilitySameGenericType : java.lang.Object() { + public open fun foo(): MutableList = throw UnsupportedOperationException() + + public open class Sub: InheritNullabilitySameGenericType() { + override fun foo(): MutableList = throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.txt b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.txt new file mode 100644 index 00000000000..d08f81b449d --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.txt @@ -0,0 +1,10 @@ +namespace test + +public open class test.InheritNullabilitySameGenericType : java.lang.Object { + public final /*constructor*/ fun (): test.InheritNullabilitySameGenericType + public open fun foo(): jet.MutableList + public open class test.InheritNullabilitySameGenericType.Sub : test.InheritNullabilitySameGenericType { + public final /*constructor*/ fun (): test.InheritNullabilitySameGenericType.Sub + public open override /*1*/ fun foo(): jet.MutableList + } +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 0f8c480a597..52c69dabf91 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -457,6 +457,16 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilityJavaSubtype.java"); } + @TestMetadata("AddNullabilitySameGenericType1.java") + public void testAddNullabilitySameGenericType1() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.java"); + } + + @TestMetadata("AddNullabilitySameGenericType2.java") + public void testAddNullabilitySameGenericType2() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.java"); + } + @TestMetadata("AddNullabilitySameJavaType.java") public void testAddNullabilitySameJavaType() throws Exception { doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameJavaType.java"); @@ -471,6 +481,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.java"); } + @TestMetadata("InheritNullabilitySameGenericType.java") + public void testInheritNullabilitySameGenericType() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.java"); + } + @TestMetadata("InheritNullabilitySameJavaType.java") public void testInheritNullabilitySameJavaType() throws Exception { doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameJavaType.java"); 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 cedb6bd6eb4..253b0f607f6 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -1352,6 +1352,16 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilityJavaSubtype.kt"); } + @TestMetadata("AddNullabilitySameGenericType1.kt") + public void testAddNullabilitySameGenericType1() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType1.kt"); + } + + @TestMetadata("AddNullabilitySameGenericType2.kt") + public void testAddNullabilitySameGenericType2() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameGenericType2.kt"); + } + @TestMetadata("AddNullabilitySameJavaType.kt") public void testAddNullabilitySameJavaType() throws Exception { doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/AddNullabilitySameJavaType.kt"); @@ -1366,6 +1376,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.kt"); } + @TestMetadata("InheritNullabilitySameGenericType.kt") + public void testInheritNullabilitySameGenericType() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameGenericType.kt"); + } + @TestMetadata("InheritNullabilitySameJavaType.kt") public void testInheritNullabilitySameJavaType() throws Exception { doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilitySameJavaType.kt");