Source file
src/go/types/initorder.go
1
2
3
4
5
6
7
8 package types
9
10 import (
11 "cmp"
12 "container/heap"
13 "fmt"
14 . "internal/types/errors"
15 "slices"
16 "sort"
17 )
18
19
20 func (check *Checker) initOrder() {
21
22
23 check.Info.InitOrder = check.Info.InitOrder[:0]
24
25
26
27 pq := nodeQueue(dependencyGraph(check.objMap))
28 heap.Init(&pq)
29
30 const debug = false
31 if debug {
32 fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
33 fmt.Println("Object dependency graph:")
34 for obj, d := range check.objMap {
35
36 if obj, _ := obj.(dependency); obj != nil {
37 if len(d.deps) > 0 {
38 fmt.Printf("\t%s depends on\n", obj.Name())
39 for dep := range d.deps {
40 fmt.Printf("\t\t%s\n", dep.Name())
41 }
42 } else {
43 fmt.Printf("\t%s has no dependencies\n", obj.Name())
44 }
45 }
46 }
47 fmt.Println()
48
49 fmt.Println("Transposed object dependency graph (functions eliminated):")
50 for _, n := range pq {
51 fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
52 for p := range n.pred {
53 fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
54 }
55 }
56 fmt.Println()
57
58 fmt.Println("Processing nodes:")
59 }
60
61
62
63
64
65
66
67 emitted := make(map[*declInfo]bool)
68 for len(pq) > 0 {
69
70 n := heap.Pop(&pq).(*graphNode)
71
72 if debug {
73 fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
74 n.obj.Name(), n.obj.order(), n.ndeps)
75 }
76
77
78 if n.ndeps > 0 {
79 cycle := findPath(check.objMap, n.obj, n.obj, make(map[Object]bool))
80
81
82
83
84
85
86
87
88 if cycle != nil {
89 check.reportCycle(cycle)
90 }
91
92
93
94 }
95
96
97
98 for p := range n.pred {
99 p.ndeps--
100 heap.Fix(&pq, p.index)
101 }
102
103
104 v, _ := n.obj.(*Var)
105 info := check.objMap[v]
106 if v == nil || !info.hasInitializer() {
107 continue
108 }
109
110
111
112
113
114 if emitted[info] {
115 continue
116 }
117 emitted[info] = true
118
119 infoLhs := info.lhs
120 if infoLhs == nil {
121 infoLhs = []*Var{v}
122 }
123 init := &Initializer{infoLhs, info.init}
124 check.Info.InitOrder = append(check.Info.InitOrder, init)
125 }
126
127 if debug {
128 fmt.Println()
129 fmt.Println("Initialization order:")
130 for _, init := range check.Info.InitOrder {
131 fmt.Printf("\t%s\n", init)
132 }
133 fmt.Println()
134 }
135 }
136
137
138
139
140 func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool) []Object {
141 if seen[from] {
142 return nil
143 }
144 seen[from] = true
145
146
147 var deps []Object
148 for d := range objMap[from].deps {
149 deps = append(deps, d)
150 }
151 sort.Slice(deps, func(i, j int) bool {
152 return deps[i].order() < deps[j].order()
153 })
154
155 for _, d := range deps {
156 if d == to {
157 return []Object{d}
158 }
159 if P := findPath(objMap, d, to, seen); P != nil {
160 return append(P, d)
161 }
162 }
163
164 return nil
165 }
166
167
168 func (check *Checker) reportCycle(cycle []Object) {
169 obj := cycle[0]
170
171
172 if len(cycle) == 1 {
173 check.errorf(obj, InvalidInitCycle, "initialization cycle: %s refers to itself", obj.Name())
174 return
175 }
176
177 err := check.newError(InvalidInitCycle)
178 err.addf(obj, "initialization cycle for %s", obj.Name())
179
180 for j := len(cycle) - 1; j >= 0; j-- {
181 next := cycle[j]
182 err.addf(obj, "%s refers to %s", obj.Name(), next.Name())
183 obj = next
184 }
185 err.report()
186 }
187
188
189
190
191
192
193
194
195 type dependency interface {
196 Object
197 isDependency()
198 }
199
200
201
202
203
204 type graphNode struct {
205 obj dependency
206 pred, succ nodeSet
207 index int
208 ndeps int
209 }
210
211
212
213 func (n *graphNode) cost() int {
214 return len(n.pred) * len(n.succ)
215 }
216
217 type nodeSet map[*graphNode]bool
218
219 func (s *nodeSet) add(p *graphNode) {
220 if *s == nil {
221 *s = make(nodeSet)
222 }
223 (*s)[p] = true
224 }
225
226
227
228
229 func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
230
231 M := make(map[dependency]*graphNode)
232 for obj := range objMap {
233
234 if obj, _ := obj.(dependency); obj != nil {
235 M[obj] = &graphNode{obj: obj}
236 }
237 }
238
239
240
241
242 for obj, n := range M {
243
244 for d := range objMap[obj].deps {
245
246 if d, _ := d.(dependency); d != nil {
247 d := M[d]
248 n.succ.add(d)
249 d.pred.add(n)
250 }
251 }
252 }
253
254 var G, funcG []*graphNode
255 for _, n := range M {
256 if _, ok := n.obj.(*Func); ok {
257 funcG = append(funcG, n)
258 } else {
259 G = append(G, n)
260 }
261 }
262
263
264
265
266
267
268
269
270
271
272
273 slices.SortFunc(funcG, func(a, b *graphNode) int {
274 return cmp.Compare(a.cost(), b.cost())
275 })
276 for _, n := range funcG {
277
278
279 for p := range n.pred {
280
281 if p != n {
282
283
284 for s := range n.succ {
285
286 if s != n {
287 p.succ.add(s)
288 s.pred.add(p)
289 }
290 }
291 delete(p.succ, n)
292 }
293 }
294 for s := range n.succ {
295 delete(s.pred, n)
296 }
297 }
298
299
300 for i, n := range G {
301 n.index = i
302 n.ndeps = len(n.succ)
303 }
304
305 return G
306 }
307
308
309
310
311
312
313 type nodeQueue []*graphNode
314
315 func (a nodeQueue) Len() int { return len(a) }
316
317 func (a nodeQueue) Swap(i, j int) {
318 x, y := a[i], a[j]
319 a[i], a[j] = y, x
320 x.index, y.index = j, i
321 }
322
323 func (a nodeQueue) Less(i, j int) bool {
324 x, y := a[i], a[j]
325
326
327 _, xConst := x.obj.(*Const)
328 _, yConst := y.obj.(*Const)
329 if xConst != yConst {
330 return xConst
331 }
332
333
334
335 return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
336 }
337
338 func (a *nodeQueue) Push(x any) {
339 panic("unreachable")
340 }
341
342 func (a *nodeQueue) Pop() any {
343 n := len(*a)
344 x := (*a)[n-1]
345 x.index = -1
346 *a = (*a)[:n-1]
347 return x
348 }
349
View as plain text