generates remove method

throwing exception
in Kotlin class extending Iterator
This commit is contained in:
Svetlana Isakova
2012-08-15 19:46:35 +04:00
parent 293452e375
commit 96d99d19f3
7 changed files with 77 additions and 12 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -64,6 +65,8 @@ public abstract class ClassBodyCodegen {
generateSyntheticParts();
generateStaticInitializer();
generateRemoveInIterator();
}
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 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.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
@@ -121,4 +124,20 @@ public class CodegenUtil {
}
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;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
/**
* @author Stepan Koltsov
*/
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() {
}
public static void generateStubThrow(MethodVisitor mv) {
InstructionAdapter iv = new InstructionAdapter(mv);
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();
CodegenUtil.generateThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
}
public static void generateStubCode(MethodVisitor mv) {
mv.visitCode();
generateStubThrow(mv);
mv.visitMaxs(-1, -1);
mv.visitEnd();
CodegenUtil.generateMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
}
}
@@ -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.scopes.receivers.ReceiverDescriptor;
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.JetStandardLibrary;
import java.util.*;
@@ -345,4 +347,22 @@ public class DescriptorUtils {
}
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 {
blackBoxFileWithJava("functions/referencesStaticInnerClassMethodL2.kt");
}
public void testRemoveInIterator() throws Exception {
blackBoxFileWithJava("functions/removeInIterator.kt");
}
}
}