Source File
initorder.go
Belonging Package
go/types
// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.// Source: ../../cmd/compile/internal/types2/initorder.go// Copyright 2014 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package typesimport (.)// initOrder computes the Info.InitOrder for package variables.func ( *Checker) () {// An InitOrder may already have been computed if a package is// built from several calls to (*Checker).Files. Clear it..Info.InitOrder = .Info.InitOrder[:0]// Compute the object dependency graph and initialize// a priority queue with the list of graph nodes.:= nodeQueue(dependencyGraph(.objMap))heap.Init(&)const = falseif {fmt.Printf("Computing initialization order for %s\n\n", .pkg)fmt.Println("Object dependency graph:")for , := range .objMap {// only print objects that may appear in the dependency graphif , := .(dependency); != nil {if len(.deps) > 0 {fmt.Printf("\t%s depends on\n", .Name())for := range .deps {fmt.Printf("\t\t%s\n", .Name())}} else {fmt.Printf("\t%s has no dependencies\n", .Name())}}}fmt.Println()fmt.Println("Transposed object dependency graph (functions eliminated):")for , := range {fmt.Printf("\t%s depends on %d nodes\n", .obj.Name(), .ndeps)for := range .pred {fmt.Printf("\t\t%s is dependent\n", .obj.Name())}}fmt.Println()fmt.Println("Processing nodes:")}// Determine initialization order by removing the highest priority node// (the one with the fewest dependencies) and its edges from the graph,// repeatedly, until there are no nodes left.// In a valid Go program, those nodes always have zero dependencies (after// removing all incoming dependencies), otherwise there are initialization// cycles.:= make(map[*declInfo]bool)for len() > 0 {// get the next node:= heap.Pop(&).(*graphNode)if {fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",.obj.Name(), .obj.order(), .ndeps)}// if n still depends on other nodes, we have a cycleif .ndeps > 0 {:= findPath(.objMap, .obj, .obj, make(map[Object]bool))// If n.obj is not part of the cycle (e.g., n.obj->b->c->d->c),// cycle will be nil. Don't report anything in that case since// the cycle is reported when the algorithm gets to an object// in the cycle.// Furthermore, once an object in the cycle is encountered,// the cycle will be broken (dependency count will be reduced// below), and so the remaining nodes in the cycle don't trigger// another error (unless they are part of multiple cycles).if != nil {.reportCycle()}// Ok to continue, but the variable initialization order// will be incorrect at this point since it assumes no// cycle errors.}// reduce dependency count of all dependent nodes// and update priority queuefor := range .pred {.ndeps--heap.Fix(&, .index)}// record the init order for variables with initializers only, := .obj.(*Var):= .objMap[]if == nil || !.hasInitializer() {continue}// n:1 variable declarations such as: a, b = f()// introduce a node for each lhs variable (here: a, b);// but they all have the same initializer - emit only// one, for the first variable seenif [] {continue // initializer already emitted, if any}[] = true:= .lhs // possibly nil (see declInfo.lhs field comment)if == nil {= []*Var{}}:= &Initializer{, .init}.Info.InitOrder = append(.Info.InitOrder, )}if {fmt.Println()fmt.Println("Initialization order:")for , := range .Info.InitOrder {fmt.Printf("\t%s\n", )}fmt.Println()}}// findPath returns the (reversed) list of objects []Object{to, ... from}// such that there is a path of object dependencies from 'from' to 'to'.// If there is no such path, the result is nil.func ( map[Object]*declInfo, , Object, map[Object]bool) []Object {if [] {return nil}[] = true// sort deps for deterministic resultvar []Objectfor := range [].deps {= append(, )}sort.Slice(, func(, int) bool {return [].order() < [].order()})for , := range {if == {return []Object{}}if := (, , , ); != nil {return append(, )}}return nil}// reportCycle reports an error for the given cycle.func ( *Checker) ( []Object) {:= [0]// report a more concise error for self referencesif len() == 1 {.errorf(, InvalidInitCycle, "initialization cycle: %s refers to itself", .Name())return}:= .newError(InvalidInitCycle).addf(, "initialization cycle for %s", .Name())// "cycle[i] refers to cycle[j]" for (i,j) = (0,n-1), (n-1,n-2), ..., (1,0) for len(cycle) = n.for := len() - 1; >= 0; -- {:= [].addf(, "%s refers to %s", .Name(), .Name())=}.report()}// ----------------------------------------------------------------------------// Object dependency graph// A dependency is an object that may be a dependency in an initialization// expression. Only constants, variables, and functions can be dependencies.// Constants are here because constant expression cycles are reported during// initialization order computation.type dependency interface {ObjectisDependency()}// A graphNode represents a node in the object dependency graph.// Each node p in n.pred represents an edge p->n, and each node// s in n.succ represents an edge n->s; with a->b indicating that// a depends on b.type graphNode struct {obj dependency // object represented by this nodepred, succ nodeSet // consumers and dependencies of this node (lazily initialized)index int // node index in graph slice/priority queuendeps int // number of outstanding dependencies before this object can be initialized}// cost returns the cost of removing this node, which involves copying each// predecessor to each successor (and vice-versa).func ( *graphNode) () int {return len(.pred) * len(.succ)}type nodeSet map[*graphNode]boolfunc ( *nodeSet) ( *graphNode) {if * == nil {* = make(nodeSet)}(*)[] = true}// dependencyGraph computes the object dependency graph from the given objMap,// with any function nodes removed. The resulting graph contains only constants// and variables.func ( map[Object]*declInfo) []*graphNode {// M is the dependency (Object) -> graphNode mapping:= make(map[dependency]*graphNode)for := range {// only consider nodes that may be an initialization dependencyif , := .(dependency); != nil {[] = &graphNode{obj: }}}// compute edges for graph M// (We need to include all nodes, even isolated ones, because they still need// to be scheduled for initialization in correct order relative to other nodes.)for , := range {// for each dependency obj -> d (= deps[i]), create graph edges n->s and s->nfor := range [].deps {// only consider nodes that may be an initialization dependencyif , := .(dependency); != nil {:= [].succ.add().pred.add()}}}var , []*graphNode // separate non-functions and functionsfor , := range {if , := .obj.(*Func); {= append(, )} else {= append(, )}}// remove function nodes and collect remaining graph nodes in G// (Mutually recursive functions may introduce cycles among themselves// which are permitted. Yet such cycles may incorrectly inflate the dependency// count for variables which in turn may not get scheduled for initialization// in correct order.)//// Note that because we recursively copy predecessors and successors// throughout the function graph, the cost of removing a function at// position X is proportional to cost * (len(funcG)-X). Therefore, we should// remove high-cost functions last.slices.SortFunc(, func(, *graphNode) int {return cmp.Compare(.cost(), .cost())})for , := range {// connect each predecessor p of n with each successor s// and drop the function node (don't collect it in G)for := range .pred {// ignore self-cyclesif != {// Each successor s of n becomes a successor of p, and// each predecessor p of n becomes a predecessor of s.for := range .succ {// ignore self-cyclesif != {.succ.add().pred.add()}}delete(.succ, ) // remove edge to n}}for := range .succ {delete(.pred, ) // remove edge to n}}// fill in index and ndeps fieldsfor , := range {.index =.ndeps = len(.succ)}return}// ----------------------------------------------------------------------------// Priority queue// nodeQueue implements the container/heap interface;// a nodeQueue may be used as a priority queue.type nodeQueue []*graphNodefunc ( nodeQueue) () int { return len() }func ( nodeQueue) (, int) {, := [], [][], [] = ,.index, .index = ,}func ( nodeQueue) (, int) bool {, := [], []// Prioritize all constants before non-constants. See go.dev/issue/66575/., := .obj.(*Const), := .obj.(*Const)if != {return}// nodes are prioritized by number of incoming dependencies (1st key)// and source order (2nd key)return .ndeps < .ndeps || .ndeps == .ndeps && .obj.order() < .obj.order()}func ( *nodeQueue) ( any) {panic("unreachable")}func ( *nodeQueue) () any {:= len(*):= (*)[-1].index = -1 // for safety* = (*)[:-1]return}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)