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 7package types2 8 9import ( 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. 49type SelectionKind int 50 51const ( 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 72type 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. 81func (s *Selection) Kind() SelectionKind { return s.kind } 82 83// Recv returns the type of x in x.f. 84func (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. 88func (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. 92func (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. 134func (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. 143func (s *Selection) Indirect() bool { return s.indirect } 144 145func (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" 156func 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