From fbad16567b9b248dac7edf71b81d8d813a217388 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 7 Jun 2017 17:43:59 +0300 Subject: [PATCH] [NI] Fix number type adjustment for greatest lower bound calculation Compute common supertype (regardless of whether the given set of lower bounds contains number types, intersection types, or whatever). If the result type S is a possibly nullable intersection X1 & ... & Xn, N = {Xi | Xi is a primitive number type}, R = {Xi | Xi is not a primitive number type}, M = default primitive number type for {Nj}, then adjusted type T* = M & R1 & ... Rm with the same nullability as S. NB: IntegerValueType(_) = Int & Byte & Short & Long --- .../components/ResultTypeResolver.kt | 78 ++++++++----------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt index dabe49b4ad8..f8117c72346 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt @@ -16,17 +16,15 @@ package org.jetbrains.kotlin.resolve.calls.inference.components -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator.ResolveDirection -import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.intersectTypes -import java.util.* +import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType class ResultTypeResolver( val typeApproximator: TypeApproximator @@ -83,7 +81,8 @@ class ResultTypeResolver( private fun findSubType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? { val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) } if (lowerConstraints.isNotEmpty()) { - val commonSupertype = NewCommonSuperTypeCalculator.commonSuperType(convertLowerTypesWithKnowledgeOfNumberTypes(lowerConstraints)) + val commonSuperType = NewCommonSuperTypeCalculator.commonSuperType(lowerConstraints.map { it.type }) + val adjustedCommonSuperType = adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType) /** * * fun Array.intersect(other: Iterable) { @@ -102,12 +101,40 @@ class ResultTypeResolver( * */ - return typeApproximator.approximateToSuperType(commonSupertype, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: commonSupertype + return typeApproximator.approximateToSuperType(adjustedCommonSuperType, TypeApproximatorConfiguration.CapturedTypesApproximation) + ?: adjustedCommonSuperType } return null } + private fun adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType: UnwrappedType): UnwrappedType { + val constructor = commonSuperType.constructor + + return when (constructor) { + is IntegerValueTypeConstructor, + is IntersectionTypeConstructor -> { + val newSupertypes = arrayListOf() + val numberSupertypes = arrayListOf() + for (supertype in constructor.supertypes.map { it.unwrap() }) { + if (supertype.isPrimitiveNumberType()) + numberSupertypes.add(supertype) + else + newSupertypes.add(supertype) + } + + TypeUtils.getDefaultPrimitiveNumberType(numberSupertypes)?.let { + newSupertypes.add(it.unwrap()) + } + + intersectTypes(newSupertypes).makeNullableAsSpecified(commonSuperType.isMarkedNullable) + } + + else -> + commonSuperType + } + } + private fun findSuperType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? { val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) } if (upperConstraints.isNotEmpty()) { @@ -138,45 +165,4 @@ class ResultTypeResolver( // may be we should just firstOrNull return notProperEqualsConstraint.singleOrNull()?.type } - - - private fun convertLowerTypesWithKnowledgeOfNumberTypes(lowerConstraints: Collection): List { - if (lowerConstraints.isEmpty()) return emptyList() - - val (numberLowerBounds, generalLowerBounds) = lowerConstraints.map { it.type }.partition { it.isNumberValueType() } - - val numberType = commonSupertypeForNumberTypes(numberLowerBounds) ?: return generalLowerBounds - return generalLowerBounds + numberType - } - - private fun KotlinType.isNumberValueType() = - constructor is IntegerValueTypeConstructor || - (constructor is IntersectionTypeConstructor && constructor.supertypes.all { it.isPrimitiveIntegerType() } ) - - private fun KotlinType.isPrimitiveIntegerType() = - KotlinBuiltIns.isByte(this) || - KotlinBuiltIns.isShort(this) || - KotlinBuiltIns.isInt(this) || - KotlinBuiltIns.isLong(this) - - private fun commonSupertypeForNumberTypes(numberLowerBounds: List): UnwrappedType? { - if (numberLowerBounds.isEmpty()) return null - val intersectionOfSupertypes = getIntersectionOfSupertypes(numberLowerBounds) - return TypeUtils.getDefaultPrimitiveNumberType(intersectionOfSupertypes)?.unwrap() ?: - NewCommonSuperTypeCalculator.commonSuperType(numberLowerBounds) - } - - private fun getIntersectionOfSupertypes(types: Collection): Set { - val upperBounds = HashSet() - for (type in types) { - val supertypes = type.constructor.supertypes.map { it.unwrap() } - if (upperBounds.isEmpty()) { - upperBounds.addAll(supertypes) - } - else { - upperBounds.retainAll(supertypes) - } - } - return upperBounds - } } \ No newline at end of file