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