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
5package ssa
6
7// This file defines a number of miscellaneous utility functions.
8
9import (
10	"fmt"
11	"go/ast"
12	"go/token"
13	"go/types"
14	"io"
15	"os"
16
17	"golang.org/x/tools/go/ast/astutil"
18)
19
20//// AST utilities
21
22func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
23
24// isBlankIdent returns true iff e is an Ident with name "_".
25// They have no associated types.Object, and thus no type.
26//
27func 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.
35func isPointer(typ types.Type) bool {
36	_, ok := typ.Underlying().(*types.Pointer)
37	return ok
38}
39
40func isInterface(T types.Type) bool { return types.IsInterface(T) }
41
42// deref returns a pointer's element type; otherwise it returns typ.
43func deref(typ types.Type) types.Type {
44	if p, ok := typ.Underlying().(*types.Pointer); ok {
45		return p.Elem()
46	}
47	return typ
48}
49
50// recvType returns the receiver type of method obj.
51func recvType(obj *types.Func) types.Type {
52	return obj.Type().(*types.Signature).Recv().Type()
53}
54
55// DefaultType returns the default "typed" type for an "untyped" type;
56// it returns the incoming type for all other types.  The default type
57// for untyped nil is untyped nil.
58//
59// Exported to ssa/interp.
60//
61// TODO(adonovan): use go/types.DefaultType after 1.8.
62//
63func DefaultType(typ types.Type) types.Type {
64	if t, ok := typ.(*types.Basic); ok {
65		k := t.Kind()
66		switch k {
67		case types.UntypedBool:
68			k = types.Bool
69		case types.UntypedInt:
70			k = types.Int
71		case types.UntypedRune:
72			k = types.Rune
73		case types.UntypedFloat:
74			k = types.Float64
75		case types.UntypedComplex:
76			k = types.Complex128
77		case types.UntypedString:
78			k = types.String
79		}
80		typ = types.Typ[k]
81	}
82	return typ
83}
84
85// logStack prints the formatted "start" message to stderr and
86// returns a closure that prints the corresponding "end" message.
87// Call using 'defer logStack(...)()' to show builder stack on panic.
88// Don't forget trailing parens!
89//
90func logStack(format string, args ...interface{}) func() {
91	msg := fmt.Sprintf(format, args...)
92	io.WriteString(os.Stderr, msg)
93	io.WriteString(os.Stderr, "\n")
94	return func() {
95		io.WriteString(os.Stderr, msg)
96		io.WriteString(os.Stderr, " end\n")
97	}
98}
99
100// newVar creates a 'var' for use in a types.Tuple.
101func newVar(name string, typ types.Type) *types.Var {
102	return types.NewParam(token.NoPos, nil, name, typ)
103}
104
105// anonVar creates an anonymous 'var' for use in a types.Tuple.
106func anonVar(typ types.Type) *types.Var {
107	return newVar("", typ)
108}
109
110var lenResults = types.NewTuple(anonVar(tInt))
111
112// makeLen returns the len builtin specialized to type func(T)int.
113func makeLen(T types.Type) *Builtin {
114	lenParams := types.NewTuple(anonVar(T))
115	return &Builtin{
116		name: "len",
117		sig:  types.NewSignature(nil, lenParams, lenResults, false),
118	}
119}
120