Edit and publish Alloy article
This commit is contained in:
		
							parent
							
								
									8a2e91e65e
								
							
						
					
					
						commit
						250884c7bc
					
				@ -62,15 +62,15 @@ sig Symbol {
 | 
				
			|||||||
    properties: set Property
 | 
					    properties: set Property
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pred flagMatchesPropery[flag: Flag, property: Property] {
 | 
					pred flagMatchesProperty[flag: Flag, property: Property] {
 | 
				
			||||||
    (flag = Method and property = PMethod) or
 | 
					    (flag = Method and property = PMethod) or
 | 
				
			||||||
    (flag = MethodOrField and (property = PMethod or property = PField)) or
 | 
					    (flag = MethodOrField and (property = PMethod or property = PField)) or
 | 
				
			||||||
    (flag = Public and property = PPublic)
 | 
					    (flag = Public and property = PPublic)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pred bitfieldMatchesProperties[bitfield: Bitfield, symbol: Symbol] {
 | 
					pred bitfieldMatchesProperties[bitfield: Bitfield, symbol: Symbol] {
 | 
				
			||||||
    all flag: bitfield.positiveFlags | some property: symbol.properties | flagMatchesPropery[flag, property]
 | 
					    all flag: bitfield.positiveFlags | some property: symbol.properties | flagMatchesProperty[flag, property]
 | 
				
			||||||
    all flag: bitfield.negativeFlags | no property: symbol.properties | flagMatchesPropery[flag, property]
 | 
					    all flag: bitfield.negativeFlags | no property: symbol.properties | flagMatchesProperty[flag, property]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bitfieldExists: run {
 | 
					bitfieldExists: run {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,8 @@
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
title: "Proving My Compiler Code Incorrect With Alloy"
 | 
					title: "Proving My Compiler Code Incorrect With Alloy"
 | 
				
			||||||
date: 2023-05-02T22:48:52-07:00
 | 
					date: 2023-06-04T21:56:00-07:00
 | 
				
			||||||
tags: ["Compilers", "Alloy"]
 | 
					tags: ["Compilers", "Alloy"]
 | 
				
			||||||
description: "In this post, I apply Alloy to a piece of code in the Chapel compiler to find a bug."
 | 
					description: "In this post, I apply Alloy to a piece of code in the Chapel compiler to find a bug."
 | 
				
			||||||
draft: true
 | 
					 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__Disclaimer:__ though "my compiler code" makes for a fun title, I do not
 | 
					__Disclaimer:__ though "my compiler code" makes for a fun title, I do not
 | 
				
			||||||
@ -26,7 +25,7 @@ fairly silly by the standards of "real" Alloy users.
 | 
				
			|||||||
One of the things that a language like Chapel has to do is called _resolution_,
 | 
					One of the things that a language like Chapel has to do is called _resolution_,
 | 
				
			||||||
which is the process of figuring out what each identifier, like `x`, refers to,
 | 
					which is the process of figuring out what each identifier, like `x`, refers to,
 | 
				
			||||||
and what its type is. Even the first part of that is pretty complicated, what
 | 
					and what its type is. Even the first part of that is pretty complicated, what
 | 
				
			||||||
with public and private variables, methods (which can be decalred outside
 | 
					with public and private variables, methods (which can be declared outside
 | 
				
			||||||
of their receiver type in Chapel), and more...
 | 
					of their receiver type in Chapel), and more...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Scope resolution in Chapel is further complicated by the fact that the same
 | 
					Scope resolution in Chapel is further complicated by the fact that the same
 | 
				
			||||||
@ -52,13 +51,34 @@ module M {
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you don't know Chapel (and you probably don't!) this program already merits a fair
 | 
					If you don't know Chapel (and you probably don't!) this program already merits a fair
 | 
				
			||||||
bit of explanation. A _module_ in Chapel (declared via a `module` keyword)
 | 
					bit of explanation. I've collapsed it for the sake of visual clarity; feel
 | 
				
			||||||
 | 
					free to expand the below section to learn more about the language features
 | 
				
			||||||
 | 
					used in the program above.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{< details summary="Click here for an explanation of the above code snippet" >}}
 | 
				
			||||||
 | 
					A _module_ in Chapel (declared via a `module` keyword)
 | 
				
			||||||
is just a collection of definitions. Such definitions could include variables,
 | 
					is just a collection of definitions. Such definitions could include variables,
 | 
				
			||||||
methods, classes and more. Putting them in a module helps group them.
 | 
					methods, classes and more. Putting them in a module helps group them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{< todo >}}
 | 
					A _class_ in Chapel (declared via a `class` keyword) is much like a class in
 | 
				
			||||||
Write the rest of this explanation.
 | 
					object oriented languages. The class `C` that we're creating on line 2 doesn't
 | 
				
			||||||
{{< /todo >}}
 | 
					have any fields or methods -- at least not yet. We will, however, add methods
 | 
				
			||||||
 | 
					to it using Chapel's _secondary method_ mechanism (more on that in a moment).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `proc` keyword is used to create functions and methods. On line 5, we
 | 
				
			||||||
 | 
					create a procedure called `foo` that does nothing. On line 8, because we
 | 
				
			||||||
 | 
					write `C.foo` instead of just `foo`, we're actually creating a method on
 | 
				
			||||||
 | 
					the class `C` we declared earlier. This method does nothing too. Notice
 | 
				
			||||||
 | 
					that although declaring classes in Chapel works about the same as declaring
 | 
				
			||||||
 | 
					classes in other languages, it's fairly unusual to be able to declare a
 | 
				
			||||||
 | 
					class method (like the `foo` on line 8 in this case) outside of the `class
 | 
				
			||||||
 | 
					C { ... }` section of code. This is part of the reason that Chapel method
 | 
				
			||||||
 | 
					resolution is complicated (methods can be declared anywhere!). The only
 | 
				
			||||||
 | 
					other language that I know of that supports this feature is Kotlin with its
 | 
				
			||||||
 | 
					[extension function
 | 
				
			||||||
 | 
					mechanism](https://kotlinlang.org/docs/extensions.html), but it's possible
 | 
				
			||||||
 | 
					that other languages have similar functionality.
 | 
				
			||||||
 | 
					{{< /details >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The interesting part of the snippet is the body of the `doSomething` method.
 | 
					The interesting part of the snippet is the body of the `doSomething` method.
 | 
				
			||||||
It has a call to `foo`: but which `foo` is it referring to? There are two:
 | 
					It has a call to `foo`: but which `foo` is it referring to? There are two:
 | 
				
			||||||
@ -87,10 +107,10 @@ the search order will be as follows:
 | 
				
			|||||||
   be the non-method `foo`.
 | 
					   be the non-method `foo`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Notice that we've already had to search the module `M` twice, looking for
 | 
					Notice that we've already had to search the module `M` twice, looking for
 | 
				
			||||||
different things each time. First, we were looking for only method, but
 | 
					different things each time. First, we were looking for only methods, but
 | 
				
			||||||
later, we were looking for anything. However, this isn't as complicated as
 | 
					later, we were looking for anything. However, this isn't as complicated as
 | 
				
			||||||
things can get. The simplifying aspect of this program is that both `doSomething`
 | 
					things can get. The simplifying aspect of this program is that both `doSomething`
 | 
				
			||||||
and `C` are defined inside the class `C`, and therefore have access to its
 | 
					and `C` are defined inside the module `M`, and therefore have access to its
 | 
				
			||||||
private methods and procedures. If we extracted `C.doSomething` into its
 | 
					private methods and procedures. If we extracted `C.doSomething` into its
 | 
				
			||||||
own separate module, the program would look like this.
 | 
					own separate module, the program would look like this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -119,7 +139,7 @@ Since `doSomething` is now in another module, it can't just access the `foo`s fr
 | 
				
			|||||||
and make use of them. I opted for a `use` statement, which, in its simplest form,
 | 
					and make use of them. I opted for a `use` statement, which, in its simplest form,
 | 
				
			||||||
just brings all the declarations inside the `use`d module into the current scope. Thus,
 | 
					just brings all the declarations inside the `use`d module into the current scope. Thus,
 | 
				
			||||||
the `use` statement on line 11 would bring all things declared in `M1` into
 | 
					the `use` statement on line 11 would bring all things declared in `M1` into
 | 
				
			||||||
the scope inside `M2`. There's a catch, though: since `M2` is not declared
 | 
					the scope inside `M2`. There's a catch, though. Since `M2` is not declared
 | 
				
			||||||
inside `M1`, a `use` statement will not be able to bring in _private_ symbols
 | 
					inside `M1`, a `use` statement will not be able to bring in _private_ symbols
 | 
				
			||||||
from `M1` (they're private for a reason!). So, this time, when searching the scope
 | 
					from `M1` (they're private for a reason!). So, this time, when searching the scope
 | 
				
			||||||
for `M1`, we will have to search only for public symbols. That's another,
 | 
					for `M1`, we will have to search only for public symbols. That's another,
 | 
				
			||||||
@ -129,14 +149,13 @@ different way of searching `M1`. So far, we've seen three:
 | 
				
			|||||||
* Search `M1` for methods only.
 | 
					* Search `M1` for methods only.
 | 
				
			||||||
* Search `M1` for public symbols only.
 | 
					* Search `M1` for public symbols only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In Dyno, there are even more different ways of searching a single scope, and
 | 
					Dyno introduces more ways to search within a scope, including combinations of
 | 
				
			||||||
some of them are mixes of others (one might consider, for instance, searching
 | 
					search types, such as looking only for public methods. To represent the various
 | 
				
			||||||
for only public methods). To represent the various search configurations,
 | 
					search configurations, the Dyno team came up with using a bitfield of _flags_,
 | 
				
			||||||
the Dyno team came up with using a bitfield of _flags_, each of which indicated
 | 
					each of which indicated a necessary condition for a symbol to be returned. A
 | 
				
			||||||
a necessary condition for a symbol to be returned. A bitfield with flags set
 | 
					bitfield with flags set for two properties (like "public" and "method") requires
 | 
				
			||||||
for two properties (like "public" and "method") requires that both such
 | 
					that both such properties be found on each symbol that's returned from a scope.
 | 
				
			||||||
properties be found on each symbol that's returned from a scope. This led to
 | 
					This led to C++ code along the lines of:
 | 
				
			||||||
C++ code along the lines of:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```C++
 | 
					```C++
 | 
				
			||||||
auto allPublicSymbols = Flags::PUBLIC;
 | 
					auto allPublicSymbols = Flags::PUBLIC;
 | 
				
			||||||
@ -167,7 +186,7 @@ In Dyno, we like to avoid additional work when we can. To do so, we track
 | 
				
			|||||||
which scopes have already been searched, and avoid searching them again.
 | 
					which scopes have already been searched, and avoid searching them again.
 | 
				
			||||||
Since what comes up from a search depends on the flags, we store the flags
 | 
					Since what comes up from a search depends on the flags, we store the flags
 | 
				
			||||||
alongside the scopes we've checked. __If we find that the previously-checked
 | 
					alongside the scopes we've checked. __If we find that the previously-checked
 | 
				
			||||||
bitfield is a subset of the current biset, we just skip the search__.
 | 
					bitfield is a subset of the current bitset, we just skip the search__.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
But then, what if it _isn't_ a subset? Another concern here is avoiding
 | 
					But then, what if it _isn't_ a subset? Another concern here is avoiding
 | 
				
			||||||
duplicate results (it's easier to check for duplicate definitions if you
 | 
					duplicate results (it's easier to check for duplicate definitions if you
 | 
				
			||||||
@ -186,7 +205,7 @@ versions of each flag available. Can't you just add those to the filter?
 | 
				
			|||||||
{{< message "answer" "Daniel" >}}
 | 
					{{< message "answer" "Daniel" >}}
 | 
				
			||||||
Good question. The difference is a little bit tricky. If we just negated
 | 
					Good question. The difference is a little bit tricky. If we just negated
 | 
				
			||||||
each flag, we'd turn an expression like \(A \land B\) into \(\lnot A \land
 | 
					each flag, we'd turn an expression like \(A \land B\) into \(\lnot A \land
 | 
				
			||||||
\lnot B\). However, according to De Morgan's laws, the proper negation of
 | 
					\lnot B\). However, according to [De Morgan's laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws), the proper negation of
 | 
				
			||||||
\(A \land B\) is \(\lnot A \lor \lnot B\) (notice the use of "or" instead
 | 
					\(A \land B\) is \(\lnot A \lor \lnot B\) (notice the use of "or" instead
 | 
				
			||||||
of "and"). On the other hand, using an "exclude" bitfield negates the whole
 | 
					of "and"). On the other hand, using an "exclude" bitfield negates the whole
 | 
				
			||||||
conjunction, rather than the individual flags, and so gives us the result
 | 
					conjunction, rather than the individual flags, and so gives us the result
 | 
				
			||||||
@ -303,7 +322,7 @@ Here's the Alloy definition for everything I just said:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{{< codelines "Alloy" "dyno-alloy/DynoAlloy.als" 59 63 >}}
 | 
					{{< codelines "Alloy" "dyno-alloy/DynoAlloy.als" 59 63 >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Now, we can specify how flags in a bitfield relates to properties on a
 | 
					Now, we can specify how flags in a bitfield relate to properties on a
 | 
				
			||||||
symbol. We can do so by saying which flags match which properties. The
 | 
					symbol. We can do so by saying which flags match which properties. The
 | 
				
			||||||
`Method` flag, for instance, will be satisfied by the `PMethod` property.
 | 
					`Method` flag, for instance, will be satisfied by the `PMethod` property.
 | 
				
			||||||
The `MethodOrField` flag is more lenient, and will be satisfied by either
 | 
					The `MethodOrField` flag is more lenient, and will be satisfied by either
 | 
				
			||||||
@ -321,9 +340,9 @@ informally, the condition for a bitfield matching a symbol is twofold:
 | 
				
			|||||||
  property on the symbol (that is to say, if `Method` is in the negative
 | 
					  property on the symbol (that is to say, if `Method` is in the negative
 | 
				
			||||||
  flags set, then the symbol must not have `PMethod` property). It is more
 | 
					  flags set, then the symbol must not have `PMethod` property). It is more
 | 
				
			||||||
  conveniently to formulate this -- equivalently -- as follows: for each
 | 
					  conveniently to formulate this -- equivalently -- as follows: for each
 | 
				
			||||||
  negative flag, there most not be a property that satisfies it.
 | 
					  negative flag, there must not be a property that satisfies it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Each of the above two conditions translate quite literally into Alloy:
 | 
					Each of the above two conditions translates quite literally into Alloy:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{< codelines "Alloy" "dyno-alloy/DynoAlloy.als" 71 74 >}}
 | 
					{{< codelines "Alloy" "dyno-alloy/DynoAlloy.als" 71 74 >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user