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