KT-9377 Support is-checks for read-only collections

Marker interfaces for mutable Kotlin collections and related classes.
This commit is contained in:
Dmitry Petrov
2015-09-30 15:06:13 +03:00
parent e91c556d06
commit 35881198c3
11 changed files with 266 additions and 2 deletions
@@ -45,6 +45,8 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass;
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -296,6 +298,27 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private static Map<String, String> KOTLIN_MARKER_INTERFACES = new HashMap<String, String>();
static {
KOTLIN_MARKER_INTERFACES.put("kotlin.Iterator", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.Iterable", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.Collection", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.List", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.ListIterator", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.Set", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.Map", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.Map.Entry", "kotlin/jvm/internal/KMappedMarker");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableIterator", "kotlin/jvm/internal/KMutableIterator");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableIterable", "kotlin/jvm/internal/KMutableIterable");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableCollection", "kotlin/jvm/internal/KMutableCollection");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableList", "kotlin/jvm/internal/KMutableList");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableListIterator", "kotlin/jvm/internal/KMutableListIterator");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableSet", "kotlin/jvm/internal/KMutableSet");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableMap", "kotlin/jvm/internal/KMutableMap");
KOTLIN_MARKER_INTERFACES.put("kotlin.MutableMap.MutableEntry", "kotlin/jvm/internal/KMutableMap$Entry");
}
@NotNull
private JvmClassSignature signature() {
BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS);
@@ -313,15 +336,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
sw.writeSuperclassEnd();
LinkedHashSet<String> superInterfaces = new LinkedHashSet<String>();
Set<String> kotlinMarkerInterfaces = new LinkedHashSet<String>();
for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) {
if (isJvmInterface(supertype.getConstructor().getDeclarationDescriptor())) {
sw.writeInterface();
Type jvmName = typeMapper.mapSupertype(supertype, sw);
Type jvmInterfaceType = typeMapper.mapSupertype(supertype, sw);
sw.writeInterfaceEnd();
superInterfaces.add(jvmName.getInternalName());
String jvmInterfaceInternalName = jvmInterfaceType.getInternalName();
superInterfaces.add(jvmInterfaceInternalName);
String kotlinInterfaceName = DescriptorUtils.getFqName(supertype.getConstructor().getDeclarationDescriptor()).asString();
String kotlinMarkerInterfaceInternalName = KOTLIN_MARKER_INTERFACES.get(kotlinInterfaceName);
if (kotlinMarkerInterfaceInternalName != null) {
kotlinMarkerInterfaces.add(kotlinMarkerInterfaceInternalName);
}
}
}
for (String kotlinMarkerInterface : kotlinMarkerInterfaces) {
sw.writeInterface();
sw.writeAsmType(Type.getObjectType(kotlinMarkerInterface));
sw.writeInterfaceEnd();
}
superInterfaces.addAll(kotlinMarkerInterfaces);
return new JvmClassSignature(classAsmType.getInternalName(), superClassAsmType.getInternalName(),
new ArrayList<String>(superInterfaces), sw.makeJavaGenericSignature());
@@ -0,0 +1,57 @@
import kotlin.reflect.jvm.*
abstract class Itr : Iterator<String>
abstract class MItr : MutableIterator<String>
abstract class LItr : ListIterator<String>
abstract class MLItr : MutableListIterator<String>
abstract class It : Iterable<String>
abstract class MIt : MutableIterable<String>
abstract class C : Collection<String>
abstract class MC : MutableCollection<String>
abstract class L : List<String>
abstract class ML : MutableList<String>
abstract class S : Set<String>
abstract class MS : MutableSet<String>
abstract class M : Map<String, String>
abstract class MM : MutableMap<String, String>
abstract class ME : Map.Entry<String, String>
abstract class MME : MutableMap.MutableEntry<String, String>
abstract class L2 : L()
abstract class ML2 : ML()
abstract class Weird : Iterator<String>, MutableList<String>
fun expectInterfaces(jClass: Class<*>, expectedInterfaceNames: Set<String>) {
val actualInterfaceNames = jClass.getInterfaces().mapTo(linkedSetOf<String>()) { it.name }
assert(actualInterfaceNames == expectedInterfaceNames) {
"${jClass.name}: interfaces: expected: $expectedInterfaceNames; actual: $actualInterfaceNames"
}
}
fun box(): String {
expectInterfaces(Itr::class.java, setOf("java.util.Iterator", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MItr::class.java, setOf("java.util.Iterator", "kotlin.jvm.internal.KMutableIterator"))
expectInterfaces(LItr::class.java, setOf("java.util.ListIterator", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MLItr::class.java, setOf("java.util.ListIterator", "kotlin.jvm.internal.KMutableListIterator"))
expectInterfaces(It::class.java, setOf("java.lang.Iterable", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MIt::class.java, setOf("java.lang.Iterable", "kotlin.jvm.internal.KMutableIterable"))
expectInterfaces(C::class.java, setOf("java.util.Collection", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MC::class.java, setOf("java.util.Collection", "kotlin.jvm.internal.KMutableCollection"))
expectInterfaces(L::class.java, setOf("java.util.List", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(ML::class.java, setOf("java.util.List", "kotlin.jvm.internal.KMutableList"))
expectInterfaces(S::class.java, setOf("java.util.Set", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MS::class.java, setOf("java.util.Set", "kotlin.jvm.internal.KMutableSet"))
expectInterfaces(M::class.java, setOf("java.util.Map", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MM::class.java, setOf("java.util.Map", "kotlin.jvm.internal.KMutableMap"))
expectInterfaces(ME::class.java, setOf("java.util.Map\$Entry", "kotlin.jvm.internal.KMappedMarker"))
expectInterfaces(MME::class.java, setOf("java.util.Map\$Entry", "kotlin.jvm.internal.KMutableMap\$Entry"))
expectInterfaces(L2::class.java, setOf<String>())
expectInterfaces(ML2::class.java, setOf<String>())
expectInterfaces(Weird::class.java,
setOf("java.util.Iterator", "kotlin.jvm.internal.KMappedMarker",
"java.util.List", "kotlin.jvm.internal.KMutableList"))
return "OK"
}
@@ -954,6 +954,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/classes/kt8011.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("mutabilityMarkerInterfaces.kt")
public void testMutabilityMarkerInterfaces() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/classes/mutabilityMarkerInterfaces.kt");
doTestWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/controlStructures")
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMappedMarker {
}
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMutableCollection extends KMutableIterable {
}
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMutableIterable extends KMappedMarker {
}
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMutableIterator extends KMappedMarker {
}
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMutableList extends KMutableCollection {
}
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMutableListIterator extends KMutableIterator {
}
@@ -0,0 +1,22 @@
/*
* 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.internal;
public interface KMutableMap extends KMappedMarker {
interface Entry extends KMappedMarker {
}
}
@@ -0,0 +1,20 @@
/*
* 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.internal;
public interface KMutableSet extends KMutableCollection {
}