Supported generic subclasses in submethods.
#KT-2776 in progress
This commit is contained in:
+55
-16
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.java.resolver;
|
package org.jetbrains.jet.lang.resolve.java.resolver;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.psi.HierarchicalMethodSignature;
|
import com.intellij.psi.HierarchicalMethodSignature;
|
||||||
import com.intellij.psi.PsiClass;
|
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.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
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 org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -318,34 +320,71 @@ public final class JavaFunctionResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static List<TypeProjection> getTypeArgsOfReturnType(@NotNull JetType autoType, Collection<JetType> typesFromSuper) {
|
private static List<TypeProjection> getTypeArgsOfReturnType(@NotNull JetType autoType, @NotNull Collection<JetType> typesFromSuper) {
|
||||||
TypeConstructor typeConstructor = autoType.getConstructor();
|
TypeConstructor typeConstructor = autoType.getConstructor();
|
||||||
List<TypeProjection> autoTypeArguments = autoType.getArguments();
|
List<TypeProjection> autoArguments = autoType.getArguments();
|
||||||
|
|
||||||
// If class is changed, then we can't say anything about type arguments
|
if (!(typeConstructor.getDeclarationDescriptor() instanceof ClassDescriptor)) {
|
||||||
for (JetType typeFromSuper : typesFromSuper) {
|
return autoArguments;
|
||||||
if (!TypeUtils.equalClasses(autoType, typeFromSuper)) {
|
|
||||||
return autoTypeArguments;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<List<JetType>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper(autoType, typesFromSuper);
|
||||||
|
|
||||||
|
// Modify type arguments using info from typesFromSuper
|
||||||
List<TypeProjection> resultArguments = Lists.newArrayList();
|
List<TypeProjection> resultArguments = Lists.newArrayList();
|
||||||
for (int i = 0; i < autoTypeArguments.size(); i++) {
|
for (int i = 0; i < autoArguments.size(); i++) {
|
||||||
TypeProjection argument = autoTypeArguments.get(i);
|
TypeProjection argument = autoArguments.get(i);
|
||||||
JetType argType = argument.getType();
|
|
||||||
Variance varianceInClass = typeConstructor.getParameters().get(i).getVariance();
|
|
||||||
|
|
||||||
List<JetType> argTypesFromSuper = Lists.newArrayList();
|
TypeCheckingProcedure.EnrichedProjectionKind effectiveProjectionKind =
|
||||||
for (JetType typeFromSuper : typesFromSuper) {
|
TypeCheckingProcedure.getEffectiveProjectionKind(typeConstructor.getParameters().get(i), argument);
|
||||||
argTypesFromSuper.add(typeFromSuper.getArguments().get(i).getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
JetType type = modifyReturnTypeAccordingToSuperMethods(argType, argTypesFromSuper, varianceInClass == Variance.OUT_VARIANCE);
|
JetType argumentType = argument.getType();
|
||||||
|
Collection<JetType> argumentTypesFromSuper = typeArgumentsFromSuper.get(i);
|
||||||
|
boolean covariantPosition = effectiveProjectionKind == TypeCheckingProcedure.EnrichedProjectionKind.OUT;
|
||||||
|
|
||||||
|
JetType type = modifyReturnTypeAccordingToSuperMethods(argumentType, argumentTypesFromSuper, covariantPosition);
|
||||||
resultArguments.add(new TypeProjection(argument.getProjectionKind(), type));
|
resultArguments.add(new TypeProjection(argument.getProjectionKind(), type));
|
||||||
}
|
}
|
||||||
return resultArguments;
|
return resultArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns list with type arguments info from supertypes
|
||||||
|
private static List<List<JetType>> calculateTypeArgumentsFromSuper(
|
||||||
|
@NotNull JetType autoType,
|
||||||
|
@NotNull Collection<JetType> 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<TypeConstructor,TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
|
||||||
|
TypeUtils.makeUnsubstitutedType(klass, null));
|
||||||
|
|
||||||
|
// for each parameter of autoType, hold arguments in corresponding supertypes
|
||||||
|
List<List<JetType>> parameterToArgTypesFromSuper = Lists.newArrayList();
|
||||||
|
for (TypeProjection ignored : autoType.getArguments()) {
|
||||||
|
parameterToArgTypesFromSuper.add(new ArrayList<JetType>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate all types from super and all its parameters
|
||||||
|
for (JetType typeFromSuper : typesFromSuper) {
|
||||||
|
List<TypeParameterDescriptor> 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<JetType> typesFromSuper, boolean covariantPosition) {
|
private static boolean returnTypeMustBeNullable(JetType autoType, Collection<JetType> typesFromSuper, boolean covariantPosition) {
|
||||||
boolean someSupersNullable = false;
|
boolean someSupersNullable = false;
|
||||||
boolean someSupersNotNull = false;
|
boolean someSupersNotNull = false;
|
||||||
|
|||||||
+5
-2
@@ -103,7 +103,7 @@ public class TypeCheckingProcedure {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum EnrichedProjectionKind {
|
public enum EnrichedProjectionKind {
|
||||||
IN, OUT, INV, STAR;
|
IN, OUT, INV, STAR;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -132,7 +132,10 @@ public class TypeCheckingProcedure {
|
|||||||
// inv * out = out
|
// inv * out = out
|
||||||
// inv * in = out
|
// inv * in = out
|
||||||
// inv * inv = inv
|
// 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 a = typeParameter.getVariance();
|
||||||
Variance b = typeArgument.getProjectionKind();
|
Variance b = typeArgument.getProjectionKind();
|
||||||
|
|
||||||
|
|||||||
+20
@@ -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<String>")
|
||||||
|
public Collection<String> foo() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Sub extends InheritNullabilityGenericSubclassSimple {
|
||||||
|
public List<String> foo() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull
|
||||||
|
|
||||||
|
public open class InheritNullabilityGenericSubclassSimple : java.lang.Object() {
|
||||||
|
public open fun foo(): MutableCollection<String> = throw UnsupportedOperationException()
|
||||||
|
|
||||||
|
public open class Sub: InheritNullabilityGenericSubclassSimple() {
|
||||||
|
override fun foo(): MutableList<String> = throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
namespace test
|
||||||
|
|
||||||
|
public open class test.InheritNullabilityGenericSubclassSimple : java.lang.Object {
|
||||||
|
public final /*constructor*/ fun <init>(): test.InheritNullabilityGenericSubclassSimple
|
||||||
|
public open fun foo(): jet.MutableCollection<jet.String>
|
||||||
|
public open class test.InheritNullabilityGenericSubclassSimple.Sub : test.InheritNullabilityGenericSubclassSimple {
|
||||||
|
public final /*constructor*/ fun <init>(): test.InheritNullabilityGenericSubclassSimple.Sub
|
||||||
|
public open override /*1*/ fun foo(): jet.MutableList<jet.String>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
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")
|
@TestMetadata("InheritNullabilityJavaSubtype.java")
|
||||||
public void testInheritNullabilityJavaSubtype() throws Exception {
|
public void testInheritNullabilityJavaSubtype() throws Exception {
|
||||||
doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.java");
|
doTest("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.java");
|
||||||
|
|||||||
+5
@@ -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);
|
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")
|
@TestMetadata("InheritNullabilityJavaSubtype.kt")
|
||||||
public void testInheritNullabilityJavaSubtype() throws Exception {
|
public void testInheritNullabilityJavaSubtype() throws Exception {
|
||||||
doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.kt");
|
doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/return/InheritNullabilityJavaSubtype.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user