fn push(&mut self, other: &Self) -> WeldResult<bool> {
        // If the other type is Unknown, we cannot infer anything. If this type is Unknown,
        // copy the other type to this one.
        if *other == Unknown {
            return Ok(false);
        } else if *self == Unknown {
            *self = other.clone();
            return Ok(true);
        }

        // Match this `Type` with `other` to make sure the variant is the same. Then, recursively
        // call `push` on any subtypes.
        match (self, other) {
            (&mut Scalar(a), &Scalar(b)) if a == b => Ok(false),
            (&mut Simd(a), &Simd(b)) if a == b => Ok(false),
            (&mut Vector(ref mut elem), &Vector(ref other_elem)) => elem.push(other_elem),
            (&mut Dict(ref mut key, ref mut value), &Dict(ref other_key, ref other_value)) => {
                let changed = key.push(other_key)? || value.push(other_value)?;
                key_hashable(key.as_ref())?;
                Ok(changed)
            }
            (&mut Struct(ref mut types), &Struct(ref other_types))
                if types.len() == other_types.len() =>
            {
                let mut changed = false;
                for (this, other) in types.iter_mut().zip(other_types) {
                    changed |= this.push(other)?;
                }
                Ok(changed)
            }
            (
                &mut Function(ref mut params, ref mut body),
                &Function(ref other_params, ref other_body),
            ) if params.len() == other_params.len() => {
                let mut changed = false;
                for (this, other) in params.iter_mut().zip(other_params) {
                    changed |= this.push(other)?;
                }
                changed |= body.push(other_body)?;
                Ok(changed)
            }
            (
                &mut Builder(ref mut kind, ref mut annotations),
                &Builder(ref other_kind, ref other_annotations),
            ) => {
                // Perform type checking on the BuilderKind, followed by the annotations.
                let changed = match (kind, other_kind) {
                    (&mut Appender(ref mut elem), &Appender(ref other_elem)) => {
                        elem.push(other_elem)
                    }
                    (
                        &mut DictMerger(ref mut key, ref mut value, ref mut op),
                        &DictMerger(ref other_key, ref other_value, ref other_op),
                    ) if *op == *other_op => {
                        let changed = key.push(other_key)? || value.push(other_value)?;
                        key_hashable(key.as_ref())?;
                        Ok(changed)
                    }
                    (
                        &mut GroupMerger(ref mut key, ref mut value),
                        &GroupMerger(ref other_key, ref other_value),
                    ) => {
                        let changed = key.push(other_key)? || value.push(other_value)?;
                        key_hashable(key.as_ref())?;
                        Ok(changed)
                    }
                    (
                        &mut VecMerger(ref mut elem, ref mut op),
                        &VecMerger(ref other_elem, ref other_op),
                    ) if *op == *other_op => elem.push(other_elem),
                    (
                        &mut Merger(ref mut elem, ref mut op),
                        &Merger(ref other_elem, ref other_op),
                    ) if *op == *other_op => elem.push(other_elem),
                    // Mismatches in the binary operator of DictMerger, VecMerger, and GroupMerger,
                    // or other type mismatches in the BuilderKind. We list them explicitly so the
                    // compiler will throw an error if we add new types.
                    (&mut Appender(_), _)
                    | (&mut DictMerger(_, _, _), _)
                    | (&mut GroupMerger(_, _), _)
                    | (&mut VecMerger(_, _), _)
                    | (&mut Merger(_, _), _) => {
                        compile_err!("Type mismatch: expected builder type {}", other)
                    }
                };

                // Check the annotations.
                if *annotations != *other_annotations && !annotations.is_empty() {
                    *annotations = other_annotations.clone();
                    Ok(true)
                } else {
                    changed
                }
            }
            (ref this, ref other) => {
                compile_err!("Type mismatch: expected {} but got {}", other, this)
            }
        }
    }
Push the type of `other` into this `Type` and return if this `Type` changed.
weld/src/ast/type_inference.rs