diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.kt new file mode 100644 index 00000000000..b28f1a8c27e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.kt @@ -0,0 +1,22 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +import java.util.* + +fun bar(): String? = null + +fun foo() { + var x = ArrayList() + x.add(null) + x.add(bar()) + x.add("") + + x[0] = null + x[0] = bar() + x[0] = "" + + val b1: MutableList = x + val b2: MutableList = x + val b3: List = x + + val b4: Collection = x + val b6: MutableCollection = x +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.txt new file mode 100644 index 00000000000..dd1f7a31060 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.txt @@ -0,0 +1,4 @@ +package + +internal fun bar(): kotlin.String? +internal fun foo(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.kt new file mode 100644 index 00000000000..fad8fa935c2 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.kt @@ -0,0 +1,22 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +import java.util.* + +fun bar(): String? = null + +fun foo() { + var x = ArrayList() + x.add(null) + x.add(bar()) + x.add("") + + x[0] = null + x[0] = bar() + x[0] = "" + + val b1: MutableList = x + val b2: MutableList = x + val b3: List = x + + val b4: Collection = x + val b6: MutableCollection = x +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.txt new file mode 100644 index 00000000000..dd1f7a31060 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.txt @@ -0,0 +1,4 @@ +package + +internal fun bar(): kotlin.String? +internal fun foo(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.kt new file mode 100644 index 00000000000..b67883babd4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.kt @@ -0,0 +1,31 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + +import java.util.* + +// FILE: A.java +@kotlin.jvm.PurelyImplements("kotlin.MutableCollection") +class A extends AbstractCollection { + @Override + public Iterator iterator() { + return null; + } + + @Override + public int size() { + return 0; + } +} + +// FILE: b.kt + +fun bar(): String? = null + +fun foo() { + var x = A() + x.add(null) + x.add(bar()) + x.add("") + + val b1: Collection = x + val b2: MutableCollection = x +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.txt new file mode 100644 index 00000000000..c8966bb576a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.txt @@ -0,0 +1,24 @@ +package + +internal fun bar(): kotlin.String? +internal fun foo(): kotlin.Unit + +kotlin.jvm.PurelyImplements(value = "kotlin.MutableCollection") public/*package*/ open class A : java.util.AbstractCollection, kotlin.MutableCollection { + public/*package*/ constructor A() + public open override /*2*/ /*fake_override*/ fun add(/*0*/ e: T): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun clear(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun contains(/*0*/ o: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun containsAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean + java.lang.Override() public open override /*2*/ fun iterator(): kotlin.MutableIterator + public open override /*2*/ /*fake_override*/ fun remove(/*0*/ o: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun removeAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun retainAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + java.lang.Override() public open override /*2*/ fun size(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>! + public open override /*1*/ /*fake_override*/ fun toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>! + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.kt new file mode 100644 index 00000000000..31e3c57ad0f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.kt @@ -0,0 +1,39 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + +import java.util.* + +// FILE: A.java +@kotlin.jvm.PurelyImplements("kotlin.MutableList") +class A extends AbstractList { + @Override + public T get(int index) { + return null; + } + + @Override + public int size() { + return 0; + } +} + +// FILE: b.kt + +fun bar(): String? = null + +fun foo() { + var x = A() + x.add(null) + x.add(bar()) + x.add("") + + x[0] = null + x[0] = bar() + x[0] = "" + + val b1: MutableList = x + val b2: MutableList = x + val b3: List = x + + val b4: Collection = x + val b6: MutableCollection = x +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.txt new file mode 100644 index 00000000000..41c160f2daf --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.txt @@ -0,0 +1,38 @@ +package + +internal fun bar(): kotlin.String? +internal fun foo(): kotlin.Unit + +kotlin.jvm.PurelyImplements(value = "kotlin.MutableList") public/*package*/ open class A : java.util.AbstractList, kotlin.MutableList { + public/*package*/ constructor A() + protected/*protected and package*/ final override /*1*/ /*fake_override*/ var modCount: kotlin.Int + public open override /*2*/ /*fake_override*/ fun add(/*0*/ e: T): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun add(/*0*/ index: kotlin.Int, /*1*/ element: T): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun addAll(/*0*/ index: kotlin.Int, /*1*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun clear(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun contains(/*0*/ o: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun containsAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + java.lang.Override() public open override /*2*/ fun get(/*0*/ index: kotlin.Int): T + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun indexOf(/*0*/ o: kotlin.Any?): kotlin.Int + public open override /*2*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun iterator(): kotlin.MutableIterator + public open override /*2*/ /*fake_override*/ fun lastIndexOf(/*0*/ o: kotlin.Any?): kotlin.Int + public open override /*2*/ /*fake_override*/ fun listIterator(): kotlin.MutableListIterator + public open override /*2*/ /*fake_override*/ fun listIterator(/*0*/ index: kotlin.Int): kotlin.MutableListIterator + invisible_fake open override /*1*/ /*fake_override*/ fun outOfBoundsMsg(/*0*/ p0: kotlin.Int): kotlin.String! + invisible_fake open override /*1*/ /*fake_override*/ fun rangeCheckForAdd(/*0*/ p0: kotlin.Int): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun remove(/*0*/ o: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun remove(/*0*/ index: kotlin.Int): T + public open override /*2*/ /*fake_override*/ fun removeAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun removeRange(/*0*/ p0: kotlin.Int, /*1*/ p1: kotlin.Int): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun retainAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: T): T + java.lang.Override() public open override /*2*/ fun size(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList + public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>! + public open override /*1*/ /*fake_override*/ fun toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>! + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.kt new file mode 100644 index 00000000000..8cb8a523cf8 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.kt @@ -0,0 +1,78 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +import java.util.* +import java.util.concurrent.* + +fun bar(): String? = null +val nullableInt: Int? = null + +fun hashMapTest() { + var x: HashMap = HashMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x.get("") + + val b8: Int? = x.get("") +} + +fun treeMapTest() { + var x: TreeMap = TreeMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x.get("") + + val b8: Int? = x.get("") +} + +fun concurrentHashMapTest() { + var x: ConcurrentHashMap = ConcurrentHashMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x.get("") + + val b8: Int? = x.get("") +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.txt new file mode 100644 index 00000000000..3b7d946afb4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.txt @@ -0,0 +1,7 @@ +package + +internal val nullableInt: kotlin.Int? = null +internal fun bar(): kotlin.String? +internal fun concurrentHashMapTest(): kotlin.Unit +internal fun hashMapTest(): kotlin.Unit +internal fun treeMapTest(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.kt new file mode 100644 index 00000000000..cbf06958749 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +import java.util.* + +fun bar(): String? = null +val nullableInt: Int? = null + +fun hashMapTest() { + var x: HashMap = HashMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x[null] + val b8: Int = x.get("") + + val b9: Int? = x.get("") +} + +fun treeMapTest() { + var x: TreeMap = TreeMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x.get("") + + val b8: Int? = x.get("") +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.txt new file mode 100644 index 00000000000..51b387b7d42 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.txt @@ -0,0 +1,6 @@ +package + +internal val nullableInt: kotlin.Int? = null +internal fun bar(): kotlin.String? +internal fun hashMapTest(): kotlin.Unit +internal fun treeMapTest(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.kt new file mode 100644 index 00000000000..2727dcaee70 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.kt @@ -0,0 +1,53 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +import java.util.* + +fun bar(): String? = null +val nullableInt: Int? = null + +fun hashMapTest() { + var x: HashMap = HashMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x.get("") + + val b8: Int? = x.get("") +} + +fun treeMapTest() { + var x: TreeMap = TreeMap() + x.put(null, null) + x.put("", null) + x.put(bar(), 1) + x.put("", 1) + + x[null] = 1 + x[bar()] = 1 + x[""] = nullableInt + x[""] = 1 + + val b1: MutableMap = x + val b2: MutableMap = x + val b3: Map = x + val b4: Map = x + val b5: Map = x + + val b6: Int = x[""] + val b7: Int = x.get("") + + val b8: Int? = x.get("") +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.txt new file mode 100644 index 00000000000..51b387b7d42 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.txt @@ -0,0 +1,6 @@ +package + +internal val nullableInt: kotlin.Int? = null +internal fun bar(): kotlin.String? +internal fun hashMapTest(): kotlin.Unit +internal fun treeMapTest(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.kt new file mode 100644 index 00000000000..7e37f0d0b55 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.kt @@ -0,0 +1,46 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +import java.util.* + +fun bar(): String? = null + +fun fooHashSet() { + var x = HashSet() + x.add(null) + x.add(bar()) + x.add("") + + val b1: MutableSet = x + val b2: MutableSet = x + val b3: Set = x + + val b4: Collection = x + val b6: MutableCollection = x +} + +fun fooTreeSet() { + var x = TreeSet() + x.add(null) + x.add(bar()) + x.add("") + + val b1: MutableSet = x + val b2: MutableSet = x + val b3: Set = x + + val b4: Collection = x + val b6: MutableCollection = x +} + +fun fooLinkedHashSet() { + var x = LinkedHashSet() + x.add(null) + x.add(bar()) + x.add("") + + val b1: MutableSet = x + val b2: MutableSet = x + val b3: Set = x + + val b4: Collection = x + val b6: MutableCollection = x +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.txt new file mode 100644 index 00000000000..60371b78964 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.txt @@ -0,0 +1,6 @@ +package + +internal fun bar(): kotlin.String? +internal fun fooHashSet(): kotlin.Unit +internal fun fooLinkedHashSet(): kotlin.Unit +internal fun fooTreeSet(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.kt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.kt new file mode 100644 index 00000000000..63d95658bdb --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.kt @@ -0,0 +1,39 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + +import java.util.* + +// FILE: A.java +@kotlin.jvm.PurelyImplements("kotlin.MutableList") +class A extends AbstractList { + @Override + public T get(int index) { + return null; + } + + @Override + public int size() { + return 0; + } +} + +// FILE: b.kt + +fun bar(): String? = null + +fun foo() { + var x = A() + x.add(null) + x.add(bar()) + x.add("") + + x[0] = null + x[0] = bar() + x[0] = "" + + val b1: MutableList = x + val b2: MutableList = x + val b3: List = x + + val b4: Collection = x + val b6: MutableCollection = x +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.txt b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.txt new file mode 100644 index 00000000000..436b84b19f5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.txt @@ -0,0 +1,38 @@ +package + +internal fun bar(): kotlin.String? +internal fun foo(): kotlin.Unit + +kotlin.jvm.PurelyImplements(value = "kotlin.MutableList") public/*package*/ open class A : java.util.AbstractList { + public/*package*/ constructor A() + protected/*protected and package*/ final override /*1*/ /*fake_override*/ var modCount: kotlin.Int + public open override /*1*/ /*fake_override*/ fun add(/*0*/ e: T!): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun add(/*0*/ index: kotlin.Int, /*1*/ element: T!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun addAll(/*0*/ index: kotlin.Int, /*1*/ c: kotlin.Collection): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun clear(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun contains(/*0*/ o: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun containsAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + java.lang.Override() public open override /*1*/ fun get(/*0*/ index: kotlin.Int): T! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun indexOf(/*0*/ o: kotlin.Any?): kotlin.Int + public open override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun iterator(): kotlin.MutableIterator + public open override /*1*/ /*fake_override*/ fun lastIndexOf(/*0*/ o: kotlin.Any?): kotlin.Int + public open override /*1*/ /*fake_override*/ fun listIterator(): kotlin.MutableListIterator + public open override /*1*/ /*fake_override*/ fun listIterator(/*0*/ index: kotlin.Int): kotlin.MutableListIterator + invisible_fake open override /*1*/ /*fake_override*/ fun outOfBoundsMsg(/*0*/ p0: kotlin.Int): kotlin.String! + invisible_fake open override /*1*/ /*fake_override*/ fun rangeCheckForAdd(/*0*/ p0: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun remove(/*0*/ o: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun remove(/*0*/ index: kotlin.Int): T! + public open override /*1*/ /*fake_override*/ fun removeAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun removeRange(/*0*/ p0: kotlin.Int, /*1*/ p1: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun retainAll(/*0*/ c: kotlin.Collection): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: T!): T! + java.lang.Override() public open override /*1*/ fun size(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList + public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>! + public open override /*1*/ /*fake_override*/ fun toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>! + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java index ed32fc97ab0..dd046cf6fa6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -611,6 +611,69 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PurelyImplementedCollection extends AbstractJetDiagnosticsTestWithStdLib { + public void testAllFilesPresentInPurelyImplementedCollection() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("arrayList.kt") + public void testArrayList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayList.kt"); + doTest(fileName); + } + + @TestMetadata("arrayListNullable.kt") + public void testArrayListNullable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/arrayListNullable.kt"); + doTest(fileName); + } + + @TestMetadata("customClassMutableCollection.kt") + public void testCustomClassMutableCollection() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableCollection.kt"); + doTest(fileName); + } + + @TestMetadata("customClassMutableList.kt") + public void testCustomClassMutableList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/customClassMutableList.kt"); + doTest(fileName); + } + + @TestMetadata("maps.kt") + public void testMaps() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/maps.kt"); + doTest(fileName); + } + + @TestMetadata("mapsWithNullableKey.kt") + public void testMapsWithNullableKey() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableKey.kt"); + doTest(fileName); + } + + @TestMetadata("mapsWithNullableValues.kt") + public void testMapsWithNullableValues() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/mapsWithNullableValues.kt"); + doTest(fileName); + } + + @TestMetadata("sets.kt") + public void testSets() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/sets.kt"); + doTest(fileName); + } + + @TestMetadata("wrongTypeParametersCount.kt") + public void testWrongTypeParametersCount() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/purelyImplementedCollection/wrongTypeParametersCount.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/regression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt new file mode 100644 index 00000000000..b416ae514f7 --- /dev/null +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FakePureImplementationsProvider.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.load.java + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.DescriptorUtils + +public object FakePureImplementationsProvider { + public fun getPurelyImplementedInterface(classFqName: FqName): FqName? = when(classFqName) { + in MUTABLE_LISTS_IMPLEMENTATIONS -> MUTABLE_LIST_FQ_NAME + in MUTABLE_MAPS_IMPLEMENTATIONS -> MUTABLE_MAP_FQ_NAME + in MUTABLE_SETS_IMPLEMENTATIONS -> MUTABLE_SET_FQ_NAME + else -> null + } + + private val kotlinBuiltins = KotlinBuiltIns.getInstance() + + private val MUTABLE_LIST_FQ_NAME = DescriptorUtils.getFqNameSafe(kotlinBuiltins.getMutableList()) + private val MUTABLE_SET_FQ_NAME = DescriptorUtils.getFqNameSafe(kotlinBuiltins.getMutableSet()) + private val MUTABLE_MAP_FQ_NAME = DescriptorUtils.getFqNameSafe(kotlinBuiltins.getMutableMap()) + + private val MUTABLE_LISTS_IMPLEMENTATIONS = setOfFqNames("java.util.ArrayList", "java.util.LinkedList") + private val MUTABLE_MAPS_IMPLEMENTATIONS = setOfFqNames( + "java.util.HashMap", "java.util.TreeMap", "java.util.LinkedHashMap", + "java.util.concurrent.ConcurrentHashMap", "java.util.concurrent.ConcurrentSkipListMap" + ) + private val MUTABLE_SETS_IMPLEMENTATIONS = setOfFqNames( + "java.util.HashSet", "java.util.TreeSet", "java.util.LinkedHashSet" + ) +} + +private fun setOfFqNames(vararg names: String) = names.map { FqName(it) }.toSet() diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java index 7ff48a45ae4..a6c887c1762 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java @@ -44,6 +44,8 @@ public final class JvmAnnotationNames { public static final FqName JETBRAINS_MUTABLE_ANNOTATION = new FqName("org.jetbrains.annotations.Mutable"); public static final FqName JETBRAINS_READONLY_ANNOTATION = new FqName("org.jetbrains.annotations.ReadOnly"); + public static final FqName PURELY_IMPLEMENTS_ANNOTATION = new FqName("kotlin.jvm.PurelyImplements"); + public static class KotlinClass { public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinClass"); public static final ClassId KIND_CLASS_ID = diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt index 3005f1a847b..b80311bb371 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase +import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider +import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.components.TypeUsage import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext @@ -30,11 +32,12 @@ import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClassifierType import org.jetbrains.kotlin.load.java.structure.JavaType import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.isValidJavaFqName +import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.scopes.InnerClassesScopeWrapper import org.jetbrains.kotlin.resolve.scopes.JetScope -import org.jetbrains.kotlin.types.AbstractClassTypeConstructor -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.toReadOnlyList import java.util.ArrayList @@ -121,17 +124,26 @@ class LazyJavaClassDescriptor( val result = ArrayList(javaTypes.size()) val incomplete = ArrayList(0) + val purelyImplementedSupertype: JetType? = getPurelyImplementedSupertype() + for (javaType in javaTypes) { val jetType = c.typeResolver.transformJavaType(javaType, TypeUsage.SUPERTYPE.toAttributes()) if (jetType.isError()) { incomplete.add(javaType) continue } + + if (jetType.getConstructor() == purelyImplementedSupertype?.getConstructor()) { + continue + } + if (!KotlinBuiltIns.isAnyOrNullableAny(jetType)) { result.add(jetType) } } + result.addIfNotNull(purelyImplementedSupertype) + if (incomplete.isNotEmpty()) { c.errorReporter.reportIncompleteHierarchy(getDeclarationDescriptor(), incomplete.map { javaType -> (javaType as JavaClassifierType).getPresentableText() @@ -141,6 +153,40 @@ class LazyJavaClassDescriptor( if (result.isNotEmpty()) result.toReadOnlyList() else listOf(c.module.builtIns.getAnyType()) } + private fun getPurelyImplementedSupertype(): JetType? { + val purelyImplementedFqName = getPurelyImplementsFqNameFromAnnotation() + ?: FakePureImplementationsProvider.getPurelyImplementedInterface(fqName) + ?: return null + + if (purelyImplementedFqName.parent() != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) return null + + val classDescriptor = KotlinBuiltIns.getInstance().getBuiltInClassByNameNullable(purelyImplementedFqName.shortName()) + ?: return null + + if (classDescriptor.getTypeConstructor().getParameters().size() != getParameters().size()) return null + + val parametersAsTypeProjections = getParameters().map { + parameter -> TypeProjectionImpl(Variance.INVARIANT, parameter.getDefaultType()) + } + + return JetTypeImpl( + Annotations.EMPTY, classDescriptor.getTypeConstructor(), + /* nullable =*/ false, parametersAsTypeProjections, + classDescriptor.getMemberScope(parametersAsTypeProjections) + ) + } + + private fun getPurelyImplementsFqNameFromAnnotation(): FqName? { + val annotation = this@LazyJavaClassDescriptor. + getAnnotations(). + findAnnotation(JvmAnnotationNames.PURELY_IMPLEMENTS_ANNOTATION) ?: return null + + val fqNameString = (annotation.getAllValueArguments().values().singleOrNull() as? StringValue)?.getValue() ?: return null + if (!isValidJavaFqName(fqNameString)) return null + + return FqName(fqNameString) + } + override fun getSupertypes(): Collection = supertypes() override fun getAnnotations() = Annotations.EMPTY diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index f7c80e56a14..5c8a0a59259 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -225,8 +225,16 @@ public class KotlinBuiltIns { @NotNull public ClassDescriptor getBuiltInClassByName(@NotNull Name simpleName) { + ClassDescriptor classDescriptor = getBuiltInClassByNameNullable(simpleName); + assert classDescriptor != null : "Must be a class descriptor " + simpleName + ", but was null"; + return classDescriptor; + } + + @Nullable + public ClassDescriptor getBuiltInClassByNameNullable(@NotNull Name simpleName) { ClassifierDescriptor classifier = getBuiltInsPackageFragment().getMemberScope().getClassifier(simpleName); - assert classifier instanceof ClassDescriptor : "Must be a class descriptor " + simpleName + ", but was " + classifier; + assert classifier == null || + classifier instanceof ClassDescriptor : "Must be a class descriptor " + simpleName + ", but was " + classifier; return (ClassDescriptor) classifier; } diff --git a/core/runtime.jvm/src/kotlin/jvm/PurelyImplements.kt b/core/runtime.jvm/src/kotlin/jvm/PurelyImplements.kt new file mode 100644 index 00000000000..3f0d061d69f --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/PurelyImplements.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.jvm + +/** + * Instructs the Kotlin compiler to treat annotated Java class as pure implementation of given Kotlin interface. + * "Pure" means here that each type parameter of class becomes non-platform type argument of that interface. + * + * Example: + * + * class MyList extends AbstractList { ... } + * + * Methods defined in MyList use T as platform, i.e. it's possible to perform unsafe operation in Kotlin: + * MyList().add(null) // compiles + * + * @PurelyImplements("kotlin.MutableList") + * class MyPureList extends AbstractList { ... } + * + * Methods defined in MyPureList overriding methods in MutableList use T as non-platform types: + * MyList().add(null) // Error + * MyList().add(null) // Ok + */ +public annotation class PurelyImplements(public val value: String)