Inline PLATFORM_TYPES = true, simplify signature propagation
This commit is contained in:
+2
-2
@@ -50,8 +50,8 @@ public class TraceBasedExternalSignatureResolver implements ExternalSignatureRes
|
||||
SignaturesPropagationData data =
|
||||
new SignaturesPropagationData(owner, returnType, receiverType, valueParameters, typeParameters, method);
|
||||
return new AlternativeMethodSignature(
|
||||
data.getModifiedReturnType(), data.getModifiedReceiverType(), data.getModifiedValueParameters(),
|
||||
data.getModifiedTypeParameters(), data.getSignatureErrors(), data.getModifiedHasStableParameterNames()
|
||||
returnType, data.getModifiedReceiverType(), data.getModifiedValueParameters(),
|
||||
typeParameters, data.getSignatureErrors(), data.getModifiedHasStableParameterNames()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
|
||||
@@ -104,7 +103,7 @@ public class SingleAbstractMethodUtils {
|
||||
KotlinType type = fixProjections(substitute);
|
||||
if (type == null) return null;
|
||||
|
||||
if (JavaDescriptorResolverKt.getPLATFORM_TYPES() && FlexibleTypesKt.isNullabilityFlexible(samType)) {
|
||||
if (FlexibleTypesKt.isNullabilityFlexible(samType)) {
|
||||
return LazyJavaTypeResolver.FlexibleJavaClassifierTypeCapabilities.create(type, TypeUtils.makeNullable(type));
|
||||
}
|
||||
|
||||
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.jvm.kotlinSignature;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.KotlinTypeImpl;
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl;
|
||||
import org.jetbrains.kotlin.types.Variance;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray;
|
||||
|
||||
// This class contains heuristics for processing corner cases in propagation
|
||||
class PropagationHeuristics {
|
||||
// Checks for case when method returning Super[] is overridden with method returning Sub[]
|
||||
static void checkArrayInReturnType(
|
||||
@NotNull SignaturesPropagationData data,
|
||||
@NotNull KotlinType type,
|
||||
@NotNull List<SignaturesPropagationData.TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
List<SignaturesPropagationData.TypeAndVariance> arrayTypesFromSuper = ContainerUtil
|
||||
.filter(typesFromSuper, new Condition<SignaturesPropagationData.TypeAndVariance>() {
|
||||
@Override
|
||||
public boolean value(SignaturesPropagationData.TypeAndVariance typeAndVariance) {
|
||||
return isArray(typeAndVariance.type);
|
||||
}
|
||||
});
|
||||
if (isArray(type) && !arrayTypesFromSuper.isEmpty()) {
|
||||
assert type.getArguments().size() == 1;
|
||||
if (type.getArguments().get(0).getProjectionKind() == Variance.INVARIANT) {
|
||||
for (SignaturesPropagationData.TypeAndVariance typeAndVariance : arrayTypesFromSuper) {
|
||||
KotlinType arrayTypeFromSuper = typeAndVariance.type;
|
||||
assert arrayTypeFromSuper.getArguments().size() == 1;
|
||||
KotlinType elementTypeInSuper = arrayTypeFromSuper.getArguments().get(0).getType();
|
||||
KotlinType elementType = type.getArguments().get(0).getType();
|
||||
|
||||
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(elementType, elementTypeInSuper)
|
||||
&& !KotlinTypeChecker.DEFAULT.equalTypes(elementType, elementTypeInSuper)) {
|
||||
KotlinTypeImpl betterTypeInSuper = KotlinTypeImpl.create(
|
||||
arrayTypeFromSuper.getAnnotations(),
|
||||
arrayTypeFromSuper.getConstructor(),
|
||||
arrayTypeFromSuper.isMarkedNullable(),
|
||||
Arrays.asList(new TypeProjectionImpl(Variance.OUT_VARIANCE, elementTypeInSuper)),
|
||||
MemberScope.Empty.INSTANCE);
|
||||
|
||||
data.reportError("Return type is not a subtype of overridden method. " +
|
||||
"To fix it, add annotation with Kotlin signature to super method with type "
|
||||
+ DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(arrayTypeFromSuper) + " replaced with "
|
||||
+ DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(betterTypeInSuper) + " in return type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Weird workaround for weird case. The sample code below is compiled by javac.
|
||||
// In this case, we try to replace "Any" parameter type with "T" to fix substitution principle.
|
||||
//
|
||||
// public interface Super<T> {
|
||||
// void foo(T t);
|
||||
// }
|
||||
//
|
||||
// public interface Sub<T> extends Super<T> {
|
||||
// void foo(Object o);
|
||||
// }
|
||||
//
|
||||
// This method is called from SignaturesPropagationData.
|
||||
@Nullable
|
||||
static ClassifierDescriptor tryToFixOverridingTWithRawType(
|
||||
@NotNull SignaturesPropagationData data,
|
||||
@NotNull List<SignaturesPropagationData.TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
List<TypeParameterDescriptor> typeParameterClassifiersFromSuper = Lists.newArrayList();
|
||||
for (SignaturesPropagationData.TypeAndVariance typeFromSuper : typesFromSuper) {
|
||||
ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor();
|
||||
if (classifierFromSuper instanceof TypeParameterDescriptor) {
|
||||
typeParameterClassifiersFromSuper.add((TypeParameterDescriptor) classifierFromSuper);
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeParameterClassifiersFromSuper.isEmpty() && typeParameterClassifiersFromSuper.size() == typesFromSuper.size()) {
|
||||
for (TypeParameterDescriptor typeParameter : typeParameterClassifiersFromSuper) {
|
||||
if (typeParameter.getContainingDeclaration() == data.containingClass) {
|
||||
return typeParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private PropagationHeuristics() {
|
||||
}
|
||||
}
|
||||
+12
-424
@@ -17,8 +17,6 @@
|
||||
package org.jetbrains.kotlin.resolve.jvm.kotlinSignature;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.CollectionsKt;
|
||||
@@ -28,31 +26,23 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapperKt;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.load.java.components.TypeUsage.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName;
|
||||
import static org.jetbrains.kotlin.types.Variance.INVARIANT;
|
||||
|
||||
public class SignaturesPropagationData {
|
||||
|
||||
@@ -61,16 +51,9 @@ public class SignaturesPropagationData {
|
||||
KotlinToJvmSignatureMapper.class.getClassLoader()
|
||||
).iterator().next();
|
||||
|
||||
private final JavaMethodDescriptor autoMethodDescriptor;
|
||||
|
||||
private final List<TypeParameterDescriptor> modifiedTypeParameters;
|
||||
private final ValueParameters modifiedValueParameters;
|
||||
|
||||
private final KotlinType modifiedReturnType;
|
||||
private final List<String> signatureErrors = Lists.newArrayList();
|
||||
private final List<String> signatureErrors = new ArrayList<String>(0);
|
||||
private final List<FunctionDescriptor> superFunctions;
|
||||
private final Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> autoTypeParameterToModified;
|
||||
final ClassDescriptor containingClass;
|
||||
|
||||
public SignaturesPropagationData(
|
||||
@NotNull ClassDescriptor containingClass,
|
||||
@@ -80,25 +63,21 @@ public class SignaturesPropagationData {
|
||||
@NotNull List<TypeParameterDescriptor> autoTypeParameters, // descriptors built by signature resolver
|
||||
@NotNull JavaMethod method
|
||||
) {
|
||||
this.containingClass = containingClass;
|
||||
assert receiverType == null : "Parameters before propagation have receiver type," +
|
||||
" but propagation should be disabled for functions compiled from Kotlin in class: " +
|
||||
DescriptorUtils.getFqName(containingClass);
|
||||
|
||||
autoMethodDescriptor =
|
||||
createAutoMethodDescriptor(containingClass, method, autoReturnType, receiverType, autoValueParameters, autoTypeParameters);
|
||||
JavaMethodDescriptor autoMethodDescriptor =
|
||||
createAutoMethodDescriptor(containingClass, method, autoReturnType, autoValueParameters, autoTypeParameters);
|
||||
|
||||
superFunctions = getSuperFunctionsForMethod(method, autoMethodDescriptor, containingClass);
|
||||
|
||||
autoTypeParameterToModified = JavaResolverUtils.recreateTypeParametersAndReturnMapping(autoTypeParameters, null);
|
||||
|
||||
modifiedTypeParameters = modifyTypeParametersAccordingToSuperMethods(autoTypeParameters);
|
||||
modifiedReturnType = modifyReturnTypeAccordingToSuperMethods(autoReturnType);
|
||||
modifiedValueParameters = modifyValueParametersAccordingToSuperMethods(receiverType, autoValueParameters);
|
||||
modifiedValueParameters = modifyValueParametersAccordingToSuperMethods(autoValueParameters);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JavaMethodDescriptor createAutoMethodDescriptor(
|
||||
@NotNull ClassDescriptor containingClass,
|
||||
@NotNull JavaMethod method, KotlinType autoReturnType,
|
||||
@Nullable KotlinType receiverType,
|
||||
@NotNull List<ValueParameterDescriptor> autoValueParameters,
|
||||
@NotNull List<TypeParameterDescriptor> autoTypeParameters
|
||||
) {
|
||||
@@ -110,7 +89,7 @@ public class SignaturesPropagationData {
|
||||
SourceElement.NO_SOURCE
|
||||
);
|
||||
autoMethodDescriptor.initialize(
|
||||
receiverType,
|
||||
/* receiverParameterType = */ null,
|
||||
containingClass.getThisAsReceiverParameter(),
|
||||
autoTypeParameters,
|
||||
autoValueParameters,
|
||||
@@ -121,10 +100,6 @@ public class SignaturesPropagationData {
|
||||
return autoMethodDescriptor;
|
||||
}
|
||||
|
||||
public List<TypeParameterDescriptor> getModifiedTypeParameters() {
|
||||
return modifiedTypeParameters;
|
||||
}
|
||||
|
||||
public KotlinType getModifiedReceiverType() {
|
||||
return modifiedValueParameters.receiverType;
|
||||
}
|
||||
@@ -137,84 +112,15 @@ public class SignaturesPropagationData {
|
||||
return modifiedValueParameters.hasStableParameterNames;
|
||||
}
|
||||
|
||||
public KotlinType getModifiedReturnType() {
|
||||
return modifiedReturnType;
|
||||
}
|
||||
|
||||
public List<String> getSignatureErrors() {
|
||||
return signatureErrors;
|
||||
}
|
||||
|
||||
public List<FunctionDescriptor> getSuperFunctions() {
|
||||
return superFunctions;
|
||||
}
|
||||
|
||||
void reportError(String error) {
|
||||
signatureErrors.add(error);
|
||||
}
|
||||
|
||||
private KotlinType modifyReturnTypeAccordingToSuperMethods(
|
||||
@NotNull KotlinType autoType // type built by JavaTypeTransformer
|
||||
) {
|
||||
if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return autoType;
|
||||
|
||||
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, MEMBER_SIGNATURE_COVARIANT);
|
||||
}
|
||||
|
||||
private List<TypeParameterDescriptor> modifyTypeParametersAccordingToSuperMethods(List<TypeParameterDescriptor> autoTypeParameters) {
|
||||
if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return autoTypeParameters;
|
||||
|
||||
List<TypeParameterDescriptor> result = Lists.newArrayList();
|
||||
|
||||
for (TypeParameterDescriptor autoParameter : autoTypeParameters) {
|
||||
int index = autoParameter.getIndex();
|
||||
TypeParameterDescriptorImpl modifiedTypeParameter = autoTypeParameterToModified.get(autoParameter);
|
||||
|
||||
List<Iterator<KotlinType>> upperBoundFromSuperFunctionsIterators = Lists.newArrayList();
|
||||
for (FunctionDescriptor superFunction : superFunctions) {
|
||||
upperBoundFromSuperFunctionsIterators.add(superFunction.getTypeParameters().get(index).getUpperBounds().iterator());
|
||||
}
|
||||
|
||||
for (KotlinType autoUpperBound : autoParameter.getUpperBounds()) {
|
||||
List<TypeAndVariance> upperBoundsFromSuperFunctions = Lists.newArrayList();
|
||||
|
||||
for (Iterator<KotlinType> iterator : upperBoundFromSuperFunctionsIterators) {
|
||||
assert iterator.hasNext();
|
||||
upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), INVARIANT));
|
||||
}
|
||||
|
||||
KotlinType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, UPPER_BOUND);
|
||||
modifiedTypeParameter.addUpperBound(modifiedUpperBound);
|
||||
}
|
||||
|
||||
for (Iterator<KotlinType> iterator : upperBoundFromSuperFunctionsIterators) {
|
||||
assert !iterator.hasNext();
|
||||
}
|
||||
|
||||
modifiedTypeParameter.setInitialized();
|
||||
result.add(modifiedTypeParameter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ValueParameters modifyValueParametersAccordingToSuperMethods(
|
||||
@Nullable KotlinType receiverType,
|
||||
@NotNull List<ValueParameterDescriptor> parameters // descriptors built by parameters resolver
|
||||
) {
|
||||
assert receiverType == null : "Parameters before propagation have receiver type," +
|
||||
" but propagation should be disabled for functions compiled from Kotlin in class: " +
|
||||
DescriptorUtils.getFqName(containingClass);
|
||||
|
||||
private ValueParameters modifyValueParametersAccordingToSuperMethods(@NotNull List<ValueParameterDescriptor> parameters) {
|
||||
KotlinType resultReceiverType = null;
|
||||
List<ValueParameterDescriptor> resultParameters = new ArrayList<ValueParameterDescriptor>(parameters.size());
|
||||
|
||||
@@ -239,9 +145,7 @@ public class SignaturesPropagationData {
|
||||
|
||||
VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
|
||||
|
||||
KotlinType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType,
|
||||
convertToTypeVarianceList(typesFromSuperMethods),
|
||||
MEMBER_SIGNATURE_CONTRAVARIANT);
|
||||
KotlinType altType = varargCheckResult.parameterType;
|
||||
|
||||
if (shouldBeExtension && originalIndex == 0) {
|
||||
resultReceiverType = altType;
|
||||
@@ -284,16 +188,6 @@ public class SignaturesPropagationData {
|
||||
return new ValueParameters(resultReceiverType, resultParameters, hasStableParameterNames);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<TypeAndVariance> convertToTypeVarianceList(@NotNull List<TypeAndName> list) {
|
||||
return CollectionsKt.map(list, new Function1<TypeAndName, TypeAndVariance>() {
|
||||
@Override
|
||||
public TypeAndVariance invoke(TypeAndName tvn) {
|
||||
return new TypeAndVariance(tvn.type, INVARIANT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<FunctionDescriptor> getSuperFunctionsForMethod(
|
||||
@NotNull JavaMethod method,
|
||||
@NotNull JavaMethodDescriptor autoMethodDescriptor,
|
||||
@@ -388,284 +282,6 @@ public class SignaturesPropagationData {
|
||||
return new VarargCheckResult(originalType, originalVarargElementType != null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinType modifyTypeAccordingToSuperMethods(
|
||||
@NotNull KotlinType autoType,
|
||||
@NotNull List<TypeAndVariance> typesFromSuper,
|
||||
@NotNull TypeUsage howThisTypeIsUsed
|
||||
) {
|
||||
if (autoType.isError()) return autoType;
|
||||
|
||||
if (JavaDescriptorResolverKt.getPLATFORM_TYPES()) return autoType;
|
||||
|
||||
boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
|
||||
ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
|
||||
List<TypeProjection> resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
|
||||
MemberScope resultScope;
|
||||
if (resultClassifier instanceof ClassDescriptor) {
|
||||
resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
|
||||
}
|
||||
else {
|
||||
resultScope = autoType.getMemberScope();
|
||||
}
|
||||
|
||||
KotlinType type = KotlinTypeImpl.create(autoType.getAnnotations(),
|
||||
resultClassifier.getTypeConstructor(),
|
||||
resultNullable,
|
||||
resultArguments,
|
||||
resultScope);
|
||||
|
||||
PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<TypeProjection> getTypeArgsOfType(
|
||||
@NotNull KotlinType autoType,
|
||||
@NotNull ClassifierDescriptor classifier,
|
||||
@NotNull List<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
if (typesFromSuper.isEmpty()) return autoType.getArguments();
|
||||
|
||||
List<TypeProjection> autoArguments = autoType.getArguments();
|
||||
|
||||
if (!(classifier instanceof ClassDescriptor)) {
|
||||
assert autoArguments.isEmpty() :
|
||||
"Unexpected type arguments when type constructor is not ClassDescriptor, type = " + autoType +
|
||||
", classifier = " + classifier + ", classifier class = " + classifier.getClass();
|
||||
return autoArguments;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
KotlinType argumentType = argument.getType();
|
||||
List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
|
||||
List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);
|
||||
|
||||
KotlinType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
|
||||
Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);
|
||||
|
||||
resultArguments.add(new TypeProjectionImpl(projectionKind, type));
|
||||
}
|
||||
return resultArguments;
|
||||
}
|
||||
|
||||
private Variance calculateArgumentProjectionKindFromSuper(
|
||||
@NotNull TypeProjection argument,
|
||||
@NotNull List<TypeProjectionAndVariance> projectionsFromSuper
|
||||
) {
|
||||
if (projectionsFromSuper.isEmpty()) return argument.getProjectionKind();
|
||||
|
||||
Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
|
||||
for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
|
||||
projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
|
||||
}
|
||||
|
||||
Variance defaultProjectionKind = argument.getProjectionKind();
|
||||
if (projectionKindsInSuper.size() == 0) {
|
||||
return defaultProjectionKind;
|
||||
}
|
||||
else if (projectionKindsInSuper.size() == 1) {
|
||||
Variance projectionKindInSuper = projectionKindsInSuper.iterator().next();
|
||||
if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) {
|
||||
return projectionKindInSuper;
|
||||
}
|
||||
else {
|
||||
reportError("Incompatible projection kinds in type arguments of super methods' return types: "
|
||||
+ projectionsFromSuper + ", defined in current: " + argument);
|
||||
return defaultProjectionKind;
|
||||
}
|
||||
}
|
||||
else {
|
||||
reportError("Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper);
|
||||
return defaultProjectionKind;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
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(),
|
||||
merge(projection.varianceOfPosition, projection.typeProjection.getProjectionKind())));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
private static Variance merge(Variance positionOfOuter, Variance projectionKind) {
|
||||
// Inv<Inv<out X>>, X is in invariant position
|
||||
if (positionOfOuter == INVARIANT) return INVARIANT;
|
||||
// Out<X>, X is in out-position
|
||||
if (projectionKind == INVARIANT) return positionOfOuter;
|
||||
// Out<Out<X>>, X is in out-position
|
||||
// In<In<X>>, X is in out-position
|
||||
// Out<In<X>>, X is in in-position
|
||||
// In<Out<X>>, X is in in-position
|
||||
return positionOfOuter.superpose(projectionKind);
|
||||
}
|
||||
|
||||
// Returns list with type arguments info from supertypes
|
||||
// Example:
|
||||
// - 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<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
|
||||
@NotNull ClassDescriptor klass,
|
||||
@NotNull Collection<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
// For each superclass of klass and its parameters, hold their mapping to klass' parameters
|
||||
// #0 of Bar -> A
|
||||
// #1 of Bar -> List<B>
|
||||
// #0 of Baz -> Boolean
|
||||
// #1 of Baz -> A
|
||||
// #0 of Foo -> A (mapped to itself)
|
||||
// #1 of Foo -> B (mapped to itself)
|
||||
Multimap<TypeParameterDescriptor, TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
|
||||
TypeUtils.makeUnsubstitutedType(klass, ErrorUtils.createErrorScope("Do not access this scope", true)));
|
||||
|
||||
// for each parameter of klass, hold arguments in corresponding supertypes
|
||||
List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
|
||||
for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
|
||||
parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
|
||||
}
|
||||
|
||||
// Enumerate all types from super and all its parameters
|
||||
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
|
||||
// 2. typeFromSuper = Bar<String, List<Int>>, parameter = "#1 of Bar", argument = List<Int>
|
||||
// 3. typeFromSuper = Baz<Boolean, CharSequence>, parameter = "#0 of Baz", argument = Boolean
|
||||
// 4. typeFromSuper = Baz<Boolean, CharSequence>, parameter = "#1 of Baz", argument = CharSequence
|
||||
|
||||
// if it is mapped to klass' parameter, then store it into map
|
||||
for (TypeProjection projection : substitution.get(parameter)) {
|
||||
// 1. projection = A
|
||||
// 2. projection = List<B>
|
||||
// 3. projection = Boolean
|
||||
// 4. projection = A
|
||||
ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
|
||||
|
||||
// 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();
|
||||
Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
|
||||
parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, effectiveVariance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return parameterToArgumentsFromSuper;
|
||||
}
|
||||
|
||||
private boolean typeMustBeNullable(
|
||||
@NotNull KotlinType autoType,
|
||||
@NotNull List<TypeAndVariance> typesFromSuper,
|
||||
@NotNull TypeUsage howThisTypeIsUsed
|
||||
) {
|
||||
boolean someSupersNotCovariantNullable = false;
|
||||
boolean someSupersCovariantNullable = false;
|
||||
boolean someSupersNotNull = false;
|
||||
for (TypeAndVariance typeFromSuper : typesFromSuper) {
|
||||
if (!TypeUtils.isNullableType(typeFromSuper.type)) {
|
||||
someSupersNotNull = true;
|
||||
}
|
||||
else {
|
||||
if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
|
||||
someSupersCovariantNullable = true;
|
||||
}
|
||||
else {
|
||||
someSupersNotCovariantNullable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (someSupersNotNull && someSupersNotCovariantNullable) {
|
||||
reportError("Incompatible types in superclasses: " + typesFromSuper);
|
||||
return TypeUtils.isNullableType(autoType);
|
||||
}
|
||||
else if (someSupersNotNull) {
|
||||
return false;
|
||||
}
|
||||
else if (someSupersNotCovariantNullable || someSupersCovariantNullable) {
|
||||
boolean annotatedAsNotNull = howThisTypeIsUsed != TYPE_ARGUMENT && !TypeUtils.isNullableType(autoType);
|
||||
|
||||
if (annotatedAsNotNull && someSupersNotCovariantNullable) {
|
||||
DescriptorRenderer renderer = DescriptorRenderer.SHORT_NAMES_IN_TYPES;
|
||||
reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + renderer.renderType(autoType));
|
||||
return true;
|
||||
}
|
||||
|
||||
return !annotatedAsNotNull;
|
||||
}
|
||||
return TypeUtils.isNullableType(autoType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassifierDescriptor modifyTypeClassifier(
|
||||
@NotNull KotlinType autoType,
|
||||
@NotNull List<TypeAndVariance> typesFromSuper
|
||||
) {
|
||||
ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
|
||||
if (!(classifier instanceof ClassDescriptor)) {
|
||||
assert classifier != null : "no declaration descriptor for type " + autoType + ", auto method descriptor: " + autoMethodDescriptor;
|
||||
|
||||
if (classifier instanceof TypeParameterDescriptor && autoTypeParameterToModified.containsKey(classifier)) {
|
||||
return autoTypeParameterToModified.get(classifier);
|
||||
}
|
||||
return classifier;
|
||||
}
|
||||
ClassDescriptor klass = (ClassDescriptor) classifier;
|
||||
|
||||
boolean someSupersMutable = false;
|
||||
boolean someSupersCovariantReadOnly = false;
|
||||
boolean someSupersNotCovariantReadOnly = false;
|
||||
for (TypeAndVariance typeFromSuper : typesFromSuper) {
|
||||
ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor();
|
||||
if (classifierFromSuper instanceof ClassDescriptor) {
|
||||
ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
|
||||
|
||||
if (JavaToKotlinClassMap.INSTANCE.isMutable(classFromSuper)) {
|
||||
someSupersMutable = true;
|
||||
}
|
||||
else if (JavaToKotlinClassMap.INSTANCE.isReadOnly(classFromSuper)) {
|
||||
if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
|
||||
someSupersCovariantReadOnly = true;
|
||||
}
|
||||
else {
|
||||
someSupersNotCovariantReadOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (someSupersMutable && someSupersNotCovariantReadOnly) {
|
||||
reportError("Incompatible types in superclasses: " + typesFromSuper);
|
||||
return classifier;
|
||||
}
|
||||
else if (someSupersMutable) {
|
||||
if (JavaToKotlinClassMap.INSTANCE.isReadOnly(klass)) {
|
||||
return JavaToKotlinClassMap.INSTANCE.convertReadOnlyToMutable(klass);
|
||||
}
|
||||
}
|
||||
else if (someSupersNotCovariantReadOnly || someSupersCovariantReadOnly) {
|
||||
if (JavaToKotlinClassMap.INSTANCE.isMutable(klass)) {
|
||||
return JavaToKotlinClassMap.INSTANCE.convertMutableToReadOnly(klass);
|
||||
}
|
||||
}
|
||||
|
||||
ClassifierDescriptor fixed = PropagationHeuristics.tryToFixOverridingTWithRawType(this, typesFromSuper);
|
||||
return fixed != null ? fixed : classifier;
|
||||
}
|
||||
|
||||
private static boolean isArrayType(@NotNull KotlinType type) {
|
||||
return KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type);
|
||||
}
|
||||
@@ -680,34 +296,6 @@ public class SignaturesPropagationData {
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeProjectionAndVariance {
|
||||
public final TypeProjection typeProjection;
|
||||
public final Variance varianceOfPosition;
|
||||
|
||||
public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfPosition) {
|
||||
this.typeProjection = typeProjection;
|
||||
this.varianceOfPosition = varianceOfPosition;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return typeProjection.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static class TypeAndVariance {
|
||||
public final KotlinType type;
|
||||
public final Variance varianceOfPosition;
|
||||
|
||||
public TypeAndVariance(KotlinType type, Variance varianceOfPosition) {
|
||||
this.type = type;
|
||||
this.varianceOfPosition = varianceOfPosition;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeAndName {
|
||||
public final KotlinType type;
|
||||
public final Name name;
|
||||
|
||||
Reference in New Issue
Block a user