github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/pointer/reflect.go (about)

     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  // +build go1.5
     6  
     7  package pointer
     8  
     9  // This file implements the generation and resolution rules for
    10  // constraints arising from the use of reflection in the target
    11  // program.  See doc.go for explanation of the representation.
    12  //
    13  // For consistency, the names of all parameters match those of the
    14  // actual functions in the "reflect" package.
    15  //
    16  // To avoid proliferation of equivalent labels, intrinsics should
    17  // memoize as much as possible, like TypeOf and Zero do for their
    18  // tagged objects.
    19  //
    20  // TODO(adonovan): this file is rather subtle.  Explain how we derive
    21  // the implementation of each reflect operator from its spec,
    22  // including the subtleties of reflect.flag{Addr,RO,Indir}.
    23  // [Hint: our implementation is as if reflect.flagIndir was always
    24  // true, i.e. reflect.Values are pointers to tagged objects, there is
    25  // no inline allocation optimization; and indirect tagged objects (not
    26  // yet implemented) correspond to reflect.Values with
    27  // reflect.flagAddr.]
    28  // A picture would help too.
    29  //
    30  // TODO(adonovan): try factoring up the common parts of the majority of
    31  // these constraints that are single input, single output.
    32  
    33  import (
    34  	"fmt"
    35  	exact "go/constant"
    36  	"go/types"
    37  	"reflect"
    38  
    39  	"golang.org/x/tools/go/ssa"
    40  )
    41  
    42  func init() {
    43  	for name, fn := range map[string]intrinsic{
    44  		// reflect.Value methods.
    45  		"(reflect.Value).Addr":            ext۰reflect۰Value۰Addr,
    46  		"(reflect.Value).Bool":            ext۰NoEffect,
    47  		"(reflect.Value).Bytes":           ext۰reflect۰Value۰Bytes,
    48  		"(reflect.Value).Call":            ext۰reflect۰Value۰Call,
    49  		"(reflect.Value).CallSlice":       ext۰reflect۰Value۰CallSlice,
    50  		"(reflect.Value).CanAddr":         ext۰NoEffect,
    51  		"(reflect.Value).CanInterface":    ext۰NoEffect,
    52  		"(reflect.Value).CanSet":          ext۰NoEffect,
    53  		"(reflect.Value).Cap":             ext۰NoEffect,
    54  		"(reflect.Value).Close":           ext۰NoEffect,
    55  		"(reflect.Value).Complex":         ext۰NoEffect,
    56  		"(reflect.Value).Convert":         ext۰reflect۰Value۰Convert,
    57  		"(reflect.Value).Elem":            ext۰reflect۰Value۰Elem,
    58  		"(reflect.Value).Field":           ext۰reflect۰Value۰Field,
    59  		"(reflect.Value).FieldByIndex":    ext۰reflect۰Value۰FieldByIndex,
    60  		"(reflect.Value).FieldByName":     ext۰reflect۰Value۰FieldByName,
    61  		"(reflect.Value).FieldByNameFunc": ext۰reflect۰Value۰FieldByNameFunc,
    62  		"(reflect.Value).Float":           ext۰NoEffect,
    63  		"(reflect.Value).Index":           ext۰reflect۰Value۰Index,
    64  		"(reflect.Value).Int":             ext۰NoEffect,
    65  		"(reflect.Value).Interface":       ext۰reflect۰Value۰Interface,
    66  		"(reflect.Value).InterfaceData":   ext۰NoEffect,
    67  		"(reflect.Value).IsNil":           ext۰NoEffect,
    68  		"(reflect.Value).IsValid":         ext۰NoEffect,
    69  		"(reflect.Value).Kind":            ext۰NoEffect,
    70  		"(reflect.Value).Len":             ext۰NoEffect,
    71  		"(reflect.Value).MapIndex":        ext۰reflect۰Value۰MapIndex,
    72  		"(reflect.Value).MapKeys":         ext۰reflect۰Value۰MapKeys,
    73  		"(reflect.Value).Method":          ext۰reflect۰Value۰Method,
    74  		"(reflect.Value).MethodByName":    ext۰reflect۰Value۰MethodByName,
    75  		"(reflect.Value).NumField":        ext۰NoEffect,
    76  		"(reflect.Value).NumMethod":       ext۰NoEffect,
    77  		"(reflect.Value).OverflowComplex": ext۰NoEffect,
    78  		"(reflect.Value).OverflowFloat":   ext۰NoEffect,
    79  		"(reflect.Value).OverflowInt":     ext۰NoEffect,
    80  		"(reflect.Value).OverflowUint":    ext۰NoEffect,
    81  		"(reflect.Value).Pointer":         ext۰NoEffect,
    82  		"(reflect.Value).Recv":            ext۰reflect۰Value۰Recv,
    83  		"(reflect.Value).Send":            ext۰reflect۰Value۰Send,
    84  		"(reflect.Value).Set":             ext۰reflect۰Value۰Set,
    85  		"(reflect.Value).SetBool":         ext۰NoEffect,
    86  		"(reflect.Value).SetBytes":        ext۰reflect۰Value۰SetBytes,
    87  		"(reflect.Value).SetComplex":      ext۰NoEffect,
    88  		"(reflect.Value).SetFloat":        ext۰NoEffect,
    89  		"(reflect.Value).SetInt":          ext۰NoEffect,
    90  		"(reflect.Value).SetLen":          ext۰NoEffect,
    91  		"(reflect.Value).SetMapIndex":     ext۰reflect۰Value۰SetMapIndex,
    92  		"(reflect.Value).SetPointer":      ext۰reflect۰Value۰SetPointer,
    93  		"(reflect.Value).SetString":       ext۰NoEffect,
    94  		"(reflect.Value).SetUint":         ext۰NoEffect,
    95  		"(reflect.Value).Slice":           ext۰reflect۰Value۰Slice,
    96  		"(reflect.Value).String":          ext۰NoEffect,
    97  		"(reflect.Value).TryRecv":         ext۰reflect۰Value۰Recv,
    98  		"(reflect.Value).TrySend":         ext۰reflect۰Value۰Send,
    99  		"(reflect.Value).Type":            ext۰NoEffect,
   100  		"(reflect.Value).Uint":            ext۰NoEffect,
   101  		"(reflect.Value).UnsafeAddr":      ext۰NoEffect,
   102  
   103  		// Standalone reflect.* functions.
   104  		"reflect.Append":      ext۰reflect۰Append,
   105  		"reflect.AppendSlice": ext۰reflect۰AppendSlice,
   106  		"reflect.Copy":        ext۰reflect۰Copy,
   107  		"reflect.ChanOf":      ext۰reflect۰ChanOf,
   108  		"reflect.DeepEqual":   ext۰NoEffect,
   109  		"reflect.Indirect":    ext۰reflect۰Indirect,
   110  		"reflect.MakeChan":    ext۰reflect۰MakeChan,
   111  		"reflect.MakeFunc":    ext۰reflect۰MakeFunc,
   112  		"reflect.MakeMap":     ext۰reflect۰MakeMap,
   113  		"reflect.MakeSlice":   ext۰reflect۰MakeSlice,
   114  		"reflect.MapOf":       ext۰reflect۰MapOf,
   115  		"reflect.New":         ext۰reflect۰New,
   116  		"reflect.NewAt":       ext۰reflect۰NewAt,
   117  		"reflect.PtrTo":       ext۰reflect۰PtrTo,
   118  		"reflect.Select":      ext۰reflect۰Select,
   119  		"reflect.SliceOf":     ext۰reflect۰SliceOf,
   120  		"reflect.TypeOf":      ext۰reflect۰TypeOf,
   121  		"reflect.ValueOf":     ext۰reflect۰ValueOf,
   122  		"reflect.Zero":        ext۰reflect۰Zero,
   123  		"reflect.init":        ext۰NoEffect,
   124  
   125  		// *reflect.rtype methods
   126  		"(*reflect.rtype).Align":           ext۰NoEffect,
   127  		"(*reflect.rtype).AssignableTo":    ext۰NoEffect,
   128  		"(*reflect.rtype).Bits":            ext۰NoEffect,
   129  		"(*reflect.rtype).ChanDir":         ext۰NoEffect,
   130  		"(*reflect.rtype).ConvertibleTo":   ext۰NoEffect,
   131  		"(*reflect.rtype).Elem":            ext۰reflect۰rtype۰Elem,
   132  		"(*reflect.rtype).Field":           ext۰reflect۰rtype۰Field,
   133  		"(*reflect.rtype).FieldAlign":      ext۰NoEffect,
   134  		"(*reflect.rtype).FieldByIndex":    ext۰reflect۰rtype۰FieldByIndex,
   135  		"(*reflect.rtype).FieldByName":     ext۰reflect۰rtype۰FieldByName,
   136  		"(*reflect.rtype).FieldByNameFunc": ext۰reflect۰rtype۰FieldByNameFunc,
   137  		"(*reflect.rtype).Implements":      ext۰NoEffect,
   138  		"(*reflect.rtype).In":              ext۰reflect۰rtype۰In,
   139  		"(*reflect.rtype).IsVariadic":      ext۰NoEffect,
   140  		"(*reflect.rtype).Key":             ext۰reflect۰rtype۰Key,
   141  		"(*reflect.rtype).Kind":            ext۰NoEffect,
   142  		"(*reflect.rtype).Len":             ext۰NoEffect,
   143  		"(*reflect.rtype).Method":          ext۰reflect۰rtype۰Method,
   144  		"(*reflect.rtype).MethodByName":    ext۰reflect۰rtype۰MethodByName,
   145  		"(*reflect.rtype).Name":            ext۰NoEffect,
   146  		"(*reflect.rtype).NumField":        ext۰NoEffect,
   147  		"(*reflect.rtype).NumIn":           ext۰NoEffect,
   148  		"(*reflect.rtype).NumMethod":       ext۰NoEffect,
   149  		"(*reflect.rtype).NumOut":          ext۰NoEffect,
   150  		"(*reflect.rtype).Out":             ext۰reflect۰rtype۰Out,
   151  		"(*reflect.rtype).PkgPath":         ext۰NoEffect,
   152  		"(*reflect.rtype).Size":            ext۰NoEffect,
   153  		"(*reflect.rtype).String":          ext۰NoEffect,
   154  	} {
   155  		intrinsicsByName[name] = fn
   156  	}
   157  }
   158  
   159  // -------------------- (reflect.Value) --------------------
   160  
   161  func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   162  
   163  // ---------- func (Value).Bytes() Value ----------
   164  
   165  // result = v.Bytes()
   166  type rVBytesConstraint struct {
   167  	v      nodeid // (ptr)
   168  	result nodeid // (indirect)
   169  }
   170  
   171  func (c *rVBytesConstraint) ptr() nodeid { return c.v }
   172  func (c *rVBytesConstraint) presolve(h *hvn) {
   173  	h.markIndirect(onodeid(c.result), "rVBytes.result")
   174  }
   175  func (c *rVBytesConstraint) renumber(mapping []nodeid) {
   176  	c.v = mapping[c.v]
   177  	c.result = mapping[c.result]
   178  }
   179  
   180  func (c *rVBytesConstraint) String() string {
   181  	return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v)
   182  }
   183  
   184  func (c *rVBytesConstraint) solve(a *analysis, delta *nodeset) {
   185  	changed := false
   186  	for _, x := range delta.AppendTo(a.deltaSpace) {
   187  		vObj := nodeid(x)
   188  		tDyn, slice, indirect := a.taggedValue(vObj)
   189  		if indirect {
   190  			// TODO(adonovan): we'll need to implement this
   191  			// when we start creating indirect tagged objects.
   192  			panic("indirect tagged object")
   193  		}
   194  
   195  		tSlice, ok := tDyn.Underlying().(*types.Slice)
   196  		if ok && types.Identical(tSlice.Elem(), types.Typ[types.Uint8]) {
   197  			if a.onlineCopy(c.result, slice) {
   198  				changed = true
   199  			}
   200  		}
   201  	}
   202  	if changed {
   203  		a.addWork(c.result)
   204  	}
   205  }
   206  
   207  func ext۰reflect۰Value۰Bytes(a *analysis, cgn *cgnode) {
   208  	a.addConstraint(&rVBytesConstraint{
   209  		v:      a.funcParams(cgn.obj),
   210  		result: a.funcResults(cgn.obj),
   211  	})
   212  }
   213  
   214  // ---------- func (Value).Call(in []Value) []Value ----------
   215  
   216  // result = v.Call(in)
   217  type rVCallConstraint struct {
   218  	cgn       *cgnode
   219  	targets   nodeid // (indirect)
   220  	v         nodeid // (ptr)
   221  	arg       nodeid // = in[*]
   222  	result    nodeid // (indirect)
   223  	dotdotdot bool   // interpret last arg as a "..." slice
   224  }
   225  
   226  func (c *rVCallConstraint) ptr() nodeid { return c.v }
   227  func (c *rVCallConstraint) presolve(h *hvn) {
   228  	h.markIndirect(onodeid(c.targets), "rVCall.targets")
   229  	h.markIndirect(onodeid(c.result), "rVCall.result")
   230  }
   231  func (c *rVCallConstraint) renumber(mapping []nodeid) {
   232  	c.targets = mapping[c.targets]
   233  	c.v = mapping[c.v]
   234  	c.arg = mapping[c.arg]
   235  	c.result = mapping[c.result]
   236  }
   237  
   238  func (c *rVCallConstraint) String() string {
   239  	return fmt.Sprintf("n%d = reflect n%d.Call(n%d)", c.result, c.v, c.arg)
   240  }
   241  
   242  func (c *rVCallConstraint) solve(a *analysis, delta *nodeset) {
   243  	if c.targets == 0 {
   244  		panic("no targets")
   245  	}
   246  
   247  	changed := false
   248  	for _, x := range delta.AppendTo(a.deltaSpace) {
   249  		vObj := nodeid(x)
   250  		tDyn, fn, indirect := a.taggedValue(vObj)
   251  		if indirect {
   252  			// TODO(adonovan): we'll need to implement this
   253  			// when we start creating indirect tagged objects.
   254  			panic("indirect tagged object")
   255  		}
   256  
   257  		tSig, ok := tDyn.Underlying().(*types.Signature)
   258  		if !ok {
   259  			continue // not a function
   260  		}
   261  		if tSig.Recv() != nil {
   262  			panic(tSig) // TODO(adonovan): rethink when we implement Method()
   263  		}
   264  
   265  		// Add dynamic call target.
   266  		if a.onlineCopy(c.targets, fn) {
   267  			a.addWork(c.targets)
   268  			// TODO(adonovan): is 'else continue' a sound optimisation here?
   269  		}
   270  
   271  		// Allocate a P/R block.
   272  		tParams := tSig.Params()
   273  		tResults := tSig.Results()
   274  		params := a.addNodes(tParams, "rVCall.params")
   275  		results := a.addNodes(tResults, "rVCall.results")
   276  
   277  		// Make a dynamic call to 'fn'.
   278  		a.store(fn, params, 1, a.sizeof(tParams))
   279  		a.load(results, fn, 1+a.sizeof(tParams), a.sizeof(tResults))
   280  
   281  		// Populate P by type-asserting each actual arg (all merged in c.arg).
   282  		for i, n := 0, tParams.Len(); i < n; i++ {
   283  			T := tParams.At(i).Type()
   284  			a.typeAssert(T, params, c.arg, false)
   285  			params += nodeid(a.sizeof(T))
   286  		}
   287  
   288  		// Use R by tagging and copying each actual result to c.result.
   289  		for i, n := 0, tResults.Len(); i < n; i++ {
   290  			T := tResults.At(i).Type()
   291  			// Convert from an arbitrary type to a reflect.Value
   292  			// (like MakeInterface followed by reflect.ValueOf).
   293  			if isInterface(T) {
   294  				// (don't tag)
   295  				if a.onlineCopy(c.result, results) {
   296  					changed = true
   297  				}
   298  			} else {
   299  				obj := a.makeTagged(T, c.cgn, nil)
   300  				a.onlineCopyN(obj+1, results, a.sizeof(T))
   301  				if a.addLabel(c.result, obj) { // (true)
   302  					changed = true
   303  				}
   304  			}
   305  			results += nodeid(a.sizeof(T))
   306  		}
   307  	}
   308  	if changed {
   309  		a.addWork(c.result)
   310  	}
   311  }
   312  
   313  // Common code for direct (inlined) and indirect calls to (reflect.Value).Call.
   314  func reflectCallImpl(a *analysis, cgn *cgnode, site *callsite, recv, arg nodeid, dotdotdot bool) nodeid {
   315  	// Allocate []reflect.Value array for the result.
   316  	ret := a.nextNode()
   317  	a.addNodes(types.NewArray(a.reflectValueObj.Type(), 1), "rVCall.ret")
   318  	a.endObject(ret, cgn, nil)
   319  
   320  	// pts(targets) will be the set of possible call targets.
   321  	site.targets = a.addOneNode(tInvalid, "rvCall.targets", nil)
   322  
   323  	// All arguments are merged since they arrive in a slice.
   324  	argelts := a.addOneNode(a.reflectValueObj.Type(), "rVCall.args", nil)
   325  	a.load(argelts, arg, 1, 1) // slice elements
   326  
   327  	a.addConstraint(&rVCallConstraint{
   328  		cgn:       cgn,
   329  		targets:   site.targets,
   330  		v:         recv,
   331  		arg:       argelts,
   332  		result:    ret + 1, // results go into elements of ret
   333  		dotdotdot: dotdotdot,
   334  	})
   335  	return ret
   336  }
   337  
   338  func reflectCall(a *analysis, cgn *cgnode, dotdotdot bool) {
   339  	// This is the shared contour implementation of (reflect.Value).Call
   340  	// and CallSlice, as used by indirect calls (rare).
   341  	// Direct calls are inlined in gen.go, eliding the
   342  	// intermediate cgnode for Call.
   343  	site := new(callsite)
   344  	cgn.sites = append(cgn.sites, site)
   345  	recv := a.funcParams(cgn.obj)
   346  	arg := recv + 1
   347  	ret := reflectCallImpl(a, cgn, site, recv, arg, dotdotdot)
   348  	a.addressOf(cgn.fn.Signature.Results().At(0).Type(), a.funcResults(cgn.obj), ret)
   349  }
   350  
   351  func ext۰reflect۰Value۰Call(a *analysis, cgn *cgnode) {
   352  	reflectCall(a, cgn, false)
   353  }
   354  
   355  func ext۰reflect۰Value۰CallSlice(a *analysis, cgn *cgnode) {
   356  	// TODO(adonovan): implement.  Also, inline direct calls in gen.go too.
   357  	if false {
   358  		reflectCall(a, cgn, true)
   359  	}
   360  }
   361  
   362  func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   363  
   364  // ---------- func (Value).Elem() Value ----------
   365  
   366  // result = v.Elem()
   367  type rVElemConstraint struct {
   368  	cgn    *cgnode
   369  	v      nodeid // (ptr)
   370  	result nodeid // (indirect)
   371  }
   372  
   373  func (c *rVElemConstraint) ptr() nodeid { return c.v }
   374  func (c *rVElemConstraint) presolve(h *hvn) {
   375  	h.markIndirect(onodeid(c.result), "rVElem.result")
   376  }
   377  func (c *rVElemConstraint) renumber(mapping []nodeid) {
   378  	c.v = mapping[c.v]
   379  	c.result = mapping[c.result]
   380  }
   381  
   382  func (c *rVElemConstraint) String() string {
   383  	return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v)
   384  }
   385  
   386  func (c *rVElemConstraint) solve(a *analysis, delta *nodeset) {
   387  	changed := false
   388  	for _, x := range delta.AppendTo(a.deltaSpace) {
   389  		vObj := nodeid(x)
   390  		tDyn, payload, indirect := a.taggedValue(vObj)
   391  		if indirect {
   392  			// TODO(adonovan): we'll need to implement this
   393  			// when we start creating indirect tagged objects.
   394  			panic("indirect tagged object")
   395  		}
   396  
   397  		switch t := tDyn.Underlying().(type) {
   398  		case *types.Interface:
   399  			if a.onlineCopy(c.result, payload) {
   400  				changed = true
   401  			}
   402  
   403  		case *types.Pointer:
   404  			obj := a.makeTagged(t.Elem(), c.cgn, nil)
   405  			a.load(obj+1, payload, 0, a.sizeof(t.Elem()))
   406  			if a.addLabel(c.result, obj) {
   407  				changed = true
   408  			}
   409  		}
   410  	}
   411  	if changed {
   412  		a.addWork(c.result)
   413  	}
   414  }
   415  
   416  func ext۰reflect۰Value۰Elem(a *analysis, cgn *cgnode) {
   417  	a.addConstraint(&rVElemConstraint{
   418  		cgn:    cgn,
   419  		v:      a.funcParams(cgn.obj),
   420  		result: a.funcResults(cgn.obj),
   421  	})
   422  }
   423  
   424  func ext۰reflect۰Value۰Field(a *analysis, cgn *cgnode)           {} // TODO(adonovan)
   425  func ext۰reflect۰Value۰FieldByIndex(a *analysis, cgn *cgnode)    {} // TODO(adonovan)
   426  func ext۰reflect۰Value۰FieldByName(a *analysis, cgn *cgnode)     {} // TODO(adonovan)
   427  func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   428  
   429  // ---------- func (Value).Index() Value ----------
   430  
   431  // result = v.Index()
   432  type rVIndexConstraint struct {
   433  	cgn    *cgnode
   434  	v      nodeid // (ptr)
   435  	result nodeid // (indirect)
   436  }
   437  
   438  func (c *rVIndexConstraint) ptr() nodeid { return c.v }
   439  func (c *rVIndexConstraint) presolve(h *hvn) {
   440  	h.markIndirect(onodeid(c.result), "rVIndex.result")
   441  }
   442  func (c *rVIndexConstraint) renumber(mapping []nodeid) {
   443  	c.v = mapping[c.v]
   444  	c.result = mapping[c.result]
   445  }
   446  
   447  func (c *rVIndexConstraint) String() string {
   448  	return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v)
   449  }
   450  
   451  func (c *rVIndexConstraint) solve(a *analysis, delta *nodeset) {
   452  	changed := false
   453  	for _, x := range delta.AppendTo(a.deltaSpace) {
   454  		vObj := nodeid(x)
   455  		tDyn, payload, indirect := a.taggedValue(vObj)
   456  		if indirect {
   457  			// TODO(adonovan): we'll need to implement this
   458  			// when we start creating indirect tagged objects.
   459  			panic("indirect tagged object")
   460  		}
   461  
   462  		var res nodeid
   463  		switch t := tDyn.Underlying().(type) {
   464  		case *types.Array:
   465  			res = a.makeTagged(t.Elem(), c.cgn, nil)
   466  			a.onlineCopyN(res+1, payload+1, a.sizeof(t.Elem()))
   467  
   468  		case *types.Slice:
   469  			res = a.makeTagged(t.Elem(), c.cgn, nil)
   470  			a.load(res+1, payload, 1, a.sizeof(t.Elem()))
   471  
   472  		case *types.Basic:
   473  			if t.Kind() == types.String {
   474  				res = a.makeTagged(types.Typ[types.Rune], c.cgn, nil)
   475  			}
   476  		}
   477  		if res != 0 && a.addLabel(c.result, res) {
   478  			changed = true
   479  		}
   480  	}
   481  	if changed {
   482  		a.addWork(c.result)
   483  	}
   484  }
   485  
   486  func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) {
   487  	a.addConstraint(&rVIndexConstraint{
   488  		cgn:    cgn,
   489  		v:      a.funcParams(cgn.obj),
   490  		result: a.funcResults(cgn.obj),
   491  	})
   492  }
   493  
   494  // ---------- func (Value).Interface() Value ----------
   495  
   496  // result = v.Interface()
   497  type rVInterfaceConstraint struct {
   498  	v      nodeid // (ptr)
   499  	result nodeid // (indirect)
   500  }
   501  
   502  func (c *rVInterfaceConstraint) ptr() nodeid { return c.v }
   503  func (c *rVInterfaceConstraint) presolve(h *hvn) {
   504  	h.markIndirect(onodeid(c.result), "rVInterface.result")
   505  }
   506  func (c *rVInterfaceConstraint) renumber(mapping []nodeid) {
   507  	c.v = mapping[c.v]
   508  	c.result = mapping[c.result]
   509  }
   510  
   511  func (c *rVInterfaceConstraint) String() string {
   512  	return fmt.Sprintf("n%d = reflect n%d.Interface()", c.result, c.v)
   513  }
   514  
   515  func (c *rVInterfaceConstraint) solve(a *analysis, delta *nodeset) {
   516  	changed := false
   517  	for _, x := range delta.AppendTo(a.deltaSpace) {
   518  		vObj := nodeid(x)
   519  		tDyn, payload, indirect := a.taggedValue(vObj)
   520  		if indirect {
   521  			// TODO(adonovan): we'll need to implement this
   522  			// when we start creating indirect tagged objects.
   523  			panic("indirect tagged object")
   524  		}
   525  
   526  		if isInterface(tDyn) {
   527  			if a.onlineCopy(c.result, payload) {
   528  				a.addWork(c.result)
   529  			}
   530  		} else {
   531  			if a.addLabel(c.result, vObj) {
   532  				changed = true
   533  			}
   534  		}
   535  	}
   536  	if changed {
   537  		a.addWork(c.result)
   538  	}
   539  }
   540  
   541  func ext۰reflect۰Value۰Interface(a *analysis, cgn *cgnode) {
   542  	a.addConstraint(&rVInterfaceConstraint{
   543  		v:      a.funcParams(cgn.obj),
   544  		result: a.funcResults(cgn.obj),
   545  	})
   546  }
   547  
   548  // ---------- func (Value).MapIndex(Value) Value ----------
   549  
   550  // result = v.MapIndex(_)
   551  type rVMapIndexConstraint struct {
   552  	cgn    *cgnode
   553  	v      nodeid // (ptr)
   554  	result nodeid // (indirect)
   555  }
   556  
   557  func (c *rVMapIndexConstraint) ptr() nodeid { return c.v }
   558  func (c *rVMapIndexConstraint) presolve(h *hvn) {
   559  	h.markIndirect(onodeid(c.result), "rVMapIndex.result")
   560  }
   561  func (c *rVMapIndexConstraint) renumber(mapping []nodeid) {
   562  	c.v = mapping[c.v]
   563  	c.result = mapping[c.result]
   564  }
   565  
   566  func (c *rVMapIndexConstraint) String() string {
   567  	return fmt.Sprintf("n%d = reflect n%d.MapIndex(_)", c.result, c.v)
   568  }
   569  
   570  func (c *rVMapIndexConstraint) solve(a *analysis, delta *nodeset) {
   571  	changed := false
   572  	for _, x := range delta.AppendTo(a.deltaSpace) {
   573  		vObj := nodeid(x)
   574  		tDyn, m, indirect := a.taggedValue(vObj)
   575  		tMap, _ := tDyn.Underlying().(*types.Map)
   576  		if tMap == nil {
   577  			continue // not a map
   578  		}
   579  		if indirect {
   580  			// TODO(adonovan): we'll need to implement this
   581  			// when we start creating indirect tagged objects.
   582  			panic("indirect tagged object")
   583  		}
   584  
   585  		obj := a.makeTagged(tMap.Elem(), c.cgn, nil)
   586  		a.load(obj+1, m, a.sizeof(tMap.Key()), a.sizeof(tMap.Elem()))
   587  		if a.addLabel(c.result, obj) {
   588  			changed = true
   589  		}
   590  	}
   591  	if changed {
   592  		a.addWork(c.result)
   593  	}
   594  }
   595  
   596  func ext۰reflect۰Value۰MapIndex(a *analysis, cgn *cgnode) {
   597  	a.addConstraint(&rVMapIndexConstraint{
   598  		cgn:    cgn,
   599  		v:      a.funcParams(cgn.obj),
   600  		result: a.funcResults(cgn.obj),
   601  	})
   602  }
   603  
   604  // ---------- func (Value).MapKeys() []Value ----------
   605  
   606  // result = v.MapKeys()
   607  type rVMapKeysConstraint struct {
   608  	cgn    *cgnode
   609  	v      nodeid // (ptr)
   610  	result nodeid // (indirect)
   611  }
   612  
   613  func (c *rVMapKeysConstraint) ptr() nodeid { return c.v }
   614  func (c *rVMapKeysConstraint) presolve(h *hvn) {
   615  	h.markIndirect(onodeid(c.result), "rVMapKeys.result")
   616  }
   617  func (c *rVMapKeysConstraint) renumber(mapping []nodeid) {
   618  	c.v = mapping[c.v]
   619  	c.result = mapping[c.result]
   620  }
   621  
   622  func (c *rVMapKeysConstraint) String() string {
   623  	return fmt.Sprintf("n%d = reflect n%d.MapKeys()", c.result, c.v)
   624  }
   625  
   626  func (c *rVMapKeysConstraint) solve(a *analysis, delta *nodeset) {
   627  	changed := false
   628  	for _, x := range delta.AppendTo(a.deltaSpace) {
   629  		vObj := nodeid(x)
   630  		tDyn, m, indirect := a.taggedValue(vObj)
   631  		tMap, _ := tDyn.Underlying().(*types.Map)
   632  		if tMap == nil {
   633  			continue // not a map
   634  		}
   635  		if indirect {
   636  			// TODO(adonovan): we'll need to implement this
   637  			// when we start creating indirect tagged objects.
   638  			panic("indirect tagged object")
   639  		}
   640  
   641  		kObj := a.makeTagged(tMap.Key(), c.cgn, nil)
   642  		a.load(kObj+1, m, 0, a.sizeof(tMap.Key()))
   643  		if a.addLabel(c.result, kObj) {
   644  			changed = true
   645  		}
   646  	}
   647  	if changed {
   648  		a.addWork(c.result)
   649  	}
   650  }
   651  
   652  func ext۰reflect۰Value۰MapKeys(a *analysis, cgn *cgnode) {
   653  	// Allocate an array for the result.
   654  	obj := a.nextNode()
   655  	T := types.NewSlice(a.reflectValueObj.Type())
   656  	a.addNodes(sliceToArray(T), "reflect.MapKeys result")
   657  	a.endObject(obj, cgn, nil)
   658  	a.addressOf(T, a.funcResults(cgn.obj), obj)
   659  
   660  	a.addConstraint(&rVMapKeysConstraint{
   661  		cgn:    cgn,
   662  		v:      a.funcParams(cgn.obj),
   663  		result: obj + 1, // result is stored in array elems
   664  	})
   665  }
   666  
   667  func ext۰reflect۰Value۰Method(a *analysis, cgn *cgnode)       {} // TODO(adonovan)
   668  func ext۰reflect۰Value۰MethodByName(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   669  
   670  // ---------- func (Value).Recv(Value) Value ----------
   671  
   672  // result, _ = v.Recv()
   673  type rVRecvConstraint struct {
   674  	cgn    *cgnode
   675  	v      nodeid // (ptr)
   676  	result nodeid // (indirect)
   677  }
   678  
   679  func (c *rVRecvConstraint) ptr() nodeid { return c.v }
   680  func (c *rVRecvConstraint) presolve(h *hvn) {
   681  	h.markIndirect(onodeid(c.result), "rVRecv.result")
   682  }
   683  func (c *rVRecvConstraint) renumber(mapping []nodeid) {
   684  	c.v = mapping[c.v]
   685  	c.result = mapping[c.result]
   686  }
   687  
   688  func (c *rVRecvConstraint) String() string {
   689  	return fmt.Sprintf("n%d = reflect n%d.Recv()", c.result, c.v)
   690  }
   691  
   692  func (c *rVRecvConstraint) solve(a *analysis, delta *nodeset) {
   693  	changed := false
   694  	for _, x := range delta.AppendTo(a.deltaSpace) {
   695  		vObj := nodeid(x)
   696  		tDyn, ch, indirect := a.taggedValue(vObj)
   697  		tChan, _ := tDyn.Underlying().(*types.Chan)
   698  		if tChan == nil {
   699  			continue // not a channel
   700  		}
   701  		if indirect {
   702  			// TODO(adonovan): we'll need to implement this
   703  			// when we start creating indirect tagged objects.
   704  			panic("indirect tagged object")
   705  		}
   706  
   707  		tElem := tChan.Elem()
   708  		elemObj := a.makeTagged(tElem, c.cgn, nil)
   709  		a.load(elemObj+1, ch, 0, a.sizeof(tElem))
   710  		if a.addLabel(c.result, elemObj) {
   711  			changed = true
   712  		}
   713  	}
   714  	if changed {
   715  		a.addWork(c.result)
   716  	}
   717  }
   718  
   719  func ext۰reflect۰Value۰Recv(a *analysis, cgn *cgnode) {
   720  	a.addConstraint(&rVRecvConstraint{
   721  		cgn:    cgn,
   722  		v:      a.funcParams(cgn.obj),
   723  		result: a.funcResults(cgn.obj),
   724  	})
   725  }
   726  
   727  // ---------- func (Value).Send(Value) ----------
   728  
   729  // v.Send(x)
   730  type rVSendConstraint struct {
   731  	cgn *cgnode
   732  	v   nodeid // (ptr)
   733  	x   nodeid
   734  }
   735  
   736  func (c *rVSendConstraint) ptr() nodeid   { return c.v }
   737  func (c *rVSendConstraint) presolve(*hvn) {}
   738  func (c *rVSendConstraint) renumber(mapping []nodeid) {
   739  	c.v = mapping[c.v]
   740  	c.x = mapping[c.x]
   741  }
   742  
   743  func (c *rVSendConstraint) String() string {
   744  	return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
   745  }
   746  
   747  func (c *rVSendConstraint) solve(a *analysis, delta *nodeset) {
   748  	for _, x := range delta.AppendTo(a.deltaSpace) {
   749  		vObj := nodeid(x)
   750  		tDyn, ch, indirect := a.taggedValue(vObj)
   751  		tChan, _ := tDyn.Underlying().(*types.Chan)
   752  		if tChan == nil {
   753  			continue // not a channel
   754  		}
   755  		if indirect {
   756  			// TODO(adonovan): we'll need to implement this
   757  			// when we start creating indirect tagged objects.
   758  			panic("indirect tagged object")
   759  		}
   760  
   761  		// Extract x's payload to xtmp, then store to channel.
   762  		tElem := tChan.Elem()
   763  		xtmp := a.addNodes(tElem, "Send.xtmp")
   764  		a.typeAssert(tElem, xtmp, c.x, false)
   765  		a.store(ch, xtmp, 0, a.sizeof(tElem))
   766  	}
   767  }
   768  
   769  func ext۰reflect۰Value۰Send(a *analysis, cgn *cgnode) {
   770  	params := a.funcParams(cgn.obj)
   771  	a.addConstraint(&rVSendConstraint{
   772  		cgn: cgn,
   773  		v:   params,
   774  		x:   params + 1,
   775  	})
   776  }
   777  
   778  func ext۰reflect۰Value۰Set(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   779  
   780  // ---------- func (Value).SetBytes(x []byte) ----------
   781  
   782  // v.SetBytes(x)
   783  type rVSetBytesConstraint struct {
   784  	cgn *cgnode
   785  	v   nodeid // (ptr)
   786  	x   nodeid
   787  }
   788  
   789  func (c *rVSetBytesConstraint) ptr() nodeid   { return c.v }
   790  func (c *rVSetBytesConstraint) presolve(*hvn) {}
   791  func (c *rVSetBytesConstraint) renumber(mapping []nodeid) {
   792  	c.v = mapping[c.v]
   793  	c.x = mapping[c.x]
   794  }
   795  
   796  func (c *rVSetBytesConstraint) String() string {
   797  	return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
   798  }
   799  
   800  func (c *rVSetBytesConstraint) solve(a *analysis, delta *nodeset) {
   801  	for _, x := range delta.AppendTo(a.deltaSpace) {
   802  		vObj := nodeid(x)
   803  		tDyn, slice, indirect := a.taggedValue(vObj)
   804  		if indirect {
   805  			// TODO(adonovan): we'll need to implement this
   806  			// when we start creating indirect tagged objects.
   807  			panic("indirect tagged object")
   808  		}
   809  
   810  		tSlice, ok := tDyn.Underlying().(*types.Slice)
   811  		if ok && types.Identical(tSlice.Elem(), types.Typ[types.Uint8]) {
   812  			if a.onlineCopy(slice, c.x) {
   813  				a.addWork(slice)
   814  			}
   815  		}
   816  	}
   817  }
   818  
   819  func ext۰reflect۰Value۰SetBytes(a *analysis, cgn *cgnode) {
   820  	params := a.funcParams(cgn.obj)
   821  	a.addConstraint(&rVSetBytesConstraint{
   822  		cgn: cgn,
   823  		v:   params,
   824  		x:   params + 1,
   825  	})
   826  }
   827  
   828  // ---------- func (Value).SetMapIndex(k Value, v Value) ----------
   829  
   830  // v.SetMapIndex(key, val)
   831  type rVSetMapIndexConstraint struct {
   832  	cgn *cgnode
   833  	v   nodeid // (ptr)
   834  	key nodeid
   835  	val nodeid
   836  }
   837  
   838  func (c *rVSetMapIndexConstraint) ptr() nodeid   { return c.v }
   839  func (c *rVSetMapIndexConstraint) presolve(*hvn) {}
   840  func (c *rVSetMapIndexConstraint) renumber(mapping []nodeid) {
   841  	c.v = mapping[c.v]
   842  	c.key = mapping[c.key]
   843  	c.val = mapping[c.val]
   844  }
   845  
   846  func (c *rVSetMapIndexConstraint) String() string {
   847  	return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val)
   848  }
   849  
   850  func (c *rVSetMapIndexConstraint) solve(a *analysis, delta *nodeset) {
   851  	for _, x := range delta.AppendTo(a.deltaSpace) {
   852  		vObj := nodeid(x)
   853  		tDyn, m, indirect := a.taggedValue(vObj)
   854  		tMap, _ := tDyn.Underlying().(*types.Map)
   855  		if tMap == nil {
   856  			continue // not a map
   857  		}
   858  		if indirect {
   859  			// TODO(adonovan): we'll need to implement this
   860  			// when we start creating indirect tagged objects.
   861  			panic("indirect tagged object")
   862  		}
   863  
   864  		keysize := a.sizeof(tMap.Key())
   865  
   866  		// Extract key's payload to keytmp, then store to map key.
   867  		keytmp := a.addNodes(tMap.Key(), "SetMapIndex.keytmp")
   868  		a.typeAssert(tMap.Key(), keytmp, c.key, false)
   869  		a.store(m, keytmp, 0, keysize)
   870  
   871  		// Extract val's payload to vtmp, then store to map value.
   872  		valtmp := a.addNodes(tMap.Elem(), "SetMapIndex.valtmp")
   873  		a.typeAssert(tMap.Elem(), valtmp, c.val, false)
   874  		a.store(m, valtmp, keysize, a.sizeof(tMap.Elem()))
   875  	}
   876  }
   877  
   878  func ext۰reflect۰Value۰SetMapIndex(a *analysis, cgn *cgnode) {
   879  	params := a.funcParams(cgn.obj)
   880  	a.addConstraint(&rVSetMapIndexConstraint{
   881  		cgn: cgn,
   882  		v:   params,
   883  		key: params + 1,
   884  		val: params + 2,
   885  	})
   886  }
   887  
   888  func ext۰reflect۰Value۰SetPointer(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   889  
   890  // ---------- func (Value).Slice(v Value, i, j int) Value ----------
   891  
   892  // result = v.Slice(_, _)
   893  type rVSliceConstraint struct {
   894  	cgn    *cgnode
   895  	v      nodeid // (ptr)
   896  	result nodeid // (indirect)
   897  }
   898  
   899  func (c *rVSliceConstraint) ptr() nodeid { return c.v }
   900  func (c *rVSliceConstraint) presolve(h *hvn) {
   901  	h.markIndirect(onodeid(c.result), "rVSlice.result")
   902  }
   903  func (c *rVSliceConstraint) renumber(mapping []nodeid) {
   904  	c.v = mapping[c.v]
   905  	c.result = mapping[c.result]
   906  }
   907  
   908  func (c *rVSliceConstraint) String() string {
   909  	return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v)
   910  }
   911  
   912  func (c *rVSliceConstraint) solve(a *analysis, delta *nodeset) {
   913  	changed := false
   914  	for _, x := range delta.AppendTo(a.deltaSpace) {
   915  		vObj := nodeid(x)
   916  		tDyn, payload, indirect := a.taggedValue(vObj)
   917  		if indirect {
   918  			// TODO(adonovan): we'll need to implement this
   919  			// when we start creating indirect tagged objects.
   920  			panic("indirect tagged object")
   921  		}
   922  
   923  		var res nodeid
   924  		switch t := tDyn.Underlying().(type) {
   925  		case *types.Pointer:
   926  			if tArr, ok := t.Elem().Underlying().(*types.Array); ok {
   927  				// pointer to array
   928  				res = a.makeTagged(types.NewSlice(tArr.Elem()), c.cgn, nil)
   929  				if a.onlineCopy(res+1, payload) {
   930  					a.addWork(res + 1)
   931  				}
   932  			}
   933  
   934  		case *types.Array:
   935  			// TODO(adonovan): implement addressable
   936  			// arrays when we do indirect tagged objects.
   937  
   938  		case *types.Slice:
   939  			res = vObj
   940  
   941  		case *types.Basic:
   942  			if t == types.Typ[types.String] {
   943  				res = vObj
   944  			}
   945  		}
   946  
   947  		if res != 0 && a.addLabel(c.result, res) {
   948  			changed = true
   949  		}
   950  	}
   951  	if changed {
   952  		a.addWork(c.result)
   953  	}
   954  }
   955  
   956  func ext۰reflect۰Value۰Slice(a *analysis, cgn *cgnode) {
   957  	a.addConstraint(&rVSliceConstraint{
   958  		cgn:    cgn,
   959  		v:      a.funcParams(cgn.obj),
   960  		result: a.funcResults(cgn.obj),
   961  	})
   962  }
   963  
   964  // -------------------- Standalone reflect functions --------------------
   965  
   966  func ext۰reflect۰Append(a *analysis, cgn *cgnode)      {} // TODO(adonovan)
   967  func ext۰reflect۰AppendSlice(a *analysis, cgn *cgnode) {} // TODO(adonovan)
   968  func ext۰reflect۰Copy(a *analysis, cgn *cgnode)        {} // TODO(adonovan)
   969  
   970  // ---------- func ChanOf(ChanDir, Type) Type ----------
   971  
   972  // result = ChanOf(dir, t)
   973  type reflectChanOfConstraint struct {
   974  	cgn    *cgnode
   975  	t      nodeid // (ptr)
   976  	result nodeid // (indirect)
   977  	dirs   []types.ChanDir
   978  }
   979  
   980  func (c *reflectChanOfConstraint) ptr() nodeid { return c.t }
   981  func (c *reflectChanOfConstraint) presolve(h *hvn) {
   982  	h.markIndirect(onodeid(c.result), "reflectChanOf.result")
   983  }
   984  func (c *reflectChanOfConstraint) renumber(mapping []nodeid) {
   985  	c.t = mapping[c.t]
   986  	c.result = mapping[c.result]
   987  }
   988  
   989  func (c *reflectChanOfConstraint) String() string {
   990  	return fmt.Sprintf("n%d = reflect.ChanOf(n%d)", c.result, c.t)
   991  }
   992  
   993  func (c *reflectChanOfConstraint) solve(a *analysis, delta *nodeset) {
   994  	changed := false
   995  	for _, x := range delta.AppendTo(a.deltaSpace) {
   996  		tObj := nodeid(x)
   997  		T := a.rtypeTaggedValue(tObj)
   998  
   999  		if typeTooHigh(T) {
  1000  			continue
  1001  		}
  1002  
  1003  		for _, dir := range c.dirs {
  1004  			if a.addLabel(c.result, a.makeRtype(types.NewChan(dir, T))) {
  1005  				changed = true
  1006  			}
  1007  		}
  1008  	}
  1009  	if changed {
  1010  		a.addWork(c.result)
  1011  	}
  1012  }
  1013  
  1014  // dirMap maps reflect.ChanDir to the set of channel types generated by ChanOf.
  1015  var dirMap = [...][]types.ChanDir{
  1016  	0:               {types.SendOnly, types.RecvOnly, types.SendRecv}, // unknown
  1017  	reflect.RecvDir: {types.RecvOnly},
  1018  	reflect.SendDir: {types.SendOnly},
  1019  	reflect.BothDir: {types.SendRecv},
  1020  }
  1021  
  1022  func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) {
  1023  	// If we have access to the callsite,
  1024  	// and the channel argument is a constant (as is usual),
  1025  	// only generate the requested direction.
  1026  	var dir reflect.ChanDir // unknown
  1027  	if site := cgn.callersite; site != nil {
  1028  		if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
  1029  			v, _ := exact.Int64Val(c.Value)
  1030  			if 0 <= v && v <= int64(reflect.BothDir) {
  1031  				dir = reflect.ChanDir(v)
  1032  			}
  1033  		}
  1034  	}
  1035  
  1036  	params := a.funcParams(cgn.obj)
  1037  	a.addConstraint(&reflectChanOfConstraint{
  1038  		cgn:    cgn,
  1039  		t:      params + 1,
  1040  		result: a.funcResults(cgn.obj),
  1041  		dirs:   dirMap[dir],
  1042  	})
  1043  }
  1044  
  1045  // ---------- func Indirect(v Value) Value ----------
  1046  
  1047  // result = Indirect(v)
  1048  type reflectIndirectConstraint struct {
  1049  	cgn    *cgnode
  1050  	v      nodeid // (ptr)
  1051  	result nodeid // (indirect)
  1052  }
  1053  
  1054  func (c *reflectIndirectConstraint) ptr() nodeid { return c.v }
  1055  func (c *reflectIndirectConstraint) presolve(h *hvn) {
  1056  	h.markIndirect(onodeid(c.result), "reflectIndirect.result")
  1057  }
  1058  func (c *reflectIndirectConstraint) renumber(mapping []nodeid) {
  1059  	c.v = mapping[c.v]
  1060  	c.result = mapping[c.result]
  1061  }
  1062  
  1063  func (c *reflectIndirectConstraint) String() string {
  1064  	return fmt.Sprintf("n%d = reflect.Indirect(n%d)", c.result, c.v)
  1065  }
  1066  
  1067  func (c *reflectIndirectConstraint) solve(a *analysis, delta *nodeset) {
  1068  	changed := false
  1069  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1070  		vObj := nodeid(x)
  1071  		tDyn, _, _ := a.taggedValue(vObj)
  1072  		var res nodeid
  1073  		if tPtr, ok := tDyn.Underlying().(*types.Pointer); ok {
  1074  			// load the payload of the pointer's tagged object
  1075  			// into a new tagged object
  1076  			res = a.makeTagged(tPtr.Elem(), c.cgn, nil)
  1077  			a.load(res+1, vObj+1, 0, a.sizeof(tPtr.Elem()))
  1078  		} else {
  1079  			res = vObj
  1080  		}
  1081  
  1082  		if a.addLabel(c.result, res) {
  1083  			changed = true
  1084  		}
  1085  	}
  1086  	if changed {
  1087  		a.addWork(c.result)
  1088  	}
  1089  }
  1090  
  1091  func ext۰reflect۰Indirect(a *analysis, cgn *cgnode) {
  1092  	a.addConstraint(&reflectIndirectConstraint{
  1093  		cgn:    cgn,
  1094  		v:      a.funcParams(cgn.obj),
  1095  		result: a.funcResults(cgn.obj),
  1096  	})
  1097  }
  1098  
  1099  // ---------- func MakeChan(Type) Value ----------
  1100  
  1101  // result = MakeChan(typ)
  1102  type reflectMakeChanConstraint struct {
  1103  	cgn    *cgnode
  1104  	typ    nodeid // (ptr)
  1105  	result nodeid // (indirect)
  1106  }
  1107  
  1108  func (c *reflectMakeChanConstraint) ptr() nodeid { return c.typ }
  1109  func (c *reflectMakeChanConstraint) presolve(h *hvn) {
  1110  	h.markIndirect(onodeid(c.result), "reflectMakeChan.result")
  1111  }
  1112  func (c *reflectMakeChanConstraint) renumber(mapping []nodeid) {
  1113  	c.typ = mapping[c.typ]
  1114  	c.result = mapping[c.result]
  1115  }
  1116  
  1117  func (c *reflectMakeChanConstraint) String() string {
  1118  	return fmt.Sprintf("n%d = reflect.MakeChan(n%d)", c.result, c.typ)
  1119  }
  1120  
  1121  func (c *reflectMakeChanConstraint) solve(a *analysis, delta *nodeset) {
  1122  	changed := false
  1123  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1124  		typObj := nodeid(x)
  1125  		T := a.rtypeTaggedValue(typObj)
  1126  		tChan, ok := T.Underlying().(*types.Chan)
  1127  		if !ok || tChan.Dir() != types.SendRecv {
  1128  			continue // not a bidirectional channel type
  1129  		}
  1130  
  1131  		obj := a.nextNode()
  1132  		a.addNodes(tChan.Elem(), "reflect.MakeChan.value")
  1133  		a.endObject(obj, c.cgn, nil)
  1134  
  1135  		// put its address in a new T-tagged object
  1136  		id := a.makeTagged(T, c.cgn, nil)
  1137  		a.addLabel(id+1, obj)
  1138  
  1139  		// flow the T-tagged object to the result
  1140  		if a.addLabel(c.result, id) {
  1141  			changed = true
  1142  		}
  1143  	}
  1144  	if changed {
  1145  		a.addWork(c.result)
  1146  	}
  1147  }
  1148  
  1149  func ext۰reflect۰MakeChan(a *analysis, cgn *cgnode) {
  1150  	a.addConstraint(&reflectMakeChanConstraint{
  1151  		cgn:    cgn,
  1152  		typ:    a.funcParams(cgn.obj),
  1153  		result: a.funcResults(cgn.obj),
  1154  	})
  1155  }
  1156  
  1157  func ext۰reflect۰MakeFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
  1158  
  1159  // ---------- func MakeMap(Type) Value ----------
  1160  
  1161  // result = MakeMap(typ)
  1162  type reflectMakeMapConstraint struct {
  1163  	cgn    *cgnode
  1164  	typ    nodeid // (ptr)
  1165  	result nodeid // (indirect)
  1166  }
  1167  
  1168  func (c *reflectMakeMapConstraint) ptr() nodeid { return c.typ }
  1169  func (c *reflectMakeMapConstraint) presolve(h *hvn) {
  1170  	h.markIndirect(onodeid(c.result), "reflectMakeMap.result")
  1171  }
  1172  func (c *reflectMakeMapConstraint) renumber(mapping []nodeid) {
  1173  	c.typ = mapping[c.typ]
  1174  	c.result = mapping[c.result]
  1175  }
  1176  
  1177  func (c *reflectMakeMapConstraint) String() string {
  1178  	return fmt.Sprintf("n%d = reflect.MakeMap(n%d)", c.result, c.typ)
  1179  }
  1180  
  1181  func (c *reflectMakeMapConstraint) solve(a *analysis, delta *nodeset) {
  1182  	changed := false
  1183  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1184  		typObj := nodeid(x)
  1185  		T := a.rtypeTaggedValue(typObj)
  1186  		tMap, ok := T.Underlying().(*types.Map)
  1187  		if !ok {
  1188  			continue // not a map type
  1189  		}
  1190  
  1191  		mapObj := a.nextNode()
  1192  		a.addNodes(tMap.Key(), "reflect.MakeMap.key")
  1193  		a.addNodes(tMap.Elem(), "reflect.MakeMap.value")
  1194  		a.endObject(mapObj, c.cgn, nil)
  1195  
  1196  		// put its address in a new T-tagged object
  1197  		id := a.makeTagged(T, c.cgn, nil)
  1198  		a.addLabel(id+1, mapObj)
  1199  
  1200  		// flow the T-tagged object to the result
  1201  		if a.addLabel(c.result, id) {
  1202  			changed = true
  1203  		}
  1204  	}
  1205  	if changed {
  1206  		a.addWork(c.result)
  1207  	}
  1208  }
  1209  
  1210  func ext۰reflect۰MakeMap(a *analysis, cgn *cgnode) {
  1211  	a.addConstraint(&reflectMakeMapConstraint{
  1212  		cgn:    cgn,
  1213  		typ:    a.funcParams(cgn.obj),
  1214  		result: a.funcResults(cgn.obj),
  1215  	})
  1216  }
  1217  
  1218  // ---------- func MakeSlice(Type) Value ----------
  1219  
  1220  // result = MakeSlice(typ)
  1221  type reflectMakeSliceConstraint struct {
  1222  	cgn    *cgnode
  1223  	typ    nodeid // (ptr)
  1224  	result nodeid // (indirect)
  1225  }
  1226  
  1227  func (c *reflectMakeSliceConstraint) ptr() nodeid { return c.typ }
  1228  func (c *reflectMakeSliceConstraint) presolve(h *hvn) {
  1229  	h.markIndirect(onodeid(c.result), "reflectMakeSlice.result")
  1230  }
  1231  func (c *reflectMakeSliceConstraint) renumber(mapping []nodeid) {
  1232  	c.typ = mapping[c.typ]
  1233  	c.result = mapping[c.result]
  1234  }
  1235  
  1236  func (c *reflectMakeSliceConstraint) String() string {
  1237  	return fmt.Sprintf("n%d = reflect.MakeSlice(n%d)", c.result, c.typ)
  1238  }
  1239  
  1240  func (c *reflectMakeSliceConstraint) solve(a *analysis, delta *nodeset) {
  1241  	changed := false
  1242  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1243  		typObj := nodeid(x)
  1244  		T := a.rtypeTaggedValue(typObj)
  1245  		if _, ok := T.Underlying().(*types.Slice); !ok {
  1246  			continue // not a slice type
  1247  		}
  1248  
  1249  		obj := a.nextNode()
  1250  		a.addNodes(sliceToArray(T), "reflect.MakeSlice")
  1251  		a.endObject(obj, c.cgn, nil)
  1252  
  1253  		// put its address in a new T-tagged object
  1254  		id := a.makeTagged(T, c.cgn, nil)
  1255  		a.addLabel(id+1, obj)
  1256  
  1257  		// flow the T-tagged object to the result
  1258  		if a.addLabel(c.result, id) {
  1259  			changed = true
  1260  		}
  1261  	}
  1262  	if changed {
  1263  		a.addWork(c.result)
  1264  	}
  1265  }
  1266  
  1267  func ext۰reflect۰MakeSlice(a *analysis, cgn *cgnode) {
  1268  	a.addConstraint(&reflectMakeSliceConstraint{
  1269  		cgn:    cgn,
  1270  		typ:    a.funcParams(cgn.obj),
  1271  		result: a.funcResults(cgn.obj),
  1272  	})
  1273  }
  1274  
  1275  func ext۰reflect۰MapOf(a *analysis, cgn *cgnode) {} // TODO(adonovan)
  1276  
  1277  // ---------- func New(Type) Value ----------
  1278  
  1279  // result = New(typ)
  1280  type reflectNewConstraint struct {
  1281  	cgn    *cgnode
  1282  	typ    nodeid // (ptr)
  1283  	result nodeid // (indirect)
  1284  }
  1285  
  1286  func (c *reflectNewConstraint) ptr() nodeid { return c.typ }
  1287  func (c *reflectNewConstraint) presolve(h *hvn) {
  1288  	h.markIndirect(onodeid(c.result), "reflectNew.result")
  1289  }
  1290  func (c *reflectNewConstraint) renumber(mapping []nodeid) {
  1291  	c.typ = mapping[c.typ]
  1292  	c.result = mapping[c.result]
  1293  }
  1294  
  1295  func (c *reflectNewConstraint) String() string {
  1296  	return fmt.Sprintf("n%d = reflect.New(n%d)", c.result, c.typ)
  1297  }
  1298  
  1299  func (c *reflectNewConstraint) solve(a *analysis, delta *nodeset) {
  1300  	changed := false
  1301  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1302  		typObj := nodeid(x)
  1303  		T := a.rtypeTaggedValue(typObj)
  1304  
  1305  		// allocate new T object
  1306  		newObj := a.nextNode()
  1307  		a.addNodes(T, "reflect.New")
  1308  		a.endObject(newObj, c.cgn, nil)
  1309  
  1310  		// put its address in a new *T-tagged object
  1311  		id := a.makeTagged(types.NewPointer(T), c.cgn, nil)
  1312  		a.addLabel(id+1, newObj)
  1313  
  1314  		// flow the pointer to the result
  1315  		if a.addLabel(c.result, id) {
  1316  			changed = true
  1317  		}
  1318  	}
  1319  	if changed {
  1320  		a.addWork(c.result)
  1321  	}
  1322  }
  1323  
  1324  func ext۰reflect۰New(a *analysis, cgn *cgnode) {
  1325  	a.addConstraint(&reflectNewConstraint{
  1326  		cgn:    cgn,
  1327  		typ:    a.funcParams(cgn.obj),
  1328  		result: a.funcResults(cgn.obj),
  1329  	})
  1330  }
  1331  
  1332  func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) {
  1333  	ext۰reflect۰New(a, cgn)
  1334  
  1335  	// TODO(adonovan): also report dynamic calls to unsound intrinsics.
  1336  	if site := cgn.callersite; site != nil {
  1337  		a.warnf(site.pos(), "unsound: %s contains a reflect.NewAt() call", site.instr.Parent())
  1338  	}
  1339  }
  1340  
  1341  // ---------- func PtrTo(Type) Type ----------
  1342  
  1343  // result = PtrTo(t)
  1344  type reflectPtrToConstraint struct {
  1345  	cgn    *cgnode
  1346  	t      nodeid // (ptr)
  1347  	result nodeid // (indirect)
  1348  }
  1349  
  1350  func (c *reflectPtrToConstraint) ptr() nodeid { return c.t }
  1351  func (c *reflectPtrToConstraint) presolve(h *hvn) {
  1352  	h.markIndirect(onodeid(c.result), "reflectPtrTo.result")
  1353  }
  1354  func (c *reflectPtrToConstraint) renumber(mapping []nodeid) {
  1355  	c.t = mapping[c.t]
  1356  	c.result = mapping[c.result]
  1357  }
  1358  
  1359  func (c *reflectPtrToConstraint) String() string {
  1360  	return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t)
  1361  }
  1362  
  1363  func (c *reflectPtrToConstraint) solve(a *analysis, delta *nodeset) {
  1364  	changed := false
  1365  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1366  		tObj := nodeid(x)
  1367  		T := a.rtypeTaggedValue(tObj)
  1368  
  1369  		if typeTooHigh(T) {
  1370  			continue
  1371  		}
  1372  
  1373  		if a.addLabel(c.result, a.makeRtype(types.NewPointer(T))) {
  1374  			changed = true
  1375  		}
  1376  	}
  1377  	if changed {
  1378  		a.addWork(c.result)
  1379  	}
  1380  }
  1381  
  1382  func ext۰reflect۰PtrTo(a *analysis, cgn *cgnode) {
  1383  	a.addConstraint(&reflectPtrToConstraint{
  1384  		cgn:    cgn,
  1385  		t:      a.funcParams(cgn.obj),
  1386  		result: a.funcResults(cgn.obj),
  1387  	})
  1388  }
  1389  
  1390  func ext۰reflect۰Select(a *analysis, cgn *cgnode) {} // TODO(adonovan)
  1391  
  1392  // ---------- func SliceOf(Type) Type ----------
  1393  
  1394  // result = SliceOf(t)
  1395  type reflectSliceOfConstraint struct {
  1396  	cgn    *cgnode
  1397  	t      nodeid // (ptr)
  1398  	result nodeid // (indirect)
  1399  }
  1400  
  1401  func (c *reflectSliceOfConstraint) ptr() nodeid { return c.t }
  1402  func (c *reflectSliceOfConstraint) presolve(h *hvn) {
  1403  	h.markIndirect(onodeid(c.result), "reflectSliceOf.result")
  1404  }
  1405  func (c *reflectSliceOfConstraint) renumber(mapping []nodeid) {
  1406  	c.t = mapping[c.t]
  1407  	c.result = mapping[c.result]
  1408  }
  1409  
  1410  func (c *reflectSliceOfConstraint) String() string {
  1411  	return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t)
  1412  }
  1413  
  1414  func (c *reflectSliceOfConstraint) solve(a *analysis, delta *nodeset) {
  1415  	changed := false
  1416  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1417  		tObj := nodeid(x)
  1418  		T := a.rtypeTaggedValue(tObj)
  1419  
  1420  		if typeTooHigh(T) {
  1421  			continue
  1422  		}
  1423  
  1424  		if a.addLabel(c.result, a.makeRtype(types.NewSlice(T))) {
  1425  			changed = true
  1426  		}
  1427  	}
  1428  	if changed {
  1429  		a.addWork(c.result)
  1430  	}
  1431  }
  1432  
  1433  func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) {
  1434  	a.addConstraint(&reflectSliceOfConstraint{
  1435  		cgn:    cgn,
  1436  		t:      a.funcParams(cgn.obj),
  1437  		result: a.funcResults(cgn.obj),
  1438  	})
  1439  }
  1440  
  1441  // ---------- func TypeOf(v Value) Type ----------
  1442  
  1443  // result = TypeOf(i)
  1444  type reflectTypeOfConstraint struct {
  1445  	cgn    *cgnode
  1446  	i      nodeid // (ptr)
  1447  	result nodeid // (indirect)
  1448  }
  1449  
  1450  func (c *reflectTypeOfConstraint) ptr() nodeid { return c.i }
  1451  func (c *reflectTypeOfConstraint) presolve(h *hvn) {
  1452  	h.markIndirect(onodeid(c.result), "reflectTypeOf.result")
  1453  }
  1454  func (c *reflectTypeOfConstraint) renumber(mapping []nodeid) {
  1455  	c.i = mapping[c.i]
  1456  	c.result = mapping[c.result]
  1457  }
  1458  
  1459  func (c *reflectTypeOfConstraint) String() string {
  1460  	return fmt.Sprintf("n%d = reflect.TypeOf(n%d)", c.result, c.i)
  1461  }
  1462  
  1463  func (c *reflectTypeOfConstraint) solve(a *analysis, delta *nodeset) {
  1464  	changed := false
  1465  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1466  		iObj := nodeid(x)
  1467  		tDyn, _, _ := a.taggedValue(iObj)
  1468  		if a.addLabel(c.result, a.makeRtype(tDyn)) {
  1469  			changed = true
  1470  		}
  1471  	}
  1472  	if changed {
  1473  		a.addWork(c.result)
  1474  	}
  1475  }
  1476  
  1477  func ext۰reflect۰TypeOf(a *analysis, cgn *cgnode) {
  1478  	a.addConstraint(&reflectTypeOfConstraint{
  1479  		cgn:    cgn,
  1480  		i:      a.funcParams(cgn.obj),
  1481  		result: a.funcResults(cgn.obj),
  1482  	})
  1483  }
  1484  
  1485  // ---------- func ValueOf(interface{}) Value ----------
  1486  
  1487  func ext۰reflect۰ValueOf(a *analysis, cgn *cgnode) {
  1488  	// TODO(adonovan): when we start creating indirect tagged
  1489  	// objects, we'll need to handle them specially here since
  1490  	// they must never appear in the PTS of an interface{}.
  1491  	a.copy(a.funcResults(cgn.obj), a.funcParams(cgn.obj), 1)
  1492  }
  1493  
  1494  // ---------- func Zero(Type) Value ----------
  1495  
  1496  // result = Zero(typ)
  1497  type reflectZeroConstraint struct {
  1498  	cgn    *cgnode
  1499  	typ    nodeid // (ptr)
  1500  	result nodeid // (indirect)
  1501  }
  1502  
  1503  func (c *reflectZeroConstraint) ptr() nodeid { return c.typ }
  1504  func (c *reflectZeroConstraint) presolve(h *hvn) {
  1505  	h.markIndirect(onodeid(c.result), "reflectZero.result")
  1506  }
  1507  func (c *reflectZeroConstraint) renumber(mapping []nodeid) {
  1508  	c.typ = mapping[c.typ]
  1509  	c.result = mapping[c.result]
  1510  }
  1511  
  1512  func (c *reflectZeroConstraint) String() string {
  1513  	return fmt.Sprintf("n%d = reflect.Zero(n%d)", c.result, c.typ)
  1514  }
  1515  
  1516  func (c *reflectZeroConstraint) solve(a *analysis, delta *nodeset) {
  1517  	changed := false
  1518  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1519  		typObj := nodeid(x)
  1520  		T := a.rtypeTaggedValue(typObj)
  1521  
  1522  		// TODO(adonovan): if T is an interface type, we need
  1523  		// to create an indirect tagged object containing
  1524  		// new(T).  To avoid updates of such shared values,
  1525  		// we'll need another flag on indirect tagged objects
  1526  		// that marks whether they are addressable or
  1527  		// readonly, just like the reflect package does.
  1528  
  1529  		// memoize using a.reflectZeros[T]
  1530  		var id nodeid
  1531  		if z := a.reflectZeros.At(T); false && z != nil {
  1532  			id = z.(nodeid)
  1533  		} else {
  1534  			id = a.makeTagged(T, c.cgn, nil)
  1535  			a.reflectZeros.Set(T, id)
  1536  		}
  1537  		if a.addLabel(c.result, id) {
  1538  			changed = true
  1539  		}
  1540  	}
  1541  	if changed {
  1542  		a.addWork(c.result)
  1543  	}
  1544  }
  1545  
  1546  func ext۰reflect۰Zero(a *analysis, cgn *cgnode) {
  1547  	a.addConstraint(&reflectZeroConstraint{
  1548  		cgn:    cgn,
  1549  		typ:    a.funcParams(cgn.obj),
  1550  		result: a.funcResults(cgn.obj),
  1551  	})
  1552  }
  1553  
  1554  // -------------------- (*reflect.rtype) methods --------------------
  1555  
  1556  // ---------- func (*rtype) Elem() Type ----------
  1557  
  1558  // result = Elem(t)
  1559  type rtypeElemConstraint struct {
  1560  	cgn    *cgnode
  1561  	t      nodeid // (ptr)
  1562  	result nodeid // (indirect)
  1563  }
  1564  
  1565  func (c *rtypeElemConstraint) ptr() nodeid { return c.t }
  1566  func (c *rtypeElemConstraint) presolve(h *hvn) {
  1567  	h.markIndirect(onodeid(c.result), "rtypeElem.result")
  1568  }
  1569  func (c *rtypeElemConstraint) renumber(mapping []nodeid) {
  1570  	c.t = mapping[c.t]
  1571  	c.result = mapping[c.result]
  1572  }
  1573  
  1574  func (c *rtypeElemConstraint) String() string {
  1575  	return fmt.Sprintf("n%d = (*reflect.rtype).Elem(n%d)", c.result, c.t)
  1576  }
  1577  
  1578  func (c *rtypeElemConstraint) solve(a *analysis, delta *nodeset) {
  1579  	// Implemented by *types.{Map,Chan,Array,Slice,Pointer}.
  1580  	type hasElem interface {
  1581  		Elem() types.Type
  1582  	}
  1583  	changed := false
  1584  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1585  		tObj := nodeid(x)
  1586  		T := a.nodes[tObj].obj.data.(types.Type)
  1587  		if tHasElem, ok := T.Underlying().(hasElem); ok {
  1588  			if a.addLabel(c.result, a.makeRtype(tHasElem.Elem())) {
  1589  				changed = true
  1590  			}
  1591  		}
  1592  	}
  1593  	if changed {
  1594  		a.addWork(c.result)
  1595  	}
  1596  }
  1597  
  1598  func ext۰reflect۰rtype۰Elem(a *analysis, cgn *cgnode) {
  1599  	a.addConstraint(&rtypeElemConstraint{
  1600  		cgn:    cgn,
  1601  		t:      a.funcParams(cgn.obj),
  1602  		result: a.funcResults(cgn.obj),
  1603  	})
  1604  }
  1605  
  1606  // ---------- func (*rtype) Field(int) StructField ----------
  1607  // ---------- func (*rtype) FieldByName(string) (StructField, bool) ----------
  1608  
  1609  // result = FieldByName(t, name)
  1610  // result = Field(t, _)
  1611  type rtypeFieldByNameConstraint struct {
  1612  	cgn    *cgnode
  1613  	name   string // name of field; "" for unknown
  1614  	t      nodeid // (ptr)
  1615  	result nodeid // (indirect)
  1616  }
  1617  
  1618  func (c *rtypeFieldByNameConstraint) ptr() nodeid { return c.t }
  1619  func (c *rtypeFieldByNameConstraint) presolve(h *hvn) {
  1620  	h.markIndirect(onodeid(c.result+3), "rtypeFieldByName.result.Type")
  1621  }
  1622  func (c *rtypeFieldByNameConstraint) renumber(mapping []nodeid) {
  1623  	c.t = mapping[c.t]
  1624  	c.result = mapping[c.result]
  1625  }
  1626  
  1627  func (c *rtypeFieldByNameConstraint) String() string {
  1628  	return fmt.Sprintf("n%d = (*reflect.rtype).FieldByName(n%d, %q)", c.result, c.t, c.name)
  1629  }
  1630  
  1631  func (c *rtypeFieldByNameConstraint) solve(a *analysis, delta *nodeset) {
  1632  	// type StructField struct {
  1633  	// 0	__identity__
  1634  	// 1	Name      string
  1635  	// 2	PkgPath   string
  1636  	// 3	Type      Type
  1637  	// 4	Tag       StructTag
  1638  	// 5	Offset    uintptr
  1639  	// 6	Index     []int
  1640  	// 7	Anonymous bool
  1641  	// }
  1642  
  1643  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1644  		tObj := nodeid(x)
  1645  		T := a.nodes[tObj].obj.data.(types.Type)
  1646  		tStruct, ok := T.Underlying().(*types.Struct)
  1647  		if !ok {
  1648  			continue // not a struct type
  1649  		}
  1650  
  1651  		n := tStruct.NumFields()
  1652  		for i := 0; i < n; i++ {
  1653  			f := tStruct.Field(i)
  1654  			if c.name == "" || c.name == f.Name() {
  1655  
  1656  				// a.offsetOf(Type) is 3.
  1657  				if id := c.result + 3; a.addLabel(id, a.makeRtype(f.Type())) {
  1658  					a.addWork(id)
  1659  				}
  1660  				// TODO(adonovan): StructField.Index should be non-nil.
  1661  			}
  1662  		}
  1663  	}
  1664  }
  1665  
  1666  func ext۰reflect۰rtype۰FieldByName(a *analysis, cgn *cgnode) {
  1667  	// If we have access to the callsite,
  1668  	// and the argument is a string constant,
  1669  	// return only that field.
  1670  	var name string
  1671  	if site := cgn.callersite; site != nil {
  1672  		if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
  1673  			name = exact.StringVal(c.Value)
  1674  		}
  1675  	}
  1676  
  1677  	a.addConstraint(&rtypeFieldByNameConstraint{
  1678  		cgn:    cgn,
  1679  		name:   name,
  1680  		t:      a.funcParams(cgn.obj),
  1681  		result: a.funcResults(cgn.obj),
  1682  	})
  1683  }
  1684  
  1685  func ext۰reflect۰rtype۰Field(a *analysis, cgn *cgnode) {
  1686  	// No-one ever calls Field with a constant argument,
  1687  	// so we don't specialize that case.
  1688  	a.addConstraint(&rtypeFieldByNameConstraint{
  1689  		cgn:    cgn,
  1690  		t:      a.funcParams(cgn.obj),
  1691  		result: a.funcResults(cgn.obj),
  1692  	})
  1693  }
  1694  
  1695  func ext۰reflect۰rtype۰FieldByIndex(a *analysis, cgn *cgnode)    {} // TODO(adonovan)
  1696  func ext۰reflect۰rtype۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
  1697  
  1698  // ---------- func (*rtype) In/Out(i int) Type ----------
  1699  
  1700  // result = In/Out(t, i)
  1701  type rtypeInOutConstraint struct {
  1702  	cgn    *cgnode
  1703  	t      nodeid // (ptr)
  1704  	result nodeid // (indirect)
  1705  	out    bool
  1706  	i      int // -ve if not a constant
  1707  }
  1708  
  1709  func (c *rtypeInOutConstraint) ptr() nodeid { return c.t }
  1710  func (c *rtypeInOutConstraint) presolve(h *hvn) {
  1711  	h.markIndirect(onodeid(c.result), "rtypeInOut.result")
  1712  }
  1713  func (c *rtypeInOutConstraint) renumber(mapping []nodeid) {
  1714  	c.t = mapping[c.t]
  1715  	c.result = mapping[c.result]
  1716  }
  1717  
  1718  func (c *rtypeInOutConstraint) String() string {
  1719  	return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i)
  1720  }
  1721  
  1722  func (c *rtypeInOutConstraint) solve(a *analysis, delta *nodeset) {
  1723  	changed := false
  1724  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1725  		tObj := nodeid(x)
  1726  		T := a.nodes[tObj].obj.data.(types.Type)
  1727  		sig, ok := T.Underlying().(*types.Signature)
  1728  		if !ok {
  1729  			continue // not a func type
  1730  		}
  1731  
  1732  		tuple := sig.Params()
  1733  		if c.out {
  1734  			tuple = sig.Results()
  1735  		}
  1736  		for i, n := 0, tuple.Len(); i < n; i++ {
  1737  			if c.i < 0 || c.i == i {
  1738  				if a.addLabel(c.result, a.makeRtype(tuple.At(i).Type())) {
  1739  					changed = true
  1740  				}
  1741  			}
  1742  		}
  1743  	}
  1744  	if changed {
  1745  		a.addWork(c.result)
  1746  	}
  1747  }
  1748  
  1749  func ext۰reflect۰rtype۰InOut(a *analysis, cgn *cgnode, out bool) {
  1750  	// If we have access to the callsite,
  1751  	// and the argument is an int constant,
  1752  	// return only that parameter.
  1753  	index := -1
  1754  	if site := cgn.callersite; site != nil {
  1755  		if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
  1756  			v, _ := exact.Int64Val(c.Value)
  1757  			index = int(v)
  1758  		}
  1759  	}
  1760  	a.addConstraint(&rtypeInOutConstraint{
  1761  		cgn:    cgn,
  1762  		t:      a.funcParams(cgn.obj),
  1763  		result: a.funcResults(cgn.obj),
  1764  		out:    out,
  1765  		i:      index,
  1766  	})
  1767  }
  1768  
  1769  func ext۰reflect۰rtype۰In(a *analysis, cgn *cgnode) {
  1770  	ext۰reflect۰rtype۰InOut(a, cgn, false)
  1771  }
  1772  
  1773  func ext۰reflect۰rtype۰Out(a *analysis, cgn *cgnode) {
  1774  	ext۰reflect۰rtype۰InOut(a, cgn, true)
  1775  }
  1776  
  1777  // ---------- func (*rtype) Key() Type ----------
  1778  
  1779  // result = Key(t)
  1780  type rtypeKeyConstraint struct {
  1781  	cgn    *cgnode
  1782  	t      nodeid // (ptr)
  1783  	result nodeid // (indirect)
  1784  }
  1785  
  1786  func (c *rtypeKeyConstraint) ptr() nodeid { return c.t }
  1787  func (c *rtypeKeyConstraint) presolve(h *hvn) {
  1788  	h.markIndirect(onodeid(c.result), "rtypeKey.result")
  1789  }
  1790  func (c *rtypeKeyConstraint) renumber(mapping []nodeid) {
  1791  	c.t = mapping[c.t]
  1792  	c.result = mapping[c.result]
  1793  }
  1794  
  1795  func (c *rtypeKeyConstraint) String() string {
  1796  	return fmt.Sprintf("n%d = (*reflect.rtype).Key(n%d)", c.result, c.t)
  1797  }
  1798  
  1799  func (c *rtypeKeyConstraint) solve(a *analysis, delta *nodeset) {
  1800  	changed := false
  1801  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1802  		tObj := nodeid(x)
  1803  		T := a.nodes[tObj].obj.data.(types.Type)
  1804  		if tMap, ok := T.Underlying().(*types.Map); ok {
  1805  			if a.addLabel(c.result, a.makeRtype(tMap.Key())) {
  1806  				changed = true
  1807  			}
  1808  		}
  1809  	}
  1810  	if changed {
  1811  		a.addWork(c.result)
  1812  	}
  1813  }
  1814  
  1815  func ext۰reflect۰rtype۰Key(a *analysis, cgn *cgnode) {
  1816  	a.addConstraint(&rtypeKeyConstraint{
  1817  		cgn:    cgn,
  1818  		t:      a.funcParams(cgn.obj),
  1819  		result: a.funcResults(cgn.obj),
  1820  	})
  1821  }
  1822  
  1823  // ---------- func (*rtype) Method(int) (Method, bool) ----------
  1824  // ---------- func (*rtype) MethodByName(string) (Method, bool) ----------
  1825  
  1826  // result = MethodByName(t, name)
  1827  // result = Method(t, _)
  1828  type rtypeMethodByNameConstraint struct {
  1829  	cgn    *cgnode
  1830  	name   string // name of method; "" for unknown
  1831  	t      nodeid // (ptr)
  1832  	result nodeid // (indirect)
  1833  }
  1834  
  1835  func (c *rtypeMethodByNameConstraint) ptr() nodeid { return c.t }
  1836  func (c *rtypeMethodByNameConstraint) presolve(h *hvn) {
  1837  	h.markIndirect(onodeid(c.result+3), "rtypeMethodByName.result.Type")
  1838  	h.markIndirect(onodeid(c.result+4), "rtypeMethodByName.result.Func")
  1839  }
  1840  func (c *rtypeMethodByNameConstraint) renumber(mapping []nodeid) {
  1841  	c.t = mapping[c.t]
  1842  	c.result = mapping[c.result]
  1843  }
  1844  
  1845  func (c *rtypeMethodByNameConstraint) String() string {
  1846  	return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name)
  1847  }
  1848  
  1849  // changeRecv returns sig with Recv prepended to Params().
  1850  func changeRecv(sig *types.Signature) *types.Signature {
  1851  	params := sig.Params()
  1852  	n := params.Len()
  1853  	p2 := make([]*types.Var, n+1)
  1854  	p2[0] = sig.Recv()
  1855  	for i := 0; i < n; i++ {
  1856  		p2[i+1] = params.At(i)
  1857  	}
  1858  	return types.NewSignature(nil, types.NewTuple(p2...), sig.Results(), sig.Variadic())
  1859  }
  1860  
  1861  func (c *rtypeMethodByNameConstraint) solve(a *analysis, delta *nodeset) {
  1862  	for _, x := range delta.AppendTo(a.deltaSpace) {
  1863  		tObj := nodeid(x)
  1864  		T := a.nodes[tObj].obj.data.(types.Type)
  1865  
  1866  		isIface := isInterface(T)
  1867  
  1868  		// We don't use Lookup(c.name) when c.name != "" to avoid
  1869  		// ambiguity: >1 unexported methods could match.
  1870  		mset := a.prog.MethodSets.MethodSet(T)
  1871  		for i, n := 0, mset.Len(); i < n; i++ {
  1872  			sel := mset.At(i)
  1873  			if c.name == "" || c.name == sel.Obj().Name() {
  1874  				// type Method struct {
  1875  				// 0     __identity__
  1876  				// 1	Name    string
  1877  				// 2	PkgPath string
  1878  				// 3	Type    Type
  1879  				// 4	Func    Value
  1880  				// 5	Index   int
  1881  				// }
  1882  
  1883  				var sig *types.Signature
  1884  				var fn *ssa.Function
  1885  				if isIface {
  1886  					sig = sel.Type().(*types.Signature)
  1887  				} else {
  1888  					fn = a.prog.MethodValue(sel)
  1889  					// move receiver to params[0]
  1890  					sig = changeRecv(fn.Signature)
  1891  				}
  1892  
  1893  				// a.offsetOf(Type) is 3.
  1894  				if id := c.result + 3; a.addLabel(id, a.makeRtype(sig)) {
  1895  					a.addWork(id)
  1896  				}
  1897  				if fn != nil {
  1898  					// a.offsetOf(Func) is 4.
  1899  					if id := c.result + 4; a.addLabel(id, a.objectNode(nil, fn)) {
  1900  						a.addWork(id)
  1901  					}
  1902  				}
  1903  			}
  1904  		}
  1905  	}
  1906  }
  1907  
  1908  func ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) {
  1909  	// If we have access to the callsite,
  1910  	// and the argument is a string constant,
  1911  	// return only that method.
  1912  	var name string
  1913  	if site := cgn.callersite; site != nil {
  1914  		if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
  1915  			name = exact.StringVal(c.Value)
  1916  		}
  1917  	}
  1918  
  1919  	a.addConstraint(&rtypeMethodByNameConstraint{
  1920  		cgn:    cgn,
  1921  		name:   name,
  1922  		t:      a.funcParams(cgn.obj),
  1923  		result: a.funcResults(cgn.obj),
  1924  	})
  1925  }
  1926  
  1927  func ext۰reflect۰rtype۰Method(a *analysis, cgn *cgnode) {
  1928  	// No-one ever calls Method with a constant argument,
  1929  	// so we don't specialize that case.
  1930  	a.addConstraint(&rtypeMethodByNameConstraint{
  1931  		cgn:    cgn,
  1932  		t:      a.funcParams(cgn.obj),
  1933  		result: a.funcResults(cgn.obj),
  1934  	})
  1935  }
  1936  
  1937  // typeHeight returns the "height" of the type, which is roughly
  1938  // speaking the number of chan, map, pointer and slice type constructors
  1939  // at the root of T; these are the four type kinds that can be created
  1940  // via reflection.  Chan and map constructors are counted as double the
  1941  // height of slice and pointer constructors since they are less often
  1942  // deeply nested.
  1943  //
  1944  // The solver rules for type constructors must somehow bound the set of
  1945  // types they create to ensure termination of the algorithm in cases
  1946  // where the output of a type constructor flows to its input, e.g.
  1947  //
  1948  // 	func f(t reflect.Type) {
  1949  // 		f(reflect.PtrTo(t))
  1950  // 	}
  1951  //
  1952  // It does this by limiting the type height to k, but this still leaves
  1953  // a potentially exponential (4^k) number of of types that may be
  1954  // enumerated in pathological cases.
  1955  //
  1956  func typeHeight(T types.Type) int {
  1957  	switch T := T.(type) {
  1958  	case *types.Chan:
  1959  		return 2 + typeHeight(T.Elem())
  1960  	case *types.Map:
  1961  		k := typeHeight(T.Key())
  1962  		v := typeHeight(T.Elem())
  1963  		if v > k {
  1964  			k = v // max(k, v)
  1965  		}
  1966  		return 2 + k
  1967  	case *types.Slice:
  1968  		return 1 + typeHeight(T.Elem())
  1969  	case *types.Pointer:
  1970  		return 1 + typeHeight(T.Elem())
  1971  	}
  1972  	return 0
  1973  }
  1974  
  1975  func typeTooHigh(T types.Type) bool {
  1976  	return typeHeight(T) > 3
  1977  }