From f688b1b786b7bc64480c9d6a1e23bbe0308079c1 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Fri, 22 Jan 2016 15:34:41 +0300 Subject: [PATCH] Relax rules for type parameters in property receivers --- .../kotlin/resolve/DeclarationsChecker.kt | 29 ++++++++++++------- .../typeParameters/propertyTypeParameters.kt | 13 ++++++++- .../typeParameters/propertyTypeParameters.txt | 9 ++++++ .../propertyTypeParametersWithUpperBounds.kt | 28 ++++++++++++++++++ .../propertyTypeParametersWithUpperBounds.txt | 17 +++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++ 6 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.kt create mode 100644 compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 277d1a9b7c3..1b006c8c4eb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -450,9 +450,26 @@ class DeclarationsChecker( } private fun checkPropertyTypeParametersAreUsedInReceiverType(descriptor: PropertyDescriptor) { - for (typeParameter in descriptor.typeParameters) { - if (isTypeParameterUsedInReceiverType(typeParameter, descriptor)) continue + val allTypeParameters = descriptor.typeParameters.toSet() + val allAccessibleTypeParameters = HashSet() + fun addAccessibleTypeParametersFromType(type: KotlinType?) { + TypeUtils.contains(type) { + val declarationDescriptor = it.constructor.declarationDescriptor + if (declarationDescriptor is TypeParameterDescriptor && declarationDescriptor in allTypeParameters) { + if (allAccessibleTypeParameters.add(declarationDescriptor)) { + declarationDescriptor.upperBounds.forEach { + addAccessibleTypeParametersFromType(it) + } + } + } + false + } + } + addAccessibleTypeParametersFromType(descriptor.extensionReceiverParameter?.type) + + val typeParametersInaccessibleFromReceiver = allTypeParameters - allAccessibleTypeParameters + for (typeParameter in typeParametersInaccessibleFromReceiver) { val typeParameterPsi = DescriptorToSourceUtils.getSourceFromDescriptor(typeParameter) if (typeParameterPsi is KtTypeParameter) { trace.report(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER.on(typeParameterPsi)) @@ -838,14 +855,6 @@ class DeclarationsChecker( return !modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD) } - private fun isTypeParameterUsedInReceiverType( - parameter: TypeParameterDescriptor, - descriptor: PropertyDescriptor): Boolean { - val receiverParameter = descriptor.extensionReceiverParameter ?: return false - - return TypeUtils.contains(receiverParameter.type) { parameter == it.constructor.declarationDescriptor } - } - private fun hasDefaultConstructor(classDescriptor: ClassDescriptor) = classDescriptor.constructors.any { it.valueParameters.isEmpty() } diff --git a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt index d1c7069ca1c..e407ece6ca0 100644 --- a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt +++ b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt @@ -30,4 +30,15 @@ class C { val E.c: Int get() = 3 val <E> Map.d: Int get() = 3 val Map.e: Int get() = 3 -} \ No newline at end of file +} + +val > T.z1: Int + get() = 4 + +interface D> + +val > X.z2: Int + get() = 4 + +val <Y> D<*>.z3: Int + get() = 4 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt index db253fc2e6b..a9054cded07 100644 --- a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt +++ b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt @@ -10,6 +10,9 @@ public val kotlin.collections.List kotlin.collections.List>>.g: kotlin.Int public val kotlin.collections.List>>.h: kotlin.Int public val kotlin.collections.List>>.i: kotlin.Int +public val > T.z1: kotlin.Int +public val > X.z2: kotlin.Int +public val D<*>.z3: kotlin.Int public final class C { public constructor C() @@ -23,6 +26,12 @@ public final class C { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public interface 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 +} + public interface G { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.kt b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.kt new file mode 100644 index 00000000000..b7a28d8748e --- /dev/null +++ b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.kt @@ -0,0 +1,28 @@ + +val <T : K, K> K.a: Int get() = 4 + +val <T, K> K.b: Int where T : K + get() = 4 + +val <T, K> K.c: Int where T : List + get() = 4 + +val K.d: Int where K : T + get() = 4 + +val K.e: Int where K : List + get() = 4 + +interface G +val <T> G.x1: Int where T : G + get() = 4 + + +val <X, Y, Z> Z.x2: Int where X : Y, Z : Y + get() = 4 + +val , Z: List>> Z.x3: Int + get() = 5 + +val >, Z> Map>.x4: Int + get() = 5 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.txt b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.txt new file mode 100644 index 00000000000..6a0d200c5c7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.txt @@ -0,0 +1,17 @@ +package + +public val K.a: kotlin.Int +public val K.b: kotlin.Int +public val , /*1*/ K> K.c: kotlin.Int +public val K.d: kotlin.Int +public val > K.e: kotlin.Int +public val G.x1: kotlin.Int +public val Z.x2: kotlin.Int +public val , /*2*/ Z : kotlin.collections.List>> Z.x3: kotlin.Int +public val >, /*2*/ Z> kotlin.collections.Map>.x4: kotlin.Int + +public interface G { + 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/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 3ba65347baa..f78f2f39726 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18153,6 +18153,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("propertyTypeParametersWithUpperBounds.kt") + public void testPropertyTypeParametersWithUpperBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/propertyTypeParametersWithUpperBounds.kt"); + doTest(fileName); + } + @TestMetadata("repeatedBound.kt") public void testRepeatedBound() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/repeatedBound.kt");