public class CheckForCycleOfLocalFields extends java.lang.Object implements CapsuleCheck
Checks that a given capsule core is not a part a part some cycle of capsule types linked
by @Local fields.
This check is needed to prevent the definition of certain uninstantiable capsule systems. To see the problem, consider one such uninstantiable system:
import org.paninij.lang.*;
@Capsule
class CycleCore {
@Local Cycle cycle;
}
Just before a capsule system containing this capsule begins, the runtime will instantiate one
Cycle capsule instance. Because this @Cycle instance has an @Local Cycle
field, a second instance of Cycle is needed as well. This second one is responsible for a
third, and so on without bound. Thus, capsule allocation proceeds until some resource limit is
reached and the system crashes.
We can imagine the problem as the existence of a cycle in a directed graph whose vertices are
capsule core types and whose edges are @Local fields pointing between them. In the
case above, we can imagine that this capsule core is contributing to the graph a single
vertex with a self-edge.
In our example, our capsule needs to instantiate another instance of the same capsule type, which leads to infinite regress. However, we can see the problem more generally as a problem of cycles of cores. Our example capsule core is a part of a cycle of length one, but the same hazard of infinite regress occurs for cycles of any length.
Fortunately, because of the static nature of capsule system topologies, it is easy to check
for this possibility at compile time and to thus eliminate the possibility of it happening at
runtime. This CapsuleCheck is responsible for doing just that.
The check is implemented by recursively exploring capsule core definitions across their
@Local fields. We don't explicitly construct the graph, but rather explore the
TypeElement data structures which encode the user's capsule core types. In
particular, we use a customized depth-first traversal to explore these links between capsule
core types looking for cycles. If while exploring in this way we re-find the capsule type at
which we started, the Check.Result is an error result. If the query capsule core was
not found to be in a cycle, then the result is Result#OK.
Unlike most checks, this one maintains some state throughout its lifetime: we memoize the results from our explorations checked capsule cores. This speeds up checks by preventing the re-exploration of capsules which have previously been checked. These partial results are used both within and across invocations of the check.
While exhaustively searching for cycles which involve some query capsule core, we may discover a cycle between some other capsule cores. Related to this observation, we have designed this check with two useful properties:
The first property is meant to speed up execution by saving such results. The second property is meant to keep blame for a cycle small to thus keep error messages to the user to a minimum; the principle is that a capsule core should only be marked as an error if that capsule core is directly involved in some cycle in the graph. In the current implementation, we do not report the cycles themselves to the user. Instead, we just give an error for each capsule core participating in the cycle in no particular order. TODO: Use or adapt this blurb: The main observation to understanding this recursive algorithm works is the following: if the capsule core associated with some field `f` has been fully searched and found to be `OK` (i.e. no cycles found), then there must not be any cycle including these two capsules. This means that we need not recurse down those edges to capsules which have been found to be `OK`: any cycles in which `core` is a part cannot involve these `OK` neighbors. So, to determine whether `core` is `OK`, we only need to check for this capsule's involvement in a cycle via those fields whose cores are as-yet unchecked or are part of a cycle. TODO: State which other capsule checks this one depends upon.
Check.Result| Constructor and Description |
|---|
CheckForCycleOfLocalFields(javax.annotation.processing.ProcessingEnvironment procEnv) |
| Modifier and Type | Method and Description |
|---|---|
Check.Result |
checkCapsule(javax.lang.model.element.TypeElement core) |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitcheckCapsulepublic CheckForCycleOfLocalFields(javax.annotation.processing.ProcessingEnvironment procEnv)
public Check.Result checkCapsule(javax.lang.model.element.TypeElement core)
checkCapsule in interface CapsuleCheckcore - A type element for the capsule core to be checked.