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