Report error on repeated upper bounds for type parameters

This commit is contained in:
Alexander Udalov
2015-11-20 23:06:24 +03:00
parent 21e64e02bd
commit 5fbb9bfe3b
16 changed files with 99 additions and 42 deletions
@@ -265,6 +265,7 @@ public interface Errors {
DiagnosticFactory0<KtTypeReference> DYNAMIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> ONLY_ONE_CLASS_BOUND_ALLOWED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> REPEATED_BOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtNamedDeclaration, TypeParameterDescriptor> CONFLICTING_UPPER_BOUNDS =
DiagnosticFactory1.create(ERROR, DECLARATION_NAME);
@@ -395,6 +395,7 @@ public class DefaultErrorMessages {
MAP.put(FINAL_UPPER_BOUND, "''{0}'' is a final type, and thus a value of the type parameter is predetermined", RENDER_TYPE);
MAP.put(UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE, "Extension function type can not be used as an upper bound");
MAP.put(ONLY_ONE_CLASS_BOUND_ALLOWED, "Only one of the upper bounds can be a class");
MAP.put(REPEATED_BOUND, "Type parameter already has this bound");
MAP.put(DYNAMIC_UPPER_BOUND, "Dynamic type can not be used as an upper bound");
MAP.put(USELESS_ELVIS, "Elvis operator (?:) always returns the left operand of non-nullable type {0}", RENDER_TYPE);
MAP.put(USELESS_ELVIS_ON_FUNCTION_LITERAL, "Left operand of elvis operator (?:) is function literal");
@@ -21,6 +21,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import kotlin.CollectionsKt;
import kotlin.Pair;
import kotlin.SetsKt;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
@@ -534,18 +535,25 @@ public class DescriptorResolver {
if (tasks.isEmpty()) return;
Set<Name> classBoundEncountered = new HashSet<Name>();
Set<Pair<Name, TypeConstructor>> allBounds = new HashSet<Pair<Name, TypeConstructor>>();
for (UpperBoundCheckerTask checkerTask : tasks) {
Name typeParameterName = checkerTask.typeParameterName;
KotlinType upperBound = checkerTask.upperBoundType;
KtTypeReference upperBoundElement = checkerTask.upperBound;
if (!upperBound.isError()) {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(upperBound);
if (classDescriptor != null) {
ClassKind kind = classDescriptor.getKind();
if (kind == ClassKind.CLASS || kind == ClassKind.ENUM_CLASS || kind == ClassKind.OBJECT) {
if (!classBoundEncountered.add(typeParameterName)) {
trace.report(ONLY_ONE_CLASS_BOUND_ALLOWED.on(upperBoundElement));
if (!allBounds.add(new Pair<Name, TypeConstructor>(typeParameterName, upperBound.getConstructor()))) {
trace.report(REPEATED_BOUND.on(upperBoundElement));
}
else {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(upperBound);
if (classDescriptor != null) {
ClassKind kind = classDescriptor.getKind();
if (kind == ClassKind.CLASS || kind == ClassKind.ENUM_CLASS || kind == ClassKind.OBJECT) {
if (!classBoundEncountered.add(typeParameterName)) {
trace.report(ONLY_ONE_CLASS_BOUND_ALLOWED.on(upperBoundElement));
}
}
}
}
@@ -6,15 +6,15 @@ interface B
interface D<T>
interface IncorrectF<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T : D<A><!>> where T : D<B>
interface IncorrectF<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T : D<A><!>> where T : <!REPEATED_BOUND!>D<B><!>
interface CorrectF<<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> where T : D<A>, T : D<B>
interface CorrectF<<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> where T : D<A>, T : <!REPEATED_BOUND!>D<B><!>
interface G<T>
interface IncorrectH<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T : G<D<A>><!>> where T : G<D<T>>
interface IncorrectH<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T : G<D<A>><!>> where T : <!REPEATED_BOUND!>G<D<T>><!>
interface CorrectH<<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> where T : G<D<A>>, T : G<D<B>>
interface CorrectH<<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> where T : G<D<A>>, T : <!REPEATED_BOUND!>G<D<B>><!>
interface I<T : G<D<T>>> {
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>S : T?<!>> incorrectFoo() where S : G<D<S>>
@@ -22,8 +22,8 @@ interface I<T : G<D<T>>> {
fun <<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>S<!>> correctFoo() where S : T?, S : G<D<S>>
}
interface incorrectJ<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T: G<D<T>><!>> where T : G<D<T?>>
interface incorrectJ<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS, INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T: G<D<T>><!>> where T : <!REPEATED_BOUND!>G<D<T?>><!>
interface correctJ<<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> where T : G<D<T>>, T : G<D<T?>>
interface correctJ<<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> where T : G<D<T>>, T : <!REPEATED_BOUND!>G<D<T?>><!>
fun <<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> bar() where T : D<A>, T : D<B> {}
fun <<!INCONSISTENT_TYPE_PARAMETER_BOUNDS!>T<!>> bar() where T : D<A>, T : <!REPEATED_BOUND!>D<B><!> {}
@@ -0,0 +1,7 @@
interface I1
class A1<T> where T : I1, T : <!REPEATED_BOUND!>I1<!>
class A2<T> where T : I1, T : <!REPEATED_BOUND!>I1?<!>
class A3<K, V> where K : V, K : <!REPEATED_BOUND!>V<!>
fun <T> f1() where T : I1, T : <!REPEATED_BOUND!>I1<!> {}
@@ -0,0 +1,30 @@
package
public fun </*0*/ T : I1> f1(): kotlin.Unit where T : I1
public final class A1</*0*/ T : I1> where T : I1 {
public constructor A1</*0*/ T : I1>() where T : I1
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 A2</*0*/ T : I1> where T : I1? {
public constructor A2</*0*/ T : I1>() where T : I1?
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 A3</*0*/ K : V, /*1*/ V> where K : V {
public constructor A3</*0*/ K : V, /*1*/ V>() where K : V
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 I1 {
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
}
@@ -1,6 +1,6 @@
fun <<!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<Any><!>> f1() {}
fun <T, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out T><!>> f2() {}
fun <S, T : S, <!INCONSISTENT_TYPE_PARAMETER_BOUNDS, UPPER_BOUND_CANNOT_BE_ARRAY!>A<!>> f3() where A : Array<out S>, A : <!ONLY_ONE_CLASS_BOUND_ALLOWED!>Array<out T><!> {}
fun <S, T : S, <!INCONSISTENT_TYPE_PARAMETER_BOUNDS, UPPER_BOUND_CANNOT_BE_ARRAY!>A<!>> f3() where A : Array<out S>, A : <!REPEATED_BOUND!>Array<out T><!> {}
fun <<!UPPER_BOUND_CANNOT_BE_ARRAY!>T : <!FINAL_UPPER_BOUND!>IntArray<!><!>> f4() {}
@@ -9,7 +9,7 @@ fun <<!UPPER_BOUND_CANNOT_BE_ARRAY!>T<!>> f5() where T : Array<Any> {}
val <<!UPPER_BOUND_CANNOT_BE_ARRAY!>T : Array<Any?><!>> T.v: String get() = ""
class C2<T, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out T><!>>
interface C3<S, T : S, <!INCONSISTENT_TYPE_PARAMETER_BOUNDS, UPPER_BOUND_CANNOT_BE_ARRAY!>A<!>> where A : Array<out S>, A : <!ONLY_ONE_CLASS_BOUND_ALLOWED!>Array<out T><!>
interface C3<S, T : S, <!INCONSISTENT_TYPE_PARAMETER_BOUNDS, UPPER_BOUND_CANNOT_BE_ARRAY!>A<!>> where A : Array<out S>, A : <!REPEATED_BOUND!>Array<out T><!>
fun foo() {
class C1<<!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<Any><!>> {
@@ -17022,6 +17022,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("repeatedBound.kt")
public void testRepeatedBound() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/repeatedBound.kt");
doTest(fileName);
}
@TestMetadata("upperBoundCannotBeArray.kt")
public void testUpperBoundCannotBeArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt");