pub fn substitute(
    identifiers: &[String],
    old: &Expected,
    new: &Expected,
    constraints: &mut Constraints
) -> TypeResult<Constraints> {
    // TODO deal with tuples of identifiers
    let mut substituted = Constraints::new(&constraints.in_class);
    let identifiers = Vec::from(identifiers);

    while let Some(mut constr) = constraints.pop_constr() {
        let old_constr = constr.clone();
        macro_rules! replace {
            ($new:expr) => {{
                let pos =
                    format!("({}={}) ", old_constr.parent.pos.start, old_constr.child.pos.start);
                trace!("{:width$} [substitute] {} ===> {}", pos, old_constr, $new, width = 17);
            }};
        };

        if !constr.ids.is_empty() && constr.ids == identifiers {
            let (sub_r, child) = recursive_substitute("r", &constr.child, old, new);

            constr.child = child;
            constr.is_sub = constr.is_sub || sub_r;
            if sub_r {
                replace!(constr)
            }

            substituted.push_constr(&constr);
            break;
        } else {
            let (sub_l, parent) = recursive_substitute("l", &constr.parent, old, new);
            let (sub_r, child) = recursive_substitute("r", &constr.child, old, new);

            constr.parent = parent;
            constr.child = child;
            constr.is_sub = constr.is_sub || sub_l || sub_r;
            if sub_l || sub_r {
                replace!(constr)
            }

            substituted.push_constr(&constr)
        }
    }

    substituted.append(constraints);
    Ok(substituted)
}
/// Substitute old expression with new.
///
/// Only expression are ever substituted, everything else is left as is.
///
/// identifiers is used to signal when we should stop substituting.
/// Namely, if we encounter an identifier in a constraint, we abort
/// substitution and copy over all remaining constraints.
///
/// If identifier override detected, only substitute right hand side of
/// unification before ceasing substitution.
Substitute old expression with new.
Only expression are ever substituted, everything else is left as is.

identifiers is used to signal when we should stop substituting.
Namely, if we encounter an identifier in a constraint, we abort
substitution and copy over all remaining constraints.

If identifier override detected, only substitute right hand side of
unification before ceasing substitution.
Substitute old expression with new . Only expression are ever substituted everything else is left as is . identifiers is used to signal when we should stop substituting . Namely if we encounter an identifier in a constraint we abort substitution and copy over all remaining constraints . If identifier override detected only substitute right hand side of unification before ceasing substitution .
pub fn substitute(
    identifiers: &[String],
    old: &Expected,
    new: &Expected,
    constraints: &mut Constraints
) -> TypeResult<Constraints> {
    // TODO deal with tuples of identifiers
    let mut substituted = Constraints::new(&constraints.in_class);
    let identifiers = Vec::from(identifiers);
    while let Some(mut constr) = constraints.pop_constr() {
        let old_constr = constr.clone();
        macro_rules! replace {
            ($new:expr) => {{
                let pos =
                    format!("({}={}) ", old_constr.parent.pos.start, old_constr.child.pos.start);
                trace!("{:width$} [substitute] {} ===> {}", pos, old_constr, $new, width = 17);
            }};
        };
        if !constr.ids.is_empty() && constr.ids == identifiers {
            let (sub_r, child) = recursive_substitute("r", &constr.child, old, new);
            constr.child = child;
            constr.is_sub = constr.is_sub || sub_r;
            if sub_r {
                replace!(constr)
            }
            substituted.push_constr(&constr);
            break;
        } else {
            let (sub_l, parent) = recursive_substitute("l", &constr.parent, old, new);
            let (sub_r, child) = recursive_substitute("r", &constr.child, old, new);
            constr.parent = parent;
            constr.child = child;
            constr.is_sub = constr.is_sub || sub_l || sub_r;
            if sub_l || sub_r {
                replace!(constr)
            }
            substituted.push_constr(&constr)
        }
    }
    substituted.append(constraints);
    Ok(substituted)
}
pub fn substitute ( identifiers : & [ String ] , old : & Expected , new : & Expected , constraints : & mut Constraints ) -> TypeResult < Constraints > { // TODO deal with tuples of identifiers let mut substituted = Constraints :: new ( & constraints . in_class ) ; let identifiers = Vec :: from ( identifiers ) ; while let Some ( mut constr ) = constraints . pop_constr ( ) { let old_constr = constr . clone ( ) ; macro_rules! replace { ( $new : expr ) => { { let pos format ( " " old_constr parent pos start old_constr child pos start ) trace ( " " pos old_constr $new width 17 ) } } ; } ; if ! constr . ids . is_empty ( ) && constr . ids == identifiers { let ( sub_r , child ) = recursive_substitute ( " " , & constr . child , old , new ) ; constr . child = child ; constr . is_sub = constr . is_sub || sub_r ; if sub_r { replace ! ( constr ) } substituted . push_constr ( & constr ) ; break ; } else { let ( sub_l , parent ) = recursive_substitute ( " " , & constr . parent , old , new ) ; let ( sub_r , child ) = recursive_substitute ( " " , & constr . child , old , new ) ; constr . parent = parent ; constr . child = child ; constr . is_sub = constr . is_sub || sub_l || sub_r ; if sub_l || sub_r { replace ! ( constr ) } substituted . push_constr ( & constr ) } } substituted . append ( constraints ) ; Ok ( substituted ) }
Substitute old expression with new.
Substitute old expression with new .
identifiers
&[String]
old
&Expected
new
&Expected
constraints
&mut Constraints