diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 1558a9d3c05..1faceae84d9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -269,6 +269,8 @@ public interface Errors { DiagnosticFactory0 TYPE_PARAMETERS_NOT_ALLOWED = DiagnosticFactory0.create(ERROR, TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE); + DiagnosticFactory0 TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 CYCLIC_GENERIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 MISPLACED_TYPE_PARAMETER_CONSTRAINTS = DiagnosticFactory0.create(WARNING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index dd07f82032b..ee202e54fbd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -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"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java index fed82d8591a..3726c7e8f36 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java @@ -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() { + @Override + public Boolean invoke(JetType type) { + return parameter.equals(type.getConstructor().getDeclarationDescriptor()); + } + }); } private void checkPropertyLateInit(@NotNull JetCallableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor) { diff --git a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt new file mode 100644 index 00000000000..d1c7069ca1c --- /dev/null +++ b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt @@ -0,0 +1,33 @@ +// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION + +interface G + +val T.a: Int + get() = 3 + +val Map.b: String + get() = "asds" + +val <T : G> G.c: Int get() = 5 + +val <T1, T2, T3> List>.d: Int get() = 6 + +val <T: Any> G.e: T? + get() = null + +val List>>.f: Int get() = 7 + +val List>>.g: Int get() = 7 +val List>>.h: Int get() = 7 + +val List>>.i: Int get() = 7 + +var <T1, T2, T3, T4> p = 1 + +class C { + val <E> T1.a: Int get() = 3 + val <E> T2.b: Int get() = 3 + val E.c: Int get() = 3 + val <E> Map.d: Int get() = 3 + val Map.e: Int get() = 3 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt new file mode 100644 index 00000000000..e1edf0d1bf3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.txt @@ -0,0 +1,30 @@ +package + +public var p: kotlin.Int +public val T.a: kotlin.Int +public val kotlin.Map.b: kotlin.String +public val G.c: kotlin.Int +public val kotlin.List>.d: kotlin.Int +public val G.e: T? +public val kotlin.List>>.f: kotlin.Int +public val kotlin.List>>.g: kotlin.Int +public val kotlin.List>>.h: kotlin.Int +public val kotlin.List>>.i: kotlin.Int + +public final class C { + public constructor C() + public final val T1.a: kotlin.Int + public final val T2.b: kotlin.Int + public final val E.c: kotlin.Int + public final val kotlin.Map.d: kotlin.Int + public final val kotlin.Map.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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index a34cd30519a..f6442e881e5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -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");