From b1fa740341a50b6687cfd0abd0acc3ae0a59daf6 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 30 Nov 2015 22:09:17 +0300 Subject: [PATCH] Do not report "inconsistent bounds" when there are repeated bounds Also slightly refactor DeclarationsChecker#checkSupertypesForConsistency --- .../kotlin/resolve/DeclarationsChecker.kt | 60 ++++++++++--------- .../tests/generics/TypeParameterBounds.kt | 14 ++--- .../typeParameters/upperBoundCannotBeArray.kt | 4 +- idea/testData/checker/TypeParameterBounds.kt | 4 +- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 82064c2a1b5..2253c7d35a3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -179,35 +179,37 @@ class DeclarationsChecker( } } - private fun checkSupertypesForConsistency( - classifierDescriptor: ClassifierDescriptor, - sourceElement: PsiElement) { - val multimap = SubstitutionUtils.buildDeepSubstitutionMultimap(classifierDescriptor.defaultType) - for ((typeParameterDescriptor, projections) in multimap.asMap().entries) { - if (projections.size > 1) { - // Immediate arguments of supertypes cannot be projected - val conflictingTypes = Sets.newLinkedHashSet() - for (projection in projections) { - conflictingTypes.add(projection.type) - } - removeDuplicateTypes(conflictingTypes) - if (conflictingTypes.size > 1) { - val containingDeclaration = typeParameterDescriptor.containingDeclaration as? ClassDescriptor - ?: throw AssertionError("Not a class descriptor : " + typeParameterDescriptor.containingDeclaration) - if (sourceElement is KtClassOrObject) { - val delegationSpecifierList = sourceElement.getDelegationSpecifierList() ?: continue - trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES.on(delegationSpecifierList, - typeParameterDescriptor, - containingDeclaration, - conflictingTypes)) - } - else if (sourceElement is KtTypeParameter) { - trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(sourceElement, - typeParameterDescriptor, - containingDeclaration, - conflictingTypes)) - } - } + private fun checkSupertypesForConsistency(classifier: ClassifierDescriptor, sourceElement: PsiElement) { + if (classifier is TypeParameterDescriptor) { + val immediateUpperBounds = classifier.upperBounds.map { it.constructor } + if (immediateUpperBounds.size != immediateUpperBounds.toSet().size) { + // If there are duplicate type constructors among the _immediate_ upper bounds, + // then the REPEATED_BOUNDS diagnostic would be already reported for those bounds of this type parameter + return + } + } + + val multiMap = SubstitutionUtils.buildDeepSubstitutionMultimap(classifier.defaultType) + for ((typeParameterDescriptor, projections) in multiMap.asMap()) { + if (projections.size <= 1) continue + + // Immediate arguments of supertypes cannot be projected + val conflictingTypes = projections.map { it.type }.toMutableSet() + removeDuplicateTypes(conflictingTypes) + if (conflictingTypes.size <= 1) continue + + val containingDeclaration = typeParameterDescriptor.containingDeclaration as? ClassDescriptor + ?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration) + if (sourceElement is KtClassOrObject) { + val delegationSpecifierList = sourceElement.getDelegationSpecifierList() ?: continue + trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES.on( + delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes + )) + } + else if (sourceElement is KtTypeParameter) { + trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS.on( + sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes + )) } } } diff --git a/compiler/testData/diagnostics/tests/generics/TypeParameterBounds.kt b/compiler/testData/diagnostics/tests/generics/TypeParameterBounds.kt index 5a657a14d8f..171a98eecde 100644 --- a/compiler/testData/diagnostics/tests/generics/TypeParameterBounds.kt +++ b/compiler/testData/diagnostics/tests/generics/TypeParameterBounds.kt @@ -6,15 +6,15 @@ interface B interface D -interface IncorrectF<T : D> where T : D +interface IncorrectF<T : D> where T : D -interface CorrectF<T> where T : D, T : D +interface CorrectF where T : D, T : D interface G -interface IncorrectH<T : G>> where T : G> +interface IncorrectH<T : G>> where T : G> -interface CorrectH<T> where T : G>, T : G> +interface CorrectH where T : G>, T : G> interface I>> { fun <S : T?> incorrectFoo() where S : G> @@ -22,8 +22,8 @@ interface I>> { fun <S> correctFoo() where S : T?, S : G> } -interface incorrectJ<T: G>> where T : G> +interface incorrectJ<T: G>> where T : G> -interface correctJ<T> where T : G>, T : G> +interface correctJ where T : G>, T : G> -fun <T> bar() where T : D, T : D {} +fun bar() where T : D, T : D {} diff --git a/compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt b/compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt index f7c3b9979ba..a28bf28c13b 100644 --- a/compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt +++ b/compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt @@ -1,6 +1,6 @@ fun <A : Array> f1() {} fun A : Array> f2() {} -fun A> f3() where A : Array, A : Array {} +fun A> f3() where A : Array, A : Array {} fun <T : IntArray> f4() {} @@ -9,7 +9,7 @@ fun <T> f5() where T : Array {} val <T : Array> T.v: String get() = "" class C2A : Array> -interface C3A> where A : Array, A : Array +interface C3A> where A : Array, A : Array fun foo() { class C1<A : Array> { diff --git a/idea/testData/checker/TypeParameterBounds.kt b/idea/testData/checker/TypeParameterBounds.kt index 1509ca4691b..4d962cb6bef 100644 --- a/idea/testData/checker/TypeParameterBounds.kt +++ b/idea/testData/checker/TypeParameterBounds.kt @@ -6,6 +6,6 @@ interface B interface D -interface CorrectF<T> where T : D, T : D +interface CorrectF where T : D, T : D -fun <T> bar() where T : D, T : D {} +fun bar() where T : D, T : D {}