|  | // Copyright 2013 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package pointer | 
|  |  | 
|  | import "go/types" | 
|  |  | 
|  | type constraint interface { | 
|  | // For a complex constraint, returns the nodeid of the pointer | 
|  | // to which it is attached.   For addr and copy, returns dst. | 
|  | ptr() nodeid | 
|  |  | 
|  | // renumber replaces each nodeid n in the constraint by mapping[n]. | 
|  | renumber(mapping []nodeid) | 
|  |  | 
|  | // presolve is a hook for constraint-specific behaviour during | 
|  | // pre-solver optimization.  Typical implementations mark as | 
|  | // indirect the set of nodes to which the solver will add copy | 
|  | // edges or PTS labels. | 
|  | presolve(h *hvn) | 
|  |  | 
|  | // solve is called for complex constraints when the pts for | 
|  | // the node to which they are attached has changed. | 
|  | solve(a *analysis, delta *nodeset) | 
|  |  | 
|  | String() string | 
|  | } | 
|  |  | 
|  | // dst = &src | 
|  | // pts(dst) ⊇ {src} | 
|  | // A base constraint used to initialize the solver's pt sets | 
|  | type addrConstraint struct { | 
|  | dst nodeid // (ptr) | 
|  | src nodeid | 
|  | } | 
|  |  | 
|  | func (c *addrConstraint) ptr() nodeid { return c.dst } | 
|  | func (c *addrConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // dst = src | 
|  | // A simple constraint represented directly as a copyTo graph edge. | 
|  | type copyConstraint struct { | 
|  | dst nodeid // (ptr) | 
|  | src nodeid | 
|  | } | 
|  |  | 
|  | func (c *copyConstraint) ptr() nodeid { return c.dst } | 
|  | func (c *copyConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // dst = src[offset] | 
|  | // A complex constraint attached to src (the pointer) | 
|  | type loadConstraint struct { | 
|  | offset uint32 | 
|  | dst    nodeid | 
|  | src    nodeid // (ptr) | 
|  | } | 
|  |  | 
|  | func (c *loadConstraint) ptr() nodeid { return c.src } | 
|  | func (c *loadConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // dst[offset] = src | 
|  | // A complex constraint attached to dst (the pointer) | 
|  | type storeConstraint struct { | 
|  | offset uint32 | 
|  | dst    nodeid // (ptr) | 
|  | src    nodeid | 
|  | } | 
|  |  | 
|  | func (c *storeConstraint) ptr() nodeid { return c.dst } | 
|  | func (c *storeConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // dst = &src.f  or  dst = &src[0] | 
|  | // A complex constraint attached to dst (the pointer) | 
|  | type offsetAddrConstraint struct { | 
|  | offset uint32 | 
|  | dst    nodeid | 
|  | src    nodeid // (ptr) | 
|  | } | 
|  |  | 
|  | func (c *offsetAddrConstraint) ptr() nodeid { return c.src } | 
|  | func (c *offsetAddrConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // dst = src.(typ)  where typ is an interface | 
|  | // A complex constraint attached to src (the interface). | 
|  | // No representation change: pts(dst) and pts(src) contains tagged objects. | 
|  | type typeFilterConstraint struct { | 
|  | typ types.Type // an interface type | 
|  | dst nodeid | 
|  | src nodeid // (ptr) | 
|  | } | 
|  |  | 
|  | func (c *typeFilterConstraint) ptr() nodeid { return c.src } | 
|  | func (c *typeFilterConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // dst = src.(typ)  where typ is a concrete type | 
|  | // A complex constraint attached to src (the interface). | 
|  | // | 
|  | // If exact, only tagged objects identical to typ are untagged. | 
|  | // If !exact, tagged objects assignable to typ are untagged too. | 
|  | // The latter is needed for various reflect operators, e.g. Send. | 
|  | // | 
|  | // This entails a representation change: | 
|  | // pts(src) contains tagged objects, | 
|  | // pts(dst) contains their payloads. | 
|  | type untagConstraint struct { | 
|  | typ   types.Type // a concrete type | 
|  | dst   nodeid | 
|  | src   nodeid // (ptr) | 
|  | exact bool | 
|  | } | 
|  |  | 
|  | func (c *untagConstraint) ptr() nodeid { return c.src } | 
|  | func (c *untagConstraint) renumber(mapping []nodeid) { | 
|  | c.dst = mapping[c.dst] | 
|  | c.src = mapping[c.src] | 
|  | } | 
|  |  | 
|  | // src.method(params...) | 
|  | // A complex constraint attached to iface. | 
|  | type invokeConstraint struct { | 
|  | method *types.Func // the abstract method | 
|  | iface  nodeid      // (ptr) the interface | 
|  | params nodeid      // the start of the identity/params/results block | 
|  | } | 
|  |  | 
|  | func (c *invokeConstraint) ptr() nodeid { return c.iface } | 
|  | func (c *invokeConstraint) renumber(mapping []nodeid) { | 
|  | c.iface = mapping[c.iface] | 
|  | c.params = mapping[c.params] | 
|  | } |