/// <summary>
            /// Populates the given graph based on the given compilation. Only the compilation's entry points and
            /// those callables that the entry points depend on will be included in the graph. All Generated
            /// Implementations for specializations should be resolved before calling this, except Self-Inverse,
            /// which is handled by creating a dependency to the appropriate specialization of the same callable.
            /// This will throw an error if a Generated Implementation other than a Self-Inverse is encountered.
            /// </summary>
            public static void PopulateConcreteGraph(ConcreteGraphBuilder graph, QsCompilation compilation)
            {
                var walker          = new BuildGraph(graph);
                var entryPointNodes = compilation.EntryPoints.Select(name => new ConcreteCallGraphNode(name, QsSpecializationKind.QsBody, TypeParameterResolutions.Empty));

                foreach (var entryPoint in entryPointNodes)
                {
                    // Make sure all the entry points are added to the graph
                    walker.SharedState.Graph.AddNode(entryPoint);
                    walker.SharedState.RequestStack.Push(entryPoint);
                }

                var globals = compilation.Namespaces.GlobalCallableResolutions();

                while (walker.SharedState.RequestStack.TryPop(out var currentRequest))
                {
                    // If there is a call to an unknown callable, throw exception
                    if (!globals.TryGetValue(currentRequest.CallableName, out QsCallable currentCallable))
                    {
                        throw new ArgumentException($"Couldn't find definition for callable: {currentRequest.CallableName}");
                    }

                    var spec = GetSpecializationFromRequest(currentRequest, currentCallable);

                    // The current request must be added before it is processed to prevent
                    // self-references from duplicating on the stack.
                    walker.SharedState.ResolvedNodeSet.Add(currentRequest);
                    walker.SharedState.CurrentNode            = currentRequest;
                    walker.SharedState.GetSpecializationKinds = (callableName) => GetSpecializationKinds(globals, callableName);
                    walker.Namespaces.OnSpecializationImplementation(spec.Implementation);
                }
            }
                public BuildGraph(ConcreteGraphBuilder graph) : base(new TransformationState(graph))
                {
                    this.Namespaces = new NamespaceWalker(this);
                    this.Statements = new CallGraphWalkerBase <ConcreteGraphBuilder, ConcreteCallGraphNode, ConcreteCallGraphEdge> .StatementWalker <TransformationState>(this);

                    this.StatementKinds = new StatementKindTransformation <TransformationState>(this, TransformationOptions.NoRebuild);
                    this.Expressions    = new CallGraphWalkerBase <ConcreteGraphBuilder, ConcreteCallGraphNode, ConcreteCallGraphEdge> .ExpressionWalker <TransformationState>(this);

                    this.ExpressionKinds = new ExpressionKindWalker(this);
                    this.Types           = new TypeTransformation <TransformationState>(this, TransformationOptions.Disabled);
                }
 /// <summary>
 /// Populates the given graph based on the given compilation. Only the compilation's entry points and
 /// those callables that the entry points depend on will be included in the graph. All Generated
 /// Implementations for specializations should be resolved before calling this. This will throw an
 /// error if a Generated Implementation is encountered.
 /// </summary>
 public static void PopulateConcreteGraph(ConcreteGraphBuilder graph, QsCompilation compilation) => ConcreteCallGraphWalker.PopulateConcreteGraph(graph, compilation);