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 5 // This file implements Selections. 6 7 package types 8 9 import ( 10 "bytes" 11 "fmt" 12 ) 13 14 // SelectionKind describes the kind of a selector expression x.f 15 // (excluding qualified identifiers). 16 type SelectionKind int 17 18 const ( 19 FieldVal SelectionKind = iota // x.f is a struct field selector 20 MethodVal // x.f is a method selector 21 MethodExpr // x.f is a method expression 22 ) 23 24 // A Selection describes a selector expression x.f. 25 // For the declarations: 26 // 27 // type T struct{ x int; E } 28 // type E struct{} 29 // func (e E) m() {} 30 // var p *T 31 // 32 // the following relations exist: 33 // 34 // Selector Kind Recv Obj Type Index Indirect 35 // 36 // p.x FieldVal T x int {0} true 37 // p.m MethodVal *T m func() {1, 0} true 38 // T.m MethodExpr T m func(T) {1, 0} false 39 // 40 type Selection struct { 41 kind SelectionKind 42 recv Type // type of x 43 obj Object // object denoted by x.f 44 index []int // path from x to x.f 45 indirect bool // set if there was any pointer indirection on the path 46 } 47 48 // Kind returns the selection kind. 49 func (s *Selection) Kind() SelectionKind { return s.kind } 50 51 // Recv returns the type of x in x.f. 52 func (s *Selection) Recv() Type { return s.recv } 53 54 // Obj returns the object denoted by x.f; a *Var for 55 // a field selection, and a *Func in all other cases. 56 func (s *Selection) Obj() Object { return s.obj } 57 58 // Type returns the type of x.f, which may be different from the type of f. 59 // See Selection for more information. 60 func (s *Selection) Type() Type { 61 switch s.kind { 62 case MethodVal: 63 // The type of x.f is a method with its receiver type set 64 // to the type of x. 65 sig := *s.obj.(*Func).typ.(*Signature) 66 recv := *sig.recv 67 recv.typ = s.recv 68 sig.recv = &recv 69 return &sig 70 71 case MethodExpr: 72 // The type of x.f is a function (without receiver) 73 // and an additional first argument with the same type as x. 74 // TODO(gri) Similar code is already in call.go - factor! 75 // TODO(gri) Compute this eagerly to avoid allocations. 76 sig := *s.obj.(*Func).typ.(*Signature) 77 arg0 := *sig.recv 78 sig.recv = nil 79 arg0.typ = s.recv 80 var params []*Var 81 if sig.params != nil { 82 params = sig.params.vars 83 } 84 sig.params = NewTuple(append([]*Var{&arg0}, params...)...) 85 return &sig 86 } 87 88 // In all other cases, the type of x.f is the type of x. 89 return s.obj.Type() 90 } 91 92 // Index describes the path from x to f in x.f. 93 // The last index entry is the field or method index of the type declaring f; 94 // either: 95 // 96 // 1) the list of declared methods of a named type; or 97 // 2) the list of methods of an interface type; or 98 // 3) the list of fields of a struct type. 99 // 100 // The earlier index entries are the indices of the embedded fields implicitly 101 // traversed to get from (the type of) x to f, starting at embedding depth 0. 102 func (s *Selection) Index() []int { return s.index } 103 104 // Indirect reports whether any pointer indirection was required to get from 105 // x to f in x.f. 106 func (s *Selection) Indirect() bool { return s.indirect } 107 108 func (s *Selection) String() string { return SelectionString(s, nil) } 109 110 // SelectionString returns the string form of s. 111 // The Qualifier controls the printing of 112 // package-level objects, and may be nil. 113 // 114 // Examples: 115 // "field (T) f int" 116 // "method (T) f(X) Y" 117 // "method expr (T) f(X) Y" 118 // 119 func SelectionString(s *Selection, qf Qualifier) string { 120 var k string 121 switch s.kind { 122 case FieldVal: 123 k = "field " 124 case MethodVal: 125 k = "method " 126 case MethodExpr: 127 k = "method expr " 128 default: 129 unreachable() 130 } 131 var buf bytes.Buffer 132 buf.WriteString(k) 133 buf.WriteByte('(') 134 WriteType(&buf, s.Recv(), qf) 135 fmt.Fprintf(&buf, ") %s", s.obj.Name()) 136 if T := s.Type(); s.kind == FieldVal { 137 buf.WriteByte(' ') 138 WriteType(&buf, T, qf) 139 } else { 140 WriteSignature(&buf, T.(*Signature), qf) 141 } 142 return buf.String() 143 } 144