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
) {
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) =
expandRecursively(typeAliasExpansion, annotations, 0, false)
expandRecursively(typeAliasExpansion, annotations,
isNullable = false, recursionDepth = 0, withAbbreviatedType = false)
private fun expandRecursively(
typeAliasExpansion: TypeAliasExpansion,
annotations: Annotations,
isNullable: Boolean,
recursionDepth: Int,
withAbbreviatedType: Boolean
): SimpleType {
@@ -50,34 +53,20 @@ class TypeAliasExpander(
"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)
expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(underlyingProjection, annotations))
expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(annotations, isNullable))
else
expandedTypeWithExtraAnnotations
}
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 TypeAliasExpansion.createAbbreviation(originalProjection: TypeProjection, annotations: Annotations) =
private fun TypeAliasExpansion.createAbbreviation(annotations: Annotations, isNullable: Boolean) =
KotlinTypeFactory.simpleType(
annotations,
descriptor.typeConstructor,
arguments,
originalProjection.type.isMarkedNullable,
isNullable,
MemberScope.Empty
)
@@ -94,6 +83,7 @@ class TypeAliasExpander(
val underlyingType = underlyingProjection.type
val argument = typeAliasExpansion.getReplacement(underlyingType.constructor)
if (argument == null) {
return expandNonArgumentTypeProjection(underlyingProjection, typeAliasExpansion, recursionDepth)
}
@@ -103,8 +93,7 @@ class TypeAliasExpander(
val argumentVariance = argument.projectionKind
val underlyingVariance = underlyingProjection.projectionKind
val argumentType = argument.type.unwrap() as? SimpleType ?:
throw AssertionError("Non-simple type in type alias argument: $argument")
val argumentType = argument.type.unwrap().asSimpleType()
val substitutionVariance =
when {
@@ -129,12 +118,31 @@ class TypeAliasExpander(
}
}
val substitutedType = TypeUtils.makeNullableIfNeeded(argumentType, underlyingType.isMarkedNullable)
.combineAnnotations(underlyingType.annotations)
val substitutedType = argumentType.combineNullabilityAndAnnotations(underlyingType)
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(
originalProjection: TypeProjection,
typeAliasExpansion: TypeAliasExpansion,
@@ -150,10 +158,10 @@ class TypeAliasExpander(
val typeDescriptor = typeConstructor.declarationDescriptor
assert(typeConstructor.parameters.size == type.arguments.size) { "Unexpected malformed type: $type" }
when (typeDescriptor) {
return when (typeDescriptor) {
is TypeParameterDescriptor -> {
return originalProjection
originalProjection
}
is TypeAliasDescriptor -> {
if (typeAliasExpansion.isRecursion(typeDescriptor)) {
@@ -167,12 +175,15 @@ class TypeAliasExpander(
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
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 -> {
val substitutedArguments = type.arguments.mapIndexed { i, originalArgument ->
@@ -187,7 +198,7 @@ class TypeAliasExpander(
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);
}
@TestMetadata("kt15734.kt")
public void testKt15734() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/kt15734.kt");
doTest(fileName);
}
@TestMetadata("localTypeAlias.kt")
public void testLocalTypeAlias() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt");