Source file src/cmd/compile/internal/ir/node.go

     1  // Copyright 2009 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  // “Abstract” syntax representation.
     6  
     7  package ir
     8  
     9  import (
    10  	"fmt"
    11  	"go/constant"
    12  	"sort"
    13  
    14  	"cmd/compile/internal/base"
    15  	"cmd/compile/internal/types"
    16  	"cmd/internal/src"
    17  )
    18  
    19  // A Node is the abstract interface to an IR node.
    20  type Node interface {
    21  	// Formatting
    22  	Format(s fmt.State, verb rune)
    23  
    24  	// Source position.
    25  	Pos() src.XPos
    26  	SetPos(x src.XPos)
    27  
    28  	// For making copies. For Copy and SepCopy.
    29  	copy() Node
    30  
    31  	doChildren(func(Node) bool) bool
    32  	editChildren(func(Node) Node)
    33  
    34  	// Abstract graph structure, for generic traversals.
    35  	Op() Op
    36  	Init() Nodes
    37  
    38  	// Fields specific to certain Ops only.
    39  	Type() *types.Type
    40  	SetType(t *types.Type)
    41  	Name() *Name
    42  	Sym() *types.Sym
    43  	Val() constant.Value
    44  	SetVal(v constant.Value)
    45  
    46  	// Storage for analysis passes.
    47  	Esc() uint16
    48  	SetEsc(x uint16)
    49  	Diag() bool
    50  	SetDiag(x bool)
    51  
    52  	// Typecheck values:
    53  	//  0 means the node is not typechecked
    54  	//  1 means the node is completely typechecked
    55  	//  2 means typechecking of the node is in progress
    56  	//  3 means the node has its type from types2, but may need transformation
    57  	Typecheck() uint8
    58  	SetTypecheck(x uint8)
    59  	NonNil() bool
    60  	MarkNonNil()
    61  }
    62  
    63  // Line returns n's position as a string. If n has been inlined,
    64  // it uses the outermost position where n has been inlined.
    65  func Line(n Node) string {
    66  	return base.FmtPos(n.Pos())
    67  }
    68  
    69  func IsSynthetic(n Node) bool {
    70  	name := n.Sym().Name
    71  	return name[0] == '.' || name[0] == '~'
    72  }
    73  
    74  // IsAutoTmp indicates if n was created by the compiler as a temporary,
    75  // based on the setting of the .AutoTemp flag in n's Name.
    76  func IsAutoTmp(n Node) bool {
    77  	if n == nil || n.Op() != ONAME {
    78  		return false
    79  	}
    80  	return n.Name().AutoTemp()
    81  }
    82  
    83  // MayBeShared reports whether n may occur in multiple places in the AST.
    84  // Extra care must be taken when mutating such a node.
    85  func MayBeShared(n Node) bool {
    86  	switch n.Op() {
    87  	case ONAME, OLITERAL, ONIL, OTYPE:
    88  		return true
    89  	}
    90  	return false
    91  }
    92  
    93  type InitNode interface {
    94  	Node
    95  	PtrInit() *Nodes
    96  	SetInit(x Nodes)
    97  }
    98  
    99  func TakeInit(n Node) Nodes {
   100  	init := n.Init()
   101  	if len(init) != 0 {
   102  		n.(InitNode).SetInit(nil)
   103  	}
   104  	return init
   105  }
   106  
   107  //go:generate stringer -type=Op -trimprefix=O node.go
   108  
   109  type Op uint8
   110  
   111  // Node ops.
   112  const (
   113  	OXXX Op = iota
   114  
   115  	// names
   116  	ONAME // var or func name
   117  	// Unnamed arg or return value: f(int, string) (int, error) { etc }
   118  	// Also used for a qualified package identifier that hasn't been resolved yet.
   119  	ONONAME
   120  	OTYPE    // type name
   121  	OPACK    // import
   122  	OLITERAL // literal
   123  	ONIL     // nil
   124  
   125  	// expressions
   126  	OADD          // X + Y
   127  	OSUB          // X - Y
   128  	OOR           // X | Y
   129  	OXOR          // X ^ Y
   130  	OADDSTR       // +{List} (string addition, list elements are strings)
   131  	OADDR         // &X
   132  	OANDAND       // X && Y
   133  	OAPPEND       // append(Args); after walk, X may contain elem type descriptor
   134  	OBYTES2STR    // Type(X) (Type is string, X is a []byte)
   135  	OBYTES2STRTMP // Type(X) (Type is string, X is a []byte, ephemeral)
   136  	ORUNES2STR    // Type(X) (Type is string, X is a []rune)
   137  	OSTR2BYTES    // Type(X) (Type is []byte, X is a string)
   138  	OSTR2BYTESTMP // Type(X) (Type is []byte, X is a string, ephemeral)
   139  	OSTR2RUNES    // Type(X) (Type is []rune, X is a string)
   140  	OSLICE2ARRPTR // Type(X) (Type is *[N]T, X is a []T)
   141  	// X = Y or (if Def=true) X := Y
   142  	// If Def, then Init includes a DCL node for X.
   143  	OAS
   144  	// Lhs = Rhs (x, y, z = a, b, c) or (if Def=true) Lhs := Rhs
   145  	// If Def, then Init includes DCL nodes for Lhs
   146  	OAS2
   147  	OAS2DOTTYPE // Lhs = Rhs (x, ok = I.(int))
   148  	OAS2FUNC    // Lhs = Rhs (x, y = f())
   149  	OAS2MAPR    // Lhs = Rhs (x, ok = m["foo"])
   150  	OAS2RECV    // Lhs = Rhs (x, ok = <-c)
   151  	OASOP       // X AsOp= Y (x += y)
   152  	OCALL       // X(Args) (function call, method call or type conversion)
   153  
   154  	// OCALLFUNC, OCALLMETH, and OCALLINTER have the same structure.
   155  	// Prior to walk, they are: X(Args), where Args is all regular arguments.
   156  	// After walk, if any argument whose evaluation might requires temporary variable,
   157  	// that temporary variable will be pushed to Init, Args will contains an updated
   158  	// set of arguments. KeepAlive is all OVARLIVE nodes that are attached to OCALLxxx.
   159  	OCALLFUNC  // X(Args) (function call f(args))
   160  	OCALLMETH  // X(Args) (direct method call x.Method(args))
   161  	OCALLINTER // X(Args) (interface method call x.Method(args))
   162  	OCAP       // cap(X)
   163  	OCLOSE     // close(X)
   164  	OCLOSURE   // func Type { Func.Closure.Body } (func literal)
   165  	OCOMPLIT   // Type{List} (composite literal, not yet lowered to specific form)
   166  	OMAPLIT    // Type{List} (composite literal, Type is map)
   167  	OSTRUCTLIT // Type{List} (composite literal, Type is struct)
   168  	OARRAYLIT  // Type{List} (composite literal, Type is array)
   169  	OSLICELIT  // Type{List} (composite literal, Type is slice), Len is slice length.
   170  	OPTRLIT    // &X (X is composite literal)
   171  	OCONV      // Type(X) (type conversion)
   172  	OCONVIFACE // Type(X) (type conversion, to interface)
   173  	OCONVIDATA // Builds a data word to store X in an interface. Equivalent to IDATA(CONVIFACE(X)). Is an ir.ConvExpr.
   174  	OCONVNOP   // Type(X) (type conversion, no effect)
   175  	OCOPY      // copy(X, Y)
   176  	ODCL       // var X (declares X of type X.Type)
   177  
   178  	// Used during parsing but don't last.
   179  	ODCLFUNC  // func f() or func (r) f()
   180  	ODCLCONST // const pi = 3.14
   181  	ODCLTYPE  // type Int int or type Int = int
   182  
   183  	ODELETE        // delete(Args)
   184  	ODOT           // X.Sel (X is of struct type)
   185  	ODOTPTR        // X.Sel (X is of pointer to struct type)
   186  	ODOTMETH       // X.Sel (X is non-interface, Sel is method name)
   187  	ODOTINTER      // X.Sel (X is interface, Sel is method name)
   188  	OXDOT          // X.Sel (before rewrite to one of the preceding)
   189  	ODOTTYPE       // X.Ntype or X.Type (.Ntype during parsing, .Type once resolved); after walk, Itab contains address of interface type descriptor and Itab.X contains address of concrete type descriptor
   190  	ODOTTYPE2      // X.Ntype or X.Type (.Ntype during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, Itab contains address of interface type descriptor
   191  	OEQ            // X == Y
   192  	ONE            // X != Y
   193  	OLT            // X < Y
   194  	OLE            // X <= Y
   195  	OGE            // X >= Y
   196  	OGT            // X > Y
   197  	ODEREF         // *X
   198  	OINDEX         // X[Index] (index of array or slice)
   199  	OINDEXMAP      // X[Index] (index of map)
   200  	OKEY           // Key:Value (key:value in struct/array/map literal)
   201  	OSTRUCTKEY     // Field:Value (key:value in struct literal, after type checking)
   202  	OLEN           // len(X)
   203  	OMAKE          // make(Args) (before type checking converts to one of the following)
   204  	OMAKECHAN      // make(Type[, Len]) (type is chan)
   205  	OMAKEMAP       // make(Type[, Len]) (type is map)
   206  	OMAKESLICE     // make(Type[, Len[, Cap]]) (type is slice)
   207  	OMAKESLICECOPY // makeslicecopy(Type, Len, Cap) (type is slice; Len is length and Cap is the copied from slice)
   208  	// OMAKESLICECOPY is created by the order pass and corresponds to:
   209  	//  s = make(Type, Len); copy(s, Cap)
   210  	//
   211  	// Bounded can be set on the node when Len == len(Cap) is known at compile time.
   212  	//
   213  	// This node is created so the walk pass can optimize this pattern which would
   214  	// otherwise be hard to detect after the order pass.
   215  	OMUL         // X * Y
   216  	ODIV         // X / Y
   217  	OMOD         // X % Y
   218  	OLSH         // X << Y
   219  	ORSH         // X >> Y
   220  	OAND         // X & Y
   221  	OANDNOT      // X &^ Y
   222  	ONEW         // new(X); corresponds to calls to new in source code
   223  	ONOT         // !X
   224  	OBITNOT      // ^X
   225  	OPLUS        // +X
   226  	ONEG         // -X
   227  	OOROR        // X || Y
   228  	OPANIC       // panic(X)
   229  	OPRINT       // print(List)
   230  	OPRINTN      // println(List)
   231  	OPAREN       // (X)
   232  	OSEND        // Chan <- Value
   233  	OSLICE       // X[Low : High] (X is untypechecked or slice)
   234  	OSLICEARR    // X[Low : High] (X is pointer to array)
   235  	OSLICESTR    // X[Low : High] (X is string)
   236  	OSLICE3      // X[Low : High : Max] (X is untypedchecked or slice)
   237  	OSLICE3ARR   // X[Low : High : Max] (X is pointer to array)
   238  	OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
   239  	ORECOVER     // recover()
   240  	ORECOVERFP   // recover(Args) w/ explicit FP argument
   241  	ORECV        // <-X
   242  	ORUNESTR     // Type(X) (Type is string, X is rune)
   243  	OSELRECV2    // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE)
   244  	OIOTA        // iota
   245  	OREAL        // real(X)
   246  	OIMAG        // imag(X)
   247  	OCOMPLEX     // complex(X, Y)
   248  	OALIGNOF     // unsafe.Alignof(X)
   249  	OOFFSETOF    // unsafe.Offsetof(X)
   250  	OSIZEOF      // unsafe.Sizeof(X)
   251  	OUNSAFEADD   // unsafe.Add(X, Y)
   252  	OUNSAFESLICE // unsafe.Slice(X, Y)
   253  	OMETHEXPR    // X(Args) (method expression T.Method(args), first argument is the method receiver)
   254  	OMETHVALUE   // X.Sel   (method expression t.Method, not called)
   255  
   256  	// statements
   257  	OBLOCK // { List } (block of code)
   258  	OBREAK // break [Label]
   259  	// OCASE:  case List: Body (List==nil means default)
   260  	//   For OTYPESW, List is a OTYPE node for the specified type (or OLITERAL
   261  	//   for nil) or an ODYNAMICTYPE indicating a runtime type for generics.
   262  	//   If a type-switch variable is specified, Var is an
   263  	//   ONAME for the version of the type-switch variable with the specified
   264  	//   type.
   265  	OCASE
   266  	OCONTINUE // continue [Label]
   267  	ODEFER    // defer Call
   268  	OFALL     // fallthrough
   269  	OFOR      // for Init; Cond; Post { Body }
   270  	// OFORUNTIL is like OFOR, but the test (Cond) is applied after the body:
   271  	// 	Init
   272  	// 	top: { Body }   // Execute the body at least once
   273  	// 	cont: Post
   274  	// 	if Cond {        // And then test the loop condition
   275  	// 		List     // Before looping to top, execute List
   276  	// 		goto top
   277  	// 	}
   278  	// OFORUNTIL is created by walk. There's no way to write this in Go code.
   279  	OFORUNTIL
   280  	OGOTO   // goto Label
   281  	OIF     // if Init; Cond { Then } else { Else }
   282  	OLABEL  // Label:
   283  	OGO     // go Call
   284  	ORANGE  // for Key, Value = range X { Body }
   285  	ORETURN // return Results
   286  	OSELECT // select { Cases }
   287  	OSWITCH // switch Init; Expr { Cases }
   288  	// OTYPESW:  X := Y.(type) (appears as .Tag of OSWITCH)
   289  	//   X is nil if there is no type-switch variable
   290  	OTYPESW
   291  	OFUNCINST // instantiation of a generic function
   292  
   293  	// types
   294  	OTCHAN   // chan int
   295  	OTMAP    // map[string]int
   296  	OTSTRUCT // struct{}
   297  	OTINTER  // interface{}
   298  	// OTFUNC: func() - Recv is receiver field, Params is list of param fields, Results is
   299  	// list of result fields.
   300  	OTFUNC
   301  	OTARRAY // [8]int or [...]int
   302  	OTSLICE // []int
   303  
   304  	// misc
   305  	// intermediate representation of an inlined call.  Uses Init (assignments
   306  	// for the captured variables, parameters, retvars, & INLMARK op),
   307  	// Body (body of the inlined function), and ReturnVars (list of
   308  	// return values)
   309  	OINLCALL       // intermediary representation of an inlined call.
   310  	OEFACE         // itable and data words of an empty-interface value.
   311  	OITAB          // itable word of an interface value.
   312  	OIDATA         // data word of an interface value in X
   313  	OSPTR          // base pointer of a slice or string.
   314  	OCFUNC         // reference to c function pointer (not go func value)
   315  	OCHECKNIL      // emit code to ensure pointer/interface not nil
   316  	OVARDEF        // variable is about to be fully initialized
   317  	OVARKILL       // variable is dead
   318  	OVARLIVE       // variable is alive
   319  	ORESULT        // result of a function call; Xoffset is stack offset
   320  	OINLMARK       // start of an inlined body, with file/line of caller. Xoffset is an index into the inline tree.
   321  	OLINKSYMOFFSET // offset within a name
   322  
   323  	// opcodes for generics
   324  	ODYNAMICDOTTYPE  // x = i.(T) where T is a type parameter (or derived from a type parameter)
   325  	ODYNAMICDOTTYPE2 // x, ok = i.(T) where T is a type parameter (or derived from a type parameter)
   326  	ODYNAMICTYPE     // a type node for type switches (represents a dynamic target type for a type switch)
   327  
   328  	// arch-specific opcodes
   329  	OTAILCALL    // tail call to another function
   330  	OGETG        // runtime.getg() (read g pointer)
   331  	OGETCALLERPC // runtime.getcallerpc() (continuation PC in caller frame)
   332  	OGETCALLERSP // runtime.getcallersp() (stack pointer in caller frame)
   333  
   334  	OEND
   335  )
   336  
   337  // IsCmp reports whether op is a comparison operation (==, !=, <, <=,
   338  // >, or >=).
   339  func (op Op) IsCmp() bool {
   340  	switch op {
   341  	case OEQ, ONE, OLT, OLE, OGT, OGE:
   342  		return true
   343  	}
   344  	return false
   345  }
   346  
   347  // Nodes is a pointer to a slice of *Node.
   348  // For fields that are not used in most nodes, this is used instead of
   349  // a slice to save space.
   350  type Nodes []Node
   351  
   352  // Append appends entries to Nodes.
   353  func (n *Nodes) Append(a ...Node) {
   354  	if len(a) == 0 {
   355  		return
   356  	}
   357  	*n = append(*n, a...)
   358  }
   359  
   360  // Prepend prepends entries to Nodes.
   361  // If a slice is passed in, this will take ownership of it.
   362  func (n *Nodes) Prepend(a ...Node) {
   363  	if len(a) == 0 {
   364  		return
   365  	}
   366  	*n = append(a, *n...)
   367  }
   368  
   369  // Take clears n, returning its former contents.
   370  func (n *Nodes) Take() []Node {
   371  	ret := *n
   372  	*n = nil
   373  	return ret
   374  }
   375  
   376  // Copy returns a copy of the content of the slice.
   377  func (n Nodes) Copy() Nodes {
   378  	if n == nil {
   379  		return nil
   380  	}
   381  	c := make(Nodes, len(n))
   382  	copy(c, n)
   383  	return c
   384  }
   385  
   386  // NameQueue is a FIFO queue of *Name. The zero value of NameQueue is
   387  // a ready-to-use empty queue.
   388  type NameQueue struct {
   389  	ring       []*Name
   390  	head, tail int
   391  }
   392  
   393  // Empty reports whether q contains no Names.
   394  func (q *NameQueue) Empty() bool {
   395  	return q.head == q.tail
   396  }
   397  
   398  // PushRight appends n to the right of the queue.
   399  func (q *NameQueue) PushRight(n *Name) {
   400  	if len(q.ring) == 0 {
   401  		q.ring = make([]*Name, 16)
   402  	} else if q.head+len(q.ring) == q.tail {
   403  		// Grow the ring.
   404  		nring := make([]*Name, len(q.ring)*2)
   405  		// Copy the old elements.
   406  		part := q.ring[q.head%len(q.ring):]
   407  		if q.tail-q.head <= len(part) {
   408  			part = part[:q.tail-q.head]
   409  			copy(nring, part)
   410  		} else {
   411  			pos := copy(nring, part)
   412  			copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
   413  		}
   414  		q.ring, q.head, q.tail = nring, 0, q.tail-q.head
   415  	}
   416  
   417  	q.ring[q.tail%len(q.ring)] = n
   418  	q.tail++
   419  }
   420  
   421  // PopLeft pops a Name from the left of the queue. It panics if q is
   422  // empty.
   423  func (q *NameQueue) PopLeft() *Name {
   424  	if q.Empty() {
   425  		panic("dequeue empty")
   426  	}
   427  	n := q.ring[q.head%len(q.ring)]
   428  	q.head++
   429  	return n
   430  }
   431  
   432  // NameSet is a set of Names.
   433  type NameSet map[*Name]struct{}
   434  
   435  // Has reports whether s contains n.
   436  func (s NameSet) Has(n *Name) bool {
   437  	_, isPresent := s[n]
   438  	return isPresent
   439  }
   440  
   441  // Add adds n to s.
   442  func (s *NameSet) Add(n *Name) {
   443  	if *s == nil {
   444  		*s = make(map[*Name]struct{})
   445  	}
   446  	(*s)[n] = struct{}{}
   447  }
   448  
   449  // Sorted returns s sorted according to less.
   450  func (s NameSet) Sorted(less func(*Name, *Name) bool) []*Name {
   451  	var res []*Name
   452  	for n := range s {
   453  		res = append(res, n)
   454  	}
   455  	sort.Slice(res, func(i, j int) bool { return less(res[i], res[j]) })
   456  	return res
   457  }
   458  
   459  type PragmaFlag uint16
   460  
   461  const (
   462  	// Func pragmas.
   463  	Nointerface      PragmaFlag = 1 << iota
   464  	Noescape                    // func parameters don't escape
   465  	Norace                      // func must not have race detector annotations
   466  	Nosplit                     // func should not execute on separate stack
   467  	Noinline                    // func should not be inlined
   468  	NoCheckPtr                  // func should not be instrumented by checkptr
   469  	CgoUnsafeArgs               // treat a pointer to one arg as a pointer to them all
   470  	UintptrKeepAlive            // pointers converted to uintptr must be kept alive (compiler internal only)
   471  	UintptrEscapes              // pointers converted to uintptr escape
   472  
   473  	// Runtime-only func pragmas.
   474  	// See ../../../../runtime/HACKING.md for detailed descriptions.
   475  	Systemstack        // func must run on system stack
   476  	Nowritebarrier     // emit compiler error instead of write barrier
   477  	Nowritebarrierrec  // error on write barrier in this or recursive callees
   478  	Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
   479  
   480  	// Runtime and cgo type pragmas
   481  	NotInHeap // values of this type must not be heap allocated
   482  
   483  	// Go command pragmas
   484  	GoBuildPragma
   485  
   486  	RegisterParams // TODO(register args) remove after register abi is working
   487  
   488  )
   489  
   490  func AsNode(n types.Object) Node {
   491  	if n == nil {
   492  		return nil
   493  	}
   494  	return n.(Node)
   495  }
   496  
   497  var BlankNode Node
   498  
   499  func IsConst(n Node, ct constant.Kind) bool {
   500  	return ConstType(n) == ct
   501  }
   502  
   503  // IsNil reports whether n represents the universal untyped zero value "nil".
   504  func IsNil(n Node) bool {
   505  	// Check n.Orig because constant propagation may produce typed nil constants,
   506  	// which don't exist in the Go spec.
   507  	return n != nil && Orig(n).Op() == ONIL
   508  }
   509  
   510  func IsBlank(n Node) bool {
   511  	if n == nil {
   512  		return false
   513  	}
   514  	return n.Sym().IsBlank()
   515  }
   516  
   517  // IsMethod reports whether n is a method.
   518  // n must be a function or a method.
   519  func IsMethod(n Node) bool {
   520  	return n.Type().Recv() != nil
   521  }
   522  
   523  func HasNamedResults(fn *Func) bool {
   524  	typ := fn.Type()
   525  	return typ.NumResults() > 0 && types.OrigSym(typ.Results().Field(0).Sym) != nil
   526  }
   527  
   528  // HasUniquePos reports whether n has a unique position that can be
   529  // used for reporting error messages.
   530  //
   531  // It's primarily used to distinguish references to named objects,
   532  // whose Pos will point back to their declaration position rather than
   533  // their usage position.
   534  func HasUniquePos(n Node) bool {
   535  	switch n.Op() {
   536  	case ONAME, OPACK:
   537  		return false
   538  	case OLITERAL, ONIL, OTYPE:
   539  		if n.Sym() != nil {
   540  			return false
   541  		}
   542  	}
   543  
   544  	if !n.Pos().IsKnown() {
   545  		if base.Flag.K != 0 {
   546  			base.Warn("setlineno: unknown position (line 0)")
   547  		}
   548  		return false
   549  	}
   550  
   551  	return true
   552  }
   553  
   554  func SetPos(n Node) src.XPos {
   555  	lno := base.Pos
   556  	if n != nil && HasUniquePos(n) {
   557  		base.Pos = n.Pos()
   558  	}
   559  	return lno
   560  }
   561  
   562  // The result of InitExpr MUST be assigned back to n, e.g.
   563  // 	n.X = InitExpr(init, n.X)
   564  func InitExpr(init []Node, expr Node) Node {
   565  	if len(init) == 0 {
   566  		return expr
   567  	}
   568  
   569  	n, ok := expr.(InitNode)
   570  	if !ok || MayBeShared(n) {
   571  		// Introduce OCONVNOP to hold init list.
   572  		n = NewConvExpr(base.Pos, OCONVNOP, nil, expr)
   573  		n.SetType(expr.Type())
   574  		n.SetTypecheck(1)
   575  	}
   576  
   577  	n.PtrInit().Prepend(init...)
   578  	return n
   579  }
   580  
   581  // what's the outer value that a write to n affects?
   582  // outer value means containing struct or array.
   583  func OuterValue(n Node) Node {
   584  	for {
   585  		switch nn := n; nn.Op() {
   586  		case OXDOT:
   587  			base.FatalfAt(n.Pos(), "OXDOT in OuterValue: %v", n)
   588  		case ODOT:
   589  			nn := nn.(*SelectorExpr)
   590  			n = nn.X
   591  			continue
   592  		case OPAREN:
   593  			nn := nn.(*ParenExpr)
   594  			n = nn.X
   595  			continue
   596  		case OCONVNOP:
   597  			nn := nn.(*ConvExpr)
   598  			n = nn.X
   599  			continue
   600  		case OINDEX:
   601  			nn := nn.(*IndexExpr)
   602  			if nn.X.Type() == nil {
   603  				base.Fatalf("OuterValue needs type for %v", nn.X)
   604  			}
   605  			if nn.X.Type().IsArray() {
   606  				n = nn.X
   607  				continue
   608  			}
   609  		}
   610  
   611  		return n
   612  	}
   613  }
   614  
   615  const (
   616  	EscUnknown = iota
   617  	EscNone    // Does not escape to heap, result, or parameters.
   618  	EscHeap    // Reachable from the heap
   619  	EscNever   // By construction will not escape.
   620  )
   621  

View as plain text