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