/** * Swap <code>t1</code> and <code>t2</code> if <code> kind(t1) > kind(t2) * </code> * * @param t1 * @param t2 * @return the pair of value types <code>(t1', t2')</code> that <code>kind(t1') <= kind(t2') * </code> */ private Pair<ValueType, ValueType> swap(ValueType t1, ValueType t2) { if (t1.isBottom()) return Pair.of(t1, t2); if (t2.isBottom()) return Pair.of(t2, t1); if (t1.isLambda()) { assert t2.isLambda(); return Pair.of(t1, t2); } if (t2.isLambda()) { assert t1.isLambda(); return Pair.of(t1, t2); } ValueTypeKind kind1 = t1.getKind(); ValueTypeKind kind2 = t2.getKind(); switch (kind1) { case BOTTOM: return Pair.of(t1, t2); case BLANK: switch (kind2) { case BOTTOM: case BLANK: return Pair.of(t2, t1); default: return Pair.of(t1, t2); } case SIMPLE: switch (kind2) { case BLANK: case BOTTOM: case SIMPLE: return Pair.of(t2, t1); default: return Pair.of(t1, t2); } default: // case STRUCT: switch (kind2) { case BLANK: case BOTTOM: case SIMPLE: case STRUCT: return Pair.of(t2, t1); default: return Pair.of(t1, t2); } } }
/** * Unify value types <code>t1</code> and <code>t2</code> * * @param t1 * @param t2 * @return a unified value type */ ValueType unify(ValueType t1, ValueType t2) { Pair<ValueType, ValueType> pair = swap(t1, t2); t1 = pair.fst(); t2 = pair.snd(); if (t1.equals(t2)) return t1; if (t1.isBottom()) { if (t1.hasOpTag()) t2.enableOpTag(); return t2; } Parent parent = Parent.getLUB(t1.getParent(), t2.getParent()); Size size = Size.getLUB(t1.getSize(), t2.getSize()); boolean hasOpTag = t1.hasOpTag() || t2.hasOpTag(); switch (t1.getKind()) { case BLANK: { switch (t2.getKind()) { case BLANK: return ValueType.blank(size, parent, hasOpTag); case SIMPLE: { return ValueType.simple( t2.asSimple().getLoc(), t2.asSimple().getFunc(), size, parent, hasOpTag); } default: { // case STRUCT: return ValueType.struct(t2.asStruct().getFieldMap(), size, parent, hasOpTag); } } } case SIMPLE: { switch (t2.getKind()) { case SIMPLE: { ECR loc1 = t1.asSimple().getLoc(); ECR loc2 = t2.asSimple().getLoc(); ECR func1 = t1.asSimple().getFunc(); ECR func2 = t2.asSimple().getFunc(); ECR loc = join(loc1, loc2); ECR func = join(func1, func2); return ValueType.simple(loc, func, size, parent, hasOpTag); } default: // case STRUCT: throw new IllegalArgumentException(); } } case STRUCT: { if (ValueTypeKind.STRUCT.equals(t2.getKind())) { RangeMap<Long, ECR> map = getCompatibleMap(t1.asStruct(), t2.asStruct()); return ValueType.struct(map, size, parent, hasOpTag); } else { throw new IllegalArgumentException(); } } default: { // Lambda assert (t2.isLambda()); List<ECR> params = Lists.newArrayList(); Iterator<ECR> paramItr1 = t1.asLambda().getParams().iterator(); Iterator<ECR> paramItr2 = t2.asLambda().getParams().iterator(); while (paramItr1.hasNext() && paramItr2.hasNext()) { ECR param1 = paramItr1.next(); ECR param2 = paramItr2.next(); ECR param = join(param1, param2); params.add(param); } while (paramItr1.hasNext()) params.add(paramItr1.next()); while (paramItr2.hasNext()) params.add(paramItr2.next()); ECR ret1 = t1.asLambda().getRet(); ECR ret2 = t2.asLambda().getRet(); ECR ret = join(ret1, ret2); return ValueType.lam(ret, params, parent); } } }
void ccjoin(Size rangeSize, ECR e1, ECR e2) { ValueType type1 = getType(e1); if (type1.isBottom()) { addCCjoin(rangeSize, e1, e2); return; } Size size1 = type1.getSize(); if (!Size.isLessThan(rangeSize, size1)) { addCCjoin(rangeSize, e1, e2); expand(e1, rangeSize); // expand(e1) would call setType(e1, ...) and thus ccjoin(e1, e2) return; } if (e1.equals(e2)) return; switch (type1.getKind()) { case BLANK: { addCCjoin(rangeSize, e1, e2); ValueType type2 = getType(e2); switch (type2.getKind()) { case BOTTOM: setType(e2, ValueType.blank(rangeSize, Parent.getBottom())); return; default: Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } } case SIMPLE: { ValueType type2 = getType(e2); switch (type2.getKind()) { case BOTTOM: setType( e2, ValueType.simple( type1.asSimple().getLoc(), type1.asSimple().getFunc(), rangeSize, Parent.getBottom(), type2.hasOpTag())); return; case BLANK: { setType( e2, ValueType.simple( type1.asSimple().getLoc(), type1.asSimple().getFunc(), type2.getSize(), type2.getParent(), type2.hasOpTag())); Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } case SIMPLE: { cjoin(type1.asSimple().getLoc(), type2.asSimple().getLoc()); cjoin(type1.asSimple().getFunc(), type2.asSimple().getFunc()); Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } case STRUCT: { addCCjoin(rangeSize, e1, e2); collapseStruct(e2, type2.asStruct()); return; } default: // lambda return; } } case STRUCT: { ValueType type2 = getType(e2); switch (type2.getKind()) { case BOTTOM: { RangeMap<Long, ECR> fieldMapCopy = FieldRangeMap.create(); fieldMapCopy.putAll(type1.asStruct().getFieldMap()); setType( e2, ValueType.struct( fieldMapCopy, rangeSize, Parent.getBottom(), type2.hasOpTag())); return; } case BLANK: { RangeMap<Long, ECR> fieldMapCopy = FieldRangeMap.create(); fieldMapCopy.putAll(type1.asStruct().getFieldMap()); Size size2 = type2.getSize(); setType( e2, ValueType.struct(fieldMapCopy, size2, type2.getParent(), type2.hasOpTag())); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); return; } case SIMPLE: { addCCjoin(rangeSize, e1, e2); Size size2 = type2.getSize(); if (!Size.isLessThan(rangeSize, size2)) expand(e2, rangeSize); for (ECR elemECR : type1.asStruct().getFieldMap().asMapOfRanges().values()) { ValueType elemType = getType(elemECR); Size elemSize = elemType.getSize(); ccjoin(elemSize, elemECR, e2); } return; } case STRUCT: { throw new IllegalArgumentException(); // Size size2 = type2.getSize(); // if(!Size.isLessThan(rangeSize, size2)) { // addCCjoin(rangeSize, e1, e2); // expand(e2, rangeSize); return; // } // // ValueType unifyStructType = unify(type1, type2); // unify structure type // eagerly // setType(e1, unifyStructType); // setType(e2, unifyStructType); // return; } default: return; // lambda } } default: return; // lambda } }