Prohibit constructing projected types via type aliases.

This commit is contained in:
Dmitry Petrov
2016-11-18 15:36:04 +03:00
parent bab9cde280
commit 063bce23d2
15 changed files with 243 additions and 3 deletions
@@ -137,6 +137,8 @@ public interface Errors {
DiagnosticFactory1<KtElement, KotlinType> CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtTypeReference, KotlinType> TYPEALIAS_SHOULD_EXPAND_TO_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<KtTypeReference, KotlinType, String> TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<KtElement, KotlinType> EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtTypeElement, KotlinType> EXPANDED_TYPE_CANNOT_BE_INHERITED = DiagnosticFactory1.create(ERROR);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -444,6 +444,8 @@ public class DefaultErrorMessages {
MAP.put(TYPEALIAS_SHOULD_EXPAND_TO_CLASS, "Type alias expands to {0}, which is not a class, an interface, or an object", RENDER_TYPE);
MAP.put(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE, "Type alias expanded to malformed type {0}: {1}", RENDER_TYPE, STRING);
MAP.put(UNUSED_TYPEALIAS_PARAMETER, "Type alias parameter {0} is not used in the expanded type {1} and does not affect type checking", NAME, RENDER_TYPE);
MAP.put(EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED, "Expanded type {0} contains non-invariant projections in top-level arguments and cannot be constructed", RENDER_TYPE);
MAP.put(EXPANDED_TYPE_CANNOT_BE_INHERITED, "Expanded type {0} contains non-invariant projections in top-level arguments and cannot be inherited from", RENDER_TYPE);
MAP.put(TOO_MANY_ARGUMENTS, "Too many arguments for {0}", FQ_NAMES_IN_TYPES);
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.expressions.*;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import java.util.*;
@@ -195,7 +196,7 @@ public class DescriptorResolver {
else {
result.add(supertype);
KtTypeElement bareSuperType = checkNullableSupertypeAndStripQuestionMarks(trace, typeReference.getTypeElement());
checkProjectionsInImmediateArguments(trace, bareSuperType);
checkProjectionsInImmediateArguments(trace, bareSuperType, supertype);
}
}
else {
@@ -218,16 +219,30 @@ public class DescriptorResolver {
return typeElement;
}
private static void checkProjectionsInImmediateArguments(@NotNull BindingTrace trace, @Nullable KtTypeElement typeElement) {
private static void checkProjectionsInImmediateArguments(
@NotNull BindingTrace trace,
@Nullable KtTypeElement typeElement,
@NotNull KotlinType type
) {
if (typeElement == null) return;
boolean hasProjectionsInWrittenArguments = false;
if (typeElement instanceof KtUserType) {
KtUserType userType = (KtUserType) typeElement;
List<KtTypeProjection> typeArguments = userType.getTypeArguments();
for (KtTypeProjection typeArgument : typeArguments) {
if (typeArgument.getProjectionKind() != KtProjectionKind.NONE) {
trace.report(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE.on(typeArgument));
hasProjectionsInWrittenArguments = true;
}
}
}
if (!type.isError() && SpecialTypesKt.getAbbreviatedType(type) != null && !hasProjectionsInWrittenArguments) {
if (TypeUtilsKt.isInterface(type) && TypeUtilsKt.containsTypeProjectionsInTopLevelArguments(type)) {
trace.report(EXPANDED_TYPE_CANNOT_BE_INHERITED.on(typeElement, type));
}
}
}
public static Visibility getDefaultVisibility(KtModifierListOwner modifierListOwner, DeclarationDescriptor containingDescriptor) {
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
import java.util.*
class CandidateResolver(
@@ -96,6 +97,7 @@ class CandidateResolver(
checkValueArguments()
checkAbstractAndSuper()
checkConstructedExpandedType()
}
private fun CallCandidateResolutionContext<*>.checkValueArguments() = checkAndReport {
@@ -310,6 +312,17 @@ class CandidateResolver(
}
}
private fun CallCandidateResolutionContext<*>.checkConstructedExpandedType() = check {
val descriptor = candidateDescriptor
if (descriptor is TypeAliasConstructorDescriptor) {
if (descriptor.returnType.containsTypeProjectionsInTopLevelArguments()) {
trace.report(EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED.on(call.callElement, descriptor.returnType))
candidateCall.addStatus(OTHER_ERROR)
}
}
}
private fun getReceiverSuper(receiver: Receiver?): KtSuperExpression? {
if (receiver is ExpressionReceiver) {
val expression = receiver.expression