Recursive type alias expansion:

when resolving abbreviated type, do not check bounds
if the resulting type contains type aliases.
This commit is contained in:
Dmitry Petrov
2016-06-10 10:40:35 +03:00
parent 688c742802
commit 40dd36bcf6
6 changed files with 29 additions and 4 deletions
@@ -191,7 +191,7 @@ class DeclarationsChecker(
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
// TODO more precise diagnostics
if (!argument.dependsOnTypeAliasParameters() && !bound.dependsOnTypeAliasParameters()) {
if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) {
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
}
}
@@ -163,7 +163,7 @@ class TypeAliasExpander(
val typeSubstitutor = TypeSubstitutor.create(substitutedType)
substitutedType.arguments.forEachIndexed { i, substitutedArgument ->
if (!substitutedArgument.type.dependsOnTypeAliasParameters()) {
if (!substitutedArgument.type.containsTypeAliasParameters()) {
val unsubstitutedArgument = unsubstitutedType.arguments[i]
val typeParameter = unsubstitutedType.constructor.parameters[i]
DescriptorResolver.checkBoundsInTypeAlias(reportStrategy, unsubstitutedArgument.type, substitutedArgument.type, typeParameter, typeSubstitutor)
@@ -57,11 +57,16 @@ class TypeAliasExpansion private constructor(
}
}
fun KotlinType.dependsOnTypeAliasParameters(): Boolean =
fun KotlinType.containsTypeAliasParameters(): Boolean =
TypeUtils.contains(this) {
it.constructor.declarationDescriptor?.isTypeAliasParameter() ?: false
}
fun KotlinType.containsTypeAliases(): Boolean =
TypeUtils.contains(this) {
it.constructor.declarationDescriptor is TypeAliasDescriptor
}
fun ClassifierDescriptor.isTypeAliasParameter(): Boolean =
this is TypeParameterDescriptor && containingDeclaration is TypeAliasDescriptor
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.*
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing
class TypeResolver(
@@ -402,7 +403,7 @@ class TypeResolver(
// This is not intended to be used in normal users' environments, only for tests and debugger etc
typeTransformerForTests.transformType(resultingType)?.let { return type(it) }
if (c.checkBounds && !resultingType.dependsOnTypeAliasParameters()) {
if (shouldCheckBounds(c, resultingType)) {
val substitutor = TypeSubstitutor.create(resultingType)
for (i in parameters.indices) {
val parameter = parameters[i]
@@ -423,6 +424,14 @@ class TypeResolver(
return type(resultingType)
}
private fun shouldCheckBounds(c: TypeResolutionContext, inType: KotlinType): Boolean {
if (!c.checkBounds) return false
if (inType.containsTypeAliasParameters()) return false
if (c.abbreviated && inType.containsTypeAliases()) return false
return true
}
private fun resolveTypeForTypeAlias(
c: TypeResolutionContext,
annotations: Annotations,
@@ -1,4 +1,11 @@
typealias R = <!RECURSIVE_TYPEALIAS_EXPANSION!>R<!>
typealias L = <!RECURSIVE_TYPEALIAS_EXPANSION!>List<L><!>
typealias A = <!RECURSIVE_TYPEALIAS_EXPANSION!>B<!>
typealias B = <!RECURSIVE_TYPEALIAS_EXPANSION!>A<!>
typealias F1 = <!RECURSIVE_TYPEALIAS_EXPANSION!>(Int) -> F2<!>
typealias F2 = <!RECURSIVE_TYPEALIAS_EXPANSION!>(F1) -> Int<!>
val x: <!RECURSIVE_TYPEALIAS_EXPANSION!>A<!> = TODO()
@@ -2,4 +2,8 @@ package
public typealias A = B
public typealias B = A
public typealias F1 = (kotlin.Int) -> F2
public typealias F2 = (F1) -> kotlin.Int
public typealias L = kotlin.collections.List<L>
public typealias R = R
public val x: [ERROR : Recursive type alias: A]