Types { public static boolean isSubtype(Type subType, Type superType) { if (Types.isEqual(subType, superType)) return true; if (subType instanceof IntegerType && superType instanceof FloatType) { return true; } if (superType instanceof TopReferenceType && isRefType(subType)) { return true; } if (subType instanceof BottomReferenceType && isRefType(superType)) { return true; } if (subType instanceof ObjectType && superType instanceof ObjectType) { ObjectType subObjType = (ObjectType) subType; List<Property> superTypeProps = ((ObjectType)superType).properties(); for (Property superProp: superTypeProps) { if (!subObjType.hasProperty(superProp.getName())) { return false; } Property subProp = subObjType.getProperty(superProp.getName()); if (!Types.isEqual(superProp.getType(), subProp.getType())) { return false; } if (superProp.isRW() && !subProp.isRW()) { return false; } } return true; } return false; }  static boolean isEqual(Type type1, Type type2); static Type mkArray(Type celltype); static Type mkMap(Type celltype); static ConstructorType mkCtor(List<Type> paramTypes, List<String> paramNames, Type returnType, Type proto); static FunctionType mkFunc(Type ret, List<Type> paramty); static FunctionType mkFunc(Type ret, List<Type> paramty, List<String> params); static boolean isStringType(Type targetType); static boolean isArrayType(Type targetType); static boolean isMapType(Type type); static Type mkAny(); static Type mkVoid(); static FloatType mkFloat(); static StringType mkString(); static BooleanType mkBool(); static IntegerType mkInt(); static Property mkProperty(final String name, final Type ty); static AttachedMethodType mkMethod(final Type thistype, final Type ret, List<Type> pty); static AttachedMethodType mkMethod(final Type thistype, final Type ret, Type... args); static AttachedMethodType mkMethod(Type thistype, Type ret, List<String> pnames, List<Type> pty); static ObjectType mkObject(List<Property> props); static Type mkMapIteratorType(Type t); static boolean isComponentOf(Type type, IntersectionType iType); static boolean isSubtype(Type subType, Type superType); static boolean isRefType(Type t); static boolean usableAsConstructor(Type t); static boolean isSubtypeish(Type subType, Type superType); static Type coarseUpperBound(Type t1, Type t2); static Type coarseLowerBound(Type t1, Type t2); static Type lowestSubtype(Type t);  }
@Test public void testRecursiveSubtype() { ObjectType o1 = new ObjectType(); o1.setProperty("f", o1); ObjectType o2 = new ObjectType(); o2.setProperty("f", o2); Assert.assertTrue(Types.isSubtype(o1, o2)); FunctionType f1 = new FunctionType(oneElementArrayList(null), oneElementArrayList("1"), new VoidType()); f1.setParamType(f1, 0); FunctionType f2 = new FunctionType(oneElementArrayList(null), oneElementArrayList("1"), new VoidType()); f2.setParamType(f2, 0); Assert.assertTrue(Types.isSubtype(f1, f2)); }
@Test public void testMutualRecursiveSubtype() { ObjectType o1 = new ObjectType(); ObjectType o2 = new ObjectType(); o1.setProperty("f", o2); o2.setProperty("f", o1); Assert.assertTrue(Types.isSubtype(o1, o2)); FunctionType f1 = new FunctionType(oneElementArrayList(null), oneElementArrayList("1"), new VoidType()); FunctionType f2 = new FunctionType(oneElementArrayList(null), oneElementArrayList("1"), new VoidType()); f1.setParamType(f2, 0); f2.setParamType(f1, 0); Assert.assertTrue(Types.isSubtype(f1, f2)); }