diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index b7b1a4a3d9b..d4140c3c47d 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1740,7 +1740,22 @@ public class ExpressionCodegen extends JetVisitor { v.dup(); } Type type = typeMapper.boxType(typeMapper.mapType(jetType, OwnerKind.INTERFACE)); - v.instanceOf(type); + if(jetType.isNullable()) { + Label nope = new Label(); + Label end = new Label(); + + v.dup(); + v.ifnull(nope); + v.instanceOf(type); + v.goTo(end); + v.mark(nope); + v.pop(); + v.aconst(1); + v.mark(end); + } + else { + v.instanceOf(type); + } } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index f4a58ef411e..cb44761b03e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -11,6 +11,7 @@ import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; @@ -1708,7 +1709,7 @@ public class JetTypeInferrer { return; } if (TypeUtils.intersect(semanticServices.getTypeChecker(), Sets.newHashSet(type, subjectType)) == null) { - context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType); // TODO : message + context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType + " " + ErrorHandler.atLocation(reportErrorOn)); } } diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet index d2ca498a3b9..e4a1b9099d8 100644 --- a/idea/testData/codegen/regressions/kt259.jet +++ b/idea/testData/codegen/regressions/kt259.jet @@ -1,20 +1,66 @@ class A() {} -class B() {} +class B() { + fun isT (a : Any?) : Boolean { + return a is T + } +} -fun box() : String { +fun t1() : Boolean { val a = A() - System.out?.println(a is A) //true - System.out?.println(a is A?) //true + if(a !is A) return false + if(a !is A?) return false + if(null !is A?) return false + return true +} +fun t2 () : Boolean { val b = B() - System.out?.println(b is B) //true - System.out?.println(b is B?) //false !!! + if(b !is B) return false + if(b !is B?) return false + if(null !is B?) return false val v = b as B //ok val u = b as B? //TypeCastException val w : B? = b as B //ok val x = w as B? //TypeCastException + return true +} +fun t3 () : Boolean { + val b = B() + if(!b.isT("aaa")) return false + + if(b.isT(10)) return false + if(b.isT(null)) return false + + val d = B() + if(!d.isT("aaa")) return false + if(d.isT(10)) return false + if(!d.isT(null)) return false + + val c = B() + if(c.isT("aaa")) return false + if(!c.isT(10)) return false + if(c.isT(null)) return false + + val e = B() + if(e.isT("aaa")) return false + if(!e.isT(10)) return false + if(!e.isT(null)) return false + + return true +} + +fun box() : String { + if(!t1()) { + return "t1 failed" + } + if(!t2()) { + return "t2 failed" + } + if(!t3()) { + return "t3 failed" + } return "OK" } \ No newline at end of file diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index ec93f487468..55f848c7b2c 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -40,25 +40,28 @@ public class TypeInfo implements JetObject { public boolean isInstance(Object obj) { if (obj instanceof JetObject) { - return isSubtypeOf(((JetObject) obj).getTypeInfo()); + return ((JetObject) obj).getTypeInfo().isSubtypeOf(this); } - throw new UnsupportedOperationException(); // TODO + if(obj == null) + return nullable; + + return theClass.isAssignableFrom(obj.getClass()); // TODO } - public boolean isSubtypeOf(TypeInfo other) { - if (!theClass.isAssignableFrom(other.theClass)) { + public boolean isSubtypeOf(TypeInfo superType) { + if (!superType.theClass.isAssignableFrom(theClass)) { return false; } - if (!nullable && other.nullable) { + if (nullable && !superType.nullable) { return false; } if (typeParameters != null) { - if (other.typeParameters == null || other.typeParameters.length != typeParameters.length) { + if (superType.typeParameters == null || superType.typeParameters.length != typeParameters.length) { throw new IllegalArgumentException("inconsistent type infos for the same class"); } for (int i = 0; i < typeParameters.length; i++) { // TODO handle variance here - if (!typeParameters [i].equals(other.typeParameters [i])) { + if (!typeParameters [i].equals(superType.typeParameters [i])) { return false; } } @@ -95,9 +98,22 @@ public class TypeInfo implements JetObject { @Override public int hashCode() { - int result = theClass.hashCode(); - result = 31 * result + (typeParameters != null ? Arrays.hashCode(typeParameters) : 0); - return result; + return 31 * theClass.hashCode() + (typeParameters != null ? Arrays.hashCode(typeParameters) : 0); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder().append(theClass.getName()); + if(typeParameters != null && typeParameters.length != 0) { + sb.append("<"); + for(int i = 0; i != typeParameters.length-1; ++i) { + sb.append(typeParameters[i].toString()).append(","); + } + sb.append(typeParameters[typeParameters.length - 1].toString()).append(">"); + } + if(nullable) + sb.append("?"); + return sb.toString(); } public static final TypeInfo BYTE_TYPE_INFO = new TypeInfo(Byte.class, false);