flow.go (1556B)
1 // Copyright 2026 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package flow implements a monotone flow analysis framework. 6 package dense 7 8 import ( 9 "cmp" 10 "slices" 11 12 "honnef.co/go/tools/internal/xtools-internal/graph" 13 ) 14 15 const debug = false 16 17 // Analysis is the result of a monotone analysis. Fact is the type of elements 18 // in the analysis semilattice, and represents the outcome of the analysis at 19 // every node and edge. 20 type Analysis[Fact any, NodeID comparable] struct { 21 nodeMap *graph.Index[NodeID] 22 ins []Fact // By NodeID 23 edges []edgeFact[Fact] // Sorted by (from, to) 24 } 25 26 // In returns the analysis fact on entry to nid. This is the merge of the facts 27 // on all incoming edges. 28 func (a *Analysis[Fact, NodeID]) In(nid NodeID) Fact { 29 return a.ins[a.nodeMap.Index(nid)] 30 } 31 32 // Edge returns the analysis fact propagated on edge from ==> to. 33 func (a *Analysis[Fact, NodeID]) Edge(from, to NodeID) Fact { 34 i, found := slices.BinarySearchFunc(a.edges, a.edge(from, to), edgeFact[Fact].compare) 35 if !found { 36 panic("no such edge") 37 } 38 return a.edges[i].fact 39 } 40 41 func (a *Analysis[Fact, NodeID]) edge(from, to NodeID) edge { 42 fromNum, toNum := a.nodeMap.Index(from), a.nodeMap.Index(to) 43 return edge{fromNum, toNum} 44 } 45 46 type edge struct { 47 from, to int 48 } 49 50 func (e edge) compare(f edge) int { 51 if v := cmp.Compare(e.from, f.from); v != 0 { 52 return v 53 } 54 return cmp.Compare(e.to, f.to) 55 } 56 57 type edgeFact[Fact any] struct { 58 edge 59 fact Fact 60 }