/** * During the join process, there might be cycle. It means the ECR <code> * root</code> might be set to <code>freshType</code>. The type-union should take care of it -- * union <code>freshType</code> to <code>unionType</code>. In particular, <code>freshType</code> * is an object type, while <code> * unionType</code> is a struct type, then <code>unionType</code> should be collapsed before union * with <code>freshType</code>. * * @param root * @param unionType * @param freshType * @return unified type */ private ValueType resolveType(ECR root, ValueType unionType, ValueType freshType) { Preconditions.checkArgument(!unionType.isLambda()); Preconditions.checkArgument(!freshType.isLambda()); Pair<ValueType, ValueType> pair = swap(unionType, freshType); ValueType t1 = pair.fst(), t2 = pair.snd(); if (t1.isSimple() && t2.isStruct()) { Collection<ECR> elems = t2.asStruct().getFieldMap().asMapOfRanges().values(); ValueType resType = t1; for (ECR elem : elems) { ECR elemLoc = getLoc(elem); ValueType elemLocType = getType(elemLoc); Parent parent = elemLocType.getParent().removeECR(root); elemLocType.setParent(parent); if (elemLocType.isStruct()) { elemLocType = collapseStruct(elemLoc, elemLocType.asStruct()); } union(root, elemLoc); resType = unify(resType, elemLocType); } return resType; } return unify(t1, t2); }
/** * 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); } } }