disallow putting type parameter constraints both in type parameter list and in 'where' clause

This commit is contained in:
Dmitry Jemerov
2015-10-06 18:29:00 +02:00
parent 51225d3556
commit 4c4030dfc1
11 changed files with 78 additions and 13 deletions
@@ -268,6 +268,8 @@ public interface Errors {
DiagnosticFactory0<PsiElement> CYCLIC_GENERIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetTypeParameter> MISPLACED_TYPE_PARAMETER_CONSTRAITS = DiagnosticFactory0.create(WARNING);
// Members
DiagnosticFactory2<JetDeclaration, CallableMemberDescriptor, String> CONFLICTING_OVERLOADS =
@@ -496,6 +496,8 @@ public class DefaultErrorMessages {
MAP.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Placing function type parameters after the function name is deprecated");
MAP.put(MISPLACED_TYPE_PARAMETER_CONSTRAITS, "If a type parameter has multiple constraints, they all need to be placed in the 'where' clause");
MAP.put(TYPE_VARIANCE_CONFLICT, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in type {3}",
new MultiRenderer<VarianceConflictDiagnosticData>() {
@NotNull
@@ -279,6 +279,7 @@ public class DeclarationsChecker {
private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
checkOpenMembers(classDescriptor);
checkTypeParameters(aClass);
checkTypeParameterConstraints(aClass);
if (aClass.isInterface()) {
checkConstructorInTrait(aClass);
@@ -336,6 +337,27 @@ public class DeclarationsChecker {
}
}
private void checkTypeParameterConstraints(JetTypeParameterListOwner typeParameterListOwner) {
List<JetTypeConstraint> constraints = typeParameterListOwner.getTypeConstraints();
if (!constraints.isEmpty()) {
for (JetTypeParameter typeParameter : typeParameterListOwner.getTypeParameters()) {
if (typeParameter.getExtendsBound() != null && hasConstraints(typeParameter, constraints)) {
trace.report(MISPLACED_TYPE_PARAMETER_CONSTRAITS.on(typeParameter));
}
}
}
}
private static boolean hasConstraints(JetTypeParameter typeParameter, List<JetTypeConstraint> constraints) {
for (JetTypeConstraint constraint : constraints) {
JetSimpleNameExpression parameterName = constraint.getSubjectTypeParameterName();
if (parameterName != null && parameterName.getText().equals(typeParameter.getName())) {
return true;
}
}
return false;
}
private void checkConstructorInTrait(JetClass klass) {
JetPrimaryConstructor primaryConstructor = klass.getPrimaryConstructor();
if (primaryConstructor != null) {
@@ -377,6 +399,7 @@ public class DeclarationsChecker {
checkPropertyLateInit(property, propertyDescriptor);
checkPropertyInitializer(property, propertyDescriptor);
checkAccessors(property, propertyDescriptor);
checkTypeParameterConstraints(property);
checkPropertyExposedType(property, propertyDescriptor);
}
@@ -572,6 +595,7 @@ public class DeclarationsChecker {
typeParameterList.getTextRange().getStartOffset() > nameIdentifier.getTextRange().getStartOffset()) {
trace.report(DEPRECATED_TYPE_PARAMETER_SYNTAX.on(typeParameterList));
}
checkTypeParameterConstraints(function);
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
+7 -5
View File
@@ -9,9 +9,9 @@ interface B {
}
interface G<X> {
val <X : A> boo: Double where X : B
val <X> boo: Double where X : A, X : B
val <A> bal: Double where A : B
val <Y : B> bas: Double where <!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>X<!> : B
val <Y> bas: Double where Y : B, <!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>X<!> : B
}
class C() : A(), B
@@ -20,8 +20,9 @@ class D() {
companion object : A(), B {}
}
class Test1<T : A>()
class Test1<T>()
where
T : A,
T : B,
<!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>B<!> : T // error
{
@@ -47,10 +48,11 @@ class Bar<T : <!FINAL_UPPER_BOUND!>Foo<!>>
class Buzz<T> where T : <!FINAL_UPPER_BOUND!>Bar<<!UPPER_BOUND_VIOLATED!>Int<!>><!>, T : <!UNRESOLVED_REFERENCE!>nioho<!>
class X<T : <!FINAL_UPPER_BOUND!>Foo<!>>
class Y<<!CONFLICTING_UPPER_BOUNDS!>T<!> : <!FINAL_UPPER_BOUND!>Foo<!>> where T : <!FINAL_UPPER_BOUND!>Bar<Foo><!>
class Y<<!CONFLICTING_UPPER_BOUNDS!>T<!>> where T : <!FINAL_UPPER_BOUND!>Foo<!>, T : <!FINAL_UPPER_BOUND!>Bar<Foo><!>
fun <T : A> test2(t : T)
fun <T> test2(t : T)
where
T : A,
T : B,
<!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>B<!> : T
{
@@ -3,6 +3,6 @@
interface Foo
interface Bar
<!CONFLICTING_JVM_DECLARATIONS!>fun <T: Foo> foo(x: T): T<!> where T: Bar {null!!}
<!CONFLICTING_JVM_DECLARATIONS!>fun <T> foo(x: T): T<!> where T: Foo, T: Bar {null!!}
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(x: Foo): Foo<!> {null!!}
fun foo(x: Bar): Bar {null!!}
@@ -34,7 +34,7 @@ fun test4() {
//--------------
fun <T: A, R: T> emptyStrangeMap2(t: T): Map<T, R> where R: A = throw Exception("$t")
fun <T: A, R> emptyStrangeMap2(t: T): Map<T, R> where R: T, R: A = throw Exception("$t")
fun test5(a: A) {
emptyStrangeMap2(a)
@@ -3,10 +3,10 @@ fun <NN: Any, NNN: NN> nonMisleadingNullable(
<!UNUSED_PARAMETER!>nnn<!>: NNN?
) {}
fun <NN: Any, TWO_BOUNDS: Any> twoBounds(
fun <NN: Any, TWO_BOUNDS> twoBounds(
<!UNUSED_PARAMETER!>tb<!>: TWO_BOUNDS?
) where TWO_BOUNDS : NN {}
) where TWO_BOUNDS: Any, TWO_BOUNDS : NN {}
fun <T, N: T, INDIRECT: N> misleadingNullableSimple(
<!UNUSED_PARAMETER!>t<!>: T<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!>,
@@ -15,10 +15,10 @@ fun <T, N: T, INDIRECT: N> misleadingNullableSimple(
<!UNUSED_PARAMETER!>ind<!>: INDIRECT<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!>
) {}
fun <FIRST_BOUND: Any?, SECOND_BOUND: Any> misleadingNullableMultiBound(
fun <FIRST_BOUND, SECOND_BOUND> misleadingNullableMultiBound(
<!UNUSED_PARAMETER!>fb<!>: FIRST_BOUND<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!>,
<!UNUSED_PARAMETER!>sb<!>: SECOND_BOUND<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!>
) where FIRST_BOUND: Any, SECOND_BOUND: Any? {
) where FIRST_BOUND: Any?, FIRST_BOUND: Any, SECOND_BOUND: Any, SECOND_BOUND: Any? {
}
fun <T> interactionWithRedundant(<!UNUSED_PARAMETER!>t<!>: T<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!><!REDUNDANT_NULLABLE!>?<!>) {}
@@ -0,0 +1,12 @@
class Foo<<!MISPLACED_TYPE_PARAMETER_CONSTRAITS!>T : Cloneable<!>> where T : Comparable<T> {
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAITS!>U : Cloneable<!>> foo(u: U): U where U: Comparable<U> {
return u
}
val <<!MISPLACED_TYPE_PARAMETER_CONSTRAITS!>U : Cloneable<!>> U.foo: U? where U: Comparable<U>
get() { return null }
}
class Bar<T : Cloneable, U> where U: Comparable<T> {
}
@@ -0,0 +1,17 @@
package
public final class Bar</*0*/ T : kotlin.Cloneable, /*1*/ U : kotlin.Comparable<T>> {
public constructor Bar</*0*/ T : kotlin.Cloneable, /*1*/ U : kotlin.Comparable<T>>()
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 Foo</*0*/ T : kotlin.Cloneable> where T : kotlin.Comparable<T> {
public constructor Foo</*0*/ T : kotlin.Cloneable>() where T : kotlin.Comparable<T>
public final val </*0*/ U : kotlin.Cloneable> U.foo: U? where U : kotlin.Comparable<U>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ U : kotlin.Cloneable> foo(/*0*/ u: U): U where U : kotlin.Comparable<U>
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, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out S><!>> f3() where A : Array<out T> {}
fun <S, T : S, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A<!>> f3() where A : Array<out S>, A : 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?><!>> v = ""
class C2<T, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out T><!>>
interface C3<S, T : S, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out S><!>> where A : Array<out T>
interface C3<S, T : S, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A<!>> where A : Array<out S>, A : Array<out T>
fun foo() {
class C1<<!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<Any><!>> {
@@ -15534,6 +15534,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("misplacedConstraints.kt")
public void testMisplacedConstraints() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/misplacedConstraints.kt");
doTest(fileName);
}
@TestMetadata("upperBoundCannotBeArray.kt")
public void testUpperBoundCannotBeArray() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt");