Instead, we can _relate_ two bitfields using a predicate.
> This bitfield is exactly like that bitfield.
```chapel
pred bitfieldEqual[b1: Bitfield, b2: Bitfield] {
b1.positiveFlags = b2.positiveFlags and b1.negativeFlags = b2.negativeFlags
}
```
---
# Modeling Possible Searches
Alloy isn't an imperative language. We can't mutate variables like we do in C++. Instead, we model how each statement changes the state, by relating the "current" state to the "next" state.
<divclass="side-by-side">
<div>
```C++
filter |= IdAndFlags::PUBLIC;
```
</div>
<div>
```alloy
addBitfieldFlag[filterNow, filterNext, Public]
```
</div>
</div>
This might remind you of [Hoare Logic](https://en.wikipedia.org/wiki/Hoare_logic), where statements like:
$$
\{ P \} \; s \; \{ Q \}
$$
Read as:
> If $P$ is true before executing $s$, then $Q$ will be true after executing $s$.
Finally, if C++ code has conditionals, we need to allow for the possibility of either branch being taken. We do this by using "or" on descriptions of the next state.
<divclass="side-by-side">
<div>
```C++
if (skipPrivateVisibilities) {
curFilter |= IdAndFlags::PUBLIC;
}
if (onlyMethodsFields) {
curFilter |= IdAndFlags::METHOD_FIELD;
} else if (!includeMethods && receiverScopes.empty()) {
curFilter |= IdAndFlags::NOT_METHOD;
}
```
</div>
<div>
```alloy
addBitfieldFlag[initialState.curFilter, bitfieldMiddle, Public] or
Putting this into a predicate, `possibleState`, we encode what searches the compiler can undertake.
**Takeaway**: We encoded the logic that configures possible searches in Alloy. This instructs the analyzer about possible cases to consider.
---
# Modeling `previousFilter`
So far, all we've done is encoded what queries the compiler might make about a scope.
We still need to encode how we save the flags we've already searched with.
Model the search state with a "global" (really, unique) variable:
```alloy
/* Initially, no search has happeneed for a scope, so its 'previousFilter' is not set to anything. */
one sig NotSet {}
one sig SearchState {
, var previousFilter: Bitfield + NotSet
}
```
Above, `+` is used for union. `previousFilter` can either be a `Bitfield` or `NotSet`.
---
# Modeling `previousFilter`
If no previous search has happened, we set `previousFilter` to the current `filter`.
Otherwise, we set `previousFilter` to the intersection of `filter` and `previousFilter`, as mentioned before.
<divclass="side-by-side">
<div>
```C++
if (hasPrevious) {
previousFilter = filter & previousFilter;
} else {
previousFilter = filter;
}
```
</div>
<div>
```alloy
pred update[toSet: Bitfield + NotSet, setTo: FilterState] {
toSet' != NotSet and bitfieldIntersection[toSet, setTo.include, toSet']
}
pred updateOrSet[toSet: Bitfield + NotSet, setTo: FilterState] {
(toSet = NotSet and toSet' = setTo.include) or
(toSet != NotSet and update[toSet, setTo])
}
```
</div>
</div>
---
# Putting it Together
We now have a model of what our C++ program is doing: it computes some set of filter flags, then runs a search, excluding the previous flags. It then updates the previous flags with the current search. We can encode
this as follows:
```
fact step {
always {
// Model that a new doLookupInScope could've occurred, with any combination of flags.
all searchState: SearchState {
some fs: FilterState {
// This is a possible combination of lookup flags
possibleState[fs]
// If a search has been performed before, take the intersection; otherwise,
// just insert the current filter flags.
updateOrSet[searchState.previousFilter, fs]
}
}
}
}
```
---
# Are there any bugs?
Model checkers ensure that all properties we want to hold, do hold. To find a counter example, we ask it to prove the negation of what we want.
```C
wontFindNeeded: run {
all searchState: SearchState {
eventually some props: Props, fs: FilterState, fsBroken: FilterState {
// Some search (fs) will cause a transition / modification of the search state...
configureState[fs]
updateOrSet[searchState.previousFilter, fs]
// Such that a later, valid search... (fsBroken)
configureState[fsBroken]
// Will allow for a set of properties...
// ... that are left out of the original search...
not bitfieldMatchesProperties[searchState.previousFilter, props]
// ... and out of the current search
not (bitfieldMatchesProperties[fs.include, props] and not bitfieldMatchesProperties[searchState.previousFilter, props])
To trigger this sequence of searches, we needed a lot more gymnastics.
<divclass="side-by-side">
<div>
```chapel
module TopLevel {
module XContainerUser {
public use TopLevel.XContainer;
}
module XContainer {
private var x: int;
record R {}
module MethodHaver {
use TopLevel.XContainerUser;
use TopLevel.XContainer;
proc R.foo() {
var y = x;
}
}
}
}
```
</div>
<div>
* the scope of `R` is searched with for methods
* The scope of `R`’s parent (`XContainer`) is searched for methods
* The scope of `XContainerUser` is searched for public symbols (via the `use`)
* The scope of `XContainer` is searched with public symbols (via the `public use`)
* The scope of `XContainer` searched for with no filters via the second use; but the stored filter is bad, so the lookup returns early, not finding `x`.