generates remove method
throwing exception in Kotlin class extending Iterator
This commit is contained in:
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
|||||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -64,6 +65,8 @@ public abstract class ClassBodyCodegen {
|
|||||||
generateSyntheticParts();
|
generateSyntheticParts();
|
||||||
|
|
||||||
generateStaticInitializer();
|
generateStaticInitializer();
|
||||||
|
|
||||||
|
generateRemoveInIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void generateDeclaration();
|
protected abstract void generateDeclaration();
|
||||||
@@ -137,4 +140,12 @@ public abstract class ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateRemoveInIterator() {
|
||||||
|
// generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator
|
||||||
|
if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) {
|
||||||
|
final MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "remove", "()V", null, null);
|
||||||
|
CodegenUtil.generateMethodThrow(mv, "java/lang/UnsupportedOperationException", "Mutating method called on a Kotlin Iterator");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ package org.jetbrains.jet.codegen;
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.asm4.MethodVisitor;
|
||||||
|
import org.jetbrains.asm4.Type;
|
||||||
|
import org.jetbrains.asm4.commons.InstructionAdapter;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
@@ -121,4 +124,20 @@ public class CodegenUtil {
|
|||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void generateThrow(MethodVisitor mv, String exception, String message) {
|
||||||
|
InstructionAdapter instructionAdapter = new InstructionAdapter(mv);
|
||||||
|
instructionAdapter.anew(Type.getObjectType(exception));
|
||||||
|
instructionAdapter.dup();
|
||||||
|
instructionAdapter.aconst(message);
|
||||||
|
instructionAdapter.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
|
||||||
|
instructionAdapter.athrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateMethodThrow(MethodVisitor mv, String exception, String message) {
|
||||||
|
mv.visitCode();
|
||||||
|
generateThrow(mv, exception, message);
|
||||||
|
mv.visitMaxs(-1, -1);
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,29 +17,22 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
import org.jetbrains.asm4.MethodVisitor;
|
import org.jetbrains.asm4.MethodVisitor;
|
||||||
import org.jetbrains.asm4.Type;
|
|
||||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Stepan Koltsov
|
* @author Stepan Koltsov
|
||||||
*/
|
*/
|
||||||
public class StubCodegen {
|
public class StubCodegen {
|
||||||
|
private static String STUB_EXCEPTION = "java/lang/RuntimeException";
|
||||||
|
private static String STUB_EXCEPTION_MESSAGE = "Stubs are for compiler only, do not add them to runtime classpath";
|
||||||
|
|
||||||
private StubCodegen() {
|
private StubCodegen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateStubThrow(MethodVisitor mv) {
|
public static void generateStubThrow(MethodVisitor mv) {
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
CodegenUtil.generateThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
|
||||||
iv.anew(Type.getObjectType("java/lang/RuntimeException"));
|
|
||||||
iv.dup();
|
|
||||||
iv.aconst("Stubs are for compiler only, do not add them to runtime classpath");
|
|
||||||
iv.invokespecial("java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
|
|
||||||
iv.athrow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateStubCode(MethodVisitor mv) {
|
public static void generateStubCode(MethodVisitor mv) {
|
||||||
mv.visitCode();
|
CodegenUtil.generateMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
|
||||||
generateStubThrow(mv);
|
|
||||||
mv.visitMaxs(-1, -1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
|||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
||||||
|
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -345,4 +347,22 @@ public class DescriptorUtils {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isIteratorWithoutRemoveImpl(@NotNull ClassDescriptor classDescriptor) {
|
||||||
|
ClassDescriptor iteratorOfT = JetStandardLibrary.getInstance().getIterator();
|
||||||
|
JetType iteratorOfAny = TypeUtils.substituteParameters(iteratorOfT, Collections.singletonList(JetStandardClasses.getAnyType()));
|
||||||
|
boolean isIterator = JetTypeChecker.INSTANCE.isSubtypeOf(classDescriptor.getDefaultType(), iteratorOfAny);
|
||||||
|
boolean hasRemove = hasMethod(classDescriptor, Name.identifier("remove"));
|
||||||
|
return isIterator && !hasRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasMethod(ClassDescriptor classDescriptor, Name name) {
|
||||||
|
Collection<FunctionDescriptor> removeFunctions = classDescriptor.getDefaultType().getMemberScope().getFunctions(name);
|
||||||
|
for (FunctionDescriptor function : removeFunctions) {
|
||||||
|
if (function.getValueParameters().isEmpty() && function.getTypeParameters().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
public class removeInIterator {
|
||||||
|
public static void bar(java.util.Iterator<Integer> it) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
fun box() : String {
|
||||||
|
try {
|
||||||
|
removeInIterator.bar(object : Iterator<Int> {
|
||||||
|
public override fun hasNext(): Boolean = false
|
||||||
|
public override fun next(): Int = 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
catch (e: UnsupportedOperationException) {
|
||||||
|
if (e.getMessage() == "Mutating method called on a Kotlin Iterator")
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
return "fail"
|
||||||
|
}
|
||||||
@@ -180,5 +180,9 @@ public class FunctionGenTest extends CodegenTestCase {
|
|||||||
public void testReferencesStaticInnerClassMethodTwoLevels() throws Exception {
|
public void testReferencesStaticInnerClassMethodTwoLevels() throws Exception {
|
||||||
blackBoxFileWithJava("functions/referencesStaticInnerClassMethodL2.kt");
|
blackBoxFileWithJava("functions/referencesStaticInnerClassMethodL2.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testRemoveInIterator() throws Exception {
|
||||||
|
blackBoxFileWithJava("functions/removeInIterator.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user