fn join(&mut self, state: &AbstractState) -> JoinResult {
        // A join failure occurs in each of the following situations:
        // - an unrestricted value is borrowed along one path but unavailable along the other
        // - a value that is not unrestricted, i.e., either reference or resource, is available
        //   along one path but not the other
        if Self::unrestricted_borrowed_value_unavailable(self, state)
            || Self::unrestricted_borrowed_value_unavailable(state, self)
        {
            return JoinResult::Error;
        }
        if self
            .locals
            .keys()
            .filter(|idx| !self.locals[idx].is_unrestricted_value())
            .collect::<BTreeSet<_>>()
            != state
                .locals
                .keys()
                .filter(|idx| !state.locals[idx].is_unrestricted_value())
                .collect::<BTreeSet<_>>()
        {
            return JoinResult::Error;
        }

        let mut values1 = BTreeMap::new();
        let mut references1 = BTreeMap::new();
        Self::split_locals(&self.locals, &mut values1, &mut references1);
        let mut values2 = BTreeMap::new();
        let mut references2 = BTreeMap::new();
        Self::split_locals(&state.locals, &mut values2, &mut references2);
        checked_verify!(references1 == references2);

        let mut locals = BTreeMap::new();
        for (idx, nonce) in &references1 {
            locals.insert(idx.clone(), AbstractValue::Reference(*nonce));
        }
        for (idx, (kind1, nonce_set1)) in &values1 {
            if let Some((kind2, nonce_set2)) = values2.get(idx) {
                checked_verify!(kind1 == kind2);
                locals.insert(
                    idx.clone(),
                    AbstractValue::Value(*kind1, nonce_set1.union(nonce_set2).cloned().collect()),
                );
            }
        }

        let mut globals = self.globals.clone();
        for (idx, global_nonce_set) in &state.globals {
            globals
                .entry(*idx)
                .and_modify(|nonce_set| {
                    *nonce_set = global_nonce_set.union(nonce_set).cloned().collect()
                })
                .or_insert_with(|| global_nonce_set.clone());
        }

        let mut borrows = BTreeMap::new();
        for (nonce, borrow_info) in &self.borrows {
            if state.borrows.contains_key(nonce) {
                match borrow_info {
                    BorrowInfo::BorrowedBy(borrowed_by1) => match &state.borrows[nonce] {
                        BorrowInfo::BorrowedBy(borrowed_by2) => {
                            borrows.insert(
                                *nonce,
                                BorrowInfo::BorrowedBy(
                                    borrowed_by1.union(borrowed_by2).cloned().collect(),
                                ),
                            );
                        }
                        BorrowInfo::FieldsBorrowedBy(fields_borrowed_by2) => {
                            borrows.insert(
                                *nonce,
                                BorrowInfo::BorrowedBy(Self::get_union_of_sets(
                                    borrowed_by1,
                                    fields_borrowed_by2,
                                )),
                            );
                        }
                    },
                    BorrowInfo::FieldsBorrowedBy(fields_borrowed_by1) => {
                        match &state.borrows[nonce] {
                            BorrowInfo::BorrowedBy(borrowed_by2) => {
                                borrows.insert(
                                    *nonce,
                                    BorrowInfo::BorrowedBy(Self::get_union_of_sets(
                                        borrowed_by2,
                                        fields_borrowed_by1,
                                    )),
                                );
                            }
                            BorrowInfo::FieldsBorrowedBy(fields_borrowed_by2) => {
                                borrows.insert(
                                    *nonce,
                                    BorrowInfo::FieldsBorrowedBy(Self::get_union_of_maps(
                                        fields_borrowed_by1,
                                        fields_borrowed_by2,
                                    )),
                                );
                            }
                        }
                    }
                }
            } else {
                borrows.insert(*nonce, borrow_info.clone());
            }
        }
        for (nonce, borrow_info) in &state.borrows {
            if !borrows.contains_key(nonce) {
                borrows.insert(*nonce, borrow_info.clone());
            }
        }

        let partition = self.partition.join(&state.partition);

        let next_state = AbstractState {
            locals,
            globals,
            borrows,
            partition,
        };
        if next_state == *self {
            JoinResult::Unchanged
        } else {
            *self = next_state;
            JoinResult::Changed
        }
    }
/// attempts to join state to self and returns the result
/// both self.is_canonical() and state.is_canonical() must be true
attempts to join state to self and returns the result
both self.is_canonical() and state.is_canonical() must be true
attempts to join state to self and returns the result both self . is_canonical () and state . is_canonical () must be true
fn join(&mut self, state: &AbstractState) -> JoinResult {
        // A join failure occurs in each of the following situations:
        // - an unrestricted value is borrowed along one path but unavailable along the other
        // - a value that is not unrestricted, i.e., either reference or resource, is available
        //   along one path but not the other
        if Self::unrestricted_borrowed_value_unavailable(self, state)
            || Self::unrestricted_borrowed_value_unavailable(state, self)
        {
            return JoinResult::Error;
        }
        if self
            .locals
            .keys()
            .filter(|idx| !self.locals[idx].is_unrestricted_value())
            .collect::<BTreeSet<_>>()
            != state
                .locals
                .keys()
                .filter(|idx| !state.locals[idx].is_unrestricted_value())
                .collect::<BTreeSet<_>>()
        {
            return JoinResult::Error;
        }
        let mut values1 = BTreeMap::new();
        let mut references1 = BTreeMap::new();
        Self::split_locals(&self.locals, &mut values1, &mut references1);
        let mut values2 = BTreeMap::new();
        let mut references2 = BTreeMap::new();
        Self::split_locals(&state.locals, &mut values2, &mut references2);
        checked_verify!(references1 == references2);
        let mut locals = BTreeMap::new();
        for (idx, nonce) in &references1 {
            locals.insert(idx.clone(), AbstractValue::Reference(*nonce));
        }
        for (idx, (kind1, nonce_set1)) in &values1 {
            if let Some((kind2, nonce_set2)) = values2.get(idx) {
                checked_verify!(kind1 == kind2);
                locals.insert(
                    idx.clone(),
                    AbstractValue::Value(*kind1, nonce_set1.union(nonce_set2).cloned().collect()),
                );
            }
        }
        let mut globals = self.globals.clone();
        for (idx, global_nonce_set) in &state.globals {
            globals
                .entry(*idx)
                .and_modify(|nonce_set| {
                    *nonce_set = global_nonce_set.union(nonce_set).cloned().collect()
                })
                .or_insert_with(|| global_nonce_set.clone());
        }
        let mut borrows = BTreeMap::new();
        for (nonce, borrow_info) in &self.borrows {
            if state.borrows.contains_key(nonce) {
                match borrow_info {
                    BorrowInfo::BorrowedBy(borrowed_by1) => match &state.borrows[nonce] {
                        BorrowInfo::BorrowedBy(borrowed_by2) => {
                            borrows.insert(
                                *nonce,
                                BorrowInfo::BorrowedBy(
                                    borrowed_by1.union(borrowed_by2).cloned().collect(),
                                ),
                            );
                        }
                        BorrowInfo::FieldsBorrowedBy(fields_borrowed_by2) => {
                            borrows.insert(
                                *nonce,
                                BorrowInfo::BorrowedBy(Self::get_union_of_sets(
                                    borrowed_by1,
                                    fields_borrowed_by2,
                                )),
                            );
                        }
                    },
                    BorrowInfo::FieldsBorrowedBy(fields_borrowed_by1) => {
                        match &state.borrows[nonce] {
                            BorrowInfo::BorrowedBy(borrowed_by2) => {
                                borrows.insert(
                                    *nonce,
                                    BorrowInfo::BorrowedBy(Self::get_union_of_sets(
                                        borrowed_by2,
                                        fields_borrowed_by1,
                                    )),
                                );
                            }
                            BorrowInfo::FieldsBorrowedBy(fields_borrowed_by2) => {
                                borrows.insert(
                                    *nonce,
                                    BorrowInfo::FieldsBorrowedBy(Self::get_union_of_maps(
                                        fields_borrowed_by1,
                                        fields_borrowed_by2,
                                    )),
                                );
                            }
                        }
                    }
                }
            } else {
                borrows.insert(*nonce, borrow_info.clone());
            }
        }
        for (nonce, borrow_info) in &state.borrows {
            if !borrows.contains_key(nonce) {
                borrows.insert(*nonce, borrow_info.clone());
            }
        }
        let partition = self.partition.join(&state.partition);
        let next_state = AbstractState {
            locals,
            globals,
            borrows,
            partition,
        };
        if next_state == *self {
            JoinResult::Unchanged
        } else {
            *self = next_state;
            JoinResult::Changed
        }
    }
fn join ( & mut self , state : & AbstractState ) -> JoinResult { // A join failure occurs in each of the following situations: // - an unrestricted value is borrowed along one path but unavailable along the other // - a value that is not unrestricted, i.e., either reference or resource, is available //   along one path but not the other if Self :: unrestricted_borrowed_value_unavailable ( self , state ) || Self :: unrestricted_borrowed_value_unavailable ( state , self ) { return JoinResult :: Error ; } if self . locals . keys ( ) . filter ( | idx | ! self . locals [ idx ] . is_unrestricted_value ( ) ) . collect :: < BTreeSet < _ > > ( ) != state . locals . keys ( ) . filter ( | idx | ! state . locals [ idx ] . is_unrestricted_value ( ) ) . collect :: < BTreeSet < _ > > ( ) { return JoinResult :: Error ; } let mut values1 = BTreeMap :: new ( ) ; let mut references1 = BTreeMap :: new ( ) ; Self :: split_locals ( & self . locals , & mut values1 , & mut references1 ) ; let mut values2 = BTreeMap :: new ( ) ; let mut references2 = BTreeMap :: new ( ) ; Self :: split_locals ( & state . locals , & mut values2 , & mut references2 ) ; checked_verify ! ( references1 references2 ) ; let mut locals = BTreeMap :: new ( ) ; for ( idx , nonce ) in & references1 { locals . insert ( idx . clone ( ) , AbstractValue :: Reference ( * nonce ) ) ; } for ( idx , ( kind1 , nonce_set1 ) ) in & values1 { if let Some ( ( kind2 , nonce_set2 ) ) = values2 . get ( idx ) { checked_verify ! ( kind1 kind2 ) ; locals . insert ( idx . clone ( ) , AbstractValue :: Value ( * kind1 , nonce_set1 . union ( nonce_set2 ) . cloned ( ) . collect ( ) ) , ) ; } } let mut globals = self . globals . clone ( ) ; for ( idx , global_nonce_set ) in & state . globals { globals . entry ( * idx ) . and_modify ( | nonce_set | { * nonce_set = global_nonce_set . union ( nonce_set ) . cloned ( ) . collect ( ) } ) . or_insert_with ( | | global_nonce_set . clone ( ) ) ; } let mut borrows = BTreeMap :: new ( ) ; for ( nonce , borrow_info ) in & self . borrows { if state . borrows . contains_key ( nonce ) { match borrow_info { BorrowInfo :: BorrowedBy ( borrowed_by1 ) => match & state . borrows [ nonce ] { BorrowInfo :: BorrowedBy ( borrowed_by2 ) => { borrows . insert ( * nonce , BorrowInfo :: BorrowedBy ( borrowed_by1 . union ( borrowed_by2 ) . cloned ( ) . collect ( ) , ) , ) ; } BorrowInfo :: FieldsBorrowedBy ( fields_borrowed_by2 ) => { borrows . insert ( * nonce , BorrowInfo :: BorrowedBy ( Self :: get_union_of_sets ( borrowed_by1 , fields_borrowed_by2 , ) ) , ) ; } } , BorrowInfo :: FieldsBorrowedBy ( fields_borrowed_by1 ) => { match & state . borrows [ nonce ] { BorrowInfo :: BorrowedBy ( borrowed_by2 ) => { borrows . insert ( * nonce , BorrowInfo :: BorrowedBy ( Self :: get_union_of_sets ( borrowed_by2 , fields_borrowed_by1 , ) ) , ) ; } BorrowInfo :: FieldsBorrowedBy ( fields_borrowed_by2 ) => { borrows . insert ( * nonce , BorrowInfo :: FieldsBorrowedBy ( Self :: get_union_of_maps ( fields_borrowed_by1 , fields_borrowed_by2 , ) ) , ) ; } } } } } else { borrows . insert ( * nonce , borrow_info . clone ( ) ) ; } } for ( nonce , borrow_info ) in & state . borrows { if ! borrows . contains_key ( nonce ) { borrows . insert ( * nonce , borrow_info . clone ( ) ) ; } } let partition = self . partition . join ( & state . partition ) ; let next_state = AbstractState { locals , globals , borrows , partition , } ; if next_state == * self { JoinResult :: Unchanged } else { * self = next_state ; JoinResult :: Changed } }
attempts to join state to self and returns the result
both self.is_canonical() and state.is_canonical() must be true
attempts to join state to self and returns the result both self . is_canonical () and state . is_canonical () must be true
&mut self
state
&AbstractState