disallow putting type parameter constraints both in type parameter list and in 'where' clause
This commit is contained in:
@@ -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 =
|
||||
|
||||
+2
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
Vendored
+1
-1
@@ -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!!}
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
+2
-2
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user