fn propagate_function_impurity(
        &mut self,
        mut visited: &mut BTreeMap<SpecFunId, bool>,
        spec_fun_id: SpecFunId,
    ) -> bool {
        if let Some(is_pure) = visited.get(&spec_fun_id) {
            return *is_pure;
        }
        let spec_fun_idx = spec_fun_id.as_usize();
        let body = if self.spec_funs[spec_fun_idx].body.is_some() {
            std::mem::replace(&mut self.spec_funs[spec_fun_idx].body, None).unwrap()
        } else {
            // If the function is native and contains no mutable references
            // as parameters, consider it pure.
            // Otherwise the function is non-native, its body cannot be parsed
            // so we consider it impure.
            // TODO(emmazzz) right now all the native Move functions without
            // parameters of type mutable references are considered pure.
            // In the future we might want to only allow a certain subset of the
            // native Move functions, through something similar to an allow list or
            // a pragma.
            let no_mut_ref_param = self.spec_funs[spec_fun_idx]
                .params
                .iter()
                .map(|(_, ty)| !ty.is_mutable_reference())
                .all(|b| b); // `no_mut_ref_param` if none of the types are mut refs.
            return self.spec_funs[spec_fun_idx].is_native && no_mut_ref_param;
        };
        let mut is_pure = true;
        body.visit(&mut |e: &Exp| {
            if let Exp::Call(_, Operation::Function(mid, fid), _) = e {
                if mid.to_usize() < self.module_id.to_usize() {
                    // This is calling a function from another module we already have
                    // translated. In this case, the impurity has already been propagated
                    // in translate_call.
                } else {
                    // This is calling a function from the module we are currently translating.
                    // Need to recursively ensure we have propagated impurity because of
                    // arbitrary call graphs, including cyclic.
                    if !self.propagate_function_impurity(&mut visited, *fid) {
                        is_pure = false;
                    }
                }
            }
        });
        if is_pure {
            // Restore the function body if the Move function is pure.
            self.spec_funs[spec_fun_idx].body = Some(body);
        }
        visited.insert(spec_fun_id, is_pure);
        is_pure
    }
/// Propagate the impurity of Move functions from callees to callers so
/// that we can detect pure-looking Move functions which calls impure
/// Move functions.
Propagate the impurity of Move functions from callees to callers so
that we can detect pure-looking Move functions which calls impure
Move functions.
Propagate the impurity of Move functions from callees to callers so that we can detect pure - looking Move functions which calls impure Move functions .
fn propagate_function_impurity(
        &mut self,
        mut visited: &mut BTreeMap<SpecFunId, bool>,
        spec_fun_id: SpecFunId,
    ) -> bool {
        if let Some(is_pure) = visited.get(&spec_fun_id) {
            return *is_pure;
        }
        let spec_fun_idx = spec_fun_id.as_usize();
        let body = if self.spec_funs[spec_fun_idx].body.is_some() {
            std::mem::replace(&mut self.spec_funs[spec_fun_idx].body, None).unwrap()
        } else {
            // If the function is native and contains no mutable references
            // as parameters, consider it pure.
            // Otherwise the function is non-native, its body cannot be parsed
            // so we consider it impure.
            // TODO(emmazzz) right now all the native Move functions without
            // parameters of type mutable references are considered pure.
            // In the future we might want to only allow a certain subset of the
            // native Move functions, through something similar to an allow list or
            // a pragma.
            let no_mut_ref_param = self.spec_funs[spec_fun_idx]
                .params
                .iter()
                .map(|(_, ty)| !ty.is_mutable_reference())
                .all(|b| b); // `no_mut_ref_param` if none of the types are mut refs.
            return self.spec_funs[spec_fun_idx].is_native && no_mut_ref_param;
        };
        let mut is_pure = true;
        body.visit(&mut |e: &Exp| {
            if let Exp::Call(_, Operation::Function(mid, fid), _) = e {
                if mid.to_usize() < self.module_id.to_usize() {
                    // This is calling a function from another module we already have
                    // translated. In this case, the impurity has already been propagated
                    // in translate_call.
                } else {
                    // This is calling a function from the module we are currently translating.
                    // Need to recursively ensure we have propagated impurity because of
                    // arbitrary call graphs, including cyclic.
                    if !self.propagate_function_impurity(&mut visited, *fid) {
                        is_pure = false;
                    }
                }
            }
        });
        if is_pure {
            // Restore the function body if the Move function is pure.
            self.spec_funs[spec_fun_idx].body = Some(body);
        }
        visited.insert(spec_fun_id, is_pure);
        is_pure
    }
fn propagate_function_impurity ( & mut self , mut visited : & mut BTreeMap < SpecFunId , bool > , spec_fun_id : SpecFunId , ) -> bool { if let Some ( is_pure ) = visited . get ( & spec_fun_id ) { return * is_pure ; } let spec_fun_idx = spec_fun_id . as_usize ( ) ; let body = if self . spec_funs [ spec_fun_idx ] . body . is_some ( ) { std :: mem :: replace ( & mut self . spec_funs [ spec_fun_idx ] . body , None ) . unwrap ( ) } else { // If the function is native and contains no mutable references // as parameters, consider it pure. // Otherwise the function is non-native, its body cannot be parsed // so we consider it impure. // TODO(emmazzz) right now all the native Move functions without // parameters of type mutable references are considered pure. // In the future we might want to only allow a certain subset of the // native Move functions, through something similar to an allow list or // a pragma. let no_mut_ref_param = self . spec_funs [ spec_fun_idx ] . params . iter ( ) . map ( | ( _ , ty ) | ! ty . is_mutable_reference ( ) ) . all ( | b | b ) ; // `no_mut_ref_param` if none of the types are mut refs. return self . spec_funs [ spec_fun_idx ] . is_native && no_mut_ref_param ; } ; let mut is_pure = true ; body . visit ( & mut | e : & Exp | { if let Exp :: Call ( _ , Operation :: Function ( mid , fid ) , _ ) = e { if mid . to_usize ( ) < self . module_id . to_usize ( ) { // This is calling a function from another module we already have // translated. In this case, the impurity has already been propagated // in translate_call. } else { // This is calling a function from the module we are currently translating. // Need to recursively ensure we have propagated impurity because of // arbitrary call graphs, including cyclic. if ! self . propagate_function_impurity ( & mut visited , * fid ) { is_pure = false ; } } } } ) ; if is_pure { // Restore the function body if the Move function is pure. self . spec_funs [ spec_fun_idx ] . body = Some ( body ) ; } visited . insert ( spec_fun_id , is_pure ) ; is_pure }
Propagate the impurity of Move functions from callees to callers so
that we can detect pure-looking Move functions which calls impure
Move functions.
Propagate the impurity of Move functions from callees to callers so that we can detect pure - looking Move functions which calls impure Move functions .
&mut self
visited
&mut BTreeMap<SpecFunId, bool>
spec_fun_id
SpecFunId
&mut self
visited
&mut BTreeMap<SpecFunId, bool>
spec_fun_id
SpecFunId