/** * 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); }
/** * Check if one of <code>e1</code> or <code>e2</code> is a struct, and the other is either object * or simple, collapse the one with struct type * * @param e1 * @param e2 */ private void checkStructCollapse(ECR e1, ECR e2) { ValueType t1 = getType(e1); ValueType t2 = getType(e2); if (t2.isStruct() && t1.isSimple()) { collapseStruct(e2, t2.asStruct()); return; } if (t1.isStruct() && t2.isSimple()) { collapseStruct(e1, t1.asStruct()); return; } return; }