From a6ec5cecc073205eb6e2a31433f48aca76354b7c Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 16 Oct 2015 15:49:46 +0300 Subject: [PATCH] Added 'OnlyInputTypes' annotation --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 2 ++ .../calls/tasks/AbstractTracingStrategy.java | 4 +++ .../resolveWithOnlyInputTypesAnnotation.kt | 14 ++++++++ .../resolveWithOnlyInputTypesAnnotation.txt | 32 +++++++++++++++++++ ...JetDiagnosticsTestWithStdLibGenerated.java | 6 ++++ .../kotlin/resolve/annotationsForResolve.kt | 9 ++++-- .../calls/inference/ConstraintSystemImpl.kt | 5 +++ .../calls/inference/ConstraintSystemStatus.kt | 2 ++ .../resolve/calls/inference/TypeBoundsImpl.kt | 13 ++++++-- .../stdlib/src/kotlin/internal/Annotations.kt | 9 +++++- 11 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 948cf1e7852..23239895548 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -493,6 +493,7 @@ public interface Errors { DiagnosticFactory1 TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 TYPE_INFERENCE_INCORPORATION_ERROR = DiagnosticFactory0.create(ERROR); + DiagnosticFactory1 TYPE_INFERENCE_ONLY_INPUT_TYPES = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 3c4e8f3606d..d362dc046f3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -610,6 +610,8 @@ public class DefaultErrorMessages { MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER); MAP.put(TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR, "Type inference failed: {0}", TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER); MAP.put(TYPE_INFERENCE_INCORPORATION_ERROR, "Type inference failed. Please try to specify type arguments explicitly."); + MAP.put(TYPE_INFERENCE_ONLY_INPUT_TYPES, "Type inference failed. The value of the type parameter {0} should be mentioned in input types " + + "(argument types, receiver type or expected type). Try to specify it explicitly.", NAME); MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER); MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, "Type inference failed. Expected type mismatch: found: {1} required: {0}", RENDER_TYPE, RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java index ff6d1271b22..422be54a1ef 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java @@ -242,6 +242,10 @@ public abstract class AbstractTracingStrategy implements TracingStrategy { else if (status.hasTypeInferenceIncorporationError()) { trace.report(TYPE_INFERENCE_INCORPORATION_ERROR.on(reference)); } + else if (status.hasTypeParameterWithUnsatisfiedOnlyInputTypesError()) { + //todo + trace.report(TYPE_INFERENCE_ONLY_INPUT_TYPES.on(reference, data.descriptor.getTypeParameters().get(0))); + } else { assert status.hasUnknownParameters(); trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data)); diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt new file mode 100644 index 00000000000..e892898c94a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt @@ -0,0 +1,14 @@ +//!DIAGNOSTICS: -UNUSED_PARAMETER + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +fun <@kotlin.internal.OnlyInputTypes T> assertEquals1(t1: T, t2: T) {} + +open class A +class B: A() +class C: A() +class D + +fun test1(a: A, b: B, c: C) { + assertEquals1(a, b) + assertEquals1(b, c) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.txt b/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.txt new file mode 100644 index 00000000000..ab366501ef7 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.txt @@ -0,0 +1,32 @@ +package + +@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun assertEquals1(/*0*/ t1: T, /*1*/ t2: T): kotlin.Unit +public fun test1(/*0*/ a: A, /*1*/ b: B, /*2*/ c: C): kotlin.Unit + +public open class A { + public constructor A() + 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 final class B : A { + public constructor B() + 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 final class C : A { + public constructor C() + 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 final class D { + public constructor D() + 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java index 8af739ff515..4b9103dc51d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -707,6 +707,12 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAnnotation.kt"); doTest(fileName); } + + @TestMetadata("resolveWithOnlyInputTypesAnnotation.kt") + public void testResolveWithOnlyInputTypesAnnotation() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/resolveWithOnlyInputTypesAnnotation.kt"); + doTest(fileName); + } } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt index 76320be1df7..61e4dafccd5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt @@ -16,13 +16,18 @@ package org.jetbrains.kotlin.resolve.descriptorUtil +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.name.FqName private val NO_INFER_ANNOTATION_FQ_NAME = FqName("kotlin.internal.NoInfer") -public fun Annotated.hasNoInferAnnotation(): Boolean = annotations.findAnnotation(NO_INFER_ANNOTATION_FQ_NAME) != null +public fun Annotated.hasNoInferAnnotation(): Boolean = annotations.hasAnnotation(NO_INFER_ANNOTATION_FQ_NAME) private val EXACT_ANNOTATION_FQ_NAME = FqName("kotlin.internal.Exact") -public fun Annotated.hasExactAnnotation(): Boolean = annotations.findAnnotation(EXACT_ANNOTATION_FQ_NAME) != null \ No newline at end of file +public fun Annotated.hasExactAnnotation(): Boolean = annotations.hasAnnotation(EXACT_ANNOTATION_FQ_NAME) + +private val ONLY_INPUT_TYPES_FQ_NAME = FqName("kotlin.internal.OnlyInputTypes") + +public fun TypeParameterDescriptor.hasOnlyInputTypesAnnotation(): Boolean = annotations.hasAnnotation(ONLY_INPUT_TYPES_FQ_NAME) \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 18edd9490f8..21061d4bc89 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.Constrain import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.derivedFrom import org.jetbrains.kotlin.resolve.descriptorUtil.hasNoInferAnnotation import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation +import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE @@ -82,6 +83,7 @@ public class ConstraintSystemImpl : ConstraintSystem { override fun hasContradiction() = hasParameterConstraintError() || hasConflictingConstraints() || hasCannotCaptureTypesError() || hasTypeInferenceIncorporationError() + || hasTypeParameterWithUnsatisfiedOnlyInputTypesError() override fun hasViolatedUpperBound() = !isSuccessful() && filterConstraintsOut(TYPE_BOUND_POSITION).getStatus().isSuccessful() @@ -102,6 +104,9 @@ public class ConstraintSystemImpl : ConstraintSystem { override fun hasCannotCaptureTypesError() = errors.any { it is CannotCapture } override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints() + + override fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError() = + localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null } } private fun getParameterToInferredValueMap( diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemStatus.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemStatus.kt index 1e52f56963c..23066051148 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemStatus.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemStatus.kt @@ -89,4 +89,6 @@ public interface ConstraintSystemStatus { * Returns true if there's an error in constraint system incorporation. */ public fun hasTypeInferenceIncorporationError(): Boolean + + public fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError(): Boolean } 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 2f5f99f0db0..dcf8f716105 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 @@ -24,12 +24,11 @@ import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_B import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_BOUND import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.ArrayList -import java.util.LinkedHashSet +import java.util.* public class TypeBoundsImpl( override val typeVariable: TypeParameterDescriptor, @@ -37,6 +36,10 @@ public class TypeBoundsImpl( ) : TypeBounds { override val bounds = ArrayList() + private val typesInBoundsSet: Set by lazy { + bounds.filter { it.isProper }.map { it.constrainingType }.toSet() + } + private var resultValues: Collection? = null var isFixed: Boolean = false @@ -144,6 +147,8 @@ public class TypeBoundsImpl( values.addAll(filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND)) + if (values.size == 1 && typeVariable.hasOnlyInputTypesAnnotation() && !tryPossibleAnswer(bounds, values.first())) return listOf() + return values } @@ -152,6 +157,8 @@ public class TypeBoundsImpl( // a captured type might be an answer if (!possibleAnswer.getConstructor().isDenotable() && !possibleAnswer.isCaptured()) return false + if (typeVariable.hasOnlyInputTypesAnnotation() && !typesInBoundsSet.contains(possibleAnswer)) return false + for (bound in bounds) { when (bound.kind) { LOWER_BOUND -> if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.constrainingType, possibleAnswer)) { diff --git a/libraries/stdlib/src/kotlin/internal/Annotations.kt b/libraries/stdlib/src/kotlin/internal/Annotations.kt index 5b2aed72b40..5df144a9d53 100644 --- a/libraries/stdlib/src/kotlin/internal/Annotations.kt +++ b/libraries/stdlib/src/kotlin/internal/Annotations.kt @@ -28,4 +28,11 @@ internal annotation class NoInfer */ @Target(AnnotationTarget.TYPE) @Retention(AnnotationRetention.SOURCE) -internal annotation class Exact \ No newline at end of file +internal annotation class Exact + +/** + * The value of this type parameter should be mentioned in input types (argument types, receiver type or expected type). + */ +@Target(AnnotationTarget.TYPE_PARAMETER) +@Retention(AnnotationRetention.SOURCE) +internal annotation class OnlyInputTypes \ No newline at end of file