From 89b413b7ad2388e5b6106af4aa4d2d1fb4d22377 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 9 Nov 2012 17:11:19 +0400 Subject: [PATCH] Supported generic subclasses in submethods. #KT-2776 in progress --- .../java/resolver/JavaFunctionResolver.java | 71 ++++++++++++++----- .../types/checker/TypeCheckingProcedure.java | 7 +- ...heritNullabilityGenericSubclassSimple.java | 20 ++++++ ...InheritNullabilityGenericSubclassSimple.kt | 11 +++ ...nheritNullabilityGenericSubclassSimple.txt | 10 +++ .../jvm/compiler/LoadJavaTestGenerated.java | 5 ++ ...esolveNamespaceComparingTestGenerated.java | 5 ++ 7 files changed, 111 insertions(+), 18 deletions(-) create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.java create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.kt create mode 100644 compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.txt 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 6742b59ee4c..cc5dadfda02 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 @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.intellij.psi.HierarchicalMethodSignature; import com.intellij.psi.PsiClass; @@ -37,6 +38,7 @@ import org.jetbrains.jet.lang.resolve.name.Name; 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.checker.TypeCheckingProcedure; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import javax.inject.Inject; @@ -318,34 +320,71 @@ public final class JavaFunctionResolver { } @NotNull - private static List getTypeArgsOfReturnType(@NotNull JetType autoType, Collection typesFromSuper) { + private static List getTypeArgsOfReturnType(@NotNull JetType autoType, @NotNull Collection typesFromSuper) { TypeConstructor typeConstructor = autoType.getConstructor(); - List autoTypeArguments = autoType.getArguments(); + List autoArguments = 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; - } + if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) { + return autoArguments; } + List> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper(autoType, typesFromSuper); + + // Modify type arguments using info from typesFromSuper 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(); + for (int i = 0; i < autoArguments.size(); i++) { + TypeProjection argument = autoArguments.get(i); - List argTypesFromSuper = Lists.newArrayList(); - for (JetType typeFromSuper : typesFromSuper) { - argTypesFromSuper.add(typeFromSuper.getArguments().get(i).getType()); - } + TypeCheckingProcedure.EnrichedProjectionKind effectiveProjectionKind = + TypeCheckingProcedure.getEffectiveProjectionKind(typeConstructor.getParameters().get(i), argument); - JetType type = modifyReturnTypeAccordingToSuperMethods(argType, argTypesFromSuper, varianceInClass == Variance.OUT_VARIANCE); + JetType argumentType = argument.getType(); + Collection argumentTypesFromSuper = typeArgumentsFromSuper.get(i); + boolean covariantPosition = effectiveProjectionKind == TypeCheckingProcedure.EnrichedProjectionKind.OUT; + + JetType type = modifyReturnTypeAccordingToSuperMethods(argumentType, argumentTypesFromSuper, covariantPosition); resultArguments.add(new TypeProjection(argument.getProjectionKind(), type)); } return resultArguments; } + // Returns list with type arguments info from supertypes + private static List> calculateTypeArgumentsFromSuper( + @NotNull JetType autoType, + @NotNull Collection typesFromSuper + ) { + ClassDescriptor klass = (ClassDescriptor) autoType.getConstructor().getDeclarationDescriptor(); + + // For each superclass of autoType's class and its parameters, hold their mapping to autoType's parameters + Multimap substitution = SubstitutionUtils.buildDeepSubstitutionMultimap( + TypeUtils.makeUnsubstitutedType(klass, null)); + + // for each parameter of autoType, hold arguments in corresponding supertypes + List> parameterToArgTypesFromSuper = Lists.newArrayList(); + for (TypeProjection ignored : autoType.getArguments()) { + parameterToArgTypesFromSuper.add(new ArrayList()); + } + + // Enumerate all types from super and all its parameters + for (JetType typeFromSuper : typesFromSuper) { + List typeFromSuperParameters = typeFromSuper.getConstructor().getParameters(); + for (int i = 0; i < typeFromSuperParameters.size(); i++) { + TypeParameterDescriptor typeFromSuperParam = typeFromSuperParameters.get(i); + JetType typeFromSuperArgType = typeFromSuper.getArguments().get(i).getType(); + + // if it is mapped to autoType's parameter, then store it into map + for (TypeProjection projection : substitution.get(typeFromSuperParam.getTypeConstructor())) { + ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor(); + + if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) { + parameterToArgTypesFromSuper.get(((TypeParameterDescriptor) classifier).getIndex()).add(typeFromSuperArgType); + } + } + } + } + return parameterToArgTypesFromSuper; + } + private static boolean returnTypeMustBeNullable(JetType autoType, Collection typesFromSuper, boolean covariantPosition) { boolean someSupersNullable = false; boolean someSupersNotNull = false; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java index 3018bb09ead..c76bbe8d939 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java @@ -103,7 +103,7 @@ public class TypeCheckingProcedure { return true; } - private enum EnrichedProjectionKind { + public enum EnrichedProjectionKind { IN, OUT, INV, STAR; @NotNull @@ -132,7 +132,10 @@ public class TypeCheckingProcedure { // inv * out = out // inv * in = out // inv * inv = inv - private EnrichedProjectionKind getEffectiveProjectionKind(@NotNull TypeParameterDescriptor typeParameter, @NotNull TypeProjection typeArgument) { + public static EnrichedProjectionKind getEffectiveProjectionKind( + @NotNull TypeParameterDescriptor typeParameter, + @NotNull TypeProjection typeArgument + ) { Variance a = typeParameter.getVariance(); Variance b = typeArgument.getProjectionKind(); diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.java b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.java new file mode 100644 index 00000000000..97b3ffa361f --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.java @@ -0,0 +1,20 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import java.util.List; +import java.util.Collection; + +import jet.runtime.typeinfo.KotlinSignature; + +public class InheritNullabilityGenericSubclassSimple { + @KotlinSignature("fun foo(): MutableCollection") + public Collection foo() { + throw new UnsupportedOperationException(); + } + + public class Sub extends InheritNullabilityGenericSubclassSimple { + public List foo() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.kt b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.kt new file mode 100644 index 00000000000..7e5f5be3a35 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.kt @@ -0,0 +1,11 @@ +package test + +import org.jetbrains.annotations.NotNull + +public open class InheritNullabilityGenericSubclassSimple : java.lang.Object() { + public open fun foo(): MutableCollection = throw UnsupportedOperationException() + + public open class Sub: InheritNullabilityGenericSubclassSimple() { + override fun foo(): MutableList = throw UnsupportedOperationException() + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.txt b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.txt new file mode 100644 index 00000000000..125b878d09b --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.txt @@ -0,0 +1,10 @@ +namespace test + +public open class test.InheritNullabilityGenericSubclassSimple : java.lang.Object { + public final /*constructor*/ fun (): test.InheritNullabilityGenericSubclassSimple + public open fun foo(): jet.MutableCollection + public open class test.InheritNullabilityGenericSubclassSimple.Sub : test.InheritNullabilityGenericSubclassSimple { + public final /*constructor*/ fun (): test.InheritNullabilityGenericSubclassSimple.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 52c69dabf91..70060d7b201 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -476,6 +476,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation/return"), "java", true); } + @TestMetadata("InheritNullabilityGenericSubclassSimple.java") + public void testInheritNullabilityGenericSubclassSimple() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.java"); + } + @TestMetadata("InheritNullabilityJavaSubtype.java") public void testInheritNullabilityJavaSubtype() throws Exception { doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.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 253b0f607f6..0dbe67627bf 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -1371,6 +1371,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation/return"), "kt", true); } + @TestMetadata("InheritNullabilityGenericSubclassSimple.kt") + public void testInheritNullabilityGenericSubclassSimple() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityGenericSubclassSimple.kt"); + } + @TestMetadata("InheritNullabilityJavaSubtype.kt") public void testInheritNullabilityJavaSubtype() throws Exception { doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.kt");