Combine nullability for nested type alias expansion result.
This commit is contained in:
Dmitry Petrov
2017-01-16 13:29:37 +03:00
parent 954204da82
commit cd33a40612
4 changed files with 86 additions and 31 deletions
@@ -29,14 +29,17 @@ class TypeAliasExpander(
private val reportStrategy: TypeAliasExpansionReportStrategy private val reportStrategy: TypeAliasExpansionReportStrategy
) { ) {
fun expand(typeAliasExpansion: TypeAliasExpansion, annotations: Annotations) = fun expand(typeAliasExpansion: TypeAliasExpansion, annotations: Annotations) =
expandRecursively(typeAliasExpansion, annotations, 0, true) expandRecursively(typeAliasExpansion, annotations,
isNullable = false, recursionDepth = 0, withAbbreviatedType = true)
fun expandWithoutAbbreviation(typeAliasExpansion: TypeAliasExpansion, annotations: Annotations) = fun expandWithoutAbbreviation(typeAliasExpansion: TypeAliasExpansion, annotations: Annotations) =
expandRecursively(typeAliasExpansion, annotations, 0, false) expandRecursively(typeAliasExpansion, annotations,
isNullable = false, recursionDepth = 0, withAbbreviatedType = false)
private fun expandRecursively( private fun expandRecursively(
typeAliasExpansion: TypeAliasExpansion, typeAliasExpansion: TypeAliasExpansion,
annotations: Annotations, annotations: Annotations,
isNullable: Boolean,
recursionDepth: Int, recursionDepth: Int,
withAbbreviatedType: Boolean withAbbreviatedType: Boolean
): SimpleType { ): SimpleType {
@@ -50,34 +53,20 @@ class TypeAliasExpander(
"Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant" "Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant"
} }
val expandedTypeWithExtraAnnotations = expandedType.combineAnnotations(annotations) val expandedTypeWithExtraAnnotations = expandedType.combineAnnotations(annotations).let { TypeUtils.makeNullableIfNeeded(it, isNullable) }
return if (withAbbreviatedType) return if (withAbbreviatedType)
expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(underlyingProjection, annotations)) expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(annotations, isNullable))
else else
expandedTypeWithExtraAnnotations expandedTypeWithExtraAnnotations
} }
private fun SimpleType.combineAnnotations(annotations: Annotations): SimpleType { private fun TypeAliasExpansion.createAbbreviation(annotations: Annotations, isNullable: Boolean) =
if (isError) return this
val existingAnnotationTypes = this.annotations.getAllAnnotations().mapTo(hashSetOf<KotlinType>()) { it.annotation.type }
for (annotation in annotations) {
if (annotation.type in existingAnnotationTypes) {
reportStrategy.repeatedAnnotation(annotation)
}
}
return replace(newAnnotations = CompositeAnnotations(listOf(annotations, this.annotations)))
}
private fun TypeAliasExpansion.createAbbreviation(originalProjection: TypeProjection, annotations: Annotations) =
KotlinTypeFactory.simpleType( KotlinTypeFactory.simpleType(
annotations, annotations,
descriptor.typeConstructor, descriptor.typeConstructor,
arguments, arguments,
originalProjection.type.isMarkedNullable, isNullable,
MemberScope.Empty MemberScope.Empty
) )
@@ -94,6 +83,7 @@ class TypeAliasExpander(
val underlyingType = underlyingProjection.type val underlyingType = underlyingProjection.type
val argument = typeAliasExpansion.getReplacement(underlyingType.constructor) val argument = typeAliasExpansion.getReplacement(underlyingType.constructor)
if (argument == null) { if (argument == null) {
return expandNonArgumentTypeProjection(underlyingProjection, typeAliasExpansion, recursionDepth) return expandNonArgumentTypeProjection(underlyingProjection, typeAliasExpansion, recursionDepth)
} }
@@ -103,8 +93,7 @@ class TypeAliasExpander(
val argumentVariance = argument.projectionKind val argumentVariance = argument.projectionKind
val underlyingVariance = underlyingProjection.projectionKind val underlyingVariance = underlyingProjection.projectionKind
val argumentType = argument.type.unwrap() as? SimpleType ?: val argumentType = argument.type.unwrap().asSimpleType()
throw AssertionError("Non-simple type in type alias argument: $argument")
val substitutionVariance = val substitutionVariance =
when { when {
@@ -129,12 +118,31 @@ class TypeAliasExpander(
} }
} }
val substitutedType = TypeUtils.makeNullableIfNeeded(argumentType, underlyingType.isMarkedNullable) val substitutedType = argumentType.combineNullabilityAndAnnotations(underlyingType)
.combineAnnotations(underlyingType.annotations)
return TypeProjectionImpl(resultingVariance, substitutedType) return TypeProjectionImpl(resultingVariance, substitutedType)
} }
private fun SimpleType.combineAnnotations(annotations: Annotations): SimpleType {
if (isError) return this
val existingAnnotationTypes = this.annotations.getAllAnnotations().mapTo(hashSetOf<KotlinType>()) { it.annotation.type }
for (annotation in annotations) {
if (annotation.type in existingAnnotationTypes) {
reportStrategy.repeatedAnnotation(annotation)
}
}
return replace(newAnnotations = CompositeAnnotations(listOf(annotations, this.annotations)))
}
private fun SimpleType.combineNullability(fromType: KotlinType) =
TypeUtils.makeNullableIfNeeded(this, fromType.isMarkedNullable)
private fun SimpleType.combineNullabilityAndAnnotations(fromType: KotlinType) =
combineNullability(fromType).combineAnnotations(fromType.annotations)
private fun expandNonArgumentTypeProjection( private fun expandNonArgumentTypeProjection(
originalProjection: TypeProjection, originalProjection: TypeProjection,
typeAliasExpansion: TypeAliasExpansion, typeAliasExpansion: TypeAliasExpansion,
@@ -150,10 +158,10 @@ class TypeAliasExpander(
val typeDescriptor = typeConstructor.declarationDescriptor val typeDescriptor = typeConstructor.declarationDescriptor
assert(typeConstructor.parameters.size == type.arguments.size) { "Unexpected malformed type: $type" } assert(typeConstructor.parameters.size == type.arguments.size) { "Unexpected malformed type: $type" }
when (typeDescriptor) { return when (typeDescriptor) {
is TypeParameterDescriptor -> { is TypeParameterDescriptor -> {
return originalProjection originalProjection
} }
is TypeAliasDescriptor -> { is TypeAliasDescriptor -> {
if (typeAliasExpansion.isRecursion(typeDescriptor)) { if (typeAliasExpansion.isRecursion(typeDescriptor)) {
@@ -167,12 +175,15 @@ class TypeAliasExpander(
val nestedExpansion = TypeAliasExpansion.create(typeAliasExpansion, typeDescriptor, expandedArguments) val nestedExpansion = TypeAliasExpansion.create(typeAliasExpansion, typeDescriptor, expandedArguments)
val expandedType = expandRecursively(nestedExpansion, type.annotations, recursionDepth + 1, false) val nestedExpandedType = expandRecursively(nestedExpansion, type.annotations,
isNullable = type.isMarkedNullable,
recursionDepth = recursionDepth + 1,
withAbbreviatedType = false)
// 'dynamic' type can't be abbreviated - will be reported separately // 'dynamic' type can't be abbreviated - will be reported separately
val typeWithAbbreviation = if (expandedType.isDynamic()) expandedType else expandedType.withAbbreviation(type) val typeWithAbbreviation = if (nestedExpandedType.isDynamic()) nestedExpandedType else nestedExpandedType.withAbbreviation(type)
return TypeProjectionImpl(originalProjection.projectionKind, typeWithAbbreviation) TypeProjectionImpl(originalProjection.projectionKind, typeWithAbbreviation)
} }
else -> { else -> {
val substitutedArguments = type.arguments.mapIndexed { i, originalArgument -> val substitutedArguments = type.arguments.mapIndexed { i, originalArgument ->
@@ -187,7 +198,7 @@ class TypeAliasExpander(
checkTypeArgumentsSubstitution(type, substitutedType) checkTypeArgumentsSubstitution(type, substitutedType)
return TypeProjectionImpl(originalProjection.projectionKind, substitutedType) TypeProjectionImpl(originalProjection.projectionKind, substitutedType)
} }
} }
} }
@@ -0,0 +1,19 @@
@Target(AnnotationTarget.TYPE)
annotation class Ann
typealias TString = String
typealias TNString = TString?
typealias TNAString = @Ann TString?
val test1: TNString = TODO()
val test2: TNAString = TODO()
val test3: List<TNString> = TODO()
val test4: List<TNAString> = TODO()
val test5: List<TNString<!REDUNDANT_NULLABLE!>?<!>> = TODO()
val test6: () -> List<TNString> = TODO()
fun test(x: TNString) {
x<!UNSAFE_CALL!>.<!>hashCode()
}
@@ -0,0 +1,19 @@
package
public val test1: TNString /* = kotlin.String? */
public val test2: TNAString /* = @Ann kotlin.String? */
public val test3: kotlin.collections.List<TNString /* = kotlin.String? */>
public val test4: kotlin.collections.List<TNAString /* = @Ann kotlin.String? */>
public val test5: kotlin.collections.List<TNString? /* = kotlin.String? */>
public val test6: () -> kotlin.collections.List<TNString /* = kotlin.String? */>
public fun test(/*0*/ x: TNString /* = kotlin.String? */): kotlin.Unit
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class Ann : kotlin.Annotation {
public constructor Ann()
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 TNAString = @Ann TString?
public typealias TNString = TString?
public typealias TString = kotlin.String
@@ -22081,6 +22081,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt15734.kt")
public void testKt15734() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/kt15734.kt");
doTest(fileName);
}
@TestMetadata("localTypeAlias.kt") @TestMetadata("localTypeAlias.kt")
public void testLocalTypeAlias() throws Exception { public void testLocalTypeAlias() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt");