[NI] Properly support UnsafeVariance annotation
#KT-38134 Fixed #KT-34433 Fixed #KT-31823 Fixed
This commit is contained in:
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorKt;
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor;
|
||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker;
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
|
||||
@@ -91,7 +92,7 @@ public class TypeSubstitutor implements TypeSubstitutorMarker {
|
||||
}
|
||||
|
||||
try {
|
||||
return unsafeSubstitute(new TypeProjectionImpl(howThisTypeIsUsed, type), 0).getType();
|
||||
return unsafeSubstitute(new TypeProjectionImpl(howThisTypeIsUsed, type), null, 0).getType();
|
||||
} catch (SubstitutionException e) {
|
||||
return ErrorUtils.createErrorType(e.getMessage());
|
||||
}
|
||||
@@ -121,14 +122,18 @@ public class TypeSubstitutor implements TypeSubstitutorMarker {
|
||||
}
|
||||
|
||||
try {
|
||||
return unsafeSubstitute(typeProjection, 0);
|
||||
return unsafeSubstitute(typeProjection, null, 0);
|
||||
} catch (SubstitutionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TypeProjection unsafeSubstitute(@NotNull TypeProjection originalProjection, int recursionDepth) throws SubstitutionException {
|
||||
private TypeProjection unsafeSubstitute(
|
||||
@NotNull TypeProjection originalProjection,
|
||||
@Nullable TypeParameterDescriptor typeParameter,
|
||||
int recursionDepth
|
||||
) throws SubstitutionException {
|
||||
assertRecursionDepth(recursionDepth, originalProjection, substitution);
|
||||
|
||||
if (originalProjection.isStarProjection()) return originalProjection;
|
||||
@@ -141,6 +146,7 @@ public class TypeSubstitutor implements TypeSubstitutorMarker {
|
||||
|
||||
TypeProjection substitution = unsafeSubstitute(
|
||||
new TypeProjectionImpl(originalProjection.getProjectionKind(), origin),
|
||||
typeParameter,
|
||||
recursionDepth + 1
|
||||
);
|
||||
|
||||
@@ -154,14 +160,27 @@ public class TypeSubstitutor implements TypeSubstitutorMarker {
|
||||
return originalProjection; // todo investigate
|
||||
}
|
||||
|
||||
TypeProjection replacement = substitution.get(type);
|
||||
TypeProjection substituted = substitution.get(type);
|
||||
TypeProjection replacement =
|
||||
substituted != null ?
|
||||
projectedTypeForConflictedTypeWithUnsafeVariance(type, substituted, typeParameter, originalProjection) :
|
||||
null;
|
||||
|
||||
Variance originalProjectionKind = originalProjection.getProjectionKind();
|
||||
if (replacement == null && FlexibleTypesKt.isFlexible(type) && !TypeCapabilitiesKt.isCustomTypeVariable(type)) {
|
||||
FlexibleType flexibleType = FlexibleTypesKt.asFlexibleType(type);
|
||||
TypeProjection substitutedLower =
|
||||
unsafeSubstitute(new TypeProjectionImpl(originalProjectionKind, flexibleType.getLowerBound()), recursionDepth + 1);
|
||||
unsafeSubstitute(
|
||||
new TypeProjectionImpl(originalProjectionKind, flexibleType.getLowerBound()),
|
||||
typeParameter,
|
||||
recursionDepth + 1
|
||||
);
|
||||
TypeProjection substitutedUpper =
|
||||
unsafeSubstitute(new TypeProjectionImpl(originalProjectionKind, flexibleType.getUpperBound()), recursionDepth + 1);
|
||||
unsafeSubstitute(
|
||||
new TypeProjectionImpl(originalProjectionKind, flexibleType.getUpperBound()),
|
||||
typeParameter,
|
||||
recursionDepth + 1
|
||||
);
|
||||
|
||||
Variance substitutedProjectionKind = substitutedLower.getProjectionKind();
|
||||
assert (substitutedProjectionKind == substitutedUpper.getProjectionKind()) &&
|
||||
@@ -225,6 +244,37 @@ public class TypeSubstitutor implements TypeSubstitutorMarker {
|
||||
return substituteCompoundType(originalProjection, recursionDepth);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TypeProjection projectedTypeForConflictedTypeWithUnsafeVariance(
|
||||
@NotNull KotlinType originalType,
|
||||
@NotNull TypeProjection substituted,
|
||||
@Nullable TypeParameterDescriptor typeParameter,
|
||||
@NotNull TypeProjection originalProjection
|
||||
) {
|
||||
if (!originalType.getAnnotations().hasAnnotation(KotlinBuiltIns.FQ_NAMES.unsafeVariance)) return substituted;
|
||||
|
||||
TypeConstructor constructor = substituted.getType().getConstructor();
|
||||
if (!(constructor instanceof NewCapturedTypeConstructor)) return substituted;
|
||||
|
||||
NewCapturedTypeConstructor capturedType = (NewCapturedTypeConstructor) constructor;
|
||||
TypeProjection capturedTypeProjection = capturedType.getProjection();
|
||||
Variance varianceOfCapturedType = capturedTypeProjection.getProjectionKind();
|
||||
|
||||
VarianceConflictType conflictWithTopLevelType = conflictType(originalProjection.getProjectionKind(), varianceOfCapturedType);
|
||||
if (conflictWithTopLevelType == VarianceConflictType.OUT_IN_IN_POSITION) {
|
||||
return new TypeProjectionImpl(capturedTypeProjection.getType());
|
||||
}
|
||||
|
||||
if (typeParameter == null) return substituted;
|
||||
|
||||
VarianceConflictType conflictTypeWithTypeParameter = conflictType(typeParameter.getVariance(), varianceOfCapturedType);
|
||||
if (conflictTypeWithTypeParameter == VarianceConflictType.OUT_IN_IN_POSITION) {
|
||||
return new TypeProjectionImpl(capturedTypeProjection.getType());
|
||||
}
|
||||
|
||||
return substituted;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Annotations filterOutUnsafeVariance(@NotNull Annotations annotations) {
|
||||
if (!annotations.hasAnnotation(KotlinBuiltIns.FQ_NAMES.unsafeVariance)) return annotations;
|
||||
@@ -275,7 +325,7 @@ public class TypeSubstitutor implements TypeSubstitutorMarker {
|
||||
TypeParameterDescriptor typeParameter = typeParameters.get(i);
|
||||
TypeProjection typeArgument = typeArguments.get(i);
|
||||
|
||||
TypeProjection substitutedTypeArgument = unsafeSubstitute(typeArgument, recursionDepth + 1);
|
||||
TypeProjection substitutedTypeArgument = unsafeSubstitute(typeArgument, typeParameter, recursionDepth + 1);
|
||||
|
||||
switch (conflictType(typeParameter.getVariance(), substitutedTypeArgument.getProjectionKind())) {
|
||||
case NO_CONFLICT:
|
||||
|
||||
Reference in New Issue
Block a user