Supported cases with two superclasses when they have different variances.
This commit is contained in:
+112
-102
@@ -35,7 +35,6 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.*;
|
||||
@@ -88,7 +87,7 @@ public class SignaturesPropagationData {
|
||||
public List<FunctionDescriptor> getSuperFunctions() {
|
||||
return superFunctions;
|
||||
}
|
||||
|
||||
|
||||
private void reportError(String error) {
|
||||
signatureErrors.add(error);
|
||||
}
|
||||
@@ -96,15 +95,15 @@ public class SignaturesPropagationData {
|
||||
private JetType modifyReturnTypeAccordingToSuperMethods(
|
||||
@NotNull JetType autoType // type built by JavaTypeTransformer
|
||||
) {
|
||||
List<JetType> typesFromSuperMethods = ContainerUtil.map(superFunctions,
|
||||
new Function<FunctionDescriptor, JetType>() {
|
||||
@Override
|
||||
public JetType fun(FunctionDescriptor superFunction) {
|
||||
return superFunction.getReturnType();
|
||||
}
|
||||
});
|
||||
List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
|
||||
new Function<FunctionDescriptor, TypeAndVariance>() {
|
||||
@Override
|
||||
public TypeAndVariance fun(FunctionDescriptor superFunction) {
|
||||
return new TypeAndVariance(superFunction.getReturnType(), Variance.OUT_VARIANCE);
|
||||
}
|
||||
});
|
||||
|
||||
return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, true);
|
||||
return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods);
|
||||
}
|
||||
|
||||
private List<TypeParameterDescriptor> modifyTypeParametersAccordingToSuperMethods(List<TypeParameterDescriptor> autoTypeParameters) {
|
||||
@@ -120,14 +119,14 @@ public class SignaturesPropagationData {
|
||||
}
|
||||
|
||||
for (JetType autoUpperBound : autoParameter.getUpperBounds()) {
|
||||
List<JetType> upperBoundsFromSuperFunctions = Lists.newArrayList();
|
||||
List<TypeAndVariance> upperBoundsFromSuperFunctions = Lists.newArrayList();
|
||||
|
||||
for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
|
||||
assert iterator.hasNext();
|
||||
upperBoundsFromSuperFunctions.add(iterator.next());
|
||||
upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), Variance.INVARIANT));
|
||||
}
|
||||
|
||||
JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, false);
|
||||
JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions);
|
||||
modifiedTypeParameter.addUpperBound(modifiedUpperBound);
|
||||
}
|
||||
|
||||
@@ -152,18 +151,18 @@ public class SignaturesPropagationData {
|
||||
|
||||
for (final ValueParameterDescriptor originalParam : parameters.getDescriptors()) {
|
||||
final int index = originalParam.getIndex();
|
||||
List<JetType> typesFromSuperMethods = ContainerUtil.map(superFunctions,
|
||||
new Function<FunctionDescriptor, JetType>() {
|
||||
List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
|
||||
new Function<FunctionDescriptor, TypeAndVariance>() {
|
||||
@Override
|
||||
public JetType fun(FunctionDescriptor superFunction) {
|
||||
return superFunction.getValueParameters().get(index).getType();
|
||||
public TypeAndVariance fun(FunctionDescriptor superFunction) {
|
||||
return new TypeAndVariance(superFunction.getValueParameters().get(index).getType(), Variance.INVARIANT);
|
||||
}
|
||||
});
|
||||
|
||||
VarargCheckResult varargCheckResult =
|
||||
checkVarargInSuperFunctions(originalParam);
|
||||
|
||||
JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods, false);
|
||||
JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods);
|
||||
|
||||
resultParameters.add(new ValueParameterDescriptorImpl(
|
||||
originalParam.getContainingDeclaration(),
|
||||
@@ -274,15 +273,14 @@ public class SignaturesPropagationData {
|
||||
@NotNull
|
||||
private JetType modifyTypeAccordingToSuperMethods(
|
||||
@NotNull JetType autoType,
|
||||
@NotNull List<JetType> typesFromSuper,
|
||||
boolean covariantPosition
|
||||
@NotNull List<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
if (ErrorUtils.isErrorType(autoType)) {
|
||||
return autoType;
|
||||
}
|
||||
|
||||
boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, covariantPosition);
|
||||
ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper, covariantPosition);
|
||||
boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper);
|
||||
ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
|
||||
List<TypeProjection> resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
|
||||
JetScope resultScope;
|
||||
if (resultClassifier instanceof ClassDescriptor) {
|
||||
@@ -303,7 +301,7 @@ public class SignaturesPropagationData {
|
||||
private List<TypeProjection> getTypeArgsOfType(
|
||||
@NotNull JetType autoType,
|
||||
@NotNull ClassifierDescriptor classifier,
|
||||
@NotNull List<JetType> typesFromSuper
|
||||
@NotNull List<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
List<TypeProjection> autoArguments = autoType.getArguments();
|
||||
|
||||
@@ -313,22 +311,18 @@ public class SignaturesPropagationData {
|
||||
return autoArguments;
|
||||
}
|
||||
|
||||
List<List<TypeProjection>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper((ClassDescriptor) classifier, typesFromSuper);
|
||||
List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper((ClassDescriptor) classifier, typesFromSuper);
|
||||
|
||||
// Modify type arguments using info from typesFromSuper
|
||||
List<TypeProjection> resultArguments = Lists.newArrayList();
|
||||
for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) {
|
||||
TypeProjection argument = autoArguments.get(parameter.getIndex());
|
||||
|
||||
TypeCheckingProcedure.EnrichedProjectionKind effectiveProjectionKind =
|
||||
TypeCheckingProcedure.getEffectiveProjectionKind(parameter, argument);
|
||||
|
||||
JetType argumentType = argument.getType();
|
||||
List<TypeProjection> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
|
||||
List<JetType> argTypesFromSuper = getTypes(projectionsFromSuper);
|
||||
boolean covariantPosition = effectiveProjectionKind == TypeCheckingProcedure.EnrichedProjectionKind.OUT;
|
||||
List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
|
||||
List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);
|
||||
|
||||
JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, covariantPosition);
|
||||
JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper);
|
||||
Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);
|
||||
|
||||
resultArguments.add(new TypeProjection(projectionKind, type));
|
||||
@@ -338,11 +332,11 @@ public class SignaturesPropagationData {
|
||||
|
||||
private Variance calculateArgumentProjectionKindFromSuper(
|
||||
@NotNull TypeProjection argument,
|
||||
@NotNull List<TypeProjection> projectionsFromSuper
|
||||
@NotNull List<TypeProjectionAndVariance> projectionsFromSuper
|
||||
) {
|
||||
Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
|
||||
for (TypeProjection projection : projectionsFromSuper) {
|
||||
projectionKindsInSuper.add(projection.getProjectionKind());
|
||||
for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
|
||||
projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
|
||||
}
|
||||
|
||||
Variance defaultProjectionKind = argument.getProjectionKind();
|
||||
@@ -367,10 +361,10 @@ public class SignaturesPropagationData {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<JetType> getTypes(@NotNull List<TypeProjection> projections) {
|
||||
List<JetType> types = Lists.newArrayList();
|
||||
for (TypeProjection projection : projections) {
|
||||
types.add(projection.getType());
|
||||
private static List<TypeAndVariance> getTypes(@NotNull List<TypeProjectionAndVariance> projections) {
|
||||
List<TypeAndVariance> types = Lists.newArrayList();
|
||||
for (TypeProjectionAndVariance projection : projections) {
|
||||
types.add(new TypeAndVariance(projection.typeProjection.getType(), projection.varianceOfParameter));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
@@ -380,9 +374,9 @@ public class SignaturesPropagationData {
|
||||
// - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
|
||||
// - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
|
||||
// - output[0] = [String, CharSequence], output[1] = []
|
||||
private static List<List<TypeProjection>> calculateTypeArgumentsFromSuper(
|
||||
private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
|
||||
@NotNull ClassDescriptor klass,
|
||||
@NotNull Collection<JetType> typesFromSuper
|
||||
@NotNull Collection<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
// For each superclass of klass and its parameters, hold their mapping to klass' parameters
|
||||
// #0 of Bar -> A
|
||||
@@ -395,15 +389,15 @@ public class SignaturesPropagationData {
|
||||
TypeUtils.makeUnsubstitutedType(klass, JetScope.EMPTY));
|
||||
|
||||
// for each parameter of klass, hold arguments in corresponding supertypes
|
||||
List<List<TypeProjection>> parameterToArgumentsFromSuper = Lists.newArrayList();
|
||||
List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
|
||||
for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
|
||||
parameterToArgumentsFromSuper.add(new ArrayList<TypeProjection>());
|
||||
parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
|
||||
}
|
||||
|
||||
// Enumerate all types from super and all its parameters
|
||||
for (JetType typeFromSuper : typesFromSuper) {
|
||||
for (TypeParameterDescriptor parameter : typeFromSuper.getConstructor().getParameters()) {
|
||||
TypeProjection argument = typeFromSuper.getArguments().get(parameter.getIndex());
|
||||
for (TypeAndVariance typeFromSuper : typesFromSuper) {
|
||||
for (TypeParameterDescriptor parameter : typeFromSuper.type.getConstructor().getParameters()) {
|
||||
TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());
|
||||
|
||||
// for given example, this block is executed four times:
|
||||
// 1. typeFromSuper = Bar<String, List<Int>>, parameter = "#0 of Bar", argument = String
|
||||
@@ -422,7 +416,7 @@ public class SignaturesPropagationData {
|
||||
// this condition is true for 1 and 4, false for 2 and 3
|
||||
if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
|
||||
int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
|
||||
parameterToArgumentsFromSuper.get(parameterIndex).add(argument);
|
||||
parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, parameter.getVariance()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,51 +426,42 @@ public class SignaturesPropagationData {
|
||||
|
||||
private boolean typeMustBeNullable(
|
||||
@NotNull JetType autoType,
|
||||
@NotNull List<JetType> typesFromSuper,
|
||||
boolean covariantPosition
|
||||
@NotNull List<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
if (typesFromSuper.isEmpty()) {
|
||||
return autoType.isNullable();
|
||||
}
|
||||
|
||||
boolean someSupersNullable = false;
|
||||
boolean someSupersNotCovariantNullable = false;
|
||||
boolean someSupersNotNull = false;
|
||||
for (JetType typeFromSuper : typesFromSuper) {
|
||||
if (typeFromSuper.isNullable()) {
|
||||
someSupersNullable = true;
|
||||
for (TypeAndVariance typeFromSuper : typesFromSuper) {
|
||||
if (typeFromSuper.type.isNullable() && typeFromSuper.varianceOfParameter != Variance.OUT_VARIANCE) {
|
||||
someSupersNotCovariantNullable = true;
|
||||
}
|
||||
else {
|
||||
else if (!typeFromSuper.type.isNullable()) {
|
||||
someSupersNotNull = true;
|
||||
}
|
||||
}
|
||||
if (someSupersNotNull && someSupersNullable) {
|
||||
//noinspection IfStatementWithIdenticalBranches
|
||||
if (covariantPosition) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
||||
if (someSupersNotCovariantNullable == someSupersNotNull) {
|
||||
if (someSupersNotCovariantNullable) {
|
||||
reportError("Incompatible types in superclasses: " + typesFromSuper);
|
||||
}
|
||||
return autoType.isNullable();
|
||||
}
|
||||
|
||||
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("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + autoType);
|
||||
return true;
|
||||
else {
|
||||
if (someSupersNotCovariantNullable) {
|
||||
if (!autoType.isNullable()) {
|
||||
reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + autoType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else { // someSupersNotNull is true here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return someSupersNullable && autoType.isNullable();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassifierDescriptor modifyTypeClassifier(
|
||||
@NotNull JetType autoType,
|
||||
@NotNull List<JetType> typesFromSuper,
|
||||
boolean covariantPosition
|
||||
@NotNull List<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
|
||||
if (!(classifier instanceof ClassDescriptor)) {
|
||||
@@ -487,14 +472,15 @@ public class SignaturesPropagationData {
|
||||
}
|
||||
return classifier;
|
||||
}
|
||||
ClassDescriptor clazz = (ClassDescriptor) classifier;
|
||||
ClassDescriptor klass = (ClassDescriptor) classifier;
|
||||
|
||||
CollectionClassMapping collectionMapping = CollectionClassMapping.getInstance();
|
||||
|
||||
boolean someSupersMutable = false;
|
||||
boolean someSupersReadOnly = false;
|
||||
for (JetType typeFromSuper : typesFromSuper) {
|
||||
ClassifierDescriptor classifierFromSuper = typeFromSuper.getConstructor().getDeclarationDescriptor();
|
||||
boolean someSupersCovariantReadOnly = false;
|
||||
boolean someSupersNotCovariantReadOnly = false;
|
||||
for (TypeAndVariance typeFromSuper : typesFromSuper) {
|
||||
ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor();
|
||||
if (classifierFromSuper instanceof ClassDescriptor) {
|
||||
ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
|
||||
|
||||
@@ -502,35 +488,31 @@ public class SignaturesPropagationData {
|
||||
someSupersMutable = true;
|
||||
}
|
||||
else if (collectionMapping.isReadOnlyCollection(classFromSuper)) {
|
||||
someSupersReadOnly = true;
|
||||
if (typeFromSuper.varianceOfParameter == Variance.OUT_VARIANCE) {
|
||||
someSupersCovariantReadOnly = true;
|
||||
}
|
||||
else {
|
||||
someSupersNotCovariantReadOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (covariantPosition) {
|
||||
if (collectionMapping.isMutableCollection(clazz)) {
|
||||
if (someSupersReadOnly && !someSupersMutable) {
|
||||
return collectionMapping.convertMutableToReadOnly(clazz);
|
||||
}
|
||||
if (someSupersMutable && someSupersNotCovariantReadOnly) {
|
||||
reportError("Incompatible types in superclasses: " + typesFromSuper);
|
||||
return classifier;
|
||||
}
|
||||
else if (someSupersMutable) {
|
||||
if (collectionMapping.isReadOnlyCollection(klass)) {
|
||||
return collectionMapping.convertReadOnlyToMutable(klass);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (someSupersMutable == someSupersReadOnly) {
|
||||
//noinspection ConstantConditions
|
||||
if (someSupersMutable && someSupersReadOnly) {
|
||||
reportError("Incompatible types in superclasses: " + typesFromSuper);
|
||||
}
|
||||
return classifier;
|
||||
}
|
||||
|
||||
if (someSupersMutable && collectionMapping.isReadOnlyCollection(clazz)) {
|
||||
return collectionMapping.convertReadOnlyToMutable(clazz);
|
||||
}
|
||||
|
||||
if (someSupersReadOnly && collectionMapping.isMutableCollection(clazz)) {
|
||||
return collectionMapping.convertMutableToReadOnly(clazz);
|
||||
else if (someSupersNotCovariantReadOnly || someSupersCovariantReadOnly) {
|
||||
if (collectionMapping.isMutableCollection(klass)) {
|
||||
return collectionMapping.convertMutableToReadOnly(klass);
|
||||
}
|
||||
}
|
||||
|
||||
return classifier;
|
||||
}
|
||||
|
||||
@@ -543,9 +525,37 @@ public class SignaturesPropagationData {
|
||||
public final JetType parameterType;
|
||||
public final boolean isVararg;
|
||||
|
||||
private VarargCheckResult(JetType parameterType, boolean isVararg) {
|
||||
public VarargCheckResult(JetType parameterType, boolean isVararg) {
|
||||
this.parameterType = parameterType;
|
||||
this.isVararg = isVararg;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeProjectionAndVariance {
|
||||
public final TypeProjection typeProjection;
|
||||
public final Variance varianceOfParameter;
|
||||
|
||||
public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfParameter) {
|
||||
this.typeProjection = typeProjection;
|
||||
this.varianceOfParameter = varianceOfParameter;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return typeProjection.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeAndVariance {
|
||||
public final JetType type;
|
||||
public final Variance varianceOfParameter;
|
||||
|
||||
public TypeAndVariance(JetType type, Variance varianceOfParameter) {
|
||||
this.type = type;
|
||||
this.varianceOfParameter = varianceOfParameter;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user