Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / ssa / sanity.go
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package ssa
6
7 // An optional pass for sanity-checking invariants of the SSA representation.
8 // Currently it checks CFG invariants but little at the instruction level.
9
10 import (
11         "fmt"
12         "go/types"
13         "io"
14         "os"
15         "strings"
16 )
17
18 type sanity struct {
19         reporter io.Writer
20         fn       *Function
21         block    *BasicBlock
22         instrs   map[Instruction]struct{}
23         insane   bool
24 }
25
26 // sanityCheck performs integrity checking of the SSA representation
27 // of the function fn and returns true if it was valid.  Diagnostics
28 // are written to reporter if non-nil, os.Stderr otherwise.  Some
29 // diagnostics are only warnings and do not imply a negative result.
30 //
31 // Sanity-checking is intended to facilitate the debugging of code
32 // transformation passes.
33 //
34 func sanityCheck(fn *Function, reporter io.Writer) bool {
35         if reporter == nil {
36                 reporter = os.Stderr
37         }
38         return (&sanity{reporter: reporter}).checkFunction(fn)
39 }
40
41 // mustSanityCheck is like sanityCheck but panics instead of returning
42 // a negative result.
43 //
44 func mustSanityCheck(fn *Function, reporter io.Writer) {
45         if !sanityCheck(fn, reporter) {
46                 fn.WriteTo(os.Stderr)
47                 panic("SanityCheck failed")
48         }
49 }
50
51 func (s *sanity) diagnostic(prefix, format string, args ...interface{}) {
52         fmt.Fprintf(s.reporter, "%s: function %s", prefix, s.fn)
53         if s.block != nil {
54                 fmt.Fprintf(s.reporter, ", block %s", s.block)
55         }
56         io.WriteString(s.reporter, ": ")
57         fmt.Fprintf(s.reporter, format, args...)
58         io.WriteString(s.reporter, "\n")
59 }
60
61 func (s *sanity) errorf(format string, args ...interface{}) {
62         s.insane = true
63         s.diagnostic("Error", format, args...)
64 }
65
66 func (s *sanity) warnf(format string, args ...interface{}) {
67         s.diagnostic("Warning", format, args...)
68 }
69
70 // findDuplicate returns an arbitrary basic block that appeared more
71 // than once in blocks, or nil if all were unique.
72 func findDuplicate(blocks []*BasicBlock) *BasicBlock {
73         if len(blocks) < 2 {
74                 return nil
75         }
76         if blocks[0] == blocks[1] {
77                 return blocks[0]
78         }
79         // Slow path:
80         m := make(map[*BasicBlock]bool)
81         for _, b := range blocks {
82                 if m[b] {
83                         return b
84                 }
85                 m[b] = true
86         }
87         return nil
88 }
89
90 func (s *sanity) checkInstr(idx int, instr Instruction) {
91         switch instr := instr.(type) {
92         case *If, *Jump, *Return, *Panic:
93                 s.errorf("control flow instruction not at end of block")
94         case *Phi:
95                 if idx == 0 {
96                         // It suffices to apply this check to just the first phi node.
97                         if dup := findDuplicate(s.block.Preds); dup != nil {
98                                 s.errorf("phi node in block with duplicate predecessor %s", dup)
99                         }
100                 } else {
101                         prev := s.block.Instrs[idx-1]
102                         if _, ok := prev.(*Phi); !ok {
103                                 s.errorf("Phi instruction follows a non-Phi: %T", prev)
104                         }
105                 }
106                 if ne, np := len(instr.Edges), len(s.block.Preds); ne != np {
107                         s.errorf("phi node has %d edges but %d predecessors", ne, np)
108
109                 } else {
110                         for i, e := range instr.Edges {
111                                 if e == nil {
112                                         s.errorf("phi node '%s' has no value for edge #%d from %s", instr.Comment, i, s.block.Preds[i])
113                                 }
114                         }
115                 }
116
117         case *Alloc:
118                 if !instr.Heap {
119                         found := false
120                         for _, l := range s.fn.Locals {
121                                 if l == instr {
122                                         found = true
123                                         break
124                                 }
125                         }
126                         if !found {
127                                 s.errorf("local alloc %s = %s does not appear in Function.Locals", instr.Name(), instr)
128                         }
129                 }
130
131         case *BinOp:
132         case *Call:
133         case *ChangeInterface:
134         case *ChangeType:
135         case *Convert:
136                 if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok {
137                         if _, ok := instr.Type().Underlying().(*types.Basic); !ok {
138                                 s.errorf("convert %s -> %s: at least one type must be basic", instr.X.Type(), instr.Type())
139                         }
140                 }
141
142         case *Defer:
143         case *Extract:
144         case *Field:
145         case *FieldAddr:
146         case *Go:
147         case *Index:
148         case *IndexAddr:
149         case *Lookup:
150         case *MakeChan:
151         case *MakeClosure:
152                 numFree := len(instr.Fn.(*Function).FreeVars)
153                 numBind := len(instr.Bindings)
154                 if numFree != numBind {
155                         s.errorf("MakeClosure has %d Bindings for function %s with %d free vars",
156                                 numBind, instr.Fn, numFree)
157
158                 }
159                 if recv := instr.Type().(*types.Signature).Recv(); recv != nil {
160                         s.errorf("MakeClosure's type includes receiver %s", recv.Type())
161                 }
162
163         case *MakeInterface:
164         case *MakeMap:
165         case *MakeSlice:
166         case *MapUpdate:
167         case *Next:
168         case *Range:
169         case *RunDefers:
170         case *Select:
171         case *Send:
172         case *Slice:
173         case *Store:
174         case *TypeAssert:
175         case *UnOp:
176         case *DebugRef:
177                 // TODO(adonovan): implement checks.
178         default:
179                 panic(fmt.Sprintf("Unknown instruction type: %T", instr))
180         }
181
182         if call, ok := instr.(CallInstruction); ok {
183                 if call.Common().Signature() == nil {
184                         s.errorf("nil signature: %s", call)
185                 }
186         }
187
188         // Check that value-defining instructions have valid types
189         // and a valid referrer list.
190         if v, ok := instr.(Value); ok {
191                 t := v.Type()
192                 if t == nil {
193                         s.errorf("no type: %s = %s", v.Name(), v)
194                 } else if t == tRangeIter {
195                         // not a proper type; ignore.
196                 } else if b, ok := t.Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
197                         s.errorf("instruction has 'untyped' result: %s = %s : %s", v.Name(), v, t)
198                 }
199                 s.checkReferrerList(v)
200         }
201
202         // Untyped constants are legal as instruction Operands(),
203         // for example:
204         //   _ = "foo"[0]
205         // or:
206         //   if wordsize==64 {...}
207
208         // All other non-Instruction Values can be found via their
209         // enclosing Function or Package.
210 }
211
212 func (s *sanity) checkFinalInstr(instr Instruction) {
213         switch instr := instr.(type) {
214         case *If:
215                 if nsuccs := len(s.block.Succs); nsuccs != 2 {
216                         s.errorf("If-terminated block has %d successors; expected 2", nsuccs)
217                         return
218                 }
219                 if s.block.Succs[0] == s.block.Succs[1] {
220                         s.errorf("If-instruction has same True, False target blocks: %s", s.block.Succs[0])
221                         return
222                 }
223
224         case *Jump:
225                 if nsuccs := len(s.block.Succs); nsuccs != 1 {
226                         s.errorf("Jump-terminated block has %d successors; expected 1", nsuccs)
227                         return
228                 }
229
230         case *Return:
231                 if nsuccs := len(s.block.Succs); nsuccs != 0 {
232                         s.errorf("Return-terminated block has %d successors; expected none", nsuccs)
233                         return
234                 }
235                 if na, nf := len(instr.Results), s.fn.Signature.Results().Len(); nf != na {
236                         s.errorf("%d-ary return in %d-ary function", na, nf)
237                 }
238
239         case *Panic:
240                 if nsuccs := len(s.block.Succs); nsuccs != 0 {
241                         s.errorf("Panic-terminated block has %d successors; expected none", nsuccs)
242                         return
243                 }
244
245         default:
246                 s.errorf("non-control flow instruction at end of block")
247         }
248 }
249
250 func (s *sanity) checkBlock(b *BasicBlock, index int) {
251         s.block = b
252
253         if b.Index != index {
254                 s.errorf("block has incorrect Index %d", b.Index)
255         }
256         if b.parent != s.fn {
257                 s.errorf("block has incorrect parent %s", b.parent)
258         }
259
260         // Check all blocks are reachable.
261         // (The entry block is always implicitly reachable,
262         // as is the Recover block, if any.)
263         if (index > 0 && b != b.parent.Recover) && len(b.Preds) == 0 {
264                 s.warnf("unreachable block")
265                 if b.Instrs == nil {
266                         // Since this block is about to be pruned,
267                         // tolerating transient problems in it
268                         // simplifies other optimizations.
269                         return
270                 }
271         }
272
273         // Check predecessor and successor relations are dual,
274         // and that all blocks in CFG belong to same function.
275         for _, a := range b.Preds {
276                 found := false
277                 for _, bb := range a.Succs {
278                         if bb == b {
279                                 found = true
280                                 break
281                         }
282                 }
283                 if !found {
284                         s.errorf("expected successor edge in predecessor %s; found only: %s", a, a.Succs)
285                 }
286                 if a.parent != s.fn {
287                         s.errorf("predecessor %s belongs to different function %s", a, a.parent)
288                 }
289         }
290         for _, c := range b.Succs {
291                 found := false
292                 for _, bb := range c.Preds {
293                         if bb == b {
294                                 found = true
295                                 break
296                         }
297                 }
298                 if !found {
299                         s.errorf("expected predecessor edge in successor %s; found only: %s", c, c.Preds)
300                 }
301                 if c.parent != s.fn {
302                         s.errorf("successor %s belongs to different function %s", c, c.parent)
303                 }
304         }
305
306         // Check each instruction is sane.
307         n := len(b.Instrs)
308         if n == 0 {
309                 s.errorf("basic block contains no instructions")
310         }
311         var rands [10]*Value // reuse storage
312         for j, instr := range b.Instrs {
313                 if instr == nil {
314                         s.errorf("nil instruction at index %d", j)
315                         continue
316                 }
317                 if b2 := instr.Block(); b2 == nil {
318                         s.errorf("nil Block() for instruction at index %d", j)
319                         continue
320                 } else if b2 != b {
321                         s.errorf("wrong Block() (%s) for instruction at index %d ", b2, j)
322                         continue
323                 }
324                 if j < n-1 {
325                         s.checkInstr(j, instr)
326                 } else {
327                         s.checkFinalInstr(instr)
328                 }
329
330                 // Check Instruction.Operands.
331         operands:
332                 for i, op := range instr.Operands(rands[:0]) {
333                         if op == nil {
334                                 s.errorf("nil operand pointer %d of %s", i, instr)
335                                 continue
336                         }
337                         val := *op
338                         if val == nil {
339                                 continue // a nil operand is ok
340                         }
341
342                         // Check that "untyped" types only appear on constant operands.
343                         if _, ok := (*op).(*Const); !ok {
344                                 if basic, ok := (*op).Type().(*types.Basic); ok {
345                                         if basic.Info()&types.IsUntyped != 0 {
346                                                 s.errorf("operand #%d of %s is untyped: %s", i, instr, basic)
347                                         }
348                                 }
349                         }
350
351                         // Check that Operands that are also Instructions belong to same function.
352                         // TODO(adonovan): also check their block dominates block b.
353                         if val, ok := val.(Instruction); ok {
354                                 if val.Block() == nil {
355                                         s.errorf("operand %d of %s is an instruction (%s) that belongs to no block", i, instr, val)
356                                 } else if val.Parent() != s.fn {
357                                         s.errorf("operand %d of %s is an instruction (%s) from function %s", i, instr, val, val.Parent())
358                                 }
359                         }
360
361                         // Check that each function-local operand of
362                         // instr refers back to instr.  (NB: quadratic)
363                         switch val := val.(type) {
364                         case *Const, *Global, *Builtin:
365                                 continue // not local
366                         case *Function:
367                                 if val.parent == nil {
368                                         continue // only anon functions are local
369                                 }
370                         }
371
372                         // TODO(adonovan): check val.Parent() != nil <=> val.Referrers() is defined.
373
374                         if refs := val.Referrers(); refs != nil {
375                                 for _, ref := range *refs {
376                                         if ref == instr {
377                                                 continue operands
378                                         }
379                                 }
380                                 s.errorf("operand %d of %s (%s) does not refer to us", i, instr, val)
381                         } else {
382                                 s.errorf("operand %d of %s (%s) has no referrers", i, instr, val)
383                         }
384                 }
385         }
386 }
387
388 func (s *sanity) checkReferrerList(v Value) {
389         refs := v.Referrers()
390         if refs == nil {
391                 s.errorf("%s has missing referrer list", v.Name())
392                 return
393         }
394         for i, ref := range *refs {
395                 if _, ok := s.instrs[ref]; !ok {
396                         s.errorf("%s.Referrers()[%d] = %s is not an instruction belonging to this function", v.Name(), i, ref)
397                 }
398         }
399 }
400
401 func (s *sanity) checkFunction(fn *Function) bool {
402         // TODO(adonovan): check Function invariants:
403         // - check params match signature
404         // - check transient fields are nil
405         // - warn if any fn.Locals do not appear among block instructions.
406         s.fn = fn
407         if fn.Prog == nil {
408                 s.errorf("nil Prog")
409         }
410
411         _ = fn.String()            // must not crash
412         _ = fn.RelString(fn.pkg()) // must not crash
413
414         // All functions have a package, except delegates (which are
415         // shared across packages, or duplicated as weak symbols in a
416         // separate-compilation model), and error.Error.
417         if fn.Pkg == nil {
418                 if strings.HasPrefix(fn.Synthetic, "wrapper ") ||
419                         strings.HasPrefix(fn.Synthetic, "bound ") ||
420                         strings.HasPrefix(fn.Synthetic, "thunk ") ||
421                         strings.HasSuffix(fn.name, "Error") {
422                         // ok
423                 } else {
424                         s.errorf("nil Pkg")
425                 }
426         }
427         if src, syn := fn.Synthetic == "", fn.Syntax() != nil; src != syn {
428                 s.errorf("got fromSource=%t, hasSyntax=%t; want same values", src, syn)
429         }
430         for i, l := range fn.Locals {
431                 if l.Parent() != fn {
432                         s.errorf("Local %s at index %d has wrong parent", l.Name(), i)
433                 }
434                 if l.Heap {
435                         s.errorf("Local %s at index %d has Heap flag set", l.Name(), i)
436                 }
437         }
438         // Build the set of valid referrers.
439         s.instrs = make(map[Instruction]struct{})
440         for _, b := range fn.Blocks {
441                 for _, instr := range b.Instrs {
442                         s.instrs[instr] = struct{}{}
443                 }
444         }
445         for i, p := range fn.Params {
446                 if p.Parent() != fn {
447                         s.errorf("Param %s at index %d has wrong parent", p.Name(), i)
448                 }
449                 // Check common suffix of Signature and Params match type.
450                 if sig := fn.Signature; sig != nil {
451                         j := i - len(fn.Params) + sig.Params().Len() // index within sig.Params
452                         if j < 0 {
453                                 continue
454                         }
455                         if !types.Identical(p.Type(), sig.Params().At(j).Type()) {
456                                 s.errorf("Param %s at index %d has wrong type (%s, versus %s in Signature)", p.Name(), i, p.Type(), sig.Params().At(j).Type())
457
458                         }
459                 }
460                 s.checkReferrerList(p)
461         }
462         for i, fv := range fn.FreeVars {
463                 if fv.Parent() != fn {
464                         s.errorf("FreeVar %s at index %d has wrong parent", fv.Name(), i)
465                 }
466                 s.checkReferrerList(fv)
467         }
468
469         if fn.Blocks != nil && len(fn.Blocks) == 0 {
470                 // Function _had_ blocks (so it's not external) but
471                 // they were "optimized" away, even the entry block.
472                 s.errorf("Blocks slice is non-nil but empty")
473         }
474         for i, b := range fn.Blocks {
475                 if b == nil {
476                         s.warnf("nil *BasicBlock at f.Blocks[%d]", i)
477                         continue
478                 }
479                 s.checkBlock(b, i)
480         }
481         if fn.Recover != nil && fn.Blocks[fn.Recover.Index] != fn.Recover {
482                 s.errorf("Recover block is not in Blocks slice")
483         }
484
485         s.block = nil
486         for i, anon := range fn.AnonFuncs {
487                 if anon.Parent() != fn {
488                         s.errorf("AnonFuncs[%d]=%s but %s.Parent()=%s", i, anon, anon, anon.Parent())
489                 }
490         }
491         s.fn = nil
492         return !s.insane
493 }
494
495 // sanityCheckPackage checks invariants of packages upon creation.
496 // It does not require that the package is built.
497 // Unlike sanityCheck (for functions), it just panics at the first error.
498 func sanityCheckPackage(pkg *Package) {
499         if pkg.Pkg == nil {
500                 panic(fmt.Sprintf("Package %s has no Object", pkg))
501         }
502         _ = pkg.String() // must not crash
503
504         for name, mem := range pkg.Members {
505                 if name != mem.Name() {
506                         panic(fmt.Sprintf("%s: %T.Name() = %s, want %s",
507                                 pkg.Pkg.Path(), mem, mem.Name(), name))
508                 }
509                 obj := mem.Object()
510                 if obj == nil {
511                         // This check is sound because fields
512                         // {Global,Function}.object have type
513                         // types.Object.  (If they were declared as
514                         // *types.{Var,Func}, we'd have a non-empty
515                         // interface containing a nil pointer.)
516
517                         continue // not all members have typechecker objects
518                 }
519                 if obj.Name() != name {
520                         if obj.Name() == "init" && strings.HasPrefix(mem.Name(), "init#") {
521                                 // Ok.  The name of a declared init function varies between
522                                 // its types.Func ("init") and its ssa.Function ("init#%d").
523                         } else {
524                                 panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
525                                         pkg.Pkg.Path(), mem, obj.Name(), name))
526                         }
527                 }
528                 if obj.Pos() != mem.Pos() {
529                         panic(fmt.Sprintf("%s Pos=%d obj.Pos=%d", mem, mem.Pos(), obj.Pos()))
530                 }
531         }
532 }