fn calculate_invariant_relevance<'a>(
        env: &GlobalEnv,
        mem_related: impl Iterator<Item = &'a QualifiedInstId<StructId>>,
        inv_related: &BTreeSet<GlobalId>,
        fun_type_params_arity: usize,
        fun_type_params_ghost_count: &mut usize,
        ignore_uninstantiated_invariant: bool,
    ) -> BTreeMap<GlobalId, PerBytecodeRelevance> {
        let mut result = BTreeMap::new();

        for rel_mem in mem_related {
            let rel_ty = rel_mem.to_type();
            for inv_id in inv_related {
                let inv = env.get_global_invariant(*inv_id).unwrap();
                let inv_type_params = match &inv.kind {
                    ConditionKind::GlobalInvariant(params) => params,
                    ConditionKind::GlobalInvariantUpdate(params) => params,
                    _ => unreachable!(
                        "A global invariant must have a condition kind of either \
                            `GlobalInvariant` or `GlobalInvariantUpdate`"
                    ),
                };
                let inv_type_params_arity = inv_type_params.len();

                for inv_mem in &inv.mem_usage {
                    let inv_ty = inv_mem.to_type();

                    // make sure these two types unify before trying to instantiate them
                    let adapter = TypeUnificationAdapter::new_pair(&rel_ty, &inv_ty, true, true);
                    if adapter.unify(Variance::Allow, false).is_none() {
                        continue;
                    }

                    // instantiate the bytecode first
                    //
                    // NOTE: in fact, in this phase, we don't intend to instantiation the function
                    // nor do we want to collect information on how this function (or this bytecode)
                    // needs to be instantiated. All we care is how the invariant should be
                    // instantiated in order to be instrumented at this code point, with a generic
                    // function and generic code.
                    //
                    // But unfortunately, based on how the type unification logic is written now,
                    // this two-step instantiation is needed in order to find all possible
                    // instantiations of the invariant. I won't deny that there might be a way to
                    // collect invariant instantiation combinations without instantiating the
                    // function type parameters, but I haven't iron out one so far.
                    let rel_insts = TypeInstantiationDerivation::progressive_instantiation(
                        std::iter::once(&rel_ty),
                        std::iter::once(&inv_ty),
                        true,
                        true,
                        true,
                        false,
                        fun_type_params_arity,
                        true,
                        false,
                    );

                    // for each instantiation of the bytecode, instantiate the invariants
                    for rel_inst in rel_insts {
                        let inst_rel_ty = rel_ty.instantiate(&rel_inst);
                        let inv_insts = TypeInstantiationDerivation::progressive_instantiation(
                            std::iter::once(&inst_rel_ty),
                            std::iter::once(&inv_ty),
                            false,
                            true,
                            false,
                            true,
                            inv_type_params_arity,
                            false,
                            true,
                        );

                        let mut wellformed_inv_inst = vec![];
                        for inv_inst in inv_insts {
                            if inv_inst.iter().any(|t| matches!(t, Type::Error)) {
                                if ignore_uninstantiated_invariant {
                                    continue;
                                }
                                let adapted_inv_inst = inv_inst
                                    .into_iter()
                                    .map(|t| {
                                        if matches!(t, Type::Error) {
                                            let ghost_idx = fun_type_params_arity
                                                + *fun_type_params_ghost_count;
                                            *fun_type_params_ghost_count += 1;
                                            Type::TypeParameter(ghost_idx as u16)
                                        } else {
                                            t
                                        }
                                    })
                                    .collect();
                                wellformed_inv_inst.push(adapted_inv_inst);
                            } else {
                                wellformed_inv_inst.push(inv_inst);
                            }
                        }

                        // record the relevance information
                        result
                            .entry(*inv_id)
                            .or_insert_with(PerBytecodeRelevance::default)
                            .insts
                            .entry(rel_inst)
                            .or_insert_with(BTreeSet::new)
                            .extend(wellformed_inv_inst);
                    }
                }
            }
        }

        result
    }
/// Given a set of memories, calculate the global invariants that are related to this memory
/// set and for each related global invariant, derive how to instantiate the invariant to make
/// it relevant.
Given a set of memories, calculate the global invariants that are related to this memory
set and for each related global invariant, derive how to instantiate the invariant to make
it relevant.
Given a set of memories calculate the global invariants that are related to this memory set and for each related global invariant derive how to instantiate the invariant to make it relevant .
fn calculate_invariant_relevance<'a>(
        env: &GlobalEnv,
        mem_related: impl Iterator<Item = &'a QualifiedInstId<StructId>>,
        inv_related: &BTreeSet<GlobalId>,
        fun_type_params_arity: usize,
        fun_type_params_ghost_count: &mut usize,
        ignore_uninstantiated_invariant: bool,
    ) -> BTreeMap<GlobalId, PerBytecodeRelevance> {
        let mut result = BTreeMap::new();
        for rel_mem in mem_related {
            let rel_ty = rel_mem.to_type();
            for inv_id in inv_related {
                let inv = env.get_global_invariant(*inv_id).unwrap();
                let inv_type_params = match &inv.kind {
                    ConditionKind::GlobalInvariant(params) => params,
                    ConditionKind::GlobalInvariantUpdate(params) => params,
                    _ => unreachable!(
                        "A global invariant must have a condition kind of either \
                            `GlobalInvariant` or `GlobalInvariantUpdate`"
                    ),
                };
                let inv_type_params_arity = inv_type_params.len();
                for inv_mem in &inv.mem_usage {
                    let inv_ty = inv_mem.to_type();
                    // make sure these two types unify before trying to instantiate them
                    let adapter = TypeUnificationAdapter::new_pair(&rel_ty, &inv_ty, true, true);
                    if adapter.unify(Variance::Allow, false).is_none() {
                        continue;
                    }
                    // instantiate the bytecode first
                    //
                    // NOTE: in fact, in this phase, we don't intend to instantiation the function
                    // nor do we want to collect information on how this function (or this bytecode)
                    // needs to be instantiated. All we care is how the invariant should be
                    // instantiated in order to be instrumented at this code point, with a generic
                    // function and generic code.
                    //
                    // But unfortunately, based on how the type unification logic is written now,
                    // this two-step instantiation is needed in order to find all possible
                    // instantiations of the invariant. I won't deny that there might be a way to
                    // collect invariant instantiation combinations without instantiating the
                    // function type parameters, but I haven't iron out one so far.
                    let rel_insts = TypeInstantiationDerivation::progressive_instantiation(
                        std::iter::once(&rel_ty),
                        std::iter::once(&inv_ty),
                        true,
                        true,
                        true,
                        false,
                        fun_type_params_arity,
                        true,
                        false,
                    );
                    // for each instantiation of the bytecode, instantiate the invariants
                    for rel_inst in rel_insts {
                        let inst_rel_ty = rel_ty.instantiate(&rel_inst);
                        let inv_insts = TypeInstantiationDerivation::progressive_instantiation(
                            std::iter::once(&inst_rel_ty),
                            std::iter::once(&inv_ty),
                            false,
                            true,
                            false,
                            true,
                            inv_type_params_arity,
                            false,
                            true,
                        );
                        let mut wellformed_inv_inst = vec![];
                        for inv_inst in inv_insts {
                            if inv_inst.iter().any(|t| matches!(t, Type::Error)) {
                                if ignore_uninstantiated_invariant {
                                    continue;
                                }
                                let adapted_inv_inst = inv_inst
                                    .into_iter()
                                    .map(|t| {
                                        if matches!(t, Type::Error) {
                                            let ghost_idx = fun_type_params_arity
                                                + *fun_type_params_ghost_count;
                                            *fun_type_params_ghost_count += 1;
                                            Type::TypeParameter(ghost_idx as u16)
                                        } else {
                                            t
                                        }
                                    })
                                    .collect();
                                wellformed_inv_inst.push(adapted_inv_inst);
                            } else {
                                wellformed_inv_inst.push(inv_inst);
                            }
                        }
                        // record the relevance information
                        result
                            .entry(*inv_id)
                            .or_insert_with(PerBytecodeRelevance::default)
                            .insts
                            .entry(rel_inst)
                            .or_insert_with(BTreeSet::new)
                            .extend(wellformed_inv_inst);
                    }
                }
            }
        }
        result
    }
fn calculate_invariant_relevance < ' a > ( env : & GlobalEnv , mem_related : impl Iterator < Item = & ' a QualifiedInstId < StructId > > , inv_related : & BTreeSet < GlobalId > , fun_type_params_arity : usize , fun_type_params_ghost_count : & mut usize , ignore_uninstantiated_invariant : bool , ) -> BTreeMap < GlobalId , PerBytecodeRelevance > { let mut result = BTreeMap :: new ( ) ; for rel_mem in mem_related { let rel_ty = rel_mem . to_type ( ) ; for inv_id in inv_related { let inv = env . get_global_invariant ( * inv_id ) . unwrap ( ) ; let inv_type_params = match & inv . kind { ConditionKind :: GlobalInvariant ( params ) => params , ConditionKind :: GlobalInvariantUpdate ( params ) => params , _ => unreachable ! ( " \
 " ) , } ; let inv_type_params_arity = inv_type_params . len ( ) ; for inv_mem in & inv . mem_usage { let inv_ty = inv_mem . to_type ( ) ; // make sure these two types unify before trying to instantiate them let adapter = TypeUnificationAdapter :: new_pair ( & rel_ty , & inv_ty , true , true ) ; if adapter . unify ( Variance :: Allow , false ) . is_none ( ) { continue ; } // instantiate the bytecode first // // NOTE: in fact, in this phase, we don't intend to instantiation the function // nor do we want to collect information on how this function (or this bytecode) // needs to be instantiated. All we care is how the invariant should be // instantiated in order to be instrumented at this code point, with a generic // function and generic code. // // But unfortunately, based on how the type unification logic is written now, // this two-step instantiation is needed in order to find all possible // instantiations of the invariant. I won't deny that there might be a way to // collect invariant instantiation combinations without instantiating the // function type parameters, but I haven't iron out one so far. let rel_insts = TypeInstantiationDerivation :: progressive_instantiation ( std :: iter :: once ( & rel_ty ) , std :: iter :: once ( & inv_ty ) , true , true , true , false , fun_type_params_arity , true , false , ) ; // for each instantiation of the bytecode, instantiate the invariants for rel_inst in rel_insts { let inst_rel_ty = rel_ty . instantiate ( & rel_inst ) ; let inv_insts = TypeInstantiationDerivation :: progressive_instantiation ( std :: iter :: once ( & inst_rel_ty ) , std :: iter :: once ( & inv_ty ) , false , true , false , true , inv_type_params_arity , false , true , ) ; let mut wellformed_inv_inst = vec ! [ ] ; for inv_inst in inv_insts { if inv_inst . iter ( ) . any ( | t | matches ! ( t Type Error ) ) { if ignore_uninstantiated_invariant { continue ; } let adapted_inv_inst = inv_inst . into_iter ( ) . map ( | t | { if matches ! ( t Type Error ) { let ghost_idx = fun_type_params_arity + * fun_type_params_ghost_count ; * fun_type_params_ghost_count += 1 ; Type :: TypeParameter ( ghost_idx as u16 ) } else { t } } ) . collect ( ) ; wellformed_inv_inst . push ( adapted_inv_inst ) ; } else { wellformed_inv_inst . push ( inv_inst ) ; } } // record the relevance information result . entry ( * inv_id ) . or_insert_with ( PerBytecodeRelevance :: default ) . insts . entry ( rel_inst ) . or_insert_with ( BTreeSet :: new ) . extend ( wellformed_inv_inst ) ; } } } } result }
Given a set of memories, calculate the global invariants that are related to this memory
set and for each related global invariant, derive how to instantiate the invariant to make
it relevant.
Given a set of memories calculate the global invariants that are related to this memory set and for each related global invariant derive how to instantiate the invariant to make it relevant .
env
&GlobalEnv
mem_related
impl Iterator<Item = &'a QualifiedInstId<StructId>>
inv_related
&BTreeSet<GlobalId>
fun_type_params_arity
usize
fun_type_params_ghost_count
&mut usize
ignore_uninstantiated_invariant
bool