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<PsiElement> CYCLIC_GENERIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
|
DiagnosticFactory0<JetTypeParameter> MISPLACED_TYPE_PARAMETER_CONSTRAITS = DiagnosticFactory0.create(WARNING);
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
|
|
||||||
DiagnosticFactory2<JetDeclaration, CallableMemberDescriptor, String> CONFLICTING_OVERLOADS =
|
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(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}",
|
MAP.put(TYPE_VARIANCE_CONFLICT, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in type {3}",
|
||||||
new MultiRenderer<VarianceConflictDiagnosticData>() {
|
new MultiRenderer<VarianceConflictDiagnosticData>() {
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ public class DeclarationsChecker {
|
|||||||
private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
|
private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
|
||||||
checkOpenMembers(classDescriptor);
|
checkOpenMembers(classDescriptor);
|
||||||
checkTypeParameters(aClass);
|
checkTypeParameters(aClass);
|
||||||
|
checkTypeParameterConstraints(aClass);
|
||||||
|
|
||||||
if (aClass.isInterface()) {
|
if (aClass.isInterface()) {
|
||||||
checkConstructorInTrait(aClass);
|
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) {
|
private void checkConstructorInTrait(JetClass klass) {
|
||||||
JetPrimaryConstructor primaryConstructor = klass.getPrimaryConstructor();
|
JetPrimaryConstructor primaryConstructor = klass.getPrimaryConstructor();
|
||||||
if (primaryConstructor != null) {
|
if (primaryConstructor != null) {
|
||||||
@@ -377,6 +399,7 @@ public class DeclarationsChecker {
|
|||||||
checkPropertyLateInit(property, propertyDescriptor);
|
checkPropertyLateInit(property, propertyDescriptor);
|
||||||
checkPropertyInitializer(property, propertyDescriptor);
|
checkPropertyInitializer(property, propertyDescriptor);
|
||||||
checkAccessors(property, propertyDescriptor);
|
checkAccessors(property, propertyDescriptor);
|
||||||
|
checkTypeParameterConstraints(property);
|
||||||
checkPropertyExposedType(property, propertyDescriptor);
|
checkPropertyExposedType(property, propertyDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,6 +595,7 @@ public class DeclarationsChecker {
|
|||||||
typeParameterList.getTextRange().getStartOffset() > nameIdentifier.getTextRange().getStartOffset()) {
|
typeParameterList.getTextRange().getStartOffset() > nameIdentifier.getTextRange().getStartOffset()) {
|
||||||
trace.report(DEPRECATED_TYPE_PARAMETER_SYNTAX.on(typeParameterList));
|
trace.report(DEPRECATED_TYPE_PARAMETER_SYNTAX.on(typeParameterList));
|
||||||
}
|
}
|
||||||
|
checkTypeParameterConstraints(function);
|
||||||
|
|
||||||
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
|
||||||
boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
|
boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
|
||||||
|
|||||||
+7
-5
@@ -9,9 +9,9 @@ interface B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface G<X> {
|
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 <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
|
class C() : A(), B
|
||||||
@@ -20,8 +20,9 @@ class D() {
|
|||||||
companion object : A(), B {}
|
companion object : A(), B {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Test1<T : A>()
|
class Test1<T>()
|
||||||
where
|
where
|
||||||
|
T : A,
|
||||||
T : B,
|
T : B,
|
||||||
<!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>B<!> : T // error
|
<!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 Buzz<T> where T : <!FINAL_UPPER_BOUND!>Bar<<!UPPER_BOUND_VIOLATED!>Int<!>><!>, T : <!UNRESOLVED_REFERENCE!>nioho<!>
|
||||||
|
|
||||||
class X<T : <!FINAL_UPPER_BOUND!>Foo<!>>
|
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
|
where
|
||||||
|
T : A,
|
||||||
T : B,
|
T : B,
|
||||||
<!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>B<!> : T
|
<!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>B<!> : T
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+1
-1
@@ -3,6 +3,6 @@
|
|||||||
interface Foo
|
interface Foo
|
||||||
interface Bar
|
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!!}
|
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(x: Foo): Foo<!> {null!!}
|
||||||
fun foo(x: Bar): Bar {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) {
|
fun test5(a: A) {
|
||||||
emptyStrangeMap2(a)
|
emptyStrangeMap2(a)
|
||||||
|
|||||||
+4
-4
@@ -3,10 +3,10 @@ fun <NN: Any, NNN: NN> nonMisleadingNullable(
|
|||||||
<!UNUSED_PARAMETER!>nnn<!>: NNN?
|
<!UNUSED_PARAMETER!>nnn<!>: NNN?
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
fun <NN: Any, TWO_BOUNDS: Any> twoBounds(
|
fun <NN: Any, TWO_BOUNDS> twoBounds(
|
||||||
<!UNUSED_PARAMETER!>tb<!>: TWO_BOUNDS?
|
<!UNUSED_PARAMETER!>tb<!>: TWO_BOUNDS?
|
||||||
|
|
||||||
) where TWO_BOUNDS : NN {}
|
) where TWO_BOUNDS: Any, TWO_BOUNDS : NN {}
|
||||||
|
|
||||||
fun <T, N: T, INDIRECT: N> misleadingNullableSimple(
|
fun <T, N: T, INDIRECT: N> misleadingNullableSimple(
|
||||||
<!UNUSED_PARAMETER!>t<!>: T<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!>,
|
<!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!>?<!>
|
<!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!>fb<!>: FIRST_BOUND<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!>,
|
||||||
<!UNUSED_PARAMETER!>sb<!>: SECOND_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!>?<!>) {}
|
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 <<!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<Any><!>> f1() {}
|
||||||
fun <T, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out T><!>> f2() {}
|
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() {}
|
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 = ""
|
val <<!UPPER_BOUND_CANNOT_BE_ARRAY!>T : Array<Any?><!>> v = ""
|
||||||
|
|
||||||
class C2<T, <!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<out T><!>>
|
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() {
|
fun foo() {
|
||||||
class C1<<!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<Any><!>> {
|
class C1<<!UPPER_BOUND_CANNOT_BE_ARRAY!>A : Array<Any><!>> {
|
||||||
|
|||||||
@@ -15534,6 +15534,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("upperBoundCannotBeArray.kt")
|
||||||
public void testUpperBoundCannotBeArray() throws Exception {
|
public void testUpperBoundCannotBeArray() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user