Support only simple declarations for 'impl' type aliases

E.g. 'impl typealias Foo<A, B> = Bar<A, B>' is allowed; everything else
(variance, changing order of parameters, etc.) is pretty much disallowed.

This is done for simplicity: otherwise matching the platform/impl class scopes
would be not so straightforward
This commit is contained in:
Alexander Udalov
2016-11-22 15:03:36 +03:00
parent 751949db69
commit a8bd82e863
6 changed files with 163 additions and 0 deletions
@@ -497,6 +497,11 @@ public interface Errors {
DiagnosticFactory0<KtParameter> PLATFORM_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> PLATFORM_PROPERTY_INITIALIZER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeAlias> IMPL_TYPE_ALIAS_NOT_TO_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtTypeAlias> IMPL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtTypeAlias> IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtTypeAlias> IMPL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Errors/warnings inside code blocks
@@ -263,6 +263,11 @@ public class DefaultErrorMessages {
MAP.put(PLATFORM_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, "Platform class constructor cannot have a property parameter");
MAP.put(PLATFORM_PROPERTY_INITIALIZER, "Platform property cannot have an initializer");
MAP.put(IMPL_TYPE_ALIAS_NOT_TO_CLASS, "Right-hand side of 'impl' type alias should be a class, not another type alias");
MAP.put(IMPL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE, "Aliased class should not have type parameters with declaration-site variance");
MAP.put(IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE, "Right-hand side of 'impl' type alias cannot contain use-site variance or star projections");
MAP.put(IMPL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION, "Type arguments in the right-hand side of 'impl' type alias should be its type parameters in the same order, e.g. 'impl typealias Foo<A, B> = Bar<A, B>'");
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
MAP.put(NOTHING_TO_OVERRIDE, "''{0}'' overrides nothing", NAME);
@@ -181,6 +181,35 @@ class DeclarationsChecker(
trace.report(UNUSED_TYPEALIAS_PARAMETER.on(source, typeParameter, expandedType))
}
}
if (declaration.hasModifier(KtTokens.IMPL_KEYWORD)) {
checkImplTypeAlias(declaration, typeAliasDescriptor)
}
}
private fun checkImplTypeAlias(declaration: KtTypeAlias, typeAliasDescriptor: TypeAliasDescriptor) {
val rhs = typeAliasDescriptor.underlyingType
val classDescriptor = rhs.constructor.declarationDescriptor
if (classDescriptor !is ClassDescriptor) {
trace.report(IMPL_TYPE_ALIAS_NOT_TO_CLASS.on(declaration))
return
}
if (classDescriptor.declaredTypeParameters.any { it.variance != Variance.INVARIANT }) {
trace.report(IMPL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE.on(declaration))
return
}
if (rhs.arguments.any { it.projectionKind != Variance.INVARIANT || it.isStarProjection }) {
trace.report(IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE.on(declaration))
return
}
if (rhs.arguments.map { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } !=
typeAliasDescriptor.declaredTypeParameters) {
trace.report(IMPL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION.on(declaration))
return
}
}
private fun getUsedTypeAliasParameters(type: KotlinType, typeAlias: TypeAliasDescriptor): Set<TypeParameterDescriptor> =
@@ -0,0 +1,30 @@
// !LANGUAGE: +MultiPlatformProjects
// MODULE: m1-common
// FILE: common.kt
platform class C1
platform class C2<A>
platform class C3<B>
platform class C4<D, E>
platform class C5<F, G>
platform class C6<H>
platform class C7<I>
platform class C8<J>
platform class C9<K>
platform class C10<L>
// MODULE: m2-jvm(m1-common)
// FILE: jvm.kt
impl typealias C1 = String
<!IMPL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE!>impl typealias C2<<!UNUSED_TYPEALIAS_PARAMETER!>A<!>> = List<String><!>
<!IMPL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE!>impl typealias C3<B> = List<B><!>
impl typealias C4<D, E> = MutableMap<D, E>
<!IMPL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION!>impl typealias C5<F, G> = MutableMap<G, F><!>
impl typealias C6<H> = MutableList<H>
<!IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE!>impl typealias C7<I> = MutableList<out I><!>
<!IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE!>impl typealias C8<<!UNUSED_TYPEALIAS_PARAMETER!>J<!>> = MutableList<*><!>
<!IMPL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE!>impl typealias C9<K> = MutableList<in K><!>
typealias Tmp<K> = MutableList<K>
<!IMPL_TYPE_ALIAS_NOT_TO_CLASS!>impl typealias C10<L> = Tmp<L><!>
@@ -0,0 +1,88 @@
// -- Module: <m1-common> --
package
public final platform class C1 {
public constructor C1()
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 platform class C10</*0*/ L> {
public constructor C10</*0*/ L>()
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 platform class C2</*0*/ A> {
public constructor C2</*0*/ A>()
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 platform class C3</*0*/ B> {
public constructor C3</*0*/ B>()
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 platform class C4</*0*/ D, /*1*/ E> {
public constructor C4</*0*/ D, /*1*/ E>()
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 platform class C5</*0*/ F, /*1*/ G> {
public constructor C5</*0*/ F, /*1*/ G>()
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 platform class C6</*0*/ H> {
public constructor C6</*0*/ H>()
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 platform class C7</*0*/ I> {
public constructor C7</*0*/ I>()
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 platform class C8</*0*/ J> {
public constructor C8</*0*/ J>()
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 platform class C9</*0*/ K> {
public constructor C9</*0*/ K>()
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
}
// -- Module: <m2-jvm> --
package
public typealias C1 = kotlin.String
public typealias C10</*0*/ L> = Tmp<L>
public typealias C2</*0*/ A> = kotlin.collections.List<kotlin.String>
public typealias C3</*0*/ B> = kotlin.collections.List<B>
public typealias C4</*0*/ D, /*1*/ E> = kotlin.collections.MutableMap<D, E>
public typealias C5</*0*/ F, /*1*/ G> = kotlin.collections.MutableMap<G, F>
public typealias C6</*0*/ H> = kotlin.collections.MutableList<H>
public typealias C7</*0*/ I> = kotlin.collections.MutableList<out I>
public typealias C8</*0*/ J> = kotlin.collections.MutableList<*>
public typealias C9</*0*/ K> = kotlin.collections.MutableList<in K>
public typealias Tmp</*0*/ K> = kotlin.collections.MutableList<K>
@@ -12576,6 +12576,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("genericClassImplTypeAlias.kt")
public void testGenericClassImplTypeAlias() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/platformClass/genericClassImplTypeAlias.kt");
doTest(fileName);
}
@TestMetadata("platformClassMember.kt")
public void testPlatformClassMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/platformClass/platformClassMember.kt");