Report errors for type parameters of properties that are not used in receiver types
This commit is contained in:
@@ -269,6 +269,8 @@ public interface Errors {
|
||||
DiagnosticFactory0<JetDeclaration> TYPE_PARAMETERS_NOT_ALLOWED
|
||||
= DiagnosticFactory0.create(ERROR, TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE);
|
||||
|
||||
DiagnosticFactory0<JetTypeParameter> TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<PsiElement> CYCLIC_GENERIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<JetTypeParameter> MISPLACED_TYPE_PARAMETER_CONSTRAINTS = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
+2
@@ -629,6 +629,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, "Cannot use ''{0}'' as reified type parameter", RENDER_TYPE);
|
||||
MAP.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here");
|
||||
|
||||
MAP.put(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, "Type parameter of a property must be used in its receiver type");
|
||||
|
||||
MAP.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes");
|
||||
MAP.put(MISSING_VAL_ON_ANNOTATION_PARAMETER, "'val' keyword is missing on annotation parameter");
|
||||
MAP.put(ANNOTATION_CLASS_CONSTRUCTOR_CALL, "Annotation class cannot be instantiated");
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
@@ -471,6 +472,33 @@ public class DeclarationsChecker {
|
||||
checkAccessors(property, propertyDescriptor);
|
||||
checkTypeParameterConstraints(property);
|
||||
checkPropertyExposedType(property, propertyDescriptor);
|
||||
checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor);
|
||||
}
|
||||
|
||||
private void checkPropertyTypeParametersAreUsedInReceiverType(@NotNull PropertyDescriptor descriptor) {
|
||||
for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
|
||||
if (isTypeParameterUsedInReceiverType(typeParameter, descriptor)) continue;
|
||||
|
||||
PsiElement typeParameterPsi = DescriptorToSourceUtils.getSourceFromDescriptor(typeParameter);
|
||||
if (typeParameterPsi instanceof JetTypeParameter) {
|
||||
trace.report(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER.on((JetTypeParameter) typeParameterPsi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isTypeParameterUsedInReceiverType(
|
||||
@NotNull final TypeParameterDescriptor parameter,
|
||||
@NotNull PropertyDescriptor descriptor
|
||||
) {
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
if (receiverParameter == null) return false;
|
||||
|
||||
return TypeUtils.containsSpecialType(receiverParameter.getType(), new Function1<JetType, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(JetType type) {
|
||||
return parameter.equals(type.getConstructor().getDeclarationDescriptor());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkPropertyLateInit(@NotNull JetCallableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION
|
||||
|
||||
interface G
|
||||
|
||||
val <T> T.a: Int
|
||||
get() = 3
|
||||
|
||||
val <T1, T2> Map<T1, T2>.b: String
|
||||
get() = "asds"
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T : G<!>> G.c: Int get() = 5
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T1<!>, T2, T3> List<Map<T2, T3>>.d: Int get() = 6
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T: Any<!>> G.e: T?
|
||||
get() = null
|
||||
|
||||
val <T> List<Map<Int, Map<String, T>>>.f: Int get() = 7
|
||||
|
||||
val <T> List<Map<Int, Map<String, out T>>>.g: Int get() = 7
|
||||
val <T> List<Map<Int, Map<String, in T>>>.h: Int get() = 7
|
||||
|
||||
val <T> List<Map<T, Map<T, T>>>.i: Int get() = 7
|
||||
|
||||
var <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T1<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T2<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T3<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T4<!>> p = 1
|
||||
|
||||
class C<T1, T2> {
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>E<!>> T1.a: Int get() = 3
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>E<!>> T2.b: Int get() = 3
|
||||
val <E> E.c: Int get() = 3
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>E<!>> Map<T1, T2>.d: Int get() = 3
|
||||
val <E> Map<T1, E>.e: Int get() = 3
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package
|
||||
|
||||
public var </*0*/ T1, /*1*/ T2, /*2*/ T3, /*3*/ T4> p: kotlin.Int
|
||||
public val </*0*/ T> T.a: kotlin.Int
|
||||
public val </*0*/ T1, /*1*/ T2> kotlin.Map<T1, T2>.b: kotlin.String
|
||||
public val </*0*/ T : G> G.c: kotlin.Int
|
||||
public val </*0*/ T1, /*1*/ T2, /*2*/ T3> kotlin.List<kotlin.Map<T2, T3>>.d: kotlin.Int
|
||||
public val </*0*/ T : kotlin.Any> G.e: T?
|
||||
public val </*0*/ T> kotlin.List<kotlin.Map<kotlin.Int, kotlin.Map<kotlin.String, T>>>.f: kotlin.Int
|
||||
public val </*0*/ T> kotlin.List<kotlin.Map<kotlin.Int, kotlin.Map<kotlin.String, out T>>>.g: kotlin.Int
|
||||
public val </*0*/ T> kotlin.List<kotlin.Map<kotlin.Int, kotlin.Map<kotlin.String, in T>>>.h: kotlin.Int
|
||||
public val </*0*/ T> kotlin.List<kotlin.Map<T, kotlin.Map<T, T>>>.i: kotlin.Int
|
||||
|
||||
public final class C</*0*/ T1, /*1*/ T2> {
|
||||
public constructor C</*0*/ T1, /*1*/ T2>()
|
||||
public final val </*0*/ E> T1.a: kotlin.Int
|
||||
public final val </*0*/ E> T2.b: kotlin.Int
|
||||
public final val </*0*/ E> E.c: kotlin.Int
|
||||
public final val </*0*/ E> kotlin.Map<T1, T2>.d: kotlin.Int
|
||||
public final val </*0*/ E> kotlin.Map<T1, E>.e: kotlin.Int
|
||||
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 G {
|
||||
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
|
||||
}
|
||||
@@ -15805,6 +15805,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyTypeParameters.kt")
|
||||
public void testPropertyTypeParameters() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.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