11package is .hail .expr .ir
22
33import is .hail .expr .ir .defs .Ref
4- import is .hail .types .virtual .Type
54
65import scala .collection .mutable
76
8- case class FreeVariableEnv (boundVars : Env [Unit ], freeVars : mutable.Set [Name ]) {
9- def this (boundVars : Env [Unit ]) =
10- this (boundVars, mutable.Set .empty)
11-
12- private def copy (boundVars : Env [Unit ]): FreeVariableEnv =
13- new FreeVariableEnv (boundVars, freeVars)
14-
7+ case class FreeVariableEnv (boundVars : Set [Name ], freeVars : mutable.Set [Name ]) {
158 def visitRef (name : Name ): Unit =
169 if (! boundVars.contains(name))
1710 freeVars += name
1811
19- def bindIterable (bindings : Seq [(Name , Type )]): FreeVariableEnv =
20- copy(boundVars.bindIterable( bindings.view.map(b => (b ._1, ())) ))
12+ def bindIterable (bindings : Seq [(Name , Any )]): FreeVariableEnv =
13+ copy(boundVars = boundVars ++ bindings.view.map(_ ._1))
2114
2215 def getFreeVars : Env [Unit ] = new Env [Unit ].bindIterable(freeVars.view.map(n => (n, ())))
2316}
2417
18+ // The free variables of eval, agg and scan.
2519case class FreeVariableBindingEnv (
2620 evalVars : Option [FreeVariableEnv ],
2721 aggVars : Option [FreeVariableEnv ],
2822 scanVars : Option [FreeVariableEnv ],
29- ) extends GenericBindingEnv [FreeVariableBindingEnv , Type ] {
30- override def extend (bindings : Bindings [Type ]): FreeVariableBindingEnv = {
31- val Bindings (all, eval, agg, scan, relational, dropEval) = bindings
32- var newEnv = this
33- if (dropEval) newEnv = newEnv.noEval
34- agg match {
35- case AggEnv .Drop => newEnv = newEnv.noAgg
36- case AggEnv .Promote => newEnv = newEnv.promoteAgg
37- case AggEnv .Create (bindings) =>
38- newEnv = newEnv.createAgg.bindAgg(bindings.map(all): _* )
39- case AggEnv .Bind (bindings) =>
40- newEnv = newEnv.bindAgg(bindings.map(all): _* )
41- case _ =>
42- }
43- scan match {
44- case AggEnv .Drop => newEnv = newEnv.noScan
45- case AggEnv .Promote => newEnv = newEnv.promoteScan
46- case AggEnv .Create (bindings) =>
47- newEnv = newEnv.createScan.bindScan(bindings.map(all): _* )
48- case AggEnv .Bind (bindings) =>
49- newEnv = newEnv.bindScan(bindings.map(all): _* )
50- case _ =>
51- }
52- if (eval.nonEmpty) newEnv = newEnv.bindEval(eval.map(all): _* )
53- if (relational.nonEmpty)
54- newEnv = newEnv.bindRelational(relational.map(all): _* )
55- newEnv
56- }
57-
23+ ) {
5824 def visitRef (name : Name ): Unit =
5925 evalVars.foreach(_.visitRef(name))
6026
@@ -63,44 +29,58 @@ case class FreeVariableBindingEnv(
6329 aggVars.map(_.getFreeVars),
6430 scanVars.map(_.getFreeVars),
6531 )
32+ }
6633
67- override def promoteAgg : FreeVariableBindingEnv =
68- copy(evalVars = aggVars, aggVars = None )
69-
70- override def promoteScan : FreeVariableBindingEnv =
71- copy(evalVars = scanVars, scanVars = None )
72-
73- override def bindEval (bindings : (Name , Type )* ): FreeVariableBindingEnv =
74- copy(evalVars = evalVars.map(_.bindIterable(bindings)))
75-
76- override def noEval : FreeVariableBindingEnv = copy(evalVars = None )
77-
78- override def bindAgg (bindings : (Name , Type )* ): FreeVariableBindingEnv =
79- copy(aggVars = aggVars.map(_.bindIterable(bindings)))
80-
81- override def bindScan (bindings : (Name , Type )* ): FreeVariableBindingEnv =
82- copy(scanVars = scanVars.map(_.bindIterable(bindings)))
83-
84- override def createAgg : FreeVariableBindingEnv = copy(aggVars = evalVars)
34+ object FreeVariableBindingEnv {
35+ type E [_] = FreeVariableBindingEnv
36+
37+ // As BindingEnv's, but binding or promoting a missing scope does nothing, and relational
38+ // names aren't tracked
39+ implicit object freeVariableScopes extends Scopes [E ] {
40+ override def bind [A ](e : E [A ], s : EnvScope , bs : Seq [(Name , A )]): E [A ] =
41+ s match {
42+ case Scope .EVAL => e.copy(evalVars = e.evalVars.map(_.bindIterable(bs)))
43+ case Scope .AGG => e.copy(aggVars = e.aggVars.map(_.bindIterable(bs)))
44+ case Scope .SCAN => e.copy(scanVars = e.scanVars.map(_.bindIterable(bs)))
45+ case Scope .REL => e
46+ }
8547
86- override def createScan : FreeVariableBindingEnv = copy(scanVars = evalVars)
48+ override def create [A ](e : E [A ], s : Scope ): E [A ] =
49+ s match {
50+ case Scope .AGG => e.copy(aggVars = e.evalVars)
51+ case Scope .SCAN => e.copy(scanVars = e.evalVars)
52+ case Scope .EVAL => throw new IllegalArgumentException (" can't create eval" )
53+ }
8754
88- override def noAgg : FreeVariableBindingEnv = copy(aggVars = None )
55+ override def drop [A ](e : E [A ], s : Scope ): E [A ] =
56+ s match {
57+ case Scope .EVAL => e.copy(evalVars = None )
58+ case Scope .AGG => e.copy(aggVars = None )
59+ case Scope .SCAN => e.copy(scanVars = None )
60+ }
8961
90- override def noScan : FreeVariableBindingEnv = copy(scanVars = None )
62+ override def promote [A ](e : E [A ], s : Scope ): E [A ] =
63+ s match {
64+ case Scope .EVAL => e
65+ case Scope .AGG => e.copy(evalVars = e.aggVars, aggVars = None )
66+ case Scope .SCAN => e.copy(evalVars = e.scanVars, scanVars = None )
67+ }
9168
92- override def bindRelational (bindings : (Name , Type )* ): FreeVariableBindingEnv =
93- this
69+ override def fresh [A ](e : E [A ]): E [A ] =
70+ FreeVariableBindingEnv (None , None , None )
71+ }
9472}
9573
9674object FreeVariables {
9775 def apply (ir : IR , supportsAgg : Boolean , supportsScan : Boolean ): BindingEnv [Unit ] = {
98- val env = FreeVariableBindingEnv (
99- Some (new FreeVariableEnv (Env .empty)),
100- if (supportsAgg) Some (new FreeVariableEnv (Env .empty)) else None ,
101- if (supportsScan) Some (new FreeVariableEnv (Env .empty)) else None ,
102- )
103- VisitIR .withEnv(ir, env) { (ir, env) =>
76+ val env =
77+ FreeVariableBindingEnv (
78+ Some (FreeVariableEnv (Set .empty, mutable.Set .empty)),
79+ Option .when(supportsAgg)(FreeVariableEnv (Set .empty, mutable.Set .empty)),
80+ Option .when(supportsScan)(FreeVariableEnv (Set .empty, mutable.Set .empty)),
81+ )
82+
83+ VisitIR .withEnv[FreeVariableBindingEnv .E , Unit ](ir, env)((_, _) => ()) { (ir, env) =>
10484 ir match {
10585 case Ref (name, _) => env.visitRef(name)
10686 case _ =>
0 commit comments