fn haltable_preconditions(cfg: &Cfg, node_index: Index) -> Dnf {
        let node = &cfg[node_index];
        match &node.expr {
            // Trivially, `Send`, `Recv`, and `Type` are only haltable if they continue to a
            // haltable node (as they always continue.) We also assume `Error` behaves this way to
            // try to get the maximum possible number of reported relevant errors.
            Ir::Send(_) | Ir::Recv(_) | Ir::Type(_) | Ir::Error => match node.next {
                Some(cont) => Dnf::only_if(vec![Constraint::Haltable(cont)]),
                None => Dnf::trivially_true(),
            },
            // If a node is passable and its continuation halts, then it is always haltable. Instead
            // of spitting out constraints on the child nodes of these cases, we rely on their
            // definition of passability. Note that if the continuation is `None`, then the node
            // halts only if it is passable, so in that case a `Haltable` constraint on it is not
            // generated.
            Ir::Call(_) | Ir::Split { .. } | Ir::Loop(_) => {
                let mut conj = vec![Constraint::Passable(node_index)];
                conj.extend(node.next.map(Constraint::Haltable));
                Dnf::only_if(conj)
            }
            // `Choose`/`Offer` are haltable only if any of their choices are haltable.
            Ir::Choose(choices) | Ir::Offer(choices) => Dnf(choices
                .iter()
                // If any of the choices are `Done`, we want to emit an empty `Vec` instead,
                // denoting that this constraint is trivially satisfiable.
                .map(|&c| c.map(Constraint::Haltable).into_iter().collect())
                .chain(node.next.map(|c| vec![Constraint::Haltable(c)]))
                .collect()),
            // A `Continue` only halts if whatever it jumps to halts.
            Ir::Continue(of_loop) => Dnf::only_if(vec![Constraint::Haltable(*of_loop)]),
            // Similarly, a `Break` is a kind of jump to the continuation of its relevant loop, and
            // halts only if the continuation of the loop halts.
            Ir::Break(of_loop) => match cfg[*of_loop].next {
                Some(cont) => Dnf::only_if(vec![Constraint::Haltable(cont)]),
                None => Dnf::trivially_true(),
            },
        }
    }
/// Compute the preconditions for a `Haltable` constraint.
Compute the preconditions for a `Haltable` constraint.
Compute the preconditions for a ` Haltable ` constraint .
fn haltable_preconditions(cfg: &Cfg, node_index: Index) -> Dnf {
        let node = &cfg[node_index];
        match &node.expr {
            // Trivially, `Send`, `Recv`, and `Type` are only haltable if they continue to a
            // haltable node (as they always continue.) We also assume `Error` behaves this way to
            // try to get the maximum possible number of reported relevant errors.
            Ir::Send(_) | Ir::Recv(_) | Ir::Type(_) | Ir::Error => match node.next {
                Some(cont) => Dnf::only_if(vec![Constraint::Haltable(cont)]),
                None => Dnf::trivially_true(),
            },
            // If a node is passable and its continuation halts, then it is always haltable. Instead
            // of spitting out constraints on the child nodes of these cases, we rely on their
            // definition of passability. Note that if the continuation is `None`, then the node
            // halts only if it is passable, so in that case a `Haltable` constraint on it is not
            // generated.
            Ir::Call(_) | Ir::Split { .. } | Ir::Loop(_) => {
                let mut conj = vec![Constraint::Passable(node_index)];
                conj.extend(node.next.map(Constraint::Haltable));
                Dnf::only_if(conj)
            }
            // `Choose`/`Offer` are haltable only if any of their choices are haltable.
            Ir::Choose(choices) | Ir::Offer(choices) => Dnf(choices
                .iter()
                // If any of the choices are `Done`, we want to emit an empty `Vec` instead,
                // denoting that this constraint is trivially satisfiable.
                .map(|&c| c.map(Constraint::Haltable).into_iter().collect())
                .chain(node.next.map(|c| vec![Constraint::Haltable(c)]))
                .collect()),
            // A `Continue` only halts if whatever it jumps to halts.
            Ir::Continue(of_loop) => Dnf::only_if(vec![Constraint::Haltable(*of_loop)]),
            // Similarly, a `Break` is a kind of jump to the continuation of its relevant loop, and
            // halts only if the continuation of the loop halts.
            Ir::Break(of_loop) => match cfg[*of_loop].next {
                Some(cont) => Dnf::only_if(vec![Constraint::Haltable(cont)]),
                None => Dnf::trivially_true(),
            },
        }
    }
fn haltable_preconditions ( cfg : & Cfg , node_index : Index ) -> Dnf { let node = & cfg [ node_index ] ; match & node . expr { // Trivially, `Send`, `Recv`, and `Type` are only haltable if they continue to a // haltable node (as they always continue.) We also assume `Error` behaves this way to // try to get the maximum possible number of reported relevant errors. Ir :: Send ( _ ) | Ir :: Recv ( _ ) | Ir :: Type ( _ ) | Ir :: Error => match node . next { Some ( cont ) => Dnf :: only_if ( vec ! [ Constraint Haltable ( cont ) ] ) , None => Dnf :: trivially_true ( ) , } , // If a node is passable and its continuation halts, then it is always haltable. Instead // of spitting out constraints on the child nodes of these cases, we rely on their // definition of passability. Note that if the continuation is `None`, then the node // halts only if it is passable, so in that case a `Haltable` constraint on it is not // generated. Ir :: Call ( _ ) | Ir :: Split { .. } | Ir :: Loop ( _ ) => { let mut conj = vec ! [ Constraint Passable ( node_index ) ] ; conj . extend ( node . next . map ( Constraint :: Haltable ) ) ; Dnf :: only_if ( conj ) } // `Choose`/`Offer` are haltable only if any of their choices are haltable. Ir :: Choose ( choices ) | Ir :: Offer ( choices ) => Dnf ( choices . iter ( ) // If any of the choices are `Done`, we want to emit an empty `Vec` instead, // denoting that this constraint is trivially satisfiable. . map ( | & c | c . map ( Constraint :: Haltable ) . into_iter ( ) . collect ( ) ) . chain ( node . next . map ( | c | vec ! [ Constraint Haltable ( c ) ] ) ) . collect ( ) ) , // A `Continue` only halts if whatever it jumps to halts. Ir :: Continue ( of_loop ) => Dnf :: only_if ( vec ! [ Constraint Haltable ( of_loop ) ] ) , // Similarly, a `Break` is a kind of jump to the continuation of its relevant loop, and // halts only if the continuation of the loop halts. Ir :: Break ( of_loop ) => match cfg [ * of_loop ] . next { Some ( cont ) => Dnf :: only_if ( vec ! [ Constraint Haltable ( cont ) ] ) , None => Dnf :: trivially_true ( ) , } , } }
Compute the preconditions for a `Haltable` constraint.
Compute the preconditions for a ` Haltable ` constraint .
cfg
&Cfg
node_index
Index