From 48625dd7b6199ede73c1a35e74c10b1bb9276424 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Thu, 26 Sep 2013 03:12:14 +0400 Subject: [PATCH] Disallowed using type parameter as reified type argument. #KT-3050 fixed --- .../jet/lang/diagnostics/Errors.java | 2 + .../rendering/DefaultErrorMessages.java | 2 + .../resolve/calls/CompositeExtension.java | 2 +- .../calls/TypeParameterAsReifiedCheck.java | 34 +++++++++++++++ .../testData/codegen/box/traits/stdlib.kt | 4 +- .../tests/generics/tpAsReified/Conventions.kt | 11 +++++ .../generics/tpAsReified/InConstructor.kt | 16 +++++++ .../tests/generics/tpAsReified/InFunction.kt | 16 +++++++ .../tests/generics/tpAsReified/InProperty.kt | 15 +++++++ .../tests/generics/tpAsReified/InType.kt | 4 ++ .../checkers/JetDiagnosticsTestGenerated.java | 42 ++++++++++++++++++- libraries/stdlib/src/kotlin/Arrays.kt | 3 -- libraries/stdlib/src/kotlin/ArraysJVM.kt | 2 +- libraries/stdlib/src/kotlin/JLangJVM.kt | 2 +- .../doc/highlighter/SyntaxHighlighter.kt | 2 +- 15 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TypeParameterAsReifiedCheck.java create mode 100644 compiler/testData/diagnostics/tests/generics/tpAsReified/Conventions.kt create mode 100644 compiler/testData/diagnostics/tests/generics/tpAsReified/InConstructor.kt create mode 100644 compiler/testData/diagnostics/tests/generics/tpAsReified/InFunction.kt create mode 100644 compiler/testData/diagnostics/tests/generics/tpAsReified/InProperty.kt create mode 100644 compiler/testData/diagnostics/tests/generics/tpAsReified/InType.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index a9b3bd9e629..ac9709bc744 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -345,6 +345,8 @@ public interface Errors { DiagnosticFactory0 DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED = DiagnosticFactory0.create(WARNING); + DiagnosticFactory1 TYPE_PARAMETER_AS_REIFIED = DiagnosticFactory1.create(ERROR); + // Type inference DiagnosticFactory0 CANNOT_INFER_PARAMETER_TYPE = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index d24359c5ad5..f346b9548a3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -441,6 +441,8 @@ public class DefaultErrorMessages { "This expression is treated as an argument to the function call on the previous line. " + "Separate it with a semicolon (;) if it is not intended to be an argument."); + MAP.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead.", NAME); + MAP.put(NOT_AN_ANNOTATION_CLASS, "''{0}'' is not an annotation class", TO_STRING); MAP.put(ANNOTATION_CLASS_WITH_BODY, "Body is not allowed for annotation class"); MAP.put(INVALID_TYPE_OF_ANNOTATION_MEMBER, "Invalid type of annotation member"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CompositeExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CompositeExtension.java index 31c898cd083..02460bb4782 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CompositeExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CompositeExtension.java @@ -7,7 +7,7 @@ import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImp public class CompositeExtension implements CallResolverExtension { private final CallResolverExtension[] delegates = new CallResolverExtension[]{ - new NeedSyntheticCallResolverExtension()}; + new NeedSyntheticCallResolverExtension(), new TypeParameterAsReifiedCheck()}; @Override public void run( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TypeParameterAsReifiedCheck.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TypeParameterAsReifiedCheck.java new file mode 100644 index 00000000000..9ea11fa10de --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TypeParameterAsReifiedCheck.java @@ -0,0 +1,34 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; +import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Map; + +public class TypeParameterAsReifiedCheck implements CallResolverExtension { + @Override + public void run( + @NotNull OverloadResolutionResultsImpl results, @NotNull BasicCallResolutionContext context + ) { + if (results.isSuccess()) { + Map typeArguments = results.getResultingCall().getTypeArguments(); + for (Map.Entry entry : typeArguments.entrySet()) { + TypeParameterDescriptor parameter = entry.getKey(); + JetType argument = entry.getValue(); + + if (parameter.isReified() && argument.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { + JetExpression callee = context.call.getCalleeExpression(); + PsiElement element = callee != null ? callee : context.call.getCallElement(); + context.trace.report(Errors.TYPE_PARAMETER_AS_REIFIED.on(element, typeArguments.keySet().iterator().next())); + } + } + } + } +} diff --git a/compiler/testData/codegen/box/traits/stdlib.kt b/compiler/testData/codegen/box/traits/stdlib.kt index 306d78264aa..8b31b4b1d1f 100644 --- a/compiler/testData/codegen/box/traits/stdlib.kt +++ b/compiler/testData/codegen/box/traits/stdlib.kt @@ -33,9 +33,9 @@ trait WriteOnlyArray : ISized { } class MutableArray(length: Int, init : (Int) -> T) : ReadOnlyArray, WriteOnlyArray { - private val array = Array(length, init) + private val array = Array(length, init) - override fun get(index : Int) : T = array[index] + override fun get(index : Int) : T = array[index] as T override fun set(index : Int, value : T) : Unit { array[index] = value } override val size : Int diff --git a/compiler/testData/diagnostics/tests/generics/tpAsReified/Conventions.kt b/compiler/testData/diagnostics/tests/generics/tpAsReified/Conventions.kt new file mode 100644 index 00000000000..ef8f2582c9a --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/tpAsReified/Conventions.kt @@ -0,0 +1,11 @@ +fun T.plus(p: T): T = this + +fun T.invoke(): T = this + +fun main(tp: A, any: Any) { + tp + tp + any + any + + tp() + any() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/tpAsReified/InConstructor.kt b/compiler/testData/diagnostics/tests/generics/tpAsReified/InConstructor.kt new file mode 100644 index 00000000000..66d837295c6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/tpAsReified/InConstructor.kt @@ -0,0 +1,16 @@ +class C + +fun id(p: T): T = p + +fun main() { + C() + + val a: C = C() + C() + + val b: C = C() + C() + + // TODO svtk, uncomment when extensions are called for nested calls! + //val < !UNUSED_VARIABLE!>с< !>: C = id(< !TYPE_PARAMETER_AS_REIFIED!>C< !>()) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/tpAsReified/InFunction.kt b/compiler/testData/diagnostics/tests/generics/tpAsReified/InFunction.kt new file mode 100644 index 00000000000..9e7d62fc243 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/tpAsReified/InFunction.kt @@ -0,0 +1,16 @@ +fun f(): T = throw UnsupportedOperationException() + +fun id(p: T): T = p + +fun main() { + f() + + val a: A = f() + f() + + val b: Int = f() + f() + + // TODO svtk, uncomment when extensions are called for nested calls! + //val < !UNUSED_VARIABLE!>с< !>: A = id(< !TYPE_PARAMETER_AS_REIFIED!>f< !>()) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/tpAsReified/InProperty.kt b/compiler/testData/diagnostics/tests/generics/tpAsReified/InProperty.kt new file mode 100644 index 00000000000..79a8acc836b --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/tpAsReified/InProperty.kt @@ -0,0 +1,15 @@ +val v: T + get() = throw UnsupportedOperationException() + +fun id(p: T): T = p + +fun main() { + val a = v + + val b: A = v + + val c: Int = v + + // TODO svtk, uncomment when extensions are called for nested calls! + //val < !UNUSED_VARIABLE!>d< !>: A = id(< !TYPE_PARAMETER_AS_REIFIED!>v< !>) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/tpAsReified/InType.kt b/compiler/testData/diagnostics/tests/generics/tpAsReified/InType.kt new file mode 100644 index 00000000000..bfe498fe7fd --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/tpAsReified/InType.kt @@ -0,0 +1,4 @@ +class C + +fun main(p1: C, p2: C) { +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index f5955b11713..2bcd14eda45 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2802,6 +2802,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } @TestMetadata("compiler/testData/diagnostics/tests/generics") + @InnerTestClasses({Generics.TpAsReified.class}) public static class Generics extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInGenerics() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/generics"), Pattern.compile("^(.+)\\.kt$"), true); @@ -2852,6 +2853,45 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/generics/RecursiveUpperBoundWithTwoArguments.kt"); } + @TestMetadata("compiler/testData/diagnostics/tests/generics/tpAsReified") + public static class TpAsReified extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInTpAsReified() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/generics/tpAsReified"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("Conventions.kt") + public void testConventions() throws Exception { + doTest("compiler/testData/diagnostics/tests/generics/tpAsReified/Conventions.kt"); + } + + @TestMetadata("InConstructor.kt") + public void testInConstructor() throws Exception { + doTest("compiler/testData/diagnostics/tests/generics/tpAsReified/InConstructor.kt"); + } + + @TestMetadata("InFunction.kt") + public void testInFunction() throws Exception { + doTest("compiler/testData/diagnostics/tests/generics/tpAsReified/InFunction.kt"); + } + + @TestMetadata("InProperty.kt") + public void testInProperty() throws Exception { + doTest("compiler/testData/diagnostics/tests/generics/tpAsReified/InProperty.kt"); + } + + @TestMetadata("InType.kt") + public void testInType() throws Exception { + doTest("compiler/testData/diagnostics/tests/generics/tpAsReified/InType.kt"); + } + + } + + public static Test innerSuite() { + TestSuite suite = new TestSuite("Generics"); + suite.addTestSuite(Generics.class); + suite.addTestSuite(TpAsReified.class); + return suite; + } } @TestMetadata("compiler/testData/diagnostics/tests/incompleteCode") @@ -5969,7 +6009,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage suite.addTest(Enum.innerSuite()); suite.addTestSuite(Extensions.class); suite.addTest(FunctionLiterals.innerSuite()); - suite.addTestSuite(Generics.class); + suite.addTest(Generics.innerSuite()); suite.addTest(IncompleteCode.innerSuite()); suite.addTest(Inference.innerSuite()); suite.addTestSuite(Infos.class); diff --git a/libraries/stdlib/src/kotlin/Arrays.kt b/libraries/stdlib/src/kotlin/Arrays.kt index 1ef8ea339ce..94239d69946 100644 --- a/libraries/stdlib/src/kotlin/Arrays.kt +++ b/libraries/stdlib/src/kotlin/Arrays.kt @@ -6,9 +6,6 @@ public inline fun Array.isNotEmpty() : Boolean = !this.isEmpty() /** Returns true if the array is empty */ public inline fun Array.isEmpty() : Boolean = this.size == 0 -/** Returns the array if its not null or else returns an empty array */ -public inline fun Array?.orEmpty() : Array = if (this != null) this else array() - public inline val BooleanArray.lastIndex : Int get() = this.size - 1 diff --git a/libraries/stdlib/src/kotlin/ArraysJVM.kt b/libraries/stdlib/src/kotlin/ArraysJVM.kt index 0bcb7ada0f9..753e64e5995 100644 --- a/libraries/stdlib/src/kotlin/ArraysJVM.kt +++ b/libraries/stdlib/src/kotlin/ArraysJVM.kt @@ -6,7 +6,7 @@ import java.util.Arrays import jet.runtime.Intrinsic // Array "constructor" -[Intrinsic("kotlin.arrays.array")] public inline fun array(vararg t : T) : Array = t +[Intrinsic("kotlin.arrays.array")] public inline fun array(vararg t : T) : Array = t // "constructors" for primitive types array [Intrinsic("kotlin.arrays.array")] public inline fun doubleArray(vararg content : Double) : DoubleArray = content diff --git a/libraries/stdlib/src/kotlin/JLangJVM.kt b/libraries/stdlib/src/kotlin/JLangJVM.kt index b71f3aced51..6e16ba6f8a0 100644 --- a/libraries/stdlib/src/kotlin/JLangJVM.kt +++ b/libraries/stdlib/src/kotlin/JLangJVM.kt @@ -8,7 +8,7 @@ import jet.runtime.Intrinsic [Intrinsic("kotlin.javaClass.property")] public val T.javaClass : Class get() = (this as java.lang.Object).getClass() as Class -[Intrinsic("kotlin.javaClass.function")] fun javaClass() : Class = null as Class +[Intrinsic("kotlin.javaClass.function")] fun javaClass() : Class = null as Class /** diff --git a/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/highlighter/SyntaxHighlighter.kt b/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/highlighter/SyntaxHighlighter.kt index 27c21b9553d..c31636c50bf 100644 --- a/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/highlighter/SyntaxHighlighter.kt +++ b/libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/highlighter/SyntaxHighlighter.kt @@ -102,7 +102,7 @@ class SyntaxHighligher() { fun putAll(tokenSet: TokenSet?, style: String): Unit { if (tokenSet != null) { - for (token in tokenSet.getTypes().orEmpty()) { + for (token in tokenSet.getTypes()) { styleMap.put(token, style) } }