120 lines
3.0 KiB
Go
120 lines
3.0 KiB
Go
|
// 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"
|
||
|
"go/types"
|
||
|
"io"
|
||
|
"os"
|
||
|
|
||
|
"golang.org/x/tools/go/ast/astutil"
|
||
|
)
|
||
|
|
||
|
//// 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(adonovan): use go/types.DefaultType after 1.8.
|
||
|
//
|
||
|
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),
|
||
|
}
|
||
|
}
|