| // Copyright 2015 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. |
| |
| // This file provides methods that let us export a Type as an ../ssa:Type. |
| // We don't export this package's Type directly because it would lead |
| // to an import cycle with this package and ../ssa. |
| // TODO: move Type to its own package, then we don't need to dance around import cycles. |
| |
| package gc |
| |
| import ( |
| "cmd/compile/internal/ssa" |
| "fmt" |
| ) |
| |
| // EType describes a kind of type. |
| type EType uint8 |
| |
| const ( |
| Txxx = iota |
| |
| TINT8 |
| TUINT8 |
| TINT16 |
| TUINT16 |
| TINT32 |
| TUINT32 |
| TINT64 |
| TUINT64 |
| TINT |
| TUINT |
| TUINTPTR |
| |
| TCOMPLEX64 |
| TCOMPLEX128 |
| |
| TFLOAT32 |
| TFLOAT64 |
| |
| TBOOL |
| |
| TPTR32 |
| TPTR64 |
| |
| TFUNC |
| TSLICE |
| TARRAY |
| TSTRUCT |
| TCHAN |
| TMAP |
| TINTER |
| TFORW |
| TANY |
| TSTRING |
| TUNSAFEPTR |
| |
| // pseudo-types for literals |
| TIDEAL |
| TNIL |
| TBLANK |
| |
| // pseudo-types for frame layout |
| TFUNCARGS |
| TCHANARGS |
| TINTERMETH |
| |
| // pseudo-types for import/export |
| TDDDFIELD // wrapper: contained type is a ... field |
| |
| NTYPE |
| ) |
| |
| // ChanDir is whether a channel can send, receive, or both. |
| type ChanDir uint8 |
| |
| func (c ChanDir) CanRecv() bool { return c&Crecv != 0 } |
| func (c ChanDir) CanSend() bool { return c&Csend != 0 } |
| |
| const ( |
| // types of channel |
| // must match ../../../../reflect/type.go:/ChanDir |
| Crecv ChanDir = 1 << 0 |
| Csend ChanDir = 1 << 1 |
| Cboth ChanDir = Crecv | Csend |
| ) |
| |
| // Types stores pointers to predeclared named types. |
| // |
| // It also stores pointers to several special types: |
| // - Types[TANY] is the placeholder "any" type recognized by substArgTypes. |
| // - Types[TBLANK] represents the blank variable's type. |
| // - Types[TIDEAL] represents untyped numeric constants. |
| // - Types[TNIL] represents the predeclared "nil" value's type. |
| // - Types[TUNSAFEPTR] is package unsafe's Pointer type. |
| var Types [NTYPE]*Type |
| |
| var ( |
| // Predeclared alias types. Kept separate for better error messages. |
| bytetype *Type |
| runetype *Type |
| |
| // Predeclared error interface type. |
| errortype *Type |
| |
| // Types to represent untyped string and boolean constants. |
| idealstring *Type |
| idealbool *Type |
| |
| // Types to represent untyped numeric constants. |
| // Note: Currently these are only used within the binary export |
| // data format. The rest of the compiler only uses Types[TIDEAL]. |
| idealint = typ(TIDEAL) |
| idealrune = typ(TIDEAL) |
| idealfloat = typ(TIDEAL) |
| idealcomplex = typ(TIDEAL) |
| ) |
| |
| // A Type represents a Go type. |
| type Type struct { |
| // Extra contains extra etype-specific fields. |
| // As an optimization, those etype-specific structs which contain exactly |
| // one pointer-shaped field are stored as values rather than pointers when possible. |
| // |
| // TMAP: *MapType |
| // TFORW: *ForwardType |
| // TFUNC: *FuncType |
| // TINTERMETHOD: InterMethType |
| // TSTRUCT: *StructType |
| // TINTER: *InterType |
| // TDDDFIELD: DDDFieldType |
| // TFUNCARGS: FuncArgsType |
| // TCHANARGS: ChanArgsType |
| // TCHAN: *ChanType |
| // TPTR32, TPTR64: PtrType |
| // TARRAY: *ArrayType |
| // TSLICE: SliceType |
| Extra interface{} |
| |
| // Width is the width of this Type in bytes. |
| Width int64 |
| |
| methods Fields |
| allMethods Fields |
| |
| Nod *Node // canonical OTYPE node |
| Orig *Type // original type (type literal or predefined type) |
| |
| Sym *Sym // symbol containing name, for named types |
| Vargen int32 // unique name for OTYPE/ONAME |
| Lineno int32 // line at which this type was declared, implicitly or explicitly |
| |
| Etype EType // kind of type |
| Noalg bool // suppress hash and eq algorithm generation |
| Trecur uint8 // to detect loops |
| Printed bool // prevent duplicate export printing |
| Local bool // created in this file |
| Deferwidth bool |
| Broke bool // broken type definition. |
| Align uint8 // the required alignment of this type, in bytes |
| } |
| |
| // MapType contains Type fields specific to maps. |
| type MapType struct { |
| Key *Type // Key type |
| Val *Type // Val (elem) type |
| |
| Bucket *Type // internal struct type representing a hash bucket |
| Hmap *Type // internal struct type representing the Hmap (map header object) |
| Hiter *Type // internal struct type representing hash iterator state |
| } |
| |
| // MapType returns t's extra map-specific fields. |
| func (t *Type) MapType() *MapType { |
| t.wantEtype(TMAP) |
| return t.Extra.(*MapType) |
| } |
| |
| // ForwardType contains Type fields specific to forward types. |
| type ForwardType struct { |
| Copyto []*Node // where to copy the eventual value to |
| Embedlineno int32 // first use of this type as an embedded type |
| } |
| |
| // ForwardType returns t's extra forward-type-specific fields. |
| func (t *Type) ForwardType() *ForwardType { |
| t.wantEtype(TFORW) |
| return t.Extra.(*ForwardType) |
| } |
| |
| // FuncType contains Type fields specific to func types. |
| type FuncType struct { |
| Receiver *Type // function receiver |
| Results *Type // function results |
| Params *Type // function params |
| |
| Nname *Node |
| |
| // Argwid is the total width of the function receiver, params, and results. |
| // It gets calculated via a temporary TFUNCARGS type. |
| // Note that TFUNC's Width is Widthptr. |
| Argwid int64 |
| |
| Outnamed bool |
| } |
| |
| // FuncType returns t's extra func-specific fields. |
| func (t *Type) FuncType() *FuncType { |
| t.wantEtype(TFUNC) |
| return t.Extra.(*FuncType) |
| } |
| |
| // InterMethType contains Type fields specific to interface method psuedo-types. |
| type InterMethType struct { |
| Nname *Node |
| } |
| |
| // StructType contains Type fields specific to struct types. |
| type StructType struct { |
| fields Fields |
| |
| // Maps have three associated internal structs (see struct MapType). |
| // Map links such structs back to their map type. |
| Map *Type |
| |
| Funarg Funarg // type of function arguments for arg struct |
| Haspointers uint8 // 0 unknown, 1 no, 2 yes |
| } |
| |
| // Fnstruct records the kind of function argument |
| type Funarg uint8 |
| |
| const ( |
| FunargNone Funarg = iota |
| FunargRcvr // receiver |
| FunargParams // input parameters |
| FunargResults // output results |
| ) |
| |
| // StructType returns t's extra struct-specific fields. |
| func (t *Type) StructType() *StructType { |
| t.wantEtype(TSTRUCT) |
| return t.Extra.(*StructType) |
| } |
| |
| // InterType contains Type fields specific to interface types. |
| type InterType struct { |
| fields Fields |
| } |
| |
| // PtrType contains Type fields specific to pointer types. |
| type PtrType struct { |
| Elem *Type // element type |
| } |
| |
| // DDDFieldType contains Type fields specific to TDDDFIELD types. |
| type DDDFieldType struct { |
| T *Type // reference to a slice type for ... args |
| } |
| |
| // ChanArgsType contains Type fields specific to TCHANARGS types. |
| type ChanArgsType struct { |
| T *Type // reference to a chan type whose elements need a width check |
| } |
| |
| // // FuncArgsType contains Type fields specific to TFUNCARGS types. |
| type FuncArgsType struct { |
| T *Type // reference to a func type whose elements need a width check |
| } |
| |
| // ChanType contains Type fields specific to channel types. |
| type ChanType struct { |
| Elem *Type // element type |
| Dir ChanDir // channel direction |
| } |
| |
| // ChanType returns t's extra channel-specific fields. |
| func (t *Type) ChanType() *ChanType { |
| t.wantEtype(TCHAN) |
| return t.Extra.(*ChanType) |
| } |
| |
| // ArrayType contains Type fields specific to array types. |
| type ArrayType struct { |
| Elem *Type // element type |
| Bound int64 // number of elements; <0 if unknown yet |
| Haspointers uint8 // 0 unknown, 1 no, 2 yes |
| } |
| |
| // SliceType contains Type fields specific to slice types. |
| type SliceType struct { |
| Elem *Type // element type |
| } |
| |
| // A Field represents a field in a struct or a method in an interface or |
| // associated with a named type. |
| type Field struct { |
| Nointerface bool |
| Embedded uint8 // embedded field |
| Funarg Funarg |
| Broke bool // broken field definition |
| Isddd bool // field is ... argument |
| |
| Sym *Sym |
| Nname *Node |
| |
| Type *Type // field type |
| |
| // Offset in bytes of this field or method within its enclosing struct |
| // or interface Type. |
| Offset int64 |
| |
| Note string // literal string annotation |
| } |
| |
| // End returns the offset of the first byte immediately after this field. |
| func (f *Field) End() int64 { |
| return f.Offset + f.Type.Width |
| } |
| |
| // Fields is a pointer to a slice of *Field. |
| // This saves space in Types that do not have fields or methods |
| // compared to a simple slice of *Field. |
| type Fields struct { |
| s *[]*Field |
| } |
| |
| // Len returns the number of entries in f. |
| func (f *Fields) Len() int { |
| if f.s == nil { |
| return 0 |
| } |
| return len(*f.s) |
| } |
| |
| // Slice returns the entries in f as a slice. |
| // Changes to the slice entries will be reflected in f. |
| func (f *Fields) Slice() []*Field { |
| if f.s == nil { |
| return nil |
| } |
| return *f.s |
| } |
| |
| // Index returns the i'th element of Fields. |
| // It panics if f does not have at least i+1 elements. |
| func (f *Fields) Index(i int) *Field { |
| return (*f.s)[i] |
| } |
| |
| // Set sets f to a slice. |
| // This takes ownership of the slice. |
| func (f *Fields) Set(s []*Field) { |
| if len(s) == 0 { |
| f.s = nil |
| } else { |
| // Copy s and take address of t rather than s to avoid |
| // allocation in the case where len(s) == 0. |
| t := s |
| f.s = &t |
| } |
| } |
| |
| // Append appends entries to f. |
| func (f *Fields) Append(s ...*Field) { |
| if f.s == nil { |
| f.s = new([]*Field) |
| } |
| *f.s = append(*f.s, s...) |
| } |
| |
| // typ returns a new Type of the specified kind. |
| func typ(et EType) *Type { |
| t := &Type{ |
| Etype: et, |
| Width: BADWIDTH, |
| Lineno: lineno, |
| } |
| t.Orig = t |
| // TODO(josharian): lazily initialize some of these? |
| switch t.Etype { |
| case TMAP: |
| t.Extra = new(MapType) |
| case TFORW: |
| t.Extra = new(ForwardType) |
| case TFUNC: |
| t.Extra = new(FuncType) |
| case TINTERMETH: |
| t.Extra = InterMethType{} |
| case TSTRUCT: |
| t.Extra = new(StructType) |
| case TINTER: |
| t.Extra = new(InterType) |
| case TPTR32, TPTR64: |
| t.Extra = PtrType{} |
| case TCHANARGS: |
| t.Extra = ChanArgsType{} |
| case TFUNCARGS: |
| t.Extra = FuncArgsType{} |
| case TDDDFIELD: |
| t.Extra = DDDFieldType{} |
| case TCHAN: |
| t.Extra = new(ChanType) |
| } |
| return t |
| } |
| |
| // typArray returns a new fixed-length array Type. |
| func typArray(elem *Type, bound int64) *Type { |
| if bound < 0 { |
| Fatalf("typArray: invalid bound %v", bound) |
| } |
| t := typ(TARRAY) |
| t.Extra = &ArrayType{Elem: elem, Bound: bound} |
| return t |
| } |
| |
| // typSlice returns a new slice Type. |
| func typSlice(elem *Type) *Type { |
| t := typ(TSLICE) |
| t.Extra = SliceType{Elem: elem} |
| return t |
| } |
| |
| // typDDDArray returns a new [...]T array Type. |
| func typDDDArray(elem *Type) *Type { |
| t := typ(TARRAY) |
| t.Extra = &ArrayType{Elem: elem, Bound: -1} |
| return t |
| } |
| |
| // typChan returns a new chan Type with direction dir. |
| func typChan(elem *Type, dir ChanDir) *Type { |
| t := typ(TCHAN) |
| ct := t.ChanType() |
| ct.Elem = elem |
| ct.Dir = dir |
| return t |
| } |
| |
| // typMap returns a new map Type with key type k and element (aka value) type v. |
| func typMap(k, v *Type) *Type { |
| t := typ(TMAP) |
| mt := t.MapType() |
| mt.Key = k |
| mt.Val = v |
| return t |
| } |
| |
| // typPtr returns a new pointer type pointing to t. |
| func typPtr(elem *Type) *Type { |
| t := typ(Tptr) |
| t.Extra = PtrType{Elem: elem} |
| t.Width = int64(Widthptr) |
| t.Align = uint8(Widthptr) |
| return t |
| } |
| |
| // typDDDField returns a new TDDDFIELD type for slice type s. |
| func typDDDField(s *Type) *Type { |
| t := typ(TDDDFIELD) |
| t.Extra = DDDFieldType{T: s} |
| return t |
| } |
| |
| // typChanArgs returns a new TCHANARGS type for channel type c. |
| func typChanArgs(c *Type) *Type { |
| t := typ(TCHANARGS) |
| t.Extra = ChanArgsType{T: c} |
| return t |
| } |
| |
| // typFuncArgs returns a new TFUNCARGS type for func type f. |
| func typFuncArgs(f *Type) *Type { |
| t := typ(TFUNCARGS) |
| t.Extra = FuncArgsType{T: f} |
| return t |
| } |
| |
| func newField() *Field { |
| return &Field{ |
| Offset: BADWIDTH, |
| } |
| } |
| |
| // substArgTypes substitutes the given list of types for |
| // successive occurrences of the "any" placeholder in the |
| // type syntax expression n.Type. |
| // The result of substArgTypes MUST be assigned back to old, e.g. |
| // n.Left = substArgTypes(n.Left, t1, t2) |
| func substArgTypes(old *Node, types ...*Type) *Node { |
| n := *old // make shallow copy |
| |
| for _, t := range types { |
| dowidth(t) |
| } |
| n.Type = substAny(n.Type, &types) |
| if len(types) > 0 { |
| Fatalf("substArgTypes: too many argument types") |
| } |
| return &n |
| } |
| |
| // substAny walks t, replacing instances of "any" with successive |
| // elements removed from types. It returns the substituted type. |
| func substAny(t *Type, types *[]*Type) *Type { |
| if t == nil { |
| return nil |
| } |
| |
| switch t.Etype { |
| default: |
| // Leave the type unchanged. |
| |
| case TANY: |
| if len(*types) == 0 { |
| Fatalf("substArgTypes: not enough argument types") |
| } |
| t = (*types)[0] |
| *types = (*types)[1:] |
| |
| case TPTR32, TPTR64: |
| elem := substAny(t.Elem(), types) |
| if elem != t.Elem() { |
| t = t.Copy() |
| t.Extra = PtrType{Elem: elem} |
| } |
| |
| case TARRAY: |
| elem := substAny(t.Elem(), types) |
| if elem != t.Elem() { |
| t = t.Copy() |
| t.Extra.(*ArrayType).Elem = elem |
| } |
| |
| case TSLICE: |
| elem := substAny(t.Elem(), types) |
| if elem != t.Elem() { |
| t = t.Copy() |
| t.Extra = SliceType{Elem: elem} |
| } |
| |
| case TCHAN: |
| elem := substAny(t.Elem(), types) |
| if elem != t.Elem() { |
| t = t.Copy() |
| t.Extra.(*ChanType).Elem = elem |
| } |
| |
| case TMAP: |
| key := substAny(t.Key(), types) |
| val := substAny(t.Val(), types) |
| if key != t.Key() || val != t.Val() { |
| t = t.Copy() |
| t.Extra.(*MapType).Key = key |
| t.Extra.(*MapType).Val = val |
| } |
| |
| case TFUNC: |
| recvs := substAny(t.Recvs(), types) |
| params := substAny(t.Params(), types) |
| results := substAny(t.Results(), types) |
| if recvs != t.Recvs() || params != t.Params() || results != t.Results() { |
| // Note that this code has to be aware of the |
| // representation underlying Recvs/Results/Params. |
| if recvs == t.Recvs() { |
| recvs = recvs.Copy() |
| } |
| if results == t.Results() { |
| results = results.Copy() |
| } |
| t = t.Copy() |
| *t.RecvsP() = recvs |
| *t.ResultsP() = results |
| *t.ParamsP() = params |
| } |
| |
| case TSTRUCT: |
| fields := t.FieldSlice() |
| var nfs []*Field |
| for i, f := range fields { |
| nft := substAny(f.Type, types) |
| if nft == f.Type { |
| continue |
| } |
| if nfs == nil { |
| nfs = append([]*Field(nil), fields...) |
| } |
| nfs[i] = f.Copy() |
| nfs[i].Type = nft |
| } |
| if nfs != nil { |
| t = t.Copy() |
| t.SetFields(nfs) |
| } |
| } |
| |
| return t |
| } |
| |
| // Copy returns a shallow copy of the Type. |
| func (t *Type) Copy() *Type { |
| if t == nil { |
| return nil |
| } |
| nt := *t |
| // copy any *T Extra fields, to avoid aliasing |
| switch t.Etype { |
| case TMAP: |
| x := *t.Extra.(*MapType) |
| nt.Extra = &x |
| case TFORW: |
| x := *t.Extra.(*ForwardType) |
| nt.Extra = &x |
| case TFUNC: |
| x := *t.Extra.(*FuncType) |
| nt.Extra = &x |
| case TSTRUCT: |
| x := *t.Extra.(*StructType) |
| nt.Extra = &x |
| case TINTER: |
| x := *t.Extra.(*InterType) |
| nt.Extra = &x |
| case TCHAN: |
| x := *t.Extra.(*ChanType) |
| nt.Extra = &x |
| case TARRAY: |
| x := *t.Extra.(*ArrayType) |
| nt.Extra = &x |
| } |
| // TODO(mdempsky): Find out why this is necessary and explain. |
| if t.Orig == t { |
| nt.Orig = &nt |
| } |
| return &nt |
| } |
| |
| func (f *Field) Copy() *Field { |
| nf := *f |
| return &nf |
| } |
| |
| // Iter provides an abstraction for iterating across struct fields and |
| // interface methods. |
| type Iter struct { |
| s []*Field |
| } |
| |
| // IterFields returns the first field or method in struct or interface type t |
| // and an Iter value to continue iterating across the rest. |
| func IterFields(t *Type) (*Field, Iter) { |
| return t.Fields().Iter() |
| } |
| |
| // Iter returns the first field in fs and an Iter value to continue iterating |
| // across its successor fields. |
| // Deprecated: New code should use Slice instead. |
| func (fs *Fields) Iter() (*Field, Iter) { |
| i := Iter{s: fs.Slice()} |
| f := i.Next() |
| return f, i |
| } |
| |
| // Next returns the next field or method, if any. |
| func (i *Iter) Next() *Field { |
| if len(i.s) == 0 { |
| return nil |
| } |
| f := i.s[0] |
| i.s = i.s[1:] |
| return f |
| } |
| |
| func (t *Type) wantEtype(et EType) { |
| if t.Etype != et { |
| Fatalf("want %v, but have %v", et, t) |
| } |
| } |
| |
| func (t *Type) wantEtype2(et1, et2 EType) { |
| if t.Etype != et1 && t.Etype != et2 { |
| Fatalf("want %v or %v, but have %v", et1, et2, t) |
| } |
| } |
| |
| func (t *Type) RecvsP() **Type { |
| t.wantEtype(TFUNC) |
| return &t.Extra.(*FuncType).Receiver |
| } |
| |
| func (t *Type) ParamsP() **Type { |
| t.wantEtype(TFUNC) |
| return &t.Extra.(*FuncType).Params |
| } |
| |
| func (t *Type) ResultsP() **Type { |
| t.wantEtype(TFUNC) |
| return &t.Extra.(*FuncType).Results |
| } |
| |
| func (t *Type) Recvs() *Type { return *t.RecvsP() } |
| func (t *Type) Params() *Type { return *t.ParamsP() } |
| func (t *Type) Results() *Type { return *t.ResultsP() } |
| |
| // Recv returns the receiver of function type t, if any. |
| func (t *Type) Recv() *Field { |
| s := t.Recvs() |
| if s.NumFields() == 0 { |
| return nil |
| } |
| return s.Field(0) |
| } |
| |
| // recvsParamsResults stores the accessor functions for a function Type's |
| // receiver, parameters, and result parameters, in that order. |
| // It can be used to iterate over all of a function's parameter lists. |
| var recvsParamsResults = [3]func(*Type) *Type{ |
| (*Type).Recvs, (*Type).Params, (*Type).Results, |
| } |
| |
| // paramsResults is like recvsParamsResults, but omits receiver parameters. |
| var paramsResults = [2]func(*Type) *Type{ |
| (*Type).Params, (*Type).Results, |
| } |
| |
| // Key returns the key type of map type t. |
| func (t *Type) Key() *Type { |
| t.wantEtype(TMAP) |
| return t.Extra.(*MapType).Key |
| } |
| |
| // Val returns the value type of map type t. |
| func (t *Type) Val() *Type { |
| t.wantEtype(TMAP) |
| return t.Extra.(*MapType).Val |
| } |
| |
| // Elem returns the type of elements of t. |
| // Usable with pointers, channels, arrays, and slices. |
| func (t *Type) Elem() *Type { |
| switch t.Etype { |
| case TPTR32, TPTR64: |
| return t.Extra.(PtrType).Elem |
| case TARRAY: |
| return t.Extra.(*ArrayType).Elem |
| case TSLICE: |
| return t.Extra.(SliceType).Elem |
| case TCHAN: |
| return t.Extra.(*ChanType).Elem |
| } |
| Fatalf("Type.Elem %s", t.Etype) |
| return nil |
| } |
| |
| // DDDField returns the slice ... type for TDDDFIELD type t. |
| func (t *Type) DDDField() *Type { |
| t.wantEtype(TDDDFIELD) |
| return t.Extra.(DDDFieldType).T |
| } |
| |
| // ChanArgs returns the channel type for TCHANARGS type t. |
| func (t *Type) ChanArgs() *Type { |
| t.wantEtype(TCHANARGS) |
| return t.Extra.(ChanArgsType).T |
| } |
| |
| // FuncArgs returns the channel type for TFUNCARGS type t. |
| func (t *Type) FuncArgs() *Type { |
| t.wantEtype(TFUNCARGS) |
| return t.Extra.(FuncArgsType).T |
| } |
| |
| // Nname returns the associated function's nname. |
| func (t *Type) Nname() *Node { |
| switch t.Etype { |
| case TFUNC: |
| return t.Extra.(*FuncType).Nname |
| case TINTERMETH: |
| return t.Extra.(InterMethType).Nname |
| } |
| Fatalf("Type.Nname %v %v", t.Etype, t) |
| return nil |
| } |
| |
| // Nname sets the associated function's nname. |
| func (t *Type) SetNname(n *Node) { |
| switch t.Etype { |
| case TFUNC: |
| t.Extra.(*FuncType).Nname = n |
| case TINTERMETH: |
| t.Extra = InterMethType{Nname: n} |
| default: |
| Fatalf("Type.SetNname %v %v", t.Etype, t) |
| } |
| } |
| |
| // IsFuncArgStruct reports whether t is a struct representing function parameters. |
| func (t *Type) IsFuncArgStruct() bool { |
| return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg != FunargNone |
| } |
| |
| func (t *Type) Methods() *Fields { |
| // TODO(mdempsky): Validate t? |
| return &t.methods |
| } |
| |
| func (t *Type) AllMethods() *Fields { |
| // TODO(mdempsky): Validate t? |
| return &t.allMethods |
| } |
| |
| func (t *Type) Fields() *Fields { |
| switch t.Etype { |
| case TSTRUCT: |
| return &t.Extra.(*StructType).fields |
| case TINTER: |
| return &t.Extra.(*InterType).fields |
| } |
| Fatalf("Fields: type %v does not have fields", t) |
| return nil |
| } |
| |
| // Field returns the i'th field/method of struct/interface type t. |
| func (t *Type) Field(i int) *Field { |
| return t.Fields().Slice()[i] |
| } |
| |
| // FieldSlice returns a slice of containing all fields/methods of |
| // struct/interface type t. |
| func (t *Type) FieldSlice() []*Field { |
| return t.Fields().Slice() |
| } |
| |
| // SetFields sets struct/interface type t's fields/methods to fields. |
| func (t *Type) SetFields(fields []*Field) { |
| t.Fields().Set(fields) |
| } |
| |
| func (t *Type) isDDDArray() bool { |
| if t.Etype != TARRAY { |
| return false |
| } |
| return t.Extra.(*ArrayType).Bound < 0 |
| } |
| |
| // ArgWidth returns the total aligned argument size for a function. |
| // It includes the receiver, parameters, and results. |
| func (t *Type) ArgWidth() int64 { |
| t.wantEtype(TFUNC) |
| return t.Extra.(*FuncType).Argwid |
| } |
| |
| func (t *Type) Size() int64 { |
| dowidth(t) |
| return t.Width |
| } |
| |
| func (t *Type) Alignment() int64 { |
| dowidth(t) |
| return int64(t.Align) |
| } |
| |
| func (t *Type) SimpleString() string { |
| return t.Etype.String() |
| } |
| |
| // Compare compares types for purposes of the SSA back |
| // end, returning an ssa.Cmp (one of CMPlt, CMPeq, CMPgt). |
| // The answers are correct for an optimizer |
| // or code generator, but not necessarily typechecking. |
| // The order chosen is arbitrary, only consistency and division |
| // into equivalence classes (Types that compare CMPeq) matters. |
| func (t *Type) Compare(u ssa.Type) ssa.Cmp { |
| x, ok := u.(*Type) |
| // ssa.CompilerType is smaller than gc.Type |
| // bare pointer equality is easy. |
| if !ok { |
| return ssa.CMPgt |
| } |
| if x == t { |
| return ssa.CMPeq |
| } |
| return t.cmp(x) |
| } |
| |
| func cmpForNe(x bool) ssa.Cmp { |
| if x { |
| return ssa.CMPlt |
| } |
| return ssa.CMPgt |
| } |
| |
| func (r *Sym) cmpsym(s *Sym) ssa.Cmp { |
| if r == s { |
| return ssa.CMPeq |
| } |
| if r == nil { |
| return ssa.CMPlt |
| } |
| if s == nil { |
| return ssa.CMPgt |
| } |
| // Fast sort, not pretty sort |
| if len(r.Name) != len(s.Name) { |
| return cmpForNe(len(r.Name) < len(s.Name)) |
| } |
| if r.Pkg != s.Pkg { |
| if len(r.Pkg.Prefix) != len(s.Pkg.Prefix) { |
| return cmpForNe(len(r.Pkg.Prefix) < len(s.Pkg.Prefix)) |
| } |
| if r.Pkg.Prefix != s.Pkg.Prefix { |
| return cmpForNe(r.Pkg.Prefix < s.Pkg.Prefix) |
| } |
| } |
| if r.Name != s.Name { |
| return cmpForNe(r.Name < s.Name) |
| } |
| return ssa.CMPeq |
| } |
| |
| // cmp compares two *Types t and x, returning ssa.CMPlt, |
| // ssa.CMPeq, ssa.CMPgt as t<x, t==x, t>x, for an arbitrary |
| // and optimizer-centric notion of comparison. |
| func (t *Type) cmp(x *Type) ssa.Cmp { |
| // This follows the structure of Eqtype in subr.go |
| // with two exceptions. |
| // 1. Symbols are compared more carefully because a <,=,> result is desired. |
| // 2. Maps are treated specially to avoid endless recursion -- maps |
| // contain an internal data type not expressible in Go source code. |
| if t == x { |
| return ssa.CMPeq |
| } |
| if t == nil { |
| return ssa.CMPlt |
| } |
| if x == nil { |
| return ssa.CMPgt |
| } |
| |
| if t.Etype != x.Etype { |
| return cmpForNe(t.Etype < x.Etype) |
| } |
| |
| if t.Sym != nil || x.Sym != nil { |
| // Special case: we keep byte and uint8 separate |
| // for error messages. Treat them as equal. |
| switch t.Etype { |
| case TUINT8: |
| if (t == Types[TUINT8] || t == bytetype) && (x == Types[TUINT8] || x == bytetype) { |
| return ssa.CMPeq |
| } |
| |
| case TINT32: |
| if (t == Types[runetype.Etype] || t == runetype) && (x == Types[runetype.Etype] || x == runetype) { |
| return ssa.CMPeq |
| } |
| } |
| } |
| |
| if c := t.Sym.cmpsym(x.Sym); c != ssa.CMPeq { |
| return c |
| } |
| |
| if x.Sym != nil { |
| // Syms non-nil, if vargens match then equal. |
| if t.Vargen != x.Vargen { |
| return cmpForNe(t.Vargen < x.Vargen) |
| } |
| return ssa.CMPeq |
| } |
| // both syms nil, look at structure below. |
| |
| switch t.Etype { |
| case TBOOL, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TUNSAFEPTR, TUINTPTR, |
| TINT8, TINT16, TINT32, TINT64, TINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINT: |
| return ssa.CMPeq |
| } |
| |
| switch t.Etype { |
| case TMAP: |
| if c := t.Key().cmp(x.Key()); c != ssa.CMPeq { |
| return c |
| } |
| return t.Val().cmp(x.Val()) |
| |
| case TPTR32, TPTR64, TSLICE: |
| // No special cases for these, they are handled |
| // by the general code after the switch. |
| |
| case TSTRUCT: |
| if t.StructType().Map == nil { |
| if x.StructType().Map != nil { |
| return ssa.CMPlt // nil < non-nil |
| } |
| // to the fallthrough |
| } else if x.StructType().Map == nil { |
| return ssa.CMPgt // nil > non-nil |
| } else if t.StructType().Map.MapType().Bucket == t { |
| // Both have non-nil Map |
| // Special case for Maps which include a recursive type where the recursion is not broken with a named type |
| if x.StructType().Map.MapType().Bucket != x { |
| return ssa.CMPlt // bucket maps are least |
| } |
| return t.StructType().Map.cmp(x.StructType().Map) |
| } else if x.StructType().Map.MapType().Bucket == x { |
| return ssa.CMPgt // bucket maps are least |
| } // If t != t.Map.Bucket, fall through to general case |
| |
| fallthrough |
| case TINTER: |
| t1, ti := IterFields(t) |
| x1, xi := IterFields(x) |
| for ; t1 != nil && x1 != nil; t1, x1 = ti.Next(), xi.Next() { |
| if t1.Embedded != x1.Embedded { |
| return cmpForNe(t1.Embedded < x1.Embedded) |
| } |
| if t1.Note != x1.Note { |
| return cmpForNe(t1.Note < x1.Note) |
| } |
| if c := t1.Sym.cmpsym(x1.Sym); c != ssa.CMPeq { |
| return c |
| } |
| if c := t1.Type.cmp(x1.Type); c != ssa.CMPeq { |
| return c |
| } |
| } |
| if t1 != x1 { |
| return cmpForNe(t1 == nil) |
| } |
| return ssa.CMPeq |
| |
| case TFUNC: |
| for _, f := range recvsParamsResults { |
| // Loop over fields in structs, ignoring argument names. |
| ta, ia := IterFields(f(t)) |
| tb, ib := IterFields(f(x)) |
| for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() { |
| if ta.Isddd != tb.Isddd { |
| return cmpForNe(!ta.Isddd) |
| } |
| if c := ta.Type.cmp(tb.Type); c != ssa.CMPeq { |
| return c |
| } |
| } |
| if ta != tb { |
| return cmpForNe(ta == nil) |
| } |
| } |
| return ssa.CMPeq |
| |
| case TARRAY: |
| if t.NumElem() != x.NumElem() { |
| return cmpForNe(t.NumElem() < x.NumElem()) |
| } |
| |
| case TCHAN: |
| if t.ChanDir() != x.ChanDir() { |
| return cmpForNe(t.ChanDir() < x.ChanDir()) |
| } |
| |
| default: |
| e := fmt.Sprintf("Do not know how to compare %s with %s", t, x) |
| panic(e) |
| } |
| |
| // Common element type comparison for TARRAY, TCHAN, TPTR32, TPTR64, and TSLICE. |
| return t.Elem().cmp(x.Elem()) |
| } |
| |
| // IsKind reports whether t is a Type of the specified kind. |
| func (t *Type) IsKind(et EType) bool { |
| return t != nil && t.Etype == et |
| } |
| |
| func (t *Type) IsBoolean() bool { |
| return t.Etype == TBOOL |
| } |
| |
| func (t *Type) IsInteger() bool { |
| switch t.Etype { |
| case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR: |
| return true |
| } |
| return false |
| } |
| |
| func (t *Type) IsSigned() bool { |
| switch t.Etype { |
| case TINT8, TINT16, TINT32, TINT64, TINT: |
| return true |
| } |
| return false |
| } |
| |
| func (t *Type) IsFloat() bool { |
| return t.Etype == TFLOAT32 || t.Etype == TFLOAT64 |
| } |
| |
| func (t *Type) IsComplex() bool { |
| return t.Etype == TCOMPLEX64 || t.Etype == TCOMPLEX128 |
| } |
| |
| // IsPtr reports whether t is a regular Go pointer type. |
| // This does not include unsafe.Pointer. |
| func (t *Type) IsPtr() bool { |
| return t.Etype == TPTR32 || t.Etype == TPTR64 |
| } |
| |
| // IsUnsafePtr reports whether t is an unsafe pointer. |
| func (t *Type) IsUnsafePtr() bool { |
| return t.Etype == TUNSAFEPTR |
| } |
| |
| // IsPtrShaped reports whether t is represented by a single machine pointer. |
| // In addition to regular Go pointer types, this includes map, channel, and |
| // function types and unsafe.Pointer. It does not include array or struct types |
| // that consist of a single pointer shaped type. |
| // TODO(mdempsky): Should it? See golang.org/issue/15028. |
| func (t *Type) IsPtrShaped() bool { |
| return t.Etype == TPTR32 || t.Etype == TPTR64 || t.Etype == TUNSAFEPTR || |
| t.Etype == TMAP || t.Etype == TCHAN || t.Etype == TFUNC |
| } |
| |
| func (t *Type) IsString() bool { |
| return t.Etype == TSTRING |
| } |
| |
| func (t *Type) IsMap() bool { |
| return t.Etype == TMAP |
| } |
| |
| func (t *Type) IsChan() bool { |
| return t.Etype == TCHAN |
| } |
| |
| func (t *Type) IsSlice() bool { |
| return t.Etype == TSLICE |
| } |
| |
| func (t *Type) IsArray() bool { |
| return t.Etype == TARRAY |
| } |
| |
| func (t *Type) IsStruct() bool { |
| return t.Etype == TSTRUCT |
| } |
| |
| func (t *Type) IsInterface() bool { |
| return t.Etype == TINTER |
| } |
| |
| // IsEmptyInterface reports whether t is an empty interface type. |
| func (t *Type) IsEmptyInterface() bool { |
| return t.IsInterface() && t.NumFields() == 0 |
| } |
| |
| func (t *Type) ElemType() ssa.Type { |
| // TODO(josharian): If Type ever moves to a shared |
| // internal package, remove this silly wrapper. |
| return t.Elem() |
| } |
| func (t *Type) PtrTo() ssa.Type { |
| return Ptrto(t) |
| } |
| |
| func (t *Type) NumFields() int { |
| return t.Fields().Len() |
| } |
| func (t *Type) FieldType(i int) ssa.Type { |
| return t.Field(i).Type |
| } |
| func (t *Type) FieldOff(i int) int64 { |
| return t.Field(i).Offset |
| } |
| func (t *Type) FieldName(i int) string { |
| return t.Field(i).Sym.Name |
| } |
| |
| func (t *Type) NumElem() int64 { |
| t.wantEtype(TARRAY) |
| at := t.Extra.(*ArrayType) |
| if at.Bound < 0 { |
| Fatalf("NumElem array %v does not have bound yet", t) |
| } |
| return at.Bound |
| } |
| |
| // SetNumElem sets the number of elements in an array type. |
| // The only allowed use is on array types created with typDDDArray. |
| // For other uses, create a new array with typArray instead. |
| func (t *Type) SetNumElem(n int64) { |
| t.wantEtype(TARRAY) |
| at := t.Extra.(*ArrayType) |
| if at.Bound >= 0 { |
| Fatalf("SetNumElem array %v already has bound %d", t, at.Bound) |
| } |
| at.Bound = n |
| } |
| |
| // ChanDir returns the direction of a channel type t. |
| // The direction will be one of Crecv, Csend, or Cboth. |
| func (t *Type) ChanDir() ChanDir { |
| t.wantEtype(TCHAN) |
| return t.Extra.(*ChanType).Dir |
| } |
| |
| func (t *Type) IsMemory() bool { return false } |
| func (t *Type) IsFlags() bool { return false } |
| func (t *Type) IsVoid() bool { return false } |
| |
| // IsUntyped reports whether t is an untyped type. |
| func (t *Type) IsUntyped() bool { |
| if t == nil { |
| return false |
| } |
| if t == idealstring || t == idealbool { |
| return true |
| } |
| switch t.Etype { |
| case TNIL, TIDEAL: |
| return true |
| } |
| return false |
| } |