github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/pointer/reflect.go (about)

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