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.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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user