package freeboogie.tc; import java.io.StringWriter; import freeboogie.ast.*; import freeboogie.ast.utils.PrettyPrinter; /** * Various utilities for handling {@code Type}. For the moment, it contains * a structural equality test that ignores AST locations. * * @author rgrig * @author reviewed by TODO */ public class TypeUtils { // TODO: reuse this code for TypeChecker.sub. how? private static boolean eq(ArrayType a, ArrayType b) { return eq(a.getElemType(), b.getElemType()) && eq(a.getRowType(), b.getRowType()) && eq(a.getColType(), b.getColType()); } private static boolean eq(PrimitiveType a, PrimitiveType b) { return a.getPtype() == b.getPtype(); } private static boolean eq(GenericType a, GenericType b) { return eq(a.getParam(), b.getParam()) && eq(a.getType(), b.getType()); } private static boolean eq(UserType a, UserType b) { return a.getName().equals(b.getName()); } private static boolean eq(TupleType a, TupleType b) { if (a == b) return true; if (a == null ^ b == null) return false; return eq(a.getType(), b.getType()) && eq(a.getTail(), b.getTail()); } /** * Recursively strip all dependent types from {@code a}. * @param a the type to strip of predicates * @return the type {@code a} striped of predicates */ public static Type stripDep(Type a) { if (a instanceof ArrayType) { ArrayType sa = (ArrayType)a; return ArrayType.mk(stripDep(sa.getRowType()), stripDep(sa.getColType()), stripDep(sa.getElemType())); } else if (a instanceof GenericType) { GenericType sa = (GenericType)a; return GenericType.mk(stripDep(sa.getParam()), stripDep(sa.getType())); } else if (a instanceof TupleType) { TupleType sa = (TupleType)a; return TupleType.mk(stripDep(sa.getType()), (TupleType)stripDep(sa.getTail())); } else if (a instanceof DepType) return stripDep(((DepType)a).getType()); else return a; } private static Declaration stripDep(Declaration a) { if (!(a instanceof VariableDecl)) return a; VariableDecl va = (VariableDecl)a; return VariableDecl.mk(va.getName(), stripDep(va.getType()), stripDep(va.getTail()), va.loc()); } /** * Returns a signature that looks like {@code s} but has all predicates * of dependent types removed. * @param s the signature to strip * @return the signature {@code s} without dependent types */ public static Signature stripDep(Signature s) { return Signature.mk(s.getName(), stripDep(s.getArgs()), stripDep(s.getResults()), s.loc()); } /** * Compares two types for structural equality, ignoring locations * and predicates of dependent types. * @param a the first type * @param b the second type * @return whether the two types are structurally equal */ public static boolean eq(Type a, Type b) { if (a == b) return true; if (a == null ^ b == null) return false; if (a instanceof ArrayType && b instanceof ArrayType) return eq((ArrayType)a, (ArrayType)b); else if (a instanceof PrimitiveType && b instanceof PrimitiveType) return eq((PrimitiveType)a, (PrimitiveType)b); else if (a instanceof GenericType && b instanceof GenericType) return eq((GenericType)a, (GenericType)b); else if (a instanceof UserType && b instanceof UserType) return eq((UserType)a, (UserType)b); else if (a instanceof TupleType && b instanceof TupleType) return eq((TupleType)a, (TupleType)b); else return false; } /** * Returns whether {@code t} contains a dependent type. * @param t the type to check * @return whether {@code t} contains {@code DepType} */ public static boolean hasDep(Type t) { if (t instanceof DepType) return true; else if (t instanceof ArrayType) { ArrayType st = (ArrayType)t; return hasDep(st.getElemType()) || hasDep(st.getRowType()) || hasDep(st.getRowType()); } else if (t instanceof GenericType) { GenericType st = (GenericType)t; return hasDep(st.getParam()) || hasDep(st.getType()); } else if (t instanceof TupleType) { TupleType st = (TupleType)t; return hasDep(st.getType()) || hasDep(st.getTail()); } return false; } /** * Pretty print a type * @param t the type to pretty print * @return the string representation of {@code t} */ public static String typeToString(Type t) { if (t == null) return "()"; StringWriter sw = new StringWriter(); PrettyPrinter pp = new PrettyPrinter(sw); t.eval(pp); if (t instanceof TupleType) return "(" + sw + ")"; else return sw.toString(); } }