...
Run Format

Source file src/go/types/selection.go

Documentation: go/types

  // Copyright 2013 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // This file implements Selections.
  
  package types
  
  import (
  	"bytes"
  	"fmt"
  )
  
  // SelectionKind describes the kind of a selector expression x.f
  // (excluding qualified identifiers).
  type SelectionKind int
  
  const (
  	FieldVal   SelectionKind = iota // x.f is a struct field selector
  	MethodVal                       // x.f is a method selector
  	MethodExpr                      // x.f is a method expression
  )
  
  // A Selection describes a selector expression x.f.
  // For the declarations:
  //
  //	type T struct{ x int; E }
  //	type E struct{}
  //	func (e E) m() {}
  //	var p *T
  //
  // the following relations exist:
  //
  //	Selector    Kind          Recv    Obj    Type               Index     Indirect
  //
  //	p.x         FieldVal      T       x      int                {0}       true
  //	p.m         MethodVal     *T      m      func (e *T) m()    {1, 0}    true
  //	T.m         MethodExpr    T       m      func m(_ T)        {1, 0}    false
  //
  type Selection struct {
  	kind     SelectionKind
  	recv     Type   // type of x
  	obj      Object // object denoted by x.f
  	index    []int  // path from x to x.f
  	indirect bool   // set if there was any pointer indirection on the path
  }
  
  // Kind returns the selection kind.
  func (s *Selection) Kind() SelectionKind { return s.kind }
  
  // Recv returns the type of x in x.f.
  func (s *Selection) Recv() Type { return s.recv }
  
  // Obj returns the object denoted by x.f; a *Var for
  // a field selection, and a *Func in all other cases.
  func (s *Selection) Obj() Object { return s.obj }
  
  // Type returns the type of x.f, which may be different from the type of f.
  // See Selection for more information.
  func (s *Selection) Type() Type {
  	switch s.kind {
  	case MethodVal:
  		// The type of x.f is a method with its receiver type set
  		// to the type of x.
  		sig := *s.obj.(*Func).typ.(*Signature)
  		recv := *sig.recv
  		recv.typ = s.recv
  		sig.recv = &recv
  		return &sig
  
  	case MethodExpr:
  		// The type of x.f is a function (without receiver)
  		// and an additional first argument with the same type as x.
  		// TODO(gri) Similar code is already in call.go - factor!
  		// TODO(gri) Compute this eagerly to avoid allocations.
  		sig := *s.obj.(*Func).typ.(*Signature)
  		arg0 := *sig.recv
  		sig.recv = nil
  		arg0.typ = s.recv
  		var params []*Var
  		if sig.params != nil {
  			params = sig.params.vars
  		}
  		sig.params = NewTuple(append([]*Var{&arg0}, params...)...)
  		return &sig
  	}
  
  	// In all other cases, the type of x.f is the type of x.
  	return s.obj.Type()
  }
  
  // Index describes the path from x to f in x.f.
  // The last index entry is the field or method index of the type declaring f;
  // either:
  //
  //	1) the list of declared methods of a named type; or
  //	2) the list of methods of an interface type; or
  //	3) the list of fields of a struct type.
  //
  // The earlier index entries are the indices of the embedded fields implicitly
  // traversed to get from (the type of) x to f, starting at embedding depth 0.
  func (s *Selection) Index() []int { return s.index }
  
  // Indirect reports whether any pointer indirection was required to get from
  // x to f in x.f.
  func (s *Selection) Indirect() bool { return s.indirect }
  
  func (s *Selection) String() string { return SelectionString(s, nil) }
  
  // SelectionString returns the string form of s.
  // The Qualifier controls the printing of
  // package-level objects, and may be nil.
  //
  // Examples:
  //	"field (T) f int"
  //	"method (T) f(X) Y"
  //	"method expr (T) f(X) Y"
  //
  func SelectionString(s *Selection, qf Qualifier) string {
  	var k string
  	switch s.kind {
  	case FieldVal:
  		k = "field "
  	case MethodVal:
  		k = "method "
  	case MethodExpr:
  		k = "method expr "
  	default:
  		unreachable()
  	}
  	var buf bytes.Buffer
  	buf.WriteString(k)
  	buf.WriteByte('(')
  	WriteType(&buf, s.Recv(), qf)
  	fmt.Fprintf(&buf, ") %s", s.obj.Name())
  	if T := s.Type(); s.kind == FieldVal {
  		buf.WriteByte(' ')
  		WriteType(&buf, T, qf)
  	} else {
  		WriteSignature(&buf, T.(*Signature), qf)
  	}
  	return buf.String()
  }
  

View as plain text