128 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.2 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"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 
 | |
| 	"golang.org/x/tools/astutil"
 | |
| 	"golang.org/x/tools/go/types"
 | |
| )
 | |
| 
 | |
| func unreachable() {
 | |
| 	panic("unreachable")
 | |
| }
 | |
| 
 | |
| //// 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
 | |
| }
 | |
| 
 | |
| // isInterface reports whether T's underlying type is an interface.
 | |
| func isInterface(T types.Type) bool {
 | |
| 	_, ok := T.Underlying().(*types.Interface)
 | |
| 	return ok
 | |
| }
 | |
| 
 | |
| // 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, nil, lenParams, lenResults, false),
 | |
| 	}
 | |
| }
 |