[NI] Run checks for captured types only once in NewTypeSubstitutor

Sometimes we can get Enum<Captured(*)> type here, so, supertype for
Captured(*) is Enum<Capture(*)> and we go into SO.
This commit is contained in:
Stanislav Erokhin
2017-06-09 15:19:50 +03:00
committed by Mikhail Zarechenskiy
parent d58c6e245f
commit 91241a34d1
@@ -30,15 +30,17 @@ interface NewTypeSubstitutor {
fun safeSubstitute(type: UnwrappedType): UnwrappedType = substitute(type) ?: type fun safeSubstitute(type: UnwrappedType): UnwrappedType = substitute(type) ?: type
// null means that this type isn't changed // null means that this type isn't changed
fun substitute(type: UnwrappedType): UnwrappedType? = fun substitute(type: UnwrappedType): UnwrappedType? = substitute(type, runCapturedChecks = true)
private fun substitute(type: UnwrappedType, runCapturedChecks: Boolean): UnwrappedType? =
when (type) { when (type) {
is SimpleType -> substitute(type) is SimpleType -> substitute(type, runCapturedChecks)
is FlexibleType -> if (type is DynamicType || type is RawType) { is FlexibleType -> if (type is DynamicType || type is RawType) {
null null
} }
else { else {
val lowerBound = substitute(type.lowerBound) val lowerBound = substitute(type.lowerBound, runCapturedChecks)
val upperBound = substitute(type.upperBound) val upperBound = substitute(type.upperBound, runCapturedChecks)
if (lowerBound == null && upperBound == null) { if (lowerBound == null && upperBound == null) {
null null
} }
@@ -49,27 +51,29 @@ interface NewTypeSubstitutor {
} }
} }
fun substitute(type: SimpleType): UnwrappedType? { private fun substitute(type: SimpleType, runCapturedChecks: Boolean): UnwrappedType? {
if (type.isError) return null if (type.isError) return null
if (type.arguments.isNotEmpty()) { if (type.arguments.isNotEmpty()) {
return substituteParametrizedType(type) return substituteParametrizedType(type, runCapturedChecks)
} }
val typeConstructor = type.constructor val typeConstructor = type.constructor
if (typeConstructor is NewCapturedTypeConstructor) { if (typeConstructor is NewCapturedTypeConstructor) {
if (!runCapturedChecks) return null
assert(type is NewCapturedType) { // KT-16147 assert(type is NewCapturedType) { // KT-16147
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " + "Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
"and class: ${type::class.java.canonicalName}. type.toString() = $type" "and class: ${type::class.java.canonicalName}. type.toString() = $type"
} }
val lower = (type as NewCapturedType).lowerType?.let { substitute(it) } val lower = (type as NewCapturedType).lowerType?.let { substitute(it, runCapturedChecks = false) }
if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " + if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " +
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," + "because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
"original lower type: '${type.lowerType}") "original lower type: '${type.lowerType}")
type.constructor.supertypes.forEach { supertype -> type.constructor.supertypes.forEach { supertype ->
substitute(supertype)?.let { substitute(supertype, runCapturedChecks = false)?.let {
throw IllegalStateException("Illegal type substitutor: $this, " + throw IllegalStateException("Illegal type substitutor: $this, " +
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," + "because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
"original supertype: '$supertype'") "original supertype: '$supertype'")
@@ -82,7 +86,7 @@ interface NewTypeSubstitutor {
if (typeConstructor is IntersectionTypeConstructor) { if (typeConstructor is IntersectionTypeConstructor) {
var thereIsChanges = false var thereIsChanges = false
val newTypes = typeConstructor.supertypes.map { val newTypes = typeConstructor.supertypes.map {
substitute(it.unwrap())?.apply { thereIsChanges = true } ?: it.unwrap() substitute(it.unwrap(), runCapturedChecks)?.apply { thereIsChanges = true } ?: it.unwrap()
} }
if (!thereIsChanges) return null if (!thereIsChanges) return null
return intersectTypes(newTypes).let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it } return intersectTypes(newTypes).let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
@@ -94,7 +98,7 @@ interface NewTypeSubstitutor {
return if (type.isMarkedNullable) replacement.makeNullableAsSpecified(true) else replacement return if (type.isMarkedNullable) replacement.makeNullableAsSpecified(true) else replacement
} }
private fun substituteParametrizedType(type: SimpleType): UnwrappedType? { private fun substituteParametrizedType(type: SimpleType, runCapturedChecks: Boolean): UnwrappedType? {
val parameters = type.constructor.parameters val parameters = type.constructor.parameters
val arguments = type.arguments val arguments = type.arguments
if (parameters.size != arguments.size) { if (parameters.size != arguments.size) {
@@ -107,7 +111,7 @@ interface NewTypeSubstitutor {
val argument = arguments[index] val argument = arguments[index]
if (argument.isStarProjection) continue if (argument.isStarProjection) continue
val substitutedArgumentType = substitute(argument.type.unwrap()) ?: continue val substitutedArgumentType = substitute(argument.type.unwrap(), runCapturedChecks) ?: continue
newArguments[index] = TypeProjectionImpl(argument.projectionKind, substitutedArgumentType) newArguments[index] = TypeProjectionImpl(argument.projectionKind, substitutedArgumentType)
} }