@Override
	public ReValue merge(@Nonnull ReValue value1, @Nonnull ReValue value2) {
		Type type1 = value1.type();
		Type type2 = value2.type();

		// Null types correspond to UNINITIALIZED_VALUE.
		if (type1 == null || type2 == null)
			return UninitializedValue.UNINITIALIZED_VALUE;

		// If the types are the same, we should merge their tracked value state.
		if (type1.equals(type2)) {
			try {
				return value1.mergeWith(value2);
			} catch (IllegalValueException t) {
				logger.error("Failed ReValue merge of of same type", t);
				throw new IllegalStateException("Failed ReValue merge of of same type", t);
			}
		}

		// The merge of a primitive type with a different type is the type of uninitialized values.
		if (type1.getSort() != Type.OBJECT && type1.getSort() != Type.ARRAY)
			return UninitializedValue.UNINITIALIZED_VALUE;
		if (type2.getSort() != Type.OBJECT && type2.getSort() != Type.ARRAY)
			return UninitializedValue.UNINITIALIZED_VALUE;

		// Special case for the type of the "null" literal.
		if (value1 instanceof ObjectValue ov1 && ov1.isNull())
			return value2;
		if (value2 instanceof ObjectValue ov2 && ov2.isNull())
			return value1;

		// Convert type1 to its element type and array dimension. Arrays of primitive values are seen as
		// Object arrays with one dimension less. Hence, the element type is always of Type.OBJECT sort.
		int dim1 = 0;
		if (type1.getSort() == Type.ARRAY) {
			dim1 = type1.getDimensions();
			type1 = type1.getElementType();
			if (type1.getSort() != Type.OBJECT) {
				dim1 = dim1 - 1;
				type1 = Types.OBJECT_TYPE;
			}
		}

		// Do the same for type2.
		int dim2 = 0;
		if (type2.getSort() == Type.ARRAY) {
			dim2 = type2.getDimensions();
			type2 = type2.getElementType();
			if (type2.getSort() != Type.OBJECT) {
				dim2 = dim2 - 1;
				type2 = Types.OBJECT_TYPE;
			}
		}

		// The merge of array types of different dimensions is an Object array type.
		if (dim1 != dim2)
			return newArrayValue(Types.OBJECT_TYPE, Math.min(dim1, dim2));

		// If the dimensions are the same, and there is no array aspect of these values
		// then we want to merge the values in such a way that tracks state if possible.
		if (dim1 == 0) {
			try {
				if (isAssignableFrom(type1, type2))
					return value1.mergeWith(value2);
				if (isAssignableFrom(type2, type1))
					return value2.mergeWith(value1);
			} catch (Throwable t) {
				logger.error("Failed ReValue merge of {} and {}",
						value1.getClass().getSimpleName(), value2.getClass().getSimpleName(), t);
				throw new IllegalStateException("Failed ReValue merge of of same type", t);
			}
		}

		// Type1 and type2 have a Type.OBJECT sort by construction (see above),
		// as expected by isAssignableFrom.
		if (isAssignableFrom(type1, type2))
			return newArrayValue(type1, dim1);
		if (isAssignableFrom(type2, type1))
			return newArrayValue(type2, dim1);

		if (!isInterface(type1)) {
			while (!Types.OBJECT_TYPE.equals(type1)) {
				type1 = getSuperClass(type1);
				if (isAssignableFrom(type1, type2))
					return newArrayValue(type1, dim1);
			}
		}

		return newArrayValue(Types.OBJECT_TYPE, dim1);
	}
{@inheritDoc}
<p/>
Implementation adapted from {@link SimpleVerifier}.

@param value1
		A value.
@param value2
		Another value.

@return The merged value.
recaf-core/src/main/java/software/coley/recaf/util/analysis/ReInterpreter.java