The stack (original) (raw)

The stack

The first "layer" of the recursive solver is the Stack. It is really just what it sounds like: a stack that stores each thing that the recursive solver is solving. Initially, it contains only one item, the root goal that was given by the user.

Each frame on the stack has an associated StackDepth, which is basically an index that increases (so 0 is the top of the stack, 1 is the next thing pushed, etc).

How the recursive solver works at the highest level

At the highest level, the recursive solver works like so.

Example


#![allow(unused)]
fn main() {
trait A { }
trait B { }

impl<T: B> A for Vec<T> { }

impl B for u32 { }
}

Imagine we are trying to prove Implemented(Vec<?X>: A). There is one unbound inference variable here, ?X. We will ultimately get the result Provable(?X = u32). But how do we find it?

Why do we need the stack?

You may have noticed that the description above never seemed to use the Stack, it only relied on the program stack. That's because I left out any discussion of cycles. In fact, the Stack data structure does mirror the program stack, it just adds some extra information we use in resolving cycles. We'll discuss cycles in the next chapter, when we discuss the search graph.

Figuring out if something is on the stack

The stack itself never stores the goal associated with a particular entry. That information is found in the search graph, which will be covered in detail in the next section. For now it suffices to say that the search graph maps from "some goal that we are currently solving" to "information about that goal", and one of the bits of information is the StackDepth of its entry on the stack (if any).

Therefore, when we are about to start solving some (canonical) goal G, we can detect a cycle by checking in the search graph to see whether G has an associatedStackDepth. If so, it must be on the stack already (and we can set thecycle field to true...but I get ahead of myself, read the next chapters to learn more about that).