fn update_levels(typ: &Type, own_level: usize, own_id: usize) -> Result<(), UnifyError> {
    if let Type::Var { typ } = &typ {
        let new_value = match &*typ.borrow() {
            TypeVar::Link { typ, .. } => return update_levels(typ, own_level, own_id),

            TypeVar::Unbound { id, level } => {
                if id == &own_id {
                    return Err(UnifyError::RecursiveType);
                } else if *level > own_level {
                    Some(TypeVar::Unbound {
                        id: *id,
                        level: own_level,
                    })
                } else {
                    return Ok(());
                }
            }

            TypeVar::Generic { .. } => return Ok(()),
        };

        if let Some(t) = new_value {
            *typ.borrow_mut() = t;
        }
        return Ok(());
    }

    match typ {
        Type::App { args, .. } => {
            for arg in args.iter() {
                update_levels(arg, own_level, own_id)?
            }
            Ok(())
        }

        Type::Fn { args, retrn } => {
            for arg in args.iter() {
                update_levels(arg, own_level, own_id)?;
            }
            update_levels(retrn, own_level, own_id)
        }

        Type::Tuple { elems, .. } => {
            for elem in elems.iter() {
                update_levels(elem, own_level, own_id)?
            }
            Ok(())
        }

        Type::Var { .. } => unreachable!(),
    }
}
/// This function makes sure that the type variable being unified
/// doesn't occur within the type it is being unified with. This
/// prevents the algorithm from inferring recursive types, which
/// could cause naively-implemented type checking to diverge.
/// While traversing the type tree, this function also takes care
/// of updating the levels of the type variables appearing within
/// the type, thus ensuring the type will be correctly generalized.
///
This function makes sure that the type variable being unified
doesn't occur within the type it is being unified with. This
prevents the algorithm from inferring recursive types, which
could cause naively-implemented type checking to diverge.
While traversing the type tree, this function also takes care
of updating the levels of the type variables appearing within
the type, thus ensuring the type will be correctly generalized.
This function makes sure that the type variable being unified doesn ' t occur within the type it is being unified with . This prevents the algorithm from inferring recursive types which could cause naively - implemented type checking to diverge . While traversing the type tree this function also takes care of updating the levels of the type variables appearing within the type thus ensuring the type will be correctly generalized .
fn update_levels(typ: &Type, own_level: usize, own_id: usize) -> Result<(), UnifyError> {
    if let Type::Var { typ } = &typ {
        let new_value = match &*typ.borrow() {
            TypeVar::Link { typ, .. } => return update_levels(typ, own_level, own_id),
            TypeVar::Unbound { id, level } => {
                if id == &own_id {
                    return Err(UnifyError::RecursiveType);
                } else if *level > own_level {
                    Some(TypeVar::Unbound {
                        id: *id,
                        level: own_level,
                    })
                } else {
                    return Ok(());
                }
            }
            TypeVar::Generic { .. } => return Ok(()),
        };
        if let Some(t) = new_value {
            *typ.borrow_mut() = t;
        }
        return Ok(());
    }
    match typ {
        Type::App { args, .. } => {
            for arg in args.iter() {
                update_levels(arg, own_level, own_id)?
            }
            Ok(())
        }
        Type::Fn { args, retrn } => {
            for arg in args.iter() {
                update_levels(arg, own_level, own_id)?;
            }
            update_levels(retrn, own_level, own_id)
        }
        Type::Tuple { elems, .. } => {
            for elem in elems.iter() {
                update_levels(elem, own_level, own_id)?
            }
            Ok(())
        }
        Type::Var { .. } => unreachable!(),
    }
}
fn update_levels ( typ : & Type , own_level : usize , own_id : usize ) -> Result < ( ) , UnifyError > { if let Type :: Var { typ } = & typ { let new_value = match & * typ . borrow ( ) { TypeVar :: Link { typ , .. } => return update_levels ( typ , own_level , own_id ) , TypeVar :: Unbound { id , level } => { if id == & own_id { return Err ( UnifyError :: RecursiveType ) ; } else if * level > own_level { Some ( TypeVar :: Unbound { id : * id , level : own_level , } ) } else { return Ok ( ( ) ) ; } } TypeVar :: Generic { .. } => return Ok ( ( ) ) , } ; if let Some ( t ) = new_value { * typ . borrow_mut ( ) = t ; } return Ok ( ( ) ) ; } match typ { Type :: App { args , .. } => { for arg in args . iter ( ) { update_levels ( arg , own_level , own_id ) ? } Ok ( ( ) ) } Type :: Fn { args , retrn } => { for arg in args . iter ( ) { update_levels ( arg , own_level , own_id ) ? ; } update_levels ( retrn , own_level , own_id ) } Type :: Tuple { elems , .. } => { for elem in elems . iter ( ) { update_levels ( elem , own_level , own_id ) ? } Ok ( ( ) ) } Type :: Var { .. } => unreachable ! ( ) , } }
This function makes sure that the type variable being unified
doesn't occur within the type it is being unified with.
This function makes sure that the type variable being unified doesn ' t occur within the type it is being unified with .
typ
&Type
own_level
usize
own_id
usize
typ
&Type
own_level
usize
own_id
usize