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