fix for KT-241

This commit is contained in:
Alex Tkachman
2011-09-03 12:02:42 +02:00
parent 555ebebe1b
commit 672756e459
9 changed files with 127 additions and 30 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other
class Iterator<out T> {
fun next() : T
abstract val hasNext : Boolean
abstract fun hasNext() : Boolean
}
class Iterable<out T> {
@@ -11,11 +11,13 @@ import jet.Range;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection;
@@ -38,20 +40,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private static final String CLASS_STRING = "java/lang/String";
public static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder";
private static final String CLASS_COMPARABLE = "java/lang/Comparable";
private static final String CLASS_ITERABLE = "java/lang/Iterable";
private static final String CLASS_ITERATOR = "java/util/Iterator";
private static final String CLASS_RANGE = "jet/Range";
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
private static final String ITERABLE_ITERATOR_DESCRIPTOR = "()Ljava/util/Iterator;";
private static final String ITERATOR_HASNEXT_DESCRIPTOR = "()Z";
private static final String ITERATOR_NEXT_DESCRIPTOR = "()Ljava/lang/Object;";
private static final Type OBJECT_TYPE = Type.getType(Object.class);
private static final Type INTEGER_TYPE = Type.getType(Integer.class);
private static final Type ITERATOR_TYPE = Type.getType(Iterator.class);
private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
private static final Type STRING_TYPE = Type.getObjectType(CLASS_STRING);
@@ -242,33 +237,43 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
else {
final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
if (declaration instanceof PsiClass) {
final Project project = declaration.getProject();
final PsiClass iterable = JavaPsiFacade.getInstance(project).findClass("java.lang.Iterable", ProjectScope.getAllScope(project));
if (((PsiClass) declaration).isInheritor(iterable, true)) {
generateForInIterable(expression, loopRangeType);
return StackValue.none();
}
}
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses
new ForInRangeLoopGenerator(expression, loopRangeType).invoke();
return StackValue.none();
}
throw new UnsupportedOperationException("for/in loop currently only supported for arrays and Iterable instances");
generateForInIterable(expression, loopRangeType);
return StackValue.none();
}
}
private void generateForInIterable(JetForExpression expression, Type loopRangeType) {
final JetExpression loopRange = expression.getLoopRange();
FunctionDescriptor iteratorDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_ITERATOR, loopRange);
FunctionDescriptor nextDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_NEXT, loopRange);
DeclarationDescriptor hasNextDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_HAS_NEXT, loopRange);
if(iteratorDescriptor == null)
throw new IllegalStateException("No iterator() method " + ErrorHandler.atLocation(loopRange));
if(nextDescriptor == null)
throw new IllegalStateException("No next() method " + ErrorHandler.atLocation(loopRange));
if(hasNextDescriptor == null)
throw new IllegalStateException("No iterator() method " + ErrorHandler.atLocation(loopRange));
final JetParameter loopParameter = expression.getLoopParameter();
final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter);
JetType iteratorType = parameterDescriptor.getOutType();
Type asmIterType = typeMapper.boxType(typeMapper.mapType(iteratorType));
JetType paramType = parameterDescriptor.getOutType();
Type asmParamType = typeMapper.boxType(typeMapper.mapType(paramType));
int iteratorVar = myMap.enterTemp();
gen(expression.getLoopRange(), loopRangeType);
v.invokeinterface(CLASS_ITERABLE, "iterator", ITERABLE_ITERATOR_DESCRIPTOR);
v.store(iteratorVar, ITERATOR_TYPE);
invokeFunctionNoParams(iteratorDescriptor, asmIterType, v);
v.store(iteratorVar, asmIterType);
Label begin = new Label();
Label end = new Label();
@@ -276,13 +281,21 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
myBreakTargets.push(end);
v.mark(begin);
v.load(iteratorVar, ITERATOR_TYPE);
v.invokeinterface(CLASS_ITERATOR, "hasNext", ITERATOR_HASNEXT_DESCRIPTOR);
v.load(iteratorVar, asmIterType);
FunctionDescriptor hND;
if(hasNextDescriptor instanceof FunctionDescriptor) {
hND = (FunctionDescriptor) hasNextDescriptor;
}
else {
hND = ((PropertyDescriptor) hasNextDescriptor).getGetter();
}
invokeFunctionNoParams(hND, Type.BOOLEAN_TYPE, v);
v.ifeq(end);
myMap.enter(parameterDescriptor, asmParamType.getSize());
v.load(iteratorVar, ITERATOR_TYPE);
v.invokeinterface(CLASS_ITERATOR, "next", ITERATOR_NEXT_DESCRIPTOR);
v.load(iteratorVar, asmIterType);
invokeFunctionNoParams(nextDescriptor, asmParamType, v);
// TODO checkcast should be generated via StackValue
if (asmParamType.getSort() == Type.OBJECT && !"java.lang.Object".equals(asmParamType.getClassName())) {
v.checkcast(asmParamType);
@@ -770,11 +783,36 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return myMap.getIndex(descriptor);
}
public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type type, InstructionAdapterEx v) {
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl;
functionDescriptor = functionDescriptor.getOriginal();
String owner;
boolean isInterface;
boolean isInsideClass = containingDeclaration == contextType();
if (isInsideClass || isStatic) {
owner = typeMapper.getOwner(functionDescriptor, contextKind());
isInterface = false;
}
else {
owner = typeMapper.getOwner(functionDescriptor, OwnerKind.INTERFACE);
if(containingDeclaration instanceof JavaClassDescriptor) {
PsiClass psiElement = (PsiClass) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, containingDeclaration);
isInterface = psiElement.isInterface();
}
else
isInterface = !(containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isObject());
}
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, functionDescriptor.getName(), typeMapper.mapSignature(functionDescriptor.getName(),functionDescriptor).getDescriptor());
StackValue.onStack(typeMapper.mapType(functionDescriptor.getReturnType())).coerce(type, v);
}
public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl;
while(propertyDescriptor != propertyDescriptor.getOriginal())
propertyDescriptor = propertyDescriptor.getOriginal();
propertyDescriptor = propertyDescriptor.getOriginal();
final JetType outType = propertyDescriptor.getOutType();
boolean isInsideClass = !forceInterface && containingDeclaration == contextType();
Method getter;
@@ -1779,7 +1817,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.anew(JetTypeMapper.TYPE_TYPEINFO);
v.dup();
v.aconst(jvmType);
v.aconst(jetType.isNullable());
v.iconst(jetType.isNullable()?1:0);
List<TypeProjection> arguments = jetType.getArguments();
if (arguments.size() > 0) {
v.iconst(arguments.size());
@@ -133,7 +133,7 @@ public class FunctionCodegen {
if(overriddenFunctions.size() > 0) {
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
// TODO should we check params here as well?
if(!JetTypeImpl.equalTypes(overriddenFunction.getReturnType(), functionDescriptor.getReturnType(), JetTypeImpl.EMPTY_AXIOMS)) {
if(!JetTypeImpl.equalTypeClasses(overriddenFunction.getReturnType(), functionDescriptor.getReturnType())) {
generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction));
}
}
@@ -39,7 +39,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
this.isVar = isVar;
this.memberModifiers = memberModifiers;
this.receiverType = receiverType;
this.original = original == null ? this : original;
this.original = original == null ? this : original.getOriginal();
}
public PropertyDescriptor(
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.types;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotatedImpl;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
@@ -114,6 +115,10 @@ public final class JetTypeImpl extends AnnotatedImpl implements JetType {
}
public static boolean equalTypeClasses(@NotNull JetType type1, @NotNull JetType type2) {
return type1.getConstructor().getDeclarationDescriptor().getOriginal().equals(type2.getConstructor().getDeclarationDescriptor().getOriginal());
}
public static boolean equalTypes(@NotNull JetType type1, @NotNull JetType type2, @NotNull BiMap<TypeConstructor, TypeConstructor> equalityAxioms) {
if (type1.isNullable() != type2.isNullable()) {
return false;
@@ -2078,7 +2078,7 @@ public class JetTypeInferrer {
boolean hasNextPropertySupported = hasNextProperty != null;
if (hasNextFunctionSupported && hasNextPropertySupported && !ErrorUtils.isErrorType(iteratorType)) {
// TODO : overload resolution rules impose priorities here???
context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext()' property");
context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext' property");
}
else if (!hasNextFunctionSupported && !hasNextPropertySupported) {
context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().hasNext()' function or an 'iterator().hasNext' property");
@@ -0,0 +1,45 @@
fun box() : String {
val c5 = MyCollection3()
for (el in c5) {}
val c1: java.lang.Iterable<Int> = MyCollection1()
for (el in c1) {}
val c2 = MyCollection1()
for (el in c2) {}
/*
val c3: Iterable<Int> = MyCollection2()
for (el in c3) {}
val c4 = MyCollection2()
for (el in c4) {}
*/
return "OK"
}
class MyCollection1(): java.lang.Iterable<Int> {
fun iterator(): java.util.Iterator<Int> = MyIterator()
class MyIterator(): java.util.Iterator<Int> {
fun next() = 0
fun hasNext() = false
}
}
class MyCollection2(): Iterable<Int> {
fun iterator(): Iterator<Int> = MyIterator()
class MyIterator(): Iterator<Int> {
fun next() = 0
fun hasNext() = false
}
}
class MyCollection3() {
fun iterator() = MyIterator()
class MyIterator() {
fun next() = 0
fun hasNext() = false
}
}
@@ -39,6 +39,11 @@ fun t3 () : Boolean {
if(d.isT(10)) return false
if(!d.isT(null)) return false
val f = B<java.lang.String?>()
if(!f.isT("aaa")) return false
if(f.isT(10)) return false
if(!f.isT(null)) return false
val c = B<Int>()
if(c.isT("aaa")) return false
if(!c.isT(10)) return false
@@ -140,4 +140,8 @@ public class ControlStructuresTest extends CodegenTestCase {
assertTrue(caught);
assertEquals("foobar", sb.toString());
}
public void testForUserType() throws Exception {
blackBoxFile("controlStructures/forUserType.jet");
}
}