Prohibit constructing projected types via type aliases.
This commit is contained in:
@@ -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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
+1
-1
@@ -10,4 +10,4 @@ fun <T> listOf(): List<T> = null!!
|
||||
// since it has 'out' type projection in 'in' position.
|
||||
val test1 = <!UNRESOLVED_REFERENCE!>BOutIn<!>(<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>listOf<!>(), null!!)
|
||||
|
||||
val test2 = BInIn(listOf(), null!!)
|
||||
val test2 = <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>BInIn(listOf(), null!!)<!>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class C<T>
|
||||
|
||||
typealias CStar = C<*>
|
||||
typealias CIn = C<in Int>
|
||||
typealias COut = C<out Int>
|
||||
typealias CT<T> = C<T>
|
||||
|
||||
val test1 = <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>CStar()<!>
|
||||
val test2 = <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>CIn()<!>
|
||||
val test3 = <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>COut()<!>
|
||||
val test4 = CT<<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>>()
|
||||
val test5 = CT<CT<*>>()
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package
|
||||
|
||||
public val test1: C<*>
|
||||
public val test2: C<in kotlin.Int>
|
||||
public val test3: C<out kotlin.Int>
|
||||
public val test4: C<[ERROR : Star projection in a call]>
|
||||
public val test5: C<CT<*> /* = C<*> */>
|
||||
|
||||
public final class C</*0*/ T> {
|
||||
public constructor C</*0*/ T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias CIn = C<in kotlin.Int>
|
||||
public typealias COut = C<out kotlin.Int>
|
||||
public typealias CStar = C<*>
|
||||
public typealias CT</*0*/ T> = C<T>
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
open class C<T>
|
||||
|
||||
typealias CStar = C<*>
|
||||
typealias CIn = C<in Int>
|
||||
typealias COut = C<out Int>
|
||||
typealias CT<T> = C<T>
|
||||
|
||||
class Test1 : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>CStar()<!>
|
||||
class Test2 : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>CIn()<!>
|
||||
class Test3 : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>COut()<!>
|
||||
|
||||
class Test4 : CStar {
|
||||
constructor() : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>super<!>()
|
||||
}
|
||||
|
||||
class Test5 : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>CT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>()<!>
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
package
|
||||
|
||||
public open class C</*0*/ T> {
|
||||
public constructor C</*0*/ T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test1 : CStar /* = C<*> */ {
|
||||
public constructor Test1()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test2 : CIn /* = C<in kotlin.Int> */ {
|
||||
public constructor Test2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test3 : COut /* = C<out kotlin.Int> */ {
|
||||
public constructor Test3()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test4 : CStar /* = C<*> */ {
|
||||
public constructor Test4()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test5 : CT<*> /* = C<*> */ {
|
||||
public constructor Test5()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias CIn = C<in kotlin.Int>
|
||||
public typealias COut = C<out kotlin.Int>
|
||||
public typealias CStar = C<*>
|
||||
public typealias CT</*0*/ T> = C<T>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
// !CHECK_TYPE
|
||||
// FILE: a.kt
|
||||
class B(x: String)
|
||||
|
||||
typealias A1 = B
|
||||
private typealias A2 = B
|
||||
private typealias A3 = B
|
||||
|
||||
fun A3(x: Any) = "OK"
|
||||
|
||||
fun bar() {
|
||||
A3("") checkType { _<B>() }
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public fun A3(/*0*/ x: kotlin.Any): kotlin.String
|
||||
public fun bar(): kotlin.Unit
|
||||
|
||||
public final class B {
|
||||
public constructor B(/*0*/ x: kotlin.String)
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias A1 = B
|
||||
private typealias A2 = B
|
||||
private typealias A3 = B
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
interface I<T>
|
||||
|
||||
typealias IStar = I<*>
|
||||
typealias IIn = I<in Int>
|
||||
typealias IOut = I<out Int>
|
||||
typealias IT<T> = I<T>
|
||||
|
||||
class Test1 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>IStar<!>
|
||||
class Test2 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>IIn<!>
|
||||
class Test3 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>IOut<!>
|
||||
class Test4 : IT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>
|
||||
class Test5 : IT<IT<*>>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package
|
||||
|
||||
public interface I</*0*/ T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test1 : IStar /* = I<*> */ {
|
||||
public constructor Test1()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test2 : IIn /* = I<in kotlin.Int> */ {
|
||||
public constructor Test2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test3 : IOut /* = I<out kotlin.Int> */ {
|
||||
public constructor Test3()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test4 : IT<*> /* = I<*> */ {
|
||||
public constructor Test4()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test5 : IT<IT<*> /* = I<*> */> /* = I<IT<*> /* = I<*> */> */ {
|
||||
public constructor Test5()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias IIn = I<in kotlin.Int>
|
||||
public typealias IOut = I<out kotlin.Int>
|
||||
public typealias IStar = I<*>
|
||||
public typealias IT</*0*/ T> = I<T>
|
||||
@@ -21166,6 +21166,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorForProjection.kt")
|
||||
public void testTypeAliasConstructorForProjection() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjection.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorForProjectionInSupertypes.kt")
|
||||
public void testTypeAliasConstructorForProjectionInSupertypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorInSuperCall.kt")
|
||||
public void testTypeAliasConstructorInSuperCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorInSuperCall.kt");
|
||||
@@ -21202,6 +21214,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorVsFunction.kt")
|
||||
public void testTypeAliasConstructorVsFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorVsFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorWrongClass.kt")
|
||||
public void testTypeAliasConstructorWrongClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorWrongClass.kt");
|
||||
@@ -21220,6 +21238,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasForProjectionInSuperInterfaces.kt")
|
||||
public void testTypeAliasForProjectionInSuperInterfaces() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasInAnonymousObjectType.kt")
|
||||
public void testTypeAliasInAnonymousObjectType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasInAnonymousObjectType.kt");
|
||||
|
||||
@@ -203,3 +203,8 @@ fun KotlinType.requiresTypeAliasExpansion(): Boolean =
|
||||
} ?: false
|
||||
}
|
||||
|
||||
fun KotlinType.containsTypeProjectionsInTopLevelArguments(): Boolean {
|
||||
if (isError) return false
|
||||
val possiblyInnerType = buildPossiblyInnerType() ?: return false
|
||||
return possiblyInnerType.arguments.any { it.isStarProjection || it.projectionKind != Variance.INVARIANT }
|
||||
}
|
||||
Reference in New Issue
Block a user