Add PurelyImplements annotation

It's parameter is FQ-name of class (currently only from builtins) that added as supertype to annotated Java class.

Parameters of annotated class used as non-flexible arguments of added supertype, that helps to propagate more precise types when using in Kotlin.
Some standard JDK collections loaded as they annotated with PurelyImplements.

See tests for clarification.
Before: ArrayList<Int>.add(x: Int!) // possible to add null
After: ArrayList<Int>.add(x: Int)   // impossible to add null

 #KT-7628 Fixed
 #KT-7835 Fixed
This commit is contained in:
Denis Zharkov
2015-07-01 15:31:18 +03:00
parent 8120513465
commit 8b49a1d660
24 changed files with 724 additions and 4 deletions
@@ -0,0 +1,22 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
fun bar(): String? = null
fun foo() {
var x = ArrayList<String>()
x.<!NONE_APPLICABLE!>add<!>(null)
x.<!NONE_APPLICABLE!>add<!>(bar())
x.add("")
x[0] = <!NULL_FOR_NONNULL_TYPE!>null<!>
x[0] = <!TYPE_MISMATCH!>bar()<!>
x[0] = ""
val b1: MutableList<String?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableList<String> = x
val b3: List<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = <!TYPE_MISMATCH!>x<!>
}
@@ -0,0 +1,4 @@
package
internal fun bar(): kotlin.String?
internal fun foo(): kotlin.Unit
@@ -0,0 +1,22 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
fun bar(): String? = null
fun foo() {
var x = ArrayList<String?>()
x.add(null)
x.add(bar())
x.add("")
x[0] = null
x[0] = bar()
x[0] = ""
val b1: MutableList<String?> = x
val b2: MutableList<String> = <!TYPE_MISMATCH!>x<!>
val b3: List<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = x
}
@@ -0,0 +1,4 @@
package
internal fun bar(): kotlin.String?
internal fun foo(): kotlin.Unit
@@ -0,0 +1,31 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
// FILE: A.java
@kotlin.jvm.PurelyImplements("kotlin.MutableCollection")
class A<T> extends AbstractCollection<T> {
@Override
public Iterator<T> iterator() {
return null;
}
@Override
public int size() {
return 0;
}
}
// FILE: b.kt
fun bar(): String? = null
fun foo() {
var x = A<String>()
x.add(<!NULL_FOR_NONNULL_TYPE!>null<!>)
x.add(<!TYPE_MISMATCH!>bar()<!>)
x.add("")
val b1: Collection<String?> = x
val b2: MutableCollection<String?> = <!TYPE_MISMATCH!>x<!>
}
@@ -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</*0*/ T> : java.util.AbstractCollection<T!>, kotlin.MutableCollection<T> {
public/*package*/ constructor A</*0*/ T>()
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<T>): 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.Any?>): 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<T>
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.Any?>): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun retainAll(/*0*/ c: kotlin.Collection<kotlin.Any?>): 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 </*0*/ T> toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>!
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,39 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
// FILE: A.java
@kotlin.jvm.PurelyImplements("kotlin.MutableList")
class A<T> extends AbstractList<T> {
@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<String>()
x.<!NONE_APPLICABLE!>add<!>(null)
x.<!NONE_APPLICABLE!>add<!>(bar())
x.add("")
x[0] = <!NULL_FOR_NONNULL_TYPE!>null<!>
x[0] = <!TYPE_MISMATCH!>bar()<!>
x[0] = ""
val b1: MutableList<String?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableList<String> = x
val b3: List<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = <!TYPE_MISMATCH!>x<!>
}
@@ -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</*0*/ T> : java.util.AbstractList<T!>, kotlin.MutableList<T> {
public/*package*/ constructor A</*0*/ T>()
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<T>): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun addAll(/*0*/ index: kotlin.Int, /*1*/ c: kotlin.Collection<T>): 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.Any?>): 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<T>
public open override /*2*/ /*fake_override*/ fun lastIndexOf(/*0*/ o: kotlin.Any?): kotlin.Int
public open override /*2*/ /*fake_override*/ fun listIterator(): kotlin.MutableListIterator<T>
public open override /*2*/ /*fake_override*/ fun listIterator(/*0*/ index: kotlin.Int): kotlin.MutableListIterator<T>
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.Any?>): 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.Any?>): 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<T>
public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>!
public open override /*1*/ /*fake_override*/ fun </*0*/ T> toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>!
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -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<String, Int> = HashMap<String, Int>()
x.put(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put(<!TYPE_MISMATCH!>bar()<!>, 1)
x.put("", 1)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[null]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[bar()]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[""]<!> = nullableInt
x[""] = 1
val b1: MutableMap<String, Int?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String, Int> = x
val b3: Map<String?, Int> = <!TYPE_MISMATCH!>x<!>
val b4: Map<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b5: Map<String, Int?> = x
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b8: Int? = x.get("")
}
fun treeMapTest() {
var x: TreeMap<String, Int> = TreeMap<String, Int>()
x.put(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put(<!TYPE_MISMATCH!>bar()<!>, 1)
x.put("", 1)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[null]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[bar()]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[""]<!> = nullableInt
x[""] = 1
val b1: MutableMap<String, Int?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String, Int> = x
val b3: Map<String?, Int> = <!TYPE_MISMATCH!>x<!>
val b4: Map<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b5: Map<String, Int?> = x
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b8: Int? = x.get("")
}
fun concurrentHashMapTest() {
var x: ConcurrentHashMap<String, Int> = ConcurrentHashMap<String, Int>()
x.put(<!NULL_FOR_NONNULL_TYPE!>null<!>, <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put(<!TYPE_MISMATCH!>bar()<!>, 1)
x.put("", 1)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[null]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[bar()]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[""]<!> = nullableInt
x[""] = 1
val b1: MutableMap<String, Int?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String, Int> = x
val b3: Map<String?, Int> = <!TYPE_MISMATCH!>x<!>
val b4: Map<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b5: Map<String, Int?> = x
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b8: Int? = x.get("")
}
@@ -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
@@ -0,0 +1,54 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
fun bar(): String? = null
val nullableInt: Int? = null
fun hashMapTest() {
var x: HashMap<String?, Int> = HashMap<String?, Int>()
x.put(null, <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put(bar(), 1)
x.put("", 1)
x[null] = 1
x[bar()] = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[""]<!> = nullableInt
x[""] = 1
val b1: MutableMap<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String?, Int> = x
val b3: Map<String?, Int> = x
val b4: Map<String?, Int?> = x
val b5: Map<String, Int?> = <!TYPE_MISMATCH!>x<!>
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x[null]<!>
val b8: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b9: Int? = x.get("")
}
fun treeMapTest() {
var x: TreeMap<String?, Int> = TreeMap<String?, Int>()
x.put(null, <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
x.put(bar(), 1)
x.put("", 1)
x[null] = 1
x[bar()] = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[""]<!> = nullableInt
x[""] = 1
val b1: MutableMap<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String?, Int> = x
val b3: Map<String?, Int> = x
val b4: Map<String?, Int?> = x
val b5: Map<String, Int?> = <!TYPE_MISMATCH!>x<!>
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b8: Int? = x.get("")
}
@@ -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
@@ -0,0 +1,53 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
fun bar(): String? = null
val nullableInt: Int? = null
fun hashMapTest() {
var x: HashMap<String, Int?> = HashMap<String, Int?>()
x.put(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
x.put("", null)
x.put(<!TYPE_MISMATCH!>bar()<!>, 1)
x.put("", 1)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[null]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[bar()]<!> = 1
x[""] = nullableInt
x[""] = 1
val b1: MutableMap<String, Int> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String, Int?> = x
val b3: Map<String, Int> = <!TYPE_MISMATCH!>x<!>
val b4: Map<String, Int?> = x
val b5: Map<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b8: Int? = x.get("")
}
fun treeMapTest() {
var x: TreeMap<String, Int?> = TreeMap<String, Int?>()
x.put(<!NULL_FOR_NONNULL_TYPE!>null<!>, null)
x.put("", null)
x.put(<!TYPE_MISMATCH!>bar()<!>, 1)
x.put("", 1)
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[null]<!> = 1
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>x[bar()]<!> = 1
x[""] = nullableInt
x[""] = 1
val b1: MutableMap<String, Int> = <!TYPE_MISMATCH!>x<!>
val b2: MutableMap<String, Int?> = x
val b3: Map<String, Int> = <!TYPE_MISMATCH!>x<!>
val b4: Map<String, Int?> = x
val b5: Map<String?, Int?> = <!TYPE_MISMATCH!>x<!>
val b6: Int = <!TYPE_MISMATCH!>x[""]<!>
val b7: Int = <!TYPE_MISMATCH!>x.get("")<!>
val b8: Int? = x.get("")
}
@@ -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
@@ -0,0 +1,46 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
fun bar(): String? = null
fun fooHashSet() {
var x = HashSet<String>()
x.add(<!NULL_FOR_NONNULL_TYPE!>null<!>)
x.add(<!TYPE_MISMATCH!>bar()<!>)
x.add("")
val b1: MutableSet<String?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableSet<String> = x
val b3: Set<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = <!TYPE_MISMATCH!>x<!>
}
fun fooTreeSet() {
var x = TreeSet<String>()
x.add(<!NULL_FOR_NONNULL_TYPE!>null<!>)
x.add(<!TYPE_MISMATCH!>bar()<!>)
x.add("")
val b1: MutableSet<String?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableSet<String> = x
val b3: Set<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = <!TYPE_MISMATCH!>x<!>
}
fun fooLinkedHashSet() {
var x = LinkedHashSet<String>()
x.add(<!NULL_FOR_NONNULL_TYPE!>null<!>)
x.add(<!TYPE_MISMATCH!>bar()<!>)
x.add("")
val b1: MutableSet<String?> = <!TYPE_MISMATCH!>x<!>
val b2: MutableSet<String> = x
val b3: Set<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = <!TYPE_MISMATCH!>x<!>
}
@@ -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
@@ -0,0 +1,39 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
import java.util.*
// FILE: A.java
@kotlin.jvm.PurelyImplements("kotlin.MutableList")
class A<T, V> extends AbstractList<T> {
@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<String, String>()
x.add(null)
x.add(bar())
x.add("")
x[0] = null
x[0] = bar()
x[0] = ""
val b1: MutableList<String?> = x
val b2: MutableList<String> = x
val b3: List<String?> = x
val b4: Collection<String?> = x
val b6: MutableCollection<String?> = x
}
@@ -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</*0*/ T, /*1*/ V> : java.util.AbstractList<T!> {
public/*package*/ constructor A</*0*/ T, /*1*/ V>()
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<T!>): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun addAll(/*0*/ index: kotlin.Int, /*1*/ c: kotlin.Collection<T!>): 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.Any?>): 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<T!>
public open override /*1*/ /*fake_override*/ fun lastIndexOf(/*0*/ o: kotlin.Any?): kotlin.Int
public open override /*1*/ /*fake_override*/ fun listIterator(): kotlin.MutableListIterator<T!>
public open override /*1*/ /*fake_override*/ fun listIterator(/*0*/ index: kotlin.Int): kotlin.MutableListIterator<T!>
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.Any?>): 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.Any?>): 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<T!>
public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>!
public open override /*1*/ /*fake_override*/ fun </*0*/ T> toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -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)
@@ -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()
@@ -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 =
@@ -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<JetType>(javaTypes.size())
val incomplete = ArrayList<JavaType>(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<JetType> = supertypes()
override fun getAnnotations() = Annotations.EMPTY
@@ -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;
}
@@ -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<T> extends AbstractList<T> { ... }
*
* Methods defined in MyList<T> use T as platform, i.e. it's possible to perform unsafe operation in Kotlin:
* MyList<Int>().add(null) // compiles
*
* @PurelyImplements("kotlin.MutableList")
* class MyPureList<T> extends AbstractList<T> { ... }
*
* Methods defined in MyPureList<T> overriding methods in MutableList use T as non-platform types:
* MyList<Int>().add(null) // Error
* MyList<Int?>().add(null) // Ok
*/
public annotation class PurelyImplements(public val value: String)