github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/ir/util.go (about) 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 ir 6 7 // This file defines a number of miscellaneous utility functions. 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/token" 13 "go/types" 14 "io" 15 "os" 16 17 "github.com/amarpal/go-tools/go/ast/astutil" 18 "github.com/amarpal/go-tools/go/types/typeutil" 19 ) 20 21 //// AST utilities 22 23 func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } 24 25 // isBlankIdent returns true iff e is an Ident with name "_". 26 // They have no associated types.Object, and thus no type. 27 func isBlankIdent(e ast.Expr) bool { 28 id, ok := e.(*ast.Ident) 29 return ok && id.Name == "_" 30 } 31 32 //// Type utilities. Some of these belong in go/types. 33 34 // isPointer returns true for types whose underlying type is a pointer, 35 // and for type parameters whose core type is a pointer. 36 func isPointer(typ types.Type) bool { 37 if ctyp := typeutil.CoreType(typ); ctyp != nil { 38 _, ok := ctyp.(*types.Pointer) 39 return ok 40 } 41 _, ok := typ.Underlying().(*types.Pointer) 42 return ok 43 } 44 45 func isInterface(T types.Type) bool { return types.IsInterface(T) } 46 47 // deref returns a pointer's element type; otherwise it returns typ. 48 func deref(typ types.Type) types.Type { 49 orig := typ 50 51 if t, ok := typ.(*types.TypeParam); ok { 52 if ctyp := typeutil.CoreType(t); ctyp != nil { 53 typ = ctyp 54 } 55 } 56 if p, ok := typ.Underlying().(*types.Pointer); ok { 57 return p.Elem() 58 } 59 return orig 60 } 61 62 // recvType returns the receiver type of method obj. 63 func recvType(obj *types.Func) types.Type { 64 return obj.Type().(*types.Signature).Recv().Type() 65 } 66 67 // logStack prints the formatted "start" message to stderr and 68 // returns a closure that prints the corresponding "end" message. 69 // Call using 'defer logStack(...)()' to show builder stack on panic. 70 // Don't forget trailing parens! 71 func logStack(format string, args ...interface{}) func() { 72 msg := fmt.Sprintf(format, args...) 73 io.WriteString(os.Stderr, msg) 74 io.WriteString(os.Stderr, "\n") 75 return func() { 76 io.WriteString(os.Stderr, msg) 77 io.WriteString(os.Stderr, " end\n") 78 } 79 } 80 81 // newVar creates a 'var' for use in a types.Tuple. 82 func newVar(name string, typ types.Type) *types.Var { 83 return types.NewParam(token.NoPos, nil, name, typ) 84 } 85 86 // anonVar creates an anonymous 'var' for use in a types.Tuple. 87 func anonVar(typ types.Type) *types.Var { 88 return newVar("", typ) 89 } 90 91 var lenResults = types.NewTuple(anonVar(tInt)) 92 93 // makeLen returns the len builtin specialized to type func(T)int. 94 func makeLen(T types.Type) *Builtin { 95 lenParams := types.NewTuple(anonVar(T)) 96 return &Builtin{ 97 name: "len", 98 sig: types.NewSignatureType(nil, nil, nil, lenParams, lenResults, false), 99 } 100 } 101 102 type StackMap struct { 103 m []map[Value]Value 104 } 105 106 func (m *StackMap) Push() { 107 m.m = append(m.m, map[Value]Value{}) 108 } 109 110 func (m *StackMap) Pop() { 111 m.m = m.m[:len(m.m)-1] 112 } 113 114 func (m *StackMap) Get(key Value) (Value, bool) { 115 for i := len(m.m) - 1; i >= 0; i-- { 116 if v, ok := m.m[i][key]; ok { 117 return v, true 118 } 119 } 120 return nil, false 121 } 122 123 func (m *StackMap) Set(k Value, v Value) { 124 m.m[len(m.m)-1][k] = v 125 } 126 127 // Unwrap recursively unwraps Sigma and Copy nodes. 128 func Unwrap(v Value) Value { 129 for { 130 switch vv := v.(type) { 131 case *Sigma: 132 v = vv.X 133 case *Copy: 134 v = vv.X 135 default: 136 return v 137 } 138 } 139 } 140 141 func assert(x bool) { 142 if !x { 143 panic("failed assertion") 144 } 145 } 146 147 // BlockMap is a mapping from basic blocks (identified by their indices) to values. 148 type BlockMap[T any] []T