Source file src/cmd/compile/internal/types2/selection.go
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 types2 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 // 17 // If x is a struct or *struct, a selector expression x.f may denote a 18 // sequence of selection operations x.a.b.c.f. The SelectionKind 19 // describes the kind of the final (explicit) operation; all the 20 // previous (implicit) operations are always field selections. 21 // Each element of Indices specifies an implicit field (a, b, c) 22 // by its index in the struct type of the field selection operand. 23 // 24 // For a FieldVal operation, the final selection refers to the field 25 // specified by Selection.Obj. 26 // 27 // For a MethodVal operation, the final selection refers to a method. 28 // If the "pointerness" of the method's declared receiver does not 29 // match that of the effective receiver after implicit field 30 // selection, then an & or * operation is implicitly applied to the 31 // receiver variable or value. 32 // So, x.f denotes (&x.a.b.c).f when f requires a pointer receiver but 33 // x.a.b.c is a non-pointer variable; and it denotes (*x.a.b.c).f when 34 // f requires a non-pointer receiver but x.a.b.c is a pointer value. 35 // 36 // All pointer indirections, whether due to implicit or explicit field 37 // selections or * operations inserted for "pointerness", panic if 38 // applied to a nil pointer, so a method call x.f() may panic even 39 // before the function call. 40 // 41 // By contrast, a MethodExpr operation T.f is essentially equivalent 42 // to a function literal of the form: 43 // 44 // func(x T, args) (results) { return x.f(args) } 45 // 46 // Consequently, any implicit field selections and * operations 47 // inserted for "pointerness" are not evaluated until the function is 48 // called, so a T.f or (*T).f expression never panics. 49 type SelectionKind int 50 51 const ( 52 FieldVal SelectionKind = iota // x.f is a struct field selector 53 MethodVal // x.f is a method selector 54 MethodExpr // x.f is a method expression 55 ) 56 57 // A Selection describes a selector expression x.f. 58 // For the declarations: 59 // 60 // type T struct{ x int; E } 61 // type E struct{} 62 // func (e E) m() {} 63 // var p *T 64 // 65 // the following relations exist: 66 // 67 // Selector Kind Recv Obj Type Index Indirect 68 // 69 // p.x FieldVal T x int {0} true 70 // p.m MethodVal *T m func() {1, 0} true 71 // T.m MethodExpr T m func(T) {1, 0} false 72 type Selection struct { 73 kind SelectionKind 74 recv Type // type of x 75 obj Object // object denoted by x.f 76 index []int // path from x to x.f 77 indirect bool // set if there was any pointer indirection on the path 78 } 79 80 // Kind returns the selection kind. 81 func (s *Selection) Kind() SelectionKind { return s.kind } 82 83 // Recv returns the type of x in x.f. 84 func (s *Selection) Recv() Type { return s.recv } 85 86 // Obj returns the object denoted by x.f; a *Var for 87 // a field selection, and a *Func in all other cases. 88 func (s *Selection) Obj() Object { return s.obj } 89 90 // Type returns the type of x.f, which may be different from the type of f. 91 // See Selection for more information. 92 func (s *Selection) Type() Type { 93 switch s.kind { 94 case MethodVal: 95 // The type of x.f is a method with its receiver type set 96 // to the type of x. 97 sig := *s.obj.(*Func).typ.(*Signature) 98 recv := *sig.recv 99 recv.typ = s.recv 100 sig.recv = &recv 101 return &sig 102 103 case MethodExpr: 104 // The type of x.f is a function (without receiver) 105 // and an additional first argument with the same type as x. 106 // TODO(gri) Similar code is already in call.go - factor! 107 // TODO(gri) Compute this eagerly to avoid allocations. 108 sig := *s.obj.(*Func).typ.(*Signature) 109 arg0 := *sig.recv 110 sig.recv = nil 111 arg0.typ = s.recv 112 var params []*Var 113 if sig.params != nil { 114 params = sig.params.vars 115 } 116 sig.params = NewTuple(append([]*Var{&arg0}, params...)...) 117 return &sig 118 } 119 120 // In all other cases, the type of x.f is the type of x. 121 return s.obj.Type() 122 } 123 124 // Index describes the path from x to f in x.f. 125 // The last index entry is the field or method index of the type declaring f; 126 // either: 127 // 128 // 1. the list of declared methods of a named type; or 129 // 2. the list of methods of an interface type; or 130 // 3. the list of fields of a struct type. 131 // 132 // The earlier index entries are the indices of the embedded fields implicitly 133 // traversed to get from (the type of) x to f, starting at embedding depth 0. 134 func (s *Selection) Index() []int { return s.index } 135 136 // Indirect reports whether any pointer indirection was required to get from 137 // x to f in x.f. 138 // 139 // Beware: Indirect spuriously returns true (Go issue #8353) for a 140 // MethodVal selection in which the receiver argument and parameter 141 // both have type *T so there is no indirection. 142 // Unfortunately, a fix is too risky. 143 func (s *Selection) Indirect() bool { return s.indirect } 144 145 func (s *Selection) String() string { return SelectionString(s, nil) } 146 147 // SelectionString returns the string form of s. 148 // The Qualifier controls the printing of 149 // package-level objects, and may be nil. 150 // 151 // Examples: 152 // 153 // "field (T) f int" 154 // "method (T) f(X) Y" 155 // "method expr (T) f(X) Y" 156 func SelectionString(s *Selection, qf Qualifier) string { 157 var k string 158 switch s.kind { 159 case FieldVal: 160 k = "field " 161 case MethodVal: 162 k = "method " 163 case MethodExpr: 164 k = "method expr " 165 default: 166 panic("unreachable") 167 } 168 var buf bytes.Buffer 169 buf.WriteString(k) 170 buf.WriteByte('(') 171 WriteType(&buf, s.Recv(), qf) 172 fmt.Fprintf(&buf, ") %s", s.obj.Name()) 173 if T := s.Type(); s.kind == FieldVal { 174 buf.WriteByte(' ') 175 WriteType(&buf, T, qf) 176 } else { 177 WriteSignature(&buf, T.(*Signature), qf) 178 } 179 return buf.String() 180 } 181