github.com/pankona/gometalinter@v2.0.11+incompatible/_linters/src/honnef.co/go/tools/staticcheck/vrp/vrp.go (about)

     1  package vrp
     2  
     3  // TODO(dh) widening and narrowing have a lot of code in common. Make
     4  // it reusable.
     5  
     6  import (
     7  	"fmt"
     8  	"go/constant"
     9  	"go/token"
    10  	"go/types"
    11  	"math/big"
    12  	"sort"
    13  	"strings"
    14  
    15  	"honnef.co/go/tools/ssa"
    16  )
    17  
    18  type Future interface {
    19  	Constraint
    20  	Futures() []ssa.Value
    21  	Resolve()
    22  	IsKnown() bool
    23  	MarkUnresolved()
    24  	MarkResolved()
    25  	IsResolved() bool
    26  }
    27  
    28  type Range interface {
    29  	Union(other Range) Range
    30  	IsKnown() bool
    31  }
    32  
    33  type Constraint interface {
    34  	Y() ssa.Value
    35  	isConstraint()
    36  	String() string
    37  	Eval(*Graph) Range
    38  	Operands() []ssa.Value
    39  }
    40  
    41  type aConstraint struct {
    42  	y ssa.Value
    43  }
    44  
    45  func NewConstraint(y ssa.Value) aConstraint {
    46  	return aConstraint{y}
    47  }
    48  
    49  func (aConstraint) isConstraint()  {}
    50  func (c aConstraint) Y() ssa.Value { return c.y }
    51  
    52  type PhiConstraint struct {
    53  	aConstraint
    54  	Vars []ssa.Value
    55  }
    56  
    57  func NewPhiConstraint(vars []ssa.Value, y ssa.Value) Constraint {
    58  	uniqm := map[ssa.Value]struct{}{}
    59  	for _, v := range vars {
    60  		uniqm[v] = struct{}{}
    61  	}
    62  	var uniq []ssa.Value
    63  	for v := range uniqm {
    64  		uniq = append(uniq, v)
    65  	}
    66  	return &PhiConstraint{
    67  		aConstraint: NewConstraint(y),
    68  		Vars:        uniq,
    69  	}
    70  }
    71  
    72  func (c *PhiConstraint) Operands() []ssa.Value {
    73  	return c.Vars
    74  }
    75  
    76  func (c *PhiConstraint) Eval(g *Graph) Range {
    77  	i := Range(nil)
    78  	for _, v := range c.Vars {
    79  		i = g.Range(v).Union(i)
    80  	}
    81  	return i
    82  }
    83  
    84  func (c *PhiConstraint) String() string {
    85  	names := make([]string, len(c.Vars))
    86  	for i, v := range c.Vars {
    87  		names[i] = v.Name()
    88  	}
    89  	return fmt.Sprintf("%s = φ(%s)", c.Y().Name(), strings.Join(names, ", "))
    90  }
    91  
    92  func isSupportedType(typ types.Type) bool {
    93  	switch typ := typ.Underlying().(type) {
    94  	case *types.Basic:
    95  		switch typ.Kind() {
    96  		case types.String, types.UntypedString:
    97  			return true
    98  		default:
    99  			if (typ.Info() & types.IsInteger) == 0 {
   100  				return false
   101  			}
   102  		}
   103  	case *types.Chan:
   104  		return true
   105  	case *types.Slice:
   106  		return true
   107  	default:
   108  		return false
   109  	}
   110  	return true
   111  }
   112  
   113  func ConstantToZ(c constant.Value) Z {
   114  	s := constant.ToInt(c).ExactString()
   115  	n := &big.Int{}
   116  	n.SetString(s, 10)
   117  	return NewBigZ(n)
   118  }
   119  
   120  func sigmaInteger(g *Graph, ins *ssa.Sigma, cond *ssa.BinOp, ops []*ssa.Value) Constraint {
   121  	op := cond.Op
   122  	if !ins.Branch {
   123  		op = (invertToken(op))
   124  	}
   125  
   126  	switch op {
   127  	case token.EQL, token.GTR, token.GEQ, token.LSS, token.LEQ:
   128  	default:
   129  		return nil
   130  	}
   131  	var a, b ssa.Value
   132  	if (*ops[0]) == ins.X {
   133  		a = *ops[0]
   134  		b = *ops[1]
   135  	} else {
   136  		a = *ops[1]
   137  		b = *ops[0]
   138  		op = flipToken(op)
   139  	}
   140  	return NewIntIntersectionConstraint(a, b, op, g.ranges, ins)
   141  }
   142  
   143  func sigmaString(g *Graph, ins *ssa.Sigma, cond *ssa.BinOp, ops []*ssa.Value) Constraint {
   144  	op := cond.Op
   145  	if !ins.Branch {
   146  		op = (invertToken(op))
   147  	}
   148  
   149  	switch op {
   150  	case token.EQL, token.GTR, token.GEQ, token.LSS, token.LEQ:
   151  	default:
   152  		return nil
   153  	}
   154  
   155  	if ((*ops[0]).Type().Underlying().(*types.Basic).Info() & types.IsString) == 0 {
   156  		var a, b ssa.Value
   157  		call, ok := (*ops[0]).(*ssa.Call)
   158  		if ok && call.Common().Args[0] == ins.X {
   159  			a = *ops[0]
   160  			b = *ops[1]
   161  		} else {
   162  			a = *ops[1]
   163  			b = *ops[0]
   164  			op = flipToken(op)
   165  		}
   166  		return NewStringIntersectionConstraint(a, b, op, g.ranges, ins)
   167  	}
   168  	var a, b ssa.Value
   169  	if (*ops[0]) == ins.X {
   170  		a = *ops[0]
   171  		b = *ops[1]
   172  	} else {
   173  		a = *ops[1]
   174  		b = *ops[0]
   175  		op = flipToken(op)
   176  	}
   177  	return NewStringIntersectionConstraint(a, b, op, g.ranges, ins)
   178  }
   179  
   180  func sigmaSlice(g *Graph, ins *ssa.Sigma, cond *ssa.BinOp, ops []*ssa.Value) Constraint {
   181  	// TODO(dh) sigmaSlice and sigmaString are a lot alike. Can they
   182  	// be merged?
   183  	//
   184  	// XXX support futures
   185  
   186  	op := cond.Op
   187  	if !ins.Branch {
   188  		op = (invertToken(op))
   189  	}
   190  
   191  	k, ok := (*ops[1]).(*ssa.Const)
   192  	// XXX investigate in what cases this wouldn't be a Const
   193  	//
   194  	// XXX what if left and right are swapped?
   195  	if !ok {
   196  		return nil
   197  	}
   198  
   199  	call, ok := (*ops[0]).(*ssa.Call)
   200  	if !ok {
   201  		return nil
   202  	}
   203  	builtin, ok := call.Common().Value.(*ssa.Builtin)
   204  	if !ok {
   205  		return nil
   206  	}
   207  	if builtin.Name() != "len" {
   208  		return nil
   209  	}
   210  	callops := call.Operands(nil)
   211  
   212  	v := ConstantToZ(k.Value)
   213  	c := NewSliceIntersectionConstraint(*callops[1], IntInterval{}, ins).(*SliceIntersectionConstraint)
   214  	switch op {
   215  	case token.EQL:
   216  		c.I = NewIntInterval(v, v)
   217  	case token.GTR, token.GEQ:
   218  		off := int64(0)
   219  		if cond.Op == token.GTR {
   220  			off = 1
   221  		}
   222  		c.I = NewIntInterval(
   223  			v.Add(NewZ(off)),
   224  			PInfinity,
   225  		)
   226  	case token.LSS, token.LEQ:
   227  		off := int64(0)
   228  		if cond.Op == token.LSS {
   229  			off = -1
   230  		}
   231  		c.I = NewIntInterval(
   232  			NInfinity,
   233  			v.Add(NewZ(off)),
   234  		)
   235  	default:
   236  		return nil
   237  	}
   238  	return c
   239  }
   240  
   241  func BuildGraph(f *ssa.Function) *Graph {
   242  	g := &Graph{
   243  		Vertices: map[interface{}]*Vertex{},
   244  		ranges:   Ranges{},
   245  	}
   246  
   247  	var cs []Constraint
   248  
   249  	ops := make([]*ssa.Value, 16)
   250  	seen := map[ssa.Value]bool{}
   251  	for _, block := range f.Blocks {
   252  		for _, ins := range block.Instrs {
   253  			ops = ins.Operands(ops[:0])
   254  			for _, op := range ops {
   255  				if c, ok := (*op).(*ssa.Const); ok {
   256  					if seen[c] {
   257  						continue
   258  					}
   259  					seen[c] = true
   260  					if c.Value == nil {
   261  						switch c.Type().Underlying().(type) {
   262  						case *types.Slice:
   263  							cs = append(cs, NewSliceIntervalConstraint(NewIntInterval(NewZ(0), NewZ(0)), c))
   264  						}
   265  						continue
   266  					}
   267  					switch c.Value.Kind() {
   268  					case constant.Int:
   269  						v := ConstantToZ(c.Value)
   270  						cs = append(cs, NewIntIntervalConstraint(NewIntInterval(v, v), c))
   271  					case constant.String:
   272  						s := constant.StringVal(c.Value)
   273  						n := NewZ(int64(len(s)))
   274  						cs = append(cs, NewStringIntervalConstraint(NewIntInterval(n, n), c))
   275  					}
   276  				}
   277  			}
   278  		}
   279  	}
   280  	for _, block := range f.Blocks {
   281  		for _, ins := range block.Instrs {
   282  			switch ins := ins.(type) {
   283  			case *ssa.Convert:
   284  				switch v := ins.Type().Underlying().(type) {
   285  				case *types.Basic:
   286  					if (v.Info() & types.IsInteger) == 0 {
   287  						continue
   288  					}
   289  					cs = append(cs, NewIntConversionConstraint(ins.X, ins))
   290  				}
   291  			case *ssa.Call:
   292  				if static := ins.Common().StaticCallee(); static != nil {
   293  					if fn, ok := static.Object().(*types.Func); ok {
   294  						switch fn.FullName() {
   295  						case "bytes.Index", "bytes.IndexAny", "bytes.IndexByte",
   296  							"bytes.IndexFunc", "bytes.IndexRune", "bytes.LastIndex",
   297  							"bytes.LastIndexAny", "bytes.LastIndexByte", "bytes.LastIndexFunc",
   298  							"strings.Index", "strings.IndexAny", "strings.IndexByte",
   299  							"strings.IndexFunc", "strings.IndexRune", "strings.LastIndex",
   300  							"strings.LastIndexAny", "strings.LastIndexByte", "strings.LastIndexFunc":
   301  							// TODO(dh): instead of limiting by +∞,
   302  							// limit by the upper bound of the passed
   303  							// string
   304  							cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(-1), PInfinity), ins))
   305  						case "bytes.Title", "bytes.ToLower", "bytes.ToTitle", "bytes.ToUpper",
   306  							"strings.Title", "strings.ToLower", "strings.ToTitle", "strings.ToUpper":
   307  							cs = append(cs, NewCopyConstraint(ins.Common().Args[0], ins))
   308  						case "bytes.ToLowerSpecial", "bytes.ToTitleSpecial", "bytes.ToUpperSpecial",
   309  							"strings.ToLowerSpecial", "strings.ToTitleSpecial", "strings.ToUpperSpecial":
   310  							cs = append(cs, NewCopyConstraint(ins.Common().Args[1], ins))
   311  						case "bytes.Compare", "strings.Compare":
   312  							cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(-1), NewZ(1)), ins))
   313  						case "bytes.Count", "strings.Count":
   314  							// TODO(dh): instead of limiting by +∞,
   315  							// limit by the upper bound of the passed
   316  							// string.
   317  							cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(0), PInfinity), ins))
   318  						case "bytes.Map", "bytes.TrimFunc", "bytes.TrimLeft", "bytes.TrimLeftFunc",
   319  							"bytes.TrimRight", "bytes.TrimRightFunc", "bytes.TrimSpace",
   320  							"strings.Map", "strings.TrimFunc", "strings.TrimLeft", "strings.TrimLeftFunc",
   321  							"strings.TrimRight", "strings.TrimRightFunc", "strings.TrimSpace":
   322  							// TODO(dh): lower = 0, upper = upper of passed string
   323  						case "bytes.TrimPrefix", "bytes.TrimSuffix",
   324  							"strings.TrimPrefix", "strings.TrimSuffix":
   325  							// TODO(dh) range between "unmodified" and len(cutset) removed
   326  						case "(*bytes.Buffer).Cap", "(*bytes.Buffer).Len", "(*bytes.Reader).Len", "(*bytes.Reader).Size":
   327  							cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(0), PInfinity), ins))
   328  						}
   329  					}
   330  				}
   331  				builtin, ok := ins.Common().Value.(*ssa.Builtin)
   332  				ops := ins.Operands(nil)
   333  				if !ok {
   334  					continue
   335  				}
   336  				switch builtin.Name() {
   337  				case "len":
   338  					switch op1 := (*ops[1]).Type().Underlying().(type) {
   339  					case *types.Basic:
   340  						if op1.Kind() == types.String || op1.Kind() == types.UntypedString {
   341  							cs = append(cs, NewStringLengthConstraint(*ops[1], ins))
   342  						}
   343  					case *types.Slice:
   344  						cs = append(cs, NewSliceLengthConstraint(*ops[1], ins))
   345  					}
   346  
   347  				case "append":
   348  					cs = append(cs, NewSliceAppendConstraint(ins.Common().Args[0], ins.Common().Args[1], ins))
   349  				}
   350  			case *ssa.BinOp:
   351  				ops := ins.Operands(nil)
   352  				basic, ok := (*ops[0]).Type().Underlying().(*types.Basic)
   353  				if !ok {
   354  					continue
   355  				}
   356  				switch basic.Kind() {
   357  				case types.Int, types.Int8, types.Int16, types.Int32, types.Int64,
   358  					types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.UntypedInt:
   359  					fns := map[token.Token]func(ssa.Value, ssa.Value, ssa.Value) Constraint{
   360  						token.ADD: NewIntAddConstraint,
   361  						token.SUB: NewIntSubConstraint,
   362  						token.MUL: NewIntMulConstraint,
   363  						// XXX support QUO, REM, SHL, SHR
   364  					}
   365  					fn, ok := fns[ins.Op]
   366  					if ok {
   367  						cs = append(cs, fn(*ops[0], *ops[1], ins))
   368  					}
   369  				case types.String, types.UntypedString:
   370  					if ins.Op == token.ADD {
   371  						cs = append(cs, NewStringConcatConstraint(*ops[0], *ops[1], ins))
   372  					}
   373  				}
   374  			case *ssa.Slice:
   375  				typ := ins.X.Type().Underlying()
   376  				switch typ := typ.(type) {
   377  				case *types.Basic:
   378  					cs = append(cs, NewStringSliceConstraint(ins.X, ins.Low, ins.High, ins))
   379  				case *types.Slice:
   380  					cs = append(cs, NewSliceSliceConstraint(ins.X, ins.Low, ins.High, ins))
   381  				case *types.Array:
   382  					cs = append(cs, NewArraySliceConstraint(ins.X, ins.Low, ins.High, ins))
   383  				case *types.Pointer:
   384  					if _, ok := typ.Elem().(*types.Array); !ok {
   385  						continue
   386  					}
   387  					cs = append(cs, NewArraySliceConstraint(ins.X, ins.Low, ins.High, ins))
   388  				}
   389  			case *ssa.Phi:
   390  				if !isSupportedType(ins.Type()) {
   391  					continue
   392  				}
   393  				ops := ins.Operands(nil)
   394  				dops := make([]ssa.Value, len(ops))
   395  				for i, op := range ops {
   396  					dops[i] = *op
   397  				}
   398  				cs = append(cs, NewPhiConstraint(dops, ins))
   399  			case *ssa.Sigma:
   400  				pred := ins.Block().Preds[0]
   401  				instrs := pred.Instrs
   402  				cond, ok := instrs[len(instrs)-1].(*ssa.If).Cond.(*ssa.BinOp)
   403  				ops := cond.Operands(nil)
   404  				if !ok {
   405  					continue
   406  				}
   407  				switch typ := ins.Type().Underlying().(type) {
   408  				case *types.Basic:
   409  					var c Constraint
   410  					switch typ.Kind() {
   411  					case types.Int, types.Int8, types.Int16, types.Int32, types.Int64,
   412  						types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.UntypedInt:
   413  						c = sigmaInteger(g, ins, cond, ops)
   414  					case types.String, types.UntypedString:
   415  						c = sigmaString(g, ins, cond, ops)
   416  					}
   417  					if c != nil {
   418  						cs = append(cs, c)
   419  					}
   420  				case *types.Slice:
   421  					c := sigmaSlice(g, ins, cond, ops)
   422  					if c != nil {
   423  						cs = append(cs, c)
   424  					}
   425  				default:
   426  					//log.Printf("unsupported sigma type %T", typ) // XXX
   427  				}
   428  			case *ssa.MakeChan:
   429  				cs = append(cs, NewMakeChannelConstraint(ins.Size, ins))
   430  			case *ssa.MakeSlice:
   431  				cs = append(cs, NewMakeSliceConstraint(ins.Len, ins))
   432  			case *ssa.ChangeType:
   433  				switch ins.X.Type().Underlying().(type) {
   434  				case *types.Chan:
   435  					cs = append(cs, NewChannelChangeTypeConstraint(ins.X, ins))
   436  				}
   437  			}
   438  		}
   439  	}
   440  
   441  	for _, c := range cs {
   442  		if c == nil {
   443  			panic("nil constraint")
   444  		}
   445  		// If V is used in constraint C, then we create an edge V->C
   446  		for _, op := range c.Operands() {
   447  			g.AddEdge(op, c, false)
   448  		}
   449  		if c, ok := c.(Future); ok {
   450  			for _, op := range c.Futures() {
   451  				g.AddEdge(op, c, true)
   452  			}
   453  		}
   454  		// If constraint C defines variable V, then we create an edge
   455  		// C->V
   456  		g.AddEdge(c, c.Y(), false)
   457  	}
   458  
   459  	g.FindSCCs()
   460  	g.sccEdges = make([][]Edge, len(g.SCCs))
   461  	g.futures = make([][]Future, len(g.SCCs))
   462  	for _, e := range g.Edges {
   463  		g.sccEdges[e.From.SCC] = append(g.sccEdges[e.From.SCC], e)
   464  		if !e.control {
   465  			continue
   466  		}
   467  		if c, ok := e.To.Value.(Future); ok {
   468  			g.futures[e.From.SCC] = append(g.futures[e.From.SCC], c)
   469  		}
   470  	}
   471  	return g
   472  }
   473  
   474  func (g *Graph) Solve() Ranges {
   475  	var consts []Z
   476  	off := NewZ(1)
   477  	for _, n := range g.Vertices {
   478  		if c, ok := n.Value.(*ssa.Const); ok {
   479  			basic, ok := c.Type().Underlying().(*types.Basic)
   480  			if !ok {
   481  				continue
   482  			}
   483  			if (basic.Info() & types.IsInteger) != 0 {
   484  				z := ConstantToZ(c.Value)
   485  				consts = append(consts, z)
   486  				consts = append(consts, z.Add(off))
   487  				consts = append(consts, z.Sub(off))
   488  			}
   489  		}
   490  
   491  	}
   492  	sort.Sort(Zs(consts))
   493  
   494  	for scc, vertices := range g.SCCs {
   495  		n := 0
   496  		n = len(vertices)
   497  		if n == 1 {
   498  			g.resolveFutures(scc)
   499  			v := vertices[0]
   500  			if v, ok := v.Value.(ssa.Value); ok {
   501  				switch typ := v.Type().Underlying().(type) {
   502  				case *types.Basic:
   503  					switch typ.Kind() {
   504  					case types.String, types.UntypedString:
   505  						if !g.Range(v).(StringInterval).IsKnown() {
   506  							g.SetRange(v, StringInterval{NewIntInterval(NewZ(0), PInfinity)})
   507  						}
   508  					default:
   509  						if !g.Range(v).(IntInterval).IsKnown() {
   510  							g.SetRange(v, InfinityFor(v))
   511  						}
   512  					}
   513  				case *types.Chan:
   514  					if !g.Range(v).(ChannelInterval).IsKnown() {
   515  						g.SetRange(v, ChannelInterval{NewIntInterval(NewZ(0), PInfinity)})
   516  					}
   517  				case *types.Slice:
   518  					if !g.Range(v).(SliceInterval).IsKnown() {
   519  						g.SetRange(v, SliceInterval{NewIntInterval(NewZ(0), PInfinity)})
   520  					}
   521  				}
   522  			}
   523  			if c, ok := v.Value.(Constraint); ok {
   524  				g.SetRange(c.Y(), c.Eval(g))
   525  			}
   526  		} else {
   527  			uses := g.uses(scc)
   528  			entries := g.entries(scc)
   529  			for len(entries) > 0 {
   530  				v := entries[len(entries)-1]
   531  				entries = entries[:len(entries)-1]
   532  				for _, use := range uses[v] {
   533  					if g.widen(use, consts) {
   534  						entries = append(entries, use.Y())
   535  					}
   536  				}
   537  			}
   538  
   539  			g.resolveFutures(scc)
   540  
   541  			// XXX this seems to be necessary, but shouldn't be.
   542  			// removing it leads to nil pointer derefs; investigate
   543  			// where we're not setting values correctly.
   544  			for _, n := range vertices {
   545  				if v, ok := n.Value.(ssa.Value); ok {
   546  					i, ok := g.Range(v).(IntInterval)
   547  					if !ok {
   548  						continue
   549  					}
   550  					if !i.IsKnown() {
   551  						g.SetRange(v, InfinityFor(v))
   552  					}
   553  				}
   554  			}
   555  
   556  			actives := g.actives(scc)
   557  			for len(actives) > 0 {
   558  				v := actives[len(actives)-1]
   559  				actives = actives[:len(actives)-1]
   560  				for _, use := range uses[v] {
   561  					if g.narrow(use) {
   562  						actives = append(actives, use.Y())
   563  					}
   564  				}
   565  			}
   566  		}
   567  		// propagate scc
   568  		for _, edge := range g.sccEdges[scc] {
   569  			if edge.control {
   570  				continue
   571  			}
   572  			if edge.From.SCC == edge.To.SCC {
   573  				continue
   574  			}
   575  			if c, ok := edge.To.Value.(Constraint); ok {
   576  				g.SetRange(c.Y(), c.Eval(g))
   577  			}
   578  			if c, ok := edge.To.Value.(Future); ok {
   579  				if !c.IsKnown() {
   580  					c.MarkUnresolved()
   581  				}
   582  			}
   583  		}
   584  	}
   585  
   586  	for v, r := range g.ranges {
   587  		i, ok := r.(IntInterval)
   588  		if !ok {
   589  			continue
   590  		}
   591  		if (v.Type().Underlying().(*types.Basic).Info() & types.IsUnsigned) == 0 {
   592  			if i.Upper != PInfinity {
   593  				s := &types.StdSizes{
   594  					// XXX is it okay to assume the largest word size, or do we
   595  					// need to be platform specific?
   596  					WordSize: 8,
   597  					MaxAlign: 1,
   598  				}
   599  				bits := (s.Sizeof(v.Type()) * 8) - 1
   600  				n := big.NewInt(1)
   601  				n = n.Lsh(n, uint(bits))
   602  				upper, lower := &big.Int{}, &big.Int{}
   603  				upper.Sub(n, big.NewInt(1))
   604  				lower.Neg(n)
   605  
   606  				if i.Upper.Cmp(NewBigZ(upper)) == 1 {
   607  					i = NewIntInterval(NInfinity, PInfinity)
   608  				} else if i.Lower.Cmp(NewBigZ(lower)) == -1 {
   609  					i = NewIntInterval(NInfinity, PInfinity)
   610  				}
   611  			}
   612  		}
   613  
   614  		g.ranges[v] = i
   615  	}
   616  
   617  	return g.ranges
   618  }
   619  
   620  func VertexString(v *Vertex) string {
   621  	switch v := v.Value.(type) {
   622  	case Constraint:
   623  		return v.String()
   624  	case ssa.Value:
   625  		return v.Name()
   626  	case nil:
   627  		return "BUG: nil vertex value"
   628  	default:
   629  		panic(fmt.Sprintf("unexpected type %T", v))
   630  	}
   631  }
   632  
   633  type Vertex struct {
   634  	Value   interface{} // one of Constraint or ssa.Value
   635  	SCC     int
   636  	index   int
   637  	lowlink int
   638  	stack   bool
   639  
   640  	Succs []Edge
   641  }
   642  
   643  type Ranges map[ssa.Value]Range
   644  
   645  func (r Ranges) Get(x ssa.Value) Range {
   646  	if x == nil {
   647  		return nil
   648  	}
   649  	i, ok := r[x]
   650  	if !ok {
   651  		switch x := x.Type().Underlying().(type) {
   652  		case *types.Basic:
   653  			switch x.Kind() {
   654  			case types.String, types.UntypedString:
   655  				return StringInterval{}
   656  			default:
   657  				return IntInterval{}
   658  			}
   659  		case *types.Chan:
   660  			return ChannelInterval{}
   661  		case *types.Slice:
   662  			return SliceInterval{}
   663  		}
   664  	}
   665  	return i
   666  }
   667  
   668  type Graph struct {
   669  	Vertices map[interface{}]*Vertex
   670  	Edges    []Edge
   671  	SCCs     [][]*Vertex
   672  	ranges   Ranges
   673  
   674  	// map SCCs to futures
   675  	futures [][]Future
   676  	// map SCCs to edges
   677  	sccEdges [][]Edge
   678  }
   679  
   680  func (g Graph) Graphviz() string {
   681  	var lines []string
   682  	lines = append(lines, "digraph{")
   683  	ids := map[interface{}]int{}
   684  	i := 1
   685  	for _, v := range g.Vertices {
   686  		ids[v] = i
   687  		shape := "box"
   688  		if _, ok := v.Value.(ssa.Value); ok {
   689  			shape = "oval"
   690  		}
   691  		lines = append(lines, fmt.Sprintf(`n%d [shape="%s", label=%q, colorscheme=spectral11, style="filled", fillcolor="%d"]`,
   692  			i, shape, VertexString(v), (v.SCC%11)+1))
   693  		i++
   694  	}
   695  	for _, e := range g.Edges {
   696  		style := "solid"
   697  		if e.control {
   698  			style = "dashed"
   699  		}
   700  		lines = append(lines, fmt.Sprintf(`n%d -> n%d [style="%s"]`, ids[e.From], ids[e.To], style))
   701  	}
   702  	lines = append(lines, "}")
   703  	return strings.Join(lines, "\n")
   704  }
   705  
   706  func (g *Graph) SetRange(x ssa.Value, r Range) {
   707  	g.ranges[x] = r
   708  }
   709  
   710  func (g *Graph) Range(x ssa.Value) Range {
   711  	return g.ranges.Get(x)
   712  }
   713  
   714  func (g *Graph) widen(c Constraint, consts []Z) bool {
   715  	setRange := func(i Range) {
   716  		g.SetRange(c.Y(), i)
   717  	}
   718  	widenIntInterval := func(oi, ni IntInterval) (IntInterval, bool) {
   719  		if !ni.IsKnown() {
   720  			return oi, false
   721  		}
   722  		nlc := NInfinity
   723  		nuc := PInfinity
   724  		for _, co := range consts {
   725  			if co.Cmp(ni.Lower) <= 0 {
   726  				nlc = co
   727  				break
   728  			}
   729  		}
   730  		for _, co := range consts {
   731  			if co.Cmp(ni.Upper) >= 0 {
   732  				nuc = co
   733  				break
   734  			}
   735  		}
   736  
   737  		if !oi.IsKnown() {
   738  			return ni, true
   739  		}
   740  		if ni.Lower.Cmp(oi.Lower) == -1 && ni.Upper.Cmp(oi.Upper) == 1 {
   741  			return NewIntInterval(nlc, nuc), true
   742  		}
   743  		if ni.Lower.Cmp(oi.Lower) == -1 {
   744  			return NewIntInterval(nlc, oi.Upper), true
   745  		}
   746  		if ni.Upper.Cmp(oi.Upper) == 1 {
   747  			return NewIntInterval(oi.Lower, nuc), true
   748  		}
   749  		return oi, false
   750  	}
   751  	switch oi := g.Range(c.Y()).(type) {
   752  	case IntInterval:
   753  		ni := c.Eval(g).(IntInterval)
   754  		si, changed := widenIntInterval(oi, ni)
   755  		if changed {
   756  			setRange(si)
   757  			return true
   758  		}
   759  		return false
   760  	case StringInterval:
   761  		ni := c.Eval(g).(StringInterval)
   762  		si, changed := widenIntInterval(oi.Length, ni.Length)
   763  		if changed {
   764  			setRange(StringInterval{si})
   765  			return true
   766  		}
   767  		return false
   768  	case SliceInterval:
   769  		ni := c.Eval(g).(SliceInterval)
   770  		si, changed := widenIntInterval(oi.Length, ni.Length)
   771  		if changed {
   772  			setRange(SliceInterval{si})
   773  			return true
   774  		}
   775  		return false
   776  	default:
   777  		return false
   778  	}
   779  }
   780  
   781  func (g *Graph) narrow(c Constraint) bool {
   782  	narrowIntInterval := func(oi, ni IntInterval) (IntInterval, bool) {
   783  		oLower := oi.Lower
   784  		oUpper := oi.Upper
   785  		nLower := ni.Lower
   786  		nUpper := ni.Upper
   787  
   788  		if oLower == NInfinity && nLower != NInfinity {
   789  			return NewIntInterval(nLower, oUpper), true
   790  		}
   791  		if oUpper == PInfinity && nUpper != PInfinity {
   792  			return NewIntInterval(oLower, nUpper), true
   793  		}
   794  		if oLower.Cmp(nLower) == 1 {
   795  			return NewIntInterval(nLower, oUpper), true
   796  		}
   797  		if oUpper.Cmp(nUpper) == -1 {
   798  			return NewIntInterval(oLower, nUpper), true
   799  		}
   800  		return oi, false
   801  	}
   802  	switch oi := g.Range(c.Y()).(type) {
   803  	case IntInterval:
   804  		ni := c.Eval(g).(IntInterval)
   805  		si, changed := narrowIntInterval(oi, ni)
   806  		if changed {
   807  			g.SetRange(c.Y(), si)
   808  			return true
   809  		}
   810  		return false
   811  	case StringInterval:
   812  		ni := c.Eval(g).(StringInterval)
   813  		si, changed := narrowIntInterval(oi.Length, ni.Length)
   814  		if changed {
   815  			g.SetRange(c.Y(), StringInterval{si})
   816  			return true
   817  		}
   818  		return false
   819  	case SliceInterval:
   820  		ni := c.Eval(g).(SliceInterval)
   821  		si, changed := narrowIntInterval(oi.Length, ni.Length)
   822  		if changed {
   823  			g.SetRange(c.Y(), SliceInterval{si})
   824  			return true
   825  		}
   826  		return false
   827  	default:
   828  		return false
   829  	}
   830  }
   831  
   832  func (g *Graph) resolveFutures(scc int) {
   833  	for _, c := range g.futures[scc] {
   834  		c.Resolve()
   835  	}
   836  }
   837  
   838  func (g *Graph) entries(scc int) []ssa.Value {
   839  	var entries []ssa.Value
   840  	for _, n := range g.Vertices {
   841  		if n.SCC != scc {
   842  			continue
   843  		}
   844  		if v, ok := n.Value.(ssa.Value); ok {
   845  			// XXX avoid quadratic runtime
   846  			//
   847  			// XXX I cannot think of any code where the future and its
   848  			// variables aren't in the same SCC, in which case this
   849  			// code isn't very useful (the variables won't be resolved
   850  			// yet). Before we have a cross-SCC example, however, we
   851  			// can't really verify that this code is working
   852  			// correctly, or indeed doing anything useful.
   853  			for _, on := range g.Vertices {
   854  				if c, ok := on.Value.(Future); ok {
   855  					if c.Y() == v {
   856  						if !c.IsResolved() {
   857  							g.SetRange(c.Y(), c.Eval(g))
   858  							c.MarkResolved()
   859  						}
   860  						break
   861  					}
   862  				}
   863  			}
   864  			if g.Range(v).IsKnown() {
   865  				entries = append(entries, v)
   866  			}
   867  		}
   868  	}
   869  	return entries
   870  }
   871  
   872  func (g *Graph) uses(scc int) map[ssa.Value][]Constraint {
   873  	m := map[ssa.Value][]Constraint{}
   874  	for _, e := range g.sccEdges[scc] {
   875  		if e.control {
   876  			continue
   877  		}
   878  		if v, ok := e.From.Value.(ssa.Value); ok {
   879  			c := e.To.Value.(Constraint)
   880  			sink := c.Y()
   881  			if g.Vertices[sink].SCC == scc {
   882  				m[v] = append(m[v], c)
   883  			}
   884  		}
   885  	}
   886  	return m
   887  }
   888  
   889  func (g *Graph) actives(scc int) []ssa.Value {
   890  	var actives []ssa.Value
   891  	for _, n := range g.Vertices {
   892  		if n.SCC != scc {
   893  			continue
   894  		}
   895  		if v, ok := n.Value.(ssa.Value); ok {
   896  			if _, ok := v.(*ssa.Const); !ok {
   897  				actives = append(actives, v)
   898  			}
   899  		}
   900  	}
   901  	return actives
   902  }
   903  
   904  func (g *Graph) AddEdge(from, to interface{}, ctrl bool) {
   905  	vf, ok := g.Vertices[from]
   906  	if !ok {
   907  		vf = &Vertex{Value: from}
   908  		g.Vertices[from] = vf
   909  	}
   910  	vt, ok := g.Vertices[to]
   911  	if !ok {
   912  		vt = &Vertex{Value: to}
   913  		g.Vertices[to] = vt
   914  	}
   915  	e := Edge{From: vf, To: vt, control: ctrl}
   916  	g.Edges = append(g.Edges, e)
   917  	vf.Succs = append(vf.Succs, e)
   918  }
   919  
   920  type Edge struct {
   921  	From, To *Vertex
   922  	control  bool
   923  }
   924  
   925  func (e Edge) String() string {
   926  	return fmt.Sprintf("%s -> %s", VertexString(e.From), VertexString(e.To))
   927  }
   928  
   929  func (g *Graph) FindSCCs() {
   930  	// use Tarjan to find the SCCs
   931  
   932  	index := 1
   933  	var s []*Vertex
   934  
   935  	scc := 0
   936  	var strongconnect func(v *Vertex)
   937  	strongconnect = func(v *Vertex) {
   938  		// set the depth index for v to the smallest unused index
   939  		v.index = index
   940  		v.lowlink = index
   941  		index++
   942  		s = append(s, v)
   943  		v.stack = true
   944  
   945  		for _, e := range v.Succs {
   946  			w := e.To
   947  			if w.index == 0 {
   948  				// successor w has not yet been visited; recurse on it
   949  				strongconnect(w)
   950  				if w.lowlink < v.lowlink {
   951  					v.lowlink = w.lowlink
   952  				}
   953  			} else if w.stack {
   954  				// successor w is in stack s and hence in the current scc
   955  				if w.index < v.lowlink {
   956  					v.lowlink = w.index
   957  				}
   958  			}
   959  		}
   960  
   961  		if v.lowlink == v.index {
   962  			for {
   963  				w := s[len(s)-1]
   964  				s = s[:len(s)-1]
   965  				w.stack = false
   966  				w.SCC = scc
   967  				if w == v {
   968  					break
   969  				}
   970  			}
   971  			scc++
   972  		}
   973  	}
   974  	for _, v := range g.Vertices {
   975  		if v.index == 0 {
   976  			strongconnect(v)
   977  		}
   978  	}
   979  
   980  	g.SCCs = make([][]*Vertex, scc)
   981  	for _, n := range g.Vertices {
   982  		n.SCC = scc - n.SCC - 1
   983  		g.SCCs[n.SCC] = append(g.SCCs[n.SCC], n)
   984  	}
   985  }
   986  
   987  func invertToken(tok token.Token) token.Token {
   988  	switch tok {
   989  	case token.LSS:
   990  		return token.GEQ
   991  	case token.GTR:
   992  		return token.LEQ
   993  	case token.EQL:
   994  		return token.NEQ
   995  	case token.NEQ:
   996  		return token.EQL
   997  	case token.GEQ:
   998  		return token.LSS
   999  	case token.LEQ:
  1000  		return token.GTR
  1001  	default:
  1002  		panic(fmt.Sprintf("unsupported token %s", tok))
  1003  	}
  1004  }
  1005  
  1006  func flipToken(tok token.Token) token.Token {
  1007  	switch tok {
  1008  	case token.LSS:
  1009  		return token.GTR
  1010  	case token.GTR:
  1011  		return token.LSS
  1012  	case token.EQL:
  1013  		return token.EQL
  1014  	case token.NEQ:
  1015  		return token.NEQ
  1016  	case token.GEQ:
  1017  		return token.LEQ
  1018  	case token.LEQ:
  1019  		return token.GEQ
  1020  	default:
  1021  		panic(fmt.Sprintf("unsupported token %s", tok))
  1022  	}
  1023  }
  1024  
  1025  type CopyConstraint struct {
  1026  	aConstraint
  1027  	X ssa.Value
  1028  }
  1029  
  1030  func (c *CopyConstraint) String() string {
  1031  	return fmt.Sprintf("%s = copy(%s)", c.Y().Name(), c.X.Name())
  1032  }
  1033  
  1034  func (c *CopyConstraint) Eval(g *Graph) Range {
  1035  	return g.Range(c.X)
  1036  }
  1037  
  1038  func (c *CopyConstraint) Operands() []ssa.Value {
  1039  	return []ssa.Value{c.X}
  1040  }
  1041  
  1042  func NewCopyConstraint(x, y ssa.Value) Constraint {
  1043  	return &CopyConstraint{
  1044  		aConstraint: aConstraint{
  1045  			y: y,
  1046  		},
  1047  		X: x,
  1048  	}
  1049  }