| // Copyright 2009 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 ir |
| |
| import ( |
| "cmd/compile/internal/base" |
| "cmd/compile/internal/types" |
| "cmd/internal/src" |
| "fmt" |
| ) |
| |
| // Nodes that represent the syntax of a type before type-checking. |
| // After type-checking, they serve only as shells around a *types.Type. |
| // Calling TypeNode converts a *types.Type to a Node shell. |
| |
| // An Ntype is a Node that syntactically looks like a type. |
| // It can be the raw syntax for a type before typechecking, |
| // or it can be an OTYPE with Type() set to a *types.Type. |
| // Note that syntax doesn't guarantee it's a type: an expression |
| // like *fmt is an Ntype (we don't know whether names are types yet), |
| // but at least 1+1 is not an Ntype. |
| type Ntype interface { |
| Node |
| CanBeNtype() |
| } |
| |
| // A miniType is a minimal type syntax Node implementation, |
| // to be embedded as the first field in a larger node implementation. |
| type miniType struct { |
| miniNode |
| typ *types.Type |
| } |
| |
| func (*miniType) CanBeNtype() {} |
| |
| func (n *miniType) Type() *types.Type { return n.typ } |
| |
| // setOTYPE changes n to be an OTYPE node returning t. |
| // Rewriting the node in place this way should not be strictly |
| // necessary (we should be able to update the uses with |
| // proper OTYPE nodes), but it's mostly harmless and easy |
| // to keep doing for now. |
| // |
| // setOTYPE also records t.Nod = self if t.Nod is not already set. |
| // (Some types are shared by multiple OTYPE nodes, so only |
| // the first such node is used as t.Nod.) |
| func (n *miniType) setOTYPE(t *types.Type, self Ntype) { |
| if n.typ != nil { |
| panic(n.op.String() + " SetType: type already set") |
| } |
| n.op = OTYPE |
| n.typ = t |
| t.SetNod(self) |
| } |
| |
| func (n *miniType) Sym() *types.Sym { return nil } // for Format OTYPE |
| func (n *miniType) Implicit() bool { return false } // for Format OTYPE |
| |
| // A ChanType represents a chan Elem syntax with the direction Dir. |
| type ChanType struct { |
| miniType |
| Elem Ntype |
| Dir types.ChanDir |
| } |
| |
| func NewChanType(pos src.XPos, elem Ntype, dir types.ChanDir) *ChanType { |
| n := &ChanType{Elem: elem, Dir: dir} |
| n.op = OTCHAN |
| n.pos = pos |
| return n |
| } |
| |
| func (n *ChanType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Elem = nil |
| } |
| |
| // A MapType represents a map[Key]Value type syntax. |
| type MapType struct { |
| miniType |
| Key Ntype |
| Elem Ntype |
| } |
| |
| func NewMapType(pos src.XPos, key, elem Ntype) *MapType { |
| n := &MapType{Key: key, Elem: elem} |
| n.op = OTMAP |
| n.pos = pos |
| return n |
| } |
| |
| func (n *MapType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Key = nil |
| n.Elem = nil |
| } |
| |
| // A StructType represents a struct { ... } type syntax. |
| type StructType struct { |
| miniType |
| Fields []*Field |
| } |
| |
| func NewStructType(pos src.XPos, fields []*Field) *StructType { |
| n := &StructType{Fields: fields} |
| n.op = OTSTRUCT |
| n.pos = pos |
| return n |
| } |
| |
| func (n *StructType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Fields = nil |
| } |
| |
| // An InterfaceType represents a struct { ... } type syntax. |
| type InterfaceType struct { |
| miniType |
| Methods []*Field |
| } |
| |
| func NewInterfaceType(pos src.XPos, methods []*Field) *InterfaceType { |
| n := &InterfaceType{Methods: methods} |
| n.op = OTINTER |
| n.pos = pos |
| return n |
| } |
| |
| func (n *InterfaceType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Methods = nil |
| } |
| |
| // A FuncType represents a func(Args) Results type syntax. |
| type FuncType struct { |
| miniType |
| Recv *Field |
| Params []*Field |
| Results []*Field |
| } |
| |
| func NewFuncType(pos src.XPos, rcvr *Field, args, results []*Field) *FuncType { |
| n := &FuncType{Recv: rcvr, Params: args, Results: results} |
| n.op = OTFUNC |
| n.pos = pos |
| return n |
| } |
| |
| func (n *FuncType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Recv = nil |
| n.Params = nil |
| n.Results = nil |
| } |
| |
| // A Field is a declared struct field, interface method, or function argument. |
| // It is not a Node. |
| type Field struct { |
| Pos src.XPos |
| Sym *types.Sym |
| Ntype Ntype |
| Type *types.Type |
| Embedded bool |
| IsDDD bool |
| Note string |
| Decl *Name |
| } |
| |
| func NewField(pos src.XPos, sym *types.Sym, ntyp Ntype, typ *types.Type) *Field { |
| return &Field{Pos: pos, Sym: sym, Ntype: ntyp, Type: typ} |
| } |
| |
| func (f *Field) String() string { |
| var typ string |
| if f.Type != nil { |
| typ = fmt.Sprint(f.Type) |
| } else { |
| typ = fmt.Sprint(f.Ntype) |
| } |
| if f.Sym != nil { |
| return fmt.Sprintf("%v %v", f.Sym, typ) |
| } |
| return typ |
| } |
| |
| // TODO(mdempsky): Make Field a Node again so these can be generated? |
| // Fields are Nodes in go/ast and cmd/compile/internal/syntax. |
| |
| func copyField(f *Field) *Field { |
| if f == nil { |
| return nil |
| } |
| c := *f |
| return &c |
| } |
| func doField(f *Field, do func(Node) bool) bool { |
| if f == nil { |
| return false |
| } |
| if f.Decl != nil && do(f.Decl) { |
| return true |
| } |
| if f.Ntype != nil && do(f.Ntype) { |
| return true |
| } |
| return false |
| } |
| func editField(f *Field, edit func(Node) Node) { |
| if f == nil { |
| return |
| } |
| if f.Decl != nil { |
| f.Decl = edit(f.Decl).(*Name) |
| } |
| if f.Ntype != nil { |
| f.Ntype = edit(f.Ntype).(Ntype) |
| } |
| } |
| |
| func copyFields(list []*Field) []*Field { |
| out := make([]*Field, len(list)) |
| for i, f := range list { |
| out[i] = copyField(f) |
| } |
| return out |
| } |
| func doFields(list []*Field, do func(Node) bool) bool { |
| for _, x := range list { |
| if doField(x, do) { |
| return true |
| } |
| } |
| return false |
| } |
| func editFields(list []*Field, edit func(Node) Node) { |
| for _, f := range list { |
| editField(f, edit) |
| } |
| } |
| |
| // A SliceType represents a []Elem type syntax. |
| // If DDD is true, it's the ...Elem at the end of a function list. |
| type SliceType struct { |
| miniType |
| Elem Ntype |
| DDD bool |
| } |
| |
| func NewSliceType(pos src.XPos, elem Ntype) *SliceType { |
| n := &SliceType{Elem: elem} |
| n.op = OTSLICE |
| n.pos = pos |
| return n |
| } |
| |
| func (n *SliceType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Elem = nil |
| } |
| |
| // An ArrayType represents a [Len]Elem type syntax. |
| // If Len is nil, the type is a [...]Elem in an array literal. |
| type ArrayType struct { |
| miniType |
| Len Node |
| Elem Ntype |
| } |
| |
| func NewArrayType(pos src.XPos, len Node, elem Ntype) *ArrayType { |
| n := &ArrayType{Len: len, Elem: elem} |
| n.op = OTARRAY |
| n.pos = pos |
| return n |
| } |
| |
| func (n *ArrayType) SetOTYPE(t *types.Type) { |
| n.setOTYPE(t, n) |
| n.Len = nil |
| n.Elem = nil |
| } |
| |
| // A typeNode is a Node wrapper for type t. |
| type typeNode struct { |
| miniNode |
| typ *types.Type |
| } |
| |
| func newTypeNode(pos src.XPos, typ *types.Type) *typeNode { |
| n := &typeNode{typ: typ} |
| n.pos = pos |
| n.op = OTYPE |
| return n |
| } |
| |
| func (n *typeNode) Type() *types.Type { return n.typ } |
| func (n *typeNode) Sym() *types.Sym { return n.typ.Sym() } |
| func (n *typeNode) CanBeNtype() {} |
| |
| // TypeNode returns the Node representing the type t. |
| func TypeNode(t *types.Type) Ntype { |
| return TypeNodeAt(src.NoXPos, t) |
| } |
| |
| // TypeNodeAt is like TypeNode, but allows specifying the position |
| // information if a new OTYPE needs to be constructed. |
| // |
| // Deprecated: Use TypeNode instead. For typical use, the position for |
| // an anonymous OTYPE node should not matter. However, TypeNodeAt is |
| // available for use with toolstash -cmp to refactor existing code |
| // that is sensitive to OTYPE position. |
| func TypeNodeAt(pos src.XPos, t *types.Type) Ntype { |
| if n := t.Obj(); n != nil { |
| if n.Type() != t { |
| base.Fatalf("type skew: %v has type %v, but expected %v", n, n.Type(), t) |
| } |
| return n.(Ntype) |
| } |
| return newTypeNode(pos, t) |
| } |
| |
| // A DynamicType represents the target type in a type switch. |
| type DynamicType struct { |
| miniExpr |
| X Node // a *runtime._type for the targeted type |
| ITab Node // for type switches from nonempty interfaces to non-interfaces, this is the itab for that pair. |
| } |
| |
| func NewDynamicType(pos src.XPos, x Node) *DynamicType { |
| n := &DynamicType{X: x} |
| n.pos = pos |
| n.op = ODYNAMICTYPE |
| return n |
| } |