From b24cb2a326b4181b6a5df4145494f9fd06ce4078 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 21 Oct 2015 15:09:05 +0300 Subject: [PATCH] Fixed 'OnlyInputTypes' working with number types --- .../resolve/calls/ArgumentTypeResolver.java | 9 +++--- .../kotlin/resolve/calls/CallCompleter.kt | 2 +- .../resolveWithOnlyInputTypesAnnotation.kt | 3 ++ .../resolve/calls/inference/TypeBoundsImpl.kt | 30 ++++++++++++------- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java index 4f3c2bb1efe..9f4ce5210ae 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -149,7 +149,7 @@ public class ArgumentTypeResolver { private void checkArgumentTypeWithNoCallee(CallResolutionContext context, KtExpression argumentExpression) { expressionTypingServices.getTypeInfo(argumentExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); - updateResultArgumentTypeIfNotDenotable(context, argumentExpression, null); + updateResultArgumentTypeIfNotDenotable(context, argumentExpression); } public static boolean isFunctionLiteralArgument( @@ -349,10 +349,9 @@ public class ArgumentTypeResolver { @Nullable public KotlinType updateResultArgumentTypeIfNotDenotable( @NotNull ResolutionContext context, - @NotNull KtExpression expression, - @Nullable KotlinType argumentType + @NotNull KtExpression expression ) { - KotlinType type = (argumentType != null) ? argumentType : context.trace.getType(expression); + KotlinType type = context.trace.getType(expression); if (type != null && !type.getConstructor().isDenotable()) { if (type.getConstructor() instanceof IntegerValueTypeConstructor) { IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor(); @@ -361,6 +360,6 @@ public class ArgumentTypeResolver { return primitiveType; } } - return type; + return null; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index 2ed8ce01e43..2aacc2ab280 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -251,7 +251,7 @@ public class CallCompleter( // For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.), // so while the expected type is not known, it's IntegerValueType(1), and should be updated when the expected type is known. if (recordedType != null && !recordedType.getConstructor().isDenotable()) { - updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression, updatedType) + updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression) ?: updatedType } updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context.trace) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt index b904554b4f7..65dac90353e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt @@ -11,6 +11,9 @@ class D fun test1(a: A, b: B, c: C) { assertEquals1(a, b) assertEquals1(b, c) + + assertEquals1(3, 3) + assertEquals1(1 or 2, 2 or 1) } @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt index 54462dfa208..6aa9c481b87 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt @@ -51,11 +51,7 @@ public class TypeBoundsImpl( bounds.add(bound) } - private fun filterBounds(bounds: Collection, kind: BoundKind): Set { - return filterBounds(bounds, kind, null) - } - - private fun filterBounds(bounds: Collection, kind: BoundKind, errorValues: MutableCollection?): Set { + private fun filterBounds(bounds: Collection, kind: BoundKind, errorValues: MutableCollection? = null): Set { val result = LinkedHashSet() for (bound in bounds) { if (bound.kind == kind) { @@ -106,7 +102,7 @@ public class TypeBoundsImpl( values.addAll(exactBounds) val (numberLowerBounds, generalLowerBounds) = - filterBounds(bounds, LOWER_BOUND, values).partition { it.getConstructor() is IntegerValueTypeConstructor } + filterBounds(bounds, LOWER_BOUND, values).partition { it.constructor is IntegerValueTypeConstructor } val superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds) if (tryPossibleAnswer(bounds, superTypeOfLowerBounds)) { @@ -146,15 +142,27 @@ public class TypeBoundsImpl( return values } + private fun checkOnlyInputTypes(bounds: Collection, possibleAnswer: KotlinType): Boolean { + if (!typeVariable.hasOnlyInputTypesAnnotation()) return true + + // Only type mentioned in bounds might be the result + val typesInBoundsSet = bounds.filter { it.isProper && it.constrainingType.constructor.isDenotable }.map { it.constrainingType }.toSet() + if (typesInBoundsSet.contains(possibleAnswer)) return true + + // For non-denotable number types only, no valid types are mentioned, so common supertype is valid + val numberLowerBounds = filterBounds(bounds, LOWER_BOUND).filter { it.constructor is IntegerValueTypeConstructor } + val superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds) + if (possibleAnswer == superTypeOfNumberLowerBounds) return true + + return false + } + private fun tryPossibleAnswer(bounds: Collection, possibleAnswer: KotlinType?): Boolean { if (possibleAnswer == null) return false // a captured type might be an answer - if (!possibleAnswer.getConstructor().isDenotable() && !possibleAnswer.isCaptured()) return false + if (!possibleAnswer.constructor.isDenotable && !possibleAnswer.isCaptured()) return false - if (typeVariable.hasOnlyInputTypesAnnotation()) { - val typesInBoundsSet = bounds.filter { it.isProper && it.constrainingType.constructor.isDenotable }.map { it.constrainingType }.toSet() - if (!typesInBoundsSet.contains(possibleAnswer)) return false - } + if (!checkOnlyInputTypes(bounds, possibleAnswer)) return false for (bound in bounds) { when (bound.kind) {