fix for KT-241
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user