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