KT-15734
Combine nullability for nested type alias expansion result.
This commit is contained in:
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user