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