Type alias projections & substitution rules.

1. Substitution variance (sv) is a substitution composition of type alias argument variance (av)
and corresponding expanding type argument variance (ev):
sv =
  | av == ev -> av
  | av == INVARIANT -> ev
  | ev == INVARIANT -> av
  | else -> (variance conflict error; av)

2. Resulting variance (rv) is a type argument composition of sv and type parameter variance (pv):
rv =
  | sv == tv => INVARIANT
  | sv == INVARIANT => INVARIANT
  | tv == INVARIANT => sv
  | else -> (variance conflict error; sv)
This commit is contained in:
Dmitry Petrov
2016-11-21 11:47:16 +03:00
parent 427c6386a9
commit bab9cde280
9 changed files with 126 additions and 43 deletions
@@ -40,8 +40,8 @@ class TypeAliasExpander(
recursionDepth: Int,
withAbbreviatedType: Boolean
): SimpleType {
val originalProjection = TypeProjectionImpl(Variance.INVARIANT, typeAliasExpansion.descriptor.underlyingType)
val expandedProjection = expandTypeProjection(originalProjection, typeAliasExpansion, null, recursionDepth)
val underlyingProjection = TypeProjectionImpl(Variance.INVARIANT, typeAliasExpansion.descriptor.underlyingType)
val expandedProjection = expandTypeProjection(underlyingProjection, typeAliasExpansion, null, recursionDepth)
val expandedType = expandedProjection.type.asSimpleType()
if (expandedType.isError) return expandedType
@@ -53,7 +53,7 @@ class TypeAliasExpander(
val expandedTypeWithExtraAnnotations = combineAnnotations(expandedType, annotations)
return if (withAbbreviatedType)
expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(originalProjection, annotations))
expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(underlyingProjection, annotations))
else
expandedTypeWithExtraAnnotations
}
@@ -80,50 +80,52 @@ class TypeAliasExpander(
)
private fun expandTypeProjection(
originalProjection: TypeProjection,
underlyingProjection: TypeProjection,
typeAliasExpansion: TypeAliasExpansion,
typeParameterDescriptor: TypeParameterDescriptor?,
recursionDepth: Int
): TypeProjection {
assertRecursionDepth(recursionDepth, typeAliasExpansion.descriptor)
val originalType = originalProjection.type
if (underlyingProjection.isStarProjection) return TypeUtils.makeStarProjection(typeParameterDescriptor!!)
val typeAliasArgument = typeAliasExpansion.getReplacement(originalType.constructor)
if (typeAliasArgument == null) {
return expandNonArgumentTypeProjection(originalProjection, typeAliasExpansion, recursionDepth)
val underlyingType = underlyingProjection.type
val argument = typeAliasExpansion.getReplacement(underlyingType.constructor)
if (argument == null) {
return expandNonArgumentTypeProjection(underlyingProjection, typeAliasExpansion, recursionDepth)
}
val originalVariance =
if (originalProjection.projectionKind != Variance.INVARIANT)
originalProjection.projectionKind
else
typeParameterDescriptor?.variance ?: Variance.INVARIANT
if (argument.isStarProjection) return TypeUtils.makeStarProjection(typeParameterDescriptor!!)
val argumentVariance = typeAliasArgument.projectionKind
val argumentVariance = argument.projectionKind
val underlyingVariance = underlyingProjection.projectionKind
val substitutedVariance =
if (argumentVariance == Variance.INVARIANT)
originalVariance
else if (originalVariance == Variance.INVARIANT || originalVariance == argumentVariance)
argumentVariance
else if (typeAliasArgument.isStarProjection)
argumentVariance
else {
if (originalVariance != argumentVariance && !typeAliasArgument.isStarProjection) {
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, typeAliasArgument.type)
val substitutionVariance =
when {
underlyingVariance == argumentVariance -> argumentVariance
underlyingVariance == Variance.INVARIANT -> argumentVariance
argumentVariance == Variance.INVARIANT -> underlyingVariance
else -> {
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argument.type)
argumentVariance
}
argumentVariance
}
if (typeAliasArgument.isStarProjection) {
return TypeUtils.makeStarProjection(typeParameterDescriptor!!)
}
val parameterVariance = typeParameterDescriptor?.variance ?: Variance.INVARIANT
val resultingVariance =
when {
parameterVariance == substitutionVariance -> Variance.INVARIANT
parameterVariance == Variance.INVARIANT -> substitutionVariance
substitutionVariance == Variance.INVARIANT -> Variance.INVARIANT
else -> {
reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argument.type)
substitutionVariance
}
}
val substitutedType = TypeUtils.makeNullableIfNeeded(typeAliasArgument.type, originalType.isMarkedNullable)
val substitutedType = TypeUtils.makeNullableIfNeeded(argument.type, underlyingType.isMarkedNullable)
return TypeProjectionImpl(substitutedVariance, substitutedType)
return TypeProjectionImpl(resultingVariance, substitutedType)
}
private fun expandNonArgumentTypeProjection(
@@ -14,13 +14,13 @@ public final class A : Outer<kotlin.Double, kotlin.Short> {
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 fun x(): Outer<kotlin.Float, kotlin.Long>.Alias<kotlin.String> /* = kotlin.collections.Map<kotlin.String, out kotlin.Float> */
public final fun x(): Outer<kotlin.Float, kotlin.Long>.Alias<kotlin.String> /* = kotlin.collections.Map<kotlin.String, kotlin.Float> */
}
}
public final class Derived : Outer<kotlin.String, kotlin.Int> {
public constructor Derived()
public final fun baz(): Outer<kotlin.String, kotlin.Int>.Alias<kotlin.Char> /* = kotlin.collections.Map<kotlin.Char, out kotlin.String> */
public final fun baz(): Outer<kotlin.String, kotlin.Int>.Alias<kotlin.Char> /* = kotlin.collections.Map<kotlin.Char, kotlin.String> */
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): Outer<kotlin.String, kotlin.Int>.Inner<kotlin.Char>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -18,7 +18,7 @@ public open class BaseDerived2</*0*/ X> : BaseDerived1<kotlin.String, X> {
public final class Derived : BaseDerived2<kotlin.Int> {
public constructor Derived()
public final fun baz(): Outer<kotlin.Int, kotlin.String>.Alias<kotlin.Char> /* = kotlin.collections.Map<kotlin.Char, out kotlin.Int> */
public final fun baz(): Outer<kotlin.Int, kotlin.String>.Alias<kotlin.Char> /* = kotlin.collections.Map<kotlin.Char, kotlin.Int> */
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): Outer<kotlin.Int, kotlin.String>.Inner<kotlin.Char>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -13,8 +13,8 @@ public fun test10(/*0*/ x: TC<kotlin.Number, kotlin.collections.Collection<kotli
public fun test11(/*0*/ x: TC<kotlin.Number, kotlin.collections.List<kotlin.Int>> /* = TColl<kotlin.Number, kotlin.collections.List<kotlin.Int>> */): kotlin.Unit
public fun test12(/*0*/ x: TC<kotlin.Number, kotlin.collections.List<kotlin.Any>> /* = TColl<kotlin.Number, kotlin.collections.List<kotlin.Any>> */): kotlin.Unit
public fun test2(/*0*/ x: NA<kotlin.Any> /* = Num<kotlin.Any> */): kotlin.Unit
public fun test3(/*0*/ x: NL<kotlin.Int> /* = NumColl<kotlin.collections.List<out kotlin.Int>> */): kotlin.Unit
public fun test4(/*0*/ x: NL<kotlin.Any> /* = NumColl<kotlin.collections.List<out kotlin.Any>> */): kotlin.Unit
public fun test3(/*0*/ x: NL<kotlin.Int> /* = NumColl<kotlin.collections.List<kotlin.Int>> */): kotlin.Unit
public fun test4(/*0*/ x: NL<kotlin.Any> /* = NumColl<kotlin.collections.List<kotlin.Any>> */): kotlin.Unit
public fun test9(/*0*/ x: TC<kotlin.Number, kotlin.collections.Collection<kotlin.Number>> /* = TColl<kotlin.Number, kotlin.collections.Collection<kotlin.Number>> */): kotlin.Unit
public final class Num</*0*/ T : kotlin.Number> {
+3 -3
View File
@@ -32,21 +32,21 @@ public final class Test2</*0*/ out S> : A2<kotlin.Any, S> /* = I1<S> */ {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Test3</*0*/ out S> : AOut<S> /* = Out<out S> */ {
public final class Test3</*0*/ out S> : AOut<S> /* = Out<S> */ {
public constructor Test3</*0*/ out S>()
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</*0*/ out S> : AInvOut<S, S> /* = InvOut<S, out S> */ {
public final class Test4</*0*/ out S> : AInvOut<S, S> /* = InvOut<S, S> */ {
public constructor Test4</*0*/ out S>()
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</*0*/ out S> : AInvOutTT<S> /* = InvOut<S, out S> */ {
public final class Test5</*0*/ out S> : AInvOutTT<S> /* = InvOut<S, S> */ {
public constructor Test5</*0*/ out S>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+3 -3
View File
@@ -12,19 +12,19 @@ public interface Out</*0*/ out R> {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface Q1</*0*/ out S> : Out<A1<S> /* = Out<Out<out S>> */> {
public interface Q1</*0*/ out S> : Out<A1<S> /* = Out<Out<S>> */> {
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 interface Q2</*0*/ out S> : Out<A2<S> /* = Out<Out<out S>> */> {
public interface Q2</*0*/ out S> : Out<A2<S> /* = Out<Out<S>> */> {
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 interface Q3</*0*/ out S> : Out<A3<S> /* = Inv<Out<out S>> */> {
public interface Q3</*0*/ out S> : Out<A3<S> /* = Inv<Out<S>> */> {
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
@@ -3,6 +3,6 @@ package
public fun bar1(/*0*/ a: Array2D<kotlin.Int> /* = kotlin.Array<kotlin.Array<kotlin.Int>> */): Array2D<out kotlin.Number> /* = kotlin.Array<kotlin.Array<out kotlin.Number>> */
public fun bar2(/*0*/ m: TMap<*> /* = kotlin.collections.Map<*, *> */): [ERROR : Error function type]
public fun foo1(/*0*/ a: Array2D<out kotlin.Number> /* = kotlin.Array<kotlin.Array<out kotlin.Number>> */): Array2D<out kotlin.Number> /* = kotlin.Array<kotlin.Array<out kotlin.Number>> */
public fun </*0*/ T> foo2(/*0*/ m: TMap<T> /* = kotlin.collections.Map<T, out T> */): TMap<T> /* = kotlin.collections.Map<T, out T> */
public fun </*0*/ T> foo2(/*0*/ m: TMap<T> /* = kotlin.collections.Map<T, T> */): TMap<T> /* = kotlin.collections.Map<T, T> */
public typealias Array2D</*0*/ T> = kotlin.Array<kotlin.Array<T>>
public typealias TMap</*0*/ T> = kotlin.collections.Map<T, T>
@@ -18,3 +18,48 @@ typealias Inv3<T> = Inv<out T>
typealias Inv4<<!UNUSED_TYPEALIAS_PARAMETER!>T<!>> = Inv<*>
val inv1: Inv1<Int> = Inv<Int>()
fun inInv_Inv(x: In1<Int>) = x
fun inInv_In(x: In1<in Int>) = x
fun inInv_Out(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>In1<out Int><!>) = x
fun inInv_Star(x: In1<*>) = x
fun inIn_Inv(x: In2<Int>) = x
fun inIn_In(x: In2<in Int>) = x
fun inIn_Out(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION, CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>In2<out Int><!>) = x
fun inIn_Star(x: In2<*>) = x
fun inOut_Inv(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>In3<Int><!>) = x
fun inOut_In(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>In3<in Int><!>) = x
fun inOut_Out(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>In3<out Int><!>) = x
fun inOut_Star(x: In3<*>) = x
fun outInv_Inv(x: Out1<Int>) = x
fun outInv_In(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Out1<in Int><!>) = x
fun outInv_Out(x: Out1<out Int>) = x
fun outInv_Star(x: Out1<*>) = x
fun outIn_Inv(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Out2<Int><!>) = x
fun outIn_In(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Out2<in Int><!>) = x
fun outIn_Out(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Out2<out Int><!>) = x
fun outIn_Star(x: Out2<*>) = x
fun outOut_Inv(x: Out3<Int>) = x
fun outOut_In(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION, CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Out3<in Int><!>) = x
fun outOut_Out(x: Out3<out Int>) = x
fun outOut_Star(x: Out3<*>) = x
fun invInv_Inv(x: Inv1<Int>) = x
fun invInv_In(x: Inv1<in Int>) = x
fun invInv_Out(x: Inv1<out Int>) = x
fun invInv_Star(x: Inv1<*>) = x
fun invIn_Inv(x: Inv2<Int>) = x
fun invIn_In(x: Inv2<in Int>) = x
fun invIn_Out(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Inv2<out Int><!>) = x
fun invIn_Star(x: Inv2<*>) = x
fun invOut_Inv(x: Inv3<Int>) = x
fun invOut_In(x: <!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>Inv3<in Int><!>) = x
fun invOut_Out(x: Inv3<out Int>) = x
fun invOut_Star(x: Inv3<*>) = x
@@ -1,6 +1,42 @@
package
public val inv1: Inv1<kotlin.Int> /* = Inv<kotlin.Int> */
public fun inIn_In(/*0*/ x: In2<in kotlin.Int> /* = In<kotlin.Int> */): In2<in kotlin.Int> /* = In<kotlin.Int> */
public fun inIn_Inv(/*0*/ x: In2<kotlin.Int> /* = In<kotlin.Int> */): In2<kotlin.Int> /* = In<kotlin.Int> */
public fun inIn_Out(/*0*/ x: In2<out kotlin.Int> /* = In<out kotlin.Int> */): In2<out kotlin.Int> /* = In<out kotlin.Int> */
public fun inIn_Star(/*0*/ x: In2<*> /* = In<*> */): In2<*> /* = In<*> */
public fun inInv_In(/*0*/ x: In1<in kotlin.Int> /* = In<kotlin.Int> */): In1<in kotlin.Int> /* = In<kotlin.Int> */
public fun inInv_Inv(/*0*/ x: In1<kotlin.Int> /* = In<kotlin.Int> */): In1<kotlin.Int> /* = In<kotlin.Int> */
public fun inInv_Out(/*0*/ x: In1<out kotlin.Int> /* = In<out kotlin.Int> */): In1<out kotlin.Int> /* = In<out kotlin.Int> */
public fun inInv_Star(/*0*/ x: In1<*> /* = In<*> */): In1<*> /* = In<*> */
public fun inOut_In(/*0*/ x: In3<in kotlin.Int> /* = In<kotlin.Int> */): In3<in kotlin.Int> /* = In<kotlin.Int> */
public fun inOut_Inv(/*0*/ x: In3<kotlin.Int> /* = In<out kotlin.Int> */): In3<kotlin.Int> /* = In<out kotlin.Int> */
public fun inOut_Out(/*0*/ x: In3<out kotlin.Int> /* = In<out kotlin.Int> */): In3<out kotlin.Int> /* = In<out kotlin.Int> */
public fun inOut_Star(/*0*/ x: In3<*> /* = In<*> */): In3<*> /* = In<*> */
public fun invIn_In(/*0*/ x: Inv2<in kotlin.Int> /* = Inv<in kotlin.Int> */): Inv2<in kotlin.Int> /* = Inv<in kotlin.Int> */
public fun invIn_Inv(/*0*/ x: Inv2<kotlin.Int> /* = Inv<in kotlin.Int> */): Inv2<kotlin.Int> /* = Inv<in kotlin.Int> */
public fun invIn_Out(/*0*/ x: Inv2<out kotlin.Int> /* = Inv<out kotlin.Int> */): Inv2<out kotlin.Int> /* = Inv<out kotlin.Int> */
public fun invIn_Star(/*0*/ x: Inv2<*> /* = Inv<*> */): Inv2<*> /* = Inv<*> */
public fun invInv_In(/*0*/ x: Inv1<in kotlin.Int> /* = Inv<in kotlin.Int> */): Inv1<in kotlin.Int> /* = Inv<in kotlin.Int> */
public fun invInv_Inv(/*0*/ x: Inv1<kotlin.Int> /* = Inv<kotlin.Int> */): Inv1<kotlin.Int> /* = Inv<kotlin.Int> */
public fun invInv_Out(/*0*/ x: Inv1<out kotlin.Int> /* = Inv<out kotlin.Int> */): Inv1<out kotlin.Int> /* = Inv<out kotlin.Int> */
public fun invInv_Star(/*0*/ x: Inv1<*> /* = Inv<*> */): Inv1<*> /* = Inv<*> */
public fun invOut_In(/*0*/ x: Inv3<in kotlin.Int> /* = Inv<in kotlin.Int> */): Inv3<in kotlin.Int> /* = Inv<in kotlin.Int> */
public fun invOut_Inv(/*0*/ x: Inv3<kotlin.Int> /* = Inv<out kotlin.Int> */): Inv3<kotlin.Int> /* = Inv<out kotlin.Int> */
public fun invOut_Out(/*0*/ x: Inv3<out kotlin.Int> /* = Inv<out kotlin.Int> */): Inv3<out kotlin.Int> /* = Inv<out kotlin.Int> */
public fun invOut_Star(/*0*/ x: Inv3<*> /* = Inv<*> */): Inv3<*> /* = Inv<*> */
public fun outIn_In(/*0*/ x: Out2<in kotlin.Int> /* = Out<in kotlin.Int> */): Out2<in kotlin.Int> /* = Out<in kotlin.Int> */
public fun outIn_Inv(/*0*/ x: Out2<kotlin.Int> /* = Out<in kotlin.Int> */): Out2<kotlin.Int> /* = Out<in kotlin.Int> */
public fun outIn_Out(/*0*/ x: Out2<out kotlin.Int> /* = Out<kotlin.Int> */): Out2<out kotlin.Int> /* = Out<kotlin.Int> */
public fun outIn_Star(/*0*/ x: Out2<*> /* = Out<*> */): Out2<*> /* = Out<*> */
public fun outInv_In(/*0*/ x: Out1<in kotlin.Int> /* = Out<in kotlin.Int> */): Out1<in kotlin.Int> /* = Out<in kotlin.Int> */
public fun outInv_Inv(/*0*/ x: Out1<kotlin.Int> /* = Out<kotlin.Int> */): Out1<kotlin.Int> /* = Out<kotlin.Int> */
public fun outInv_Out(/*0*/ x: Out1<out kotlin.Int> /* = Out<kotlin.Int> */): Out1<out kotlin.Int> /* = Out<kotlin.Int> */
public fun outInv_Star(/*0*/ x: Out1<*> /* = Out<*> */): Out1<*> /* = Out<*> */
public fun outOut_In(/*0*/ x: Out3<in kotlin.Int> /* = Out<in kotlin.Int> */): Out3<in kotlin.Int> /* = Out<in kotlin.Int> */
public fun outOut_Inv(/*0*/ x: Out3<kotlin.Int> /* = Out<kotlin.Int> */): Out3<kotlin.Int> /* = Out<kotlin.Int> */
public fun outOut_Out(/*0*/ x: Out3<out kotlin.Int> /* = Out<kotlin.Int> */): Out3<out kotlin.Int> /* = Out<kotlin.Int> */
public fun outOut_Star(/*0*/ x: Out3<*> /* = Out<*> */): Out3<*> /* = Out<*> */
public final class In</*0*/ in T> {
public constructor In</*0*/ in T>()