// 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 ssa // This file defines a number of miscellaneous utility functions. import ( "fmt" "go/ast" "go/token" "io" "os" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/types" ) //// 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. func isPointer(typ types.Type) bool { _, 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 { if p, ok := typ.Underlying().(*types.Pointer); ok { return p.Elem() } return typ } // recvType returns the receiver type of method obj. func recvType(obj *types.Func) types.Type { return obj.Type().(*types.Signature).Recv().Type() } // DefaultType returns the default "typed" type for an "untyped" type; // it returns the incoming type for all other types. The default type // for untyped nil is untyped nil. // // Exported to ssa/interp. // // TODO(gri): this is a copy of go/types.defaultType; export that function. // func DefaultType(typ types.Type) types.Type { if t, ok := typ.(*types.Basic); ok { k := t.Kind() switch k { case types.UntypedBool: k = types.Bool case types.UntypedInt: k = types.Int case types.UntypedRune: k = types.Rune case types.UntypedFloat: k = types.Float64 case types.UntypedComplex: k = types.Complex128 case types.UntypedString: k = types.String } typ = types.Typ[k] } return typ } // 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.NewSignature(nil, lenParams, lenResults, false), } }