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