/** * Merges two {@link Type}s into one. * * @param errorIfFailed * if true, attempting to merge two types that are incompatible causes an error. * if false, it yields {@link Type#UNKNOWN} value, indicating that value is unusable. */ /*package*/ static Type merge(Type lhs, Type rhs, boolean errorIfFailed) { try { // We won't accept an unitialized object if we know it was initialized; // compare vmspec2, 4.9.4, last paragraph. if ((!(lhs instanceof UninitializedObjectType)) && (rhs instanceof UninitializedObjectType)) { throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected."); } // Even harder, what about _different_ uninitialized object types?! if ((!(lhs.equals(rhs))) && (lhs instanceof UninitializedObjectType) && (rhs instanceof UninitializedObjectType)) { throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected."); } // If we just didn't know that it was initialized, we have now learned. if (lhs instanceof UninitializedObjectType) { if (! (rhs instanceof UninitializedObjectType)) { lhs = ((UninitializedObjectType) lhs).getInitialized(); } } if ((lhs instanceof ReferenceType) && (rhs instanceof ReferenceType)) { if(lhs.equals(rhs)) { return lhs; // same type } Type sup = ((ReferenceType) lhs).getFirstCommonSuperclass((ReferenceType) rhs); if (sup != null) { return sup; } else { // We should have checked this in Pass2! throw new AssertionViolatedException("Could not load all the super classes of '" + lhs + "' and '" + rhs + "'."); } } if ((lhs instanceof ReturnaddressType) && (rhs instanceof ReturnaddressType)) { // see 'FinallyFlow' test. return lhs; } if (!lhs.equals(rhs)) { if(errorIfFailed) { throw new StructuralCodeConstraintException("Cannot merge different types:"+lhs+" and "+rhs); } else { return Type.UNKNOWN; } } return lhs; } catch (ClassNotFoundException e) { // FIXME: maybe not the best way to handle this throw new AssertionViolatedException("Missing class: " + e.toString()); } }