Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast-ANF implementation #40

Open
wants to merge 66 commits into
base: fast-anf
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
d9e53ae
Some tests for higher-order pattern variables
LPTK Oct 10, 2017
e0b60d3
Generalize `hopHole` to handle arbitrary patterns: introduce `hopHole2`
LPTK Oct 29, 2017
3ff5419
FastANF implementation
Oct 29, 2017
e4c6479
Make ANF not retarded: proper letin implementation and arguments binding
LPTK Oct 20, 2017
f7ab7b5
HOPHole implementation
Oct 29, 2017
d5d3161
Don’t inline all arguments (cf. some are by-name); do it in `substitute`
LPTK Oct 31, 2017
f410417
Add HOPHole2 support
Oct 29, 2017
65dffc8
Handle effects
Oct 31, 2017
fa8929a
Fix HOPHole, defhole, and some cleaning
Nov 20, 2017
7b7dea5
Handle when HOPHole arg is simply a BV
Nov 20, 2017
aff2a99
Don't try to extract again failed extractions
Nov 21, 2017
b43ef09
Factor out extract updates
Nov 21, 2017
045ebe1
Make updateExtract infix
Nov 21, 2017
f2c934c
Right-bias either and fix some errors
Nov 22, 2017
7ffe328
Failed rewriting will not affect input
Nov 23, 2017
9fcb174
Make HOPHole args by-name args
Nov 24, 2017
e7372d5
Corrected HOPHole and code removal semantics
Nov 24, 2017
6855997
Fix HOPHoles
Nov 25, 2017
fedff93
Fix issue where a HOPHole extraction would happen too early in the ex…
Nov 26, 2017
0bb0ecc
Small HOPHole optimization and updated tests
Nov 27, 2017
80f46c5
Add way to shortcut extraction, hophole extraction branches now updat…
Nov 27, 2017
bf125b1
Cleanup
Nov 28, 2017
a6f6170
Fix issue where impure statements could be matched wrongly
Nov 28, 2017
9c85231
Some more extraction tests
Nov 28, 2017
4497d26
Fix issue where a hole would disappear when not referenced
Nov 28, 2017
3431b25
Fix issue where rewriting would remove the rest of xtee
Nov 28, 2017
0ff74a5
Holes now extract the entire let-binding
Nov 28, 2017
7f2e64b
Remove redundant no flags left check
Nov 28, 2017
3aef763
Check flags when looking for the return value
Nov 30, 2017
0c20ec6
Fix issue where substitute gets called outside a reification context
Nov 30, 2017
5127329
Fix issue where the generated code is wrong when there's a hole at th…
Nov 30, 2017
13ae0a0
Remove extremely slow intermediate step in the HOPHole extraction
Nov 30, 2017
44145b9
Remove remnants of the unreachable mechanism
Nov 30, 2017
0764fa9
Test rewriting with HOPHoles, lambdas, and with mutliple occurences
Dec 1, 2017
59eb658
Remove pure statements that depend on removed statements
Dec 1, 2017
8c34177
Fix issue where rewriting would remove statements that are part of th…
Dec 1, 2017
21facd9
Fix some rewriting and extraction issues
Dec 3, 2017
c114a94
Remove explicit of passing done predicate
Dec 3, 2017
f0616ec
Fix issue where order of pure statements sometimes mattered, defholes…
Dec 4, 2017
95c2c4b
Fix issue where you couldn't extract an impure statement
Dec 4, 2017
8b145b2
HOPHoles now replace all the occurences of a pattern
Dec 4, 2017
d928e38
Fix issue where HOPHoles couldn't extract nestet letbindings
Dec 4, 2017
5bafcef
Add HOPHole tests
Dec 5, 2017
201706b
Cleanup tests
Dec 5, 2017
f9d8205
Automatically convert to ANF valid reps, correct handling of lambdas,…
Dec 6, 2017
c038600
Add lambda rewriting tests
Dec 7, 2017
e137ed1
Fix issue where rewriting in the arg position of a methodApp would ge…
Dec 7, 2017
7b4e0c5
Fix issue where HOPHoles would disregard pureness and add ByName wrapper
Dec 10, 2017
2188610
Documentation and cleanup
Dec 11, 2017
57926a3
Simplify hole extraction and add mechanism to revert to the default i…
Dec 13, 2017
9afe790
Rename HOPV tests file to be more uniform
Dec 13, 2017
8d1093c
Simplify extraction with a SplicedArgument
Dec 13, 2017
a9f83e5
Remove wrong and buggy check
Dec 13, 2017
cdb21e3
Better function name
Dec 13, 2017
3473bc5
Fix issue where rewriting with code having unused statements would no…
Dec 15, 2017
06c3f8a
Simplify merging of xtee and generated code
Dec 16, 2017
6f37095
Fix documentation and cleanup
Dec 17, 2017
0ada464
Move filterLBs to call-site
Dec 17, 2017
7f4388b
HOPV foldLeft extraction test
Dec 17, 2017
6b50f95
Fix issue where generated code would not appear in the right position…
Dec 17, 2017
0b58dab
Add HOPV test, documentation, and cleaning
Dec 18, 2017
f8ef360
Remove catch-all cases
Dec 18, 2017
02f8c62
Simplify handling of failed matches
Dec 19, 2017
6c5360c
Add HOP test and cleanup
Dec 19, 2017
4f8b85d
Add helper functions
Dec 20, 2017
6593318
Add documentation and cleanup
Jan 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/main/scala/squid/lang/InspectableBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ trait InspectableBase extends IntermediateBase with quasi.QuasiBase with TraceDe

}
protected implicit class ProtectedInspectableRepOps(private val self: Rep) {
def extract (that: Rep) = baseSelf.extract(self, that)
def extract (that: Rep) = baseSelf.extractRep(self, that)
}
implicit class InspectableRepOps(private val self: Rep) {
/** Note: this is only a to-level call to `base.extractRep`; not supposed to be called in implementations of `extract` itself */
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/squid/lang/IntermediateBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ trait IntermediateBase extends Base { ibase: IntermediateBase =>

def reinterpret(r: Rep, newBase: Base)(extrudedHandle: (BoundVal => newBase.Rep) = DefaultExtrudedHandler): newBase.Rep

// TODO rename to `defaultValue`
def nullValue[T: IRType]: IR[T,{}]


Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/squid/lang/Optimizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait Optimizer {
//final def optimizeRep(pgrm: Rep): Rep = pipeline(pgrm)
final def optimizeRep(pgrm: Rep): Rep = { // TODO do this Transformer's `pipeline`......?
val r = pipeline(pgrm)
if (!(r eq pgrm)) substitute(r) else r // only calls substitute if a transformation actually happened
if (!(r eq pgrm)) insertAfterTransformation(r) else r // only calls insertAfterTransformation if a transformation actually happened
}
final def optimize[T,C](pgrm: IR[T,C]): IR[T,C] = `internal IR`[T,C](optimizeRep(pgrm.rep))

Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/squid/quasi/MetaBases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ trait MetaBases {
def hole(name: String, typ: TypeRep): Rep = q"$Base.hole($name, $typ)"
def hopHole(name: String, typ: TypeRep, yes: List[List[BoundVal]], no: List[BoundVal]): Rep =
q"$Base.hopHole($name, $typ, ${yes map (_ map (_._2))}, ${no map (_._2)})"
override def hopHole2(name: String, typ: TypeRep, argss: List[List[Rep]], visible: List[BoundVal]): Rep =
q"$Base.hopHole2($name, $typ, ${argss}, ${visible map (_._2)})"
def splicedHole(name: String, typ: TypeRep): Rep = q"$Base.splicedHole($name, $typ)"

def substitute(r: => Rep, defs: Map[String, Rep]): Rep =
Expand Down
19 changes: 18 additions & 1 deletion core/src/main/scala/squid/quasi/QuasiBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ self: Base =>
def substitute(r: => Rep, defs: Map[String, Rep]): Rep
def substituteLazy(r: => Rep, defs: Map[String, () => Rep]): Rep = substitute(r, defs map (kv => kv._1 -> kv._2()))

def insertAfterTransformation(r: => Rep, defs: Map[String, Rep]): Rep = substitute(r, defs)

/** Not yet used: should eventually be defined by all IRs as something different than hole */
def freeVar(name: String, typ: TypeRep) = hole(name, typ)

Expand All @@ -46,6 +48,14 @@ self: Base =>
* this should check that the extracted term does not contain any reference to a bound value contained in the `no`
* parameter, and it should extract a function term with the arity of the `yes` parameter. */
def hopHole(name: String, typ: TypeRep, yes: List[List[BoundVal]], no: List[BoundVal]): Rep
def hopHole2(name: String, typ: TypeRep, args: List[List[Rep]], visible: List[BoundVal]): Rep = {
// TODO remove `hopHole` and implement this correctly everywhere
//val vars = args map (_ map (_.asInstanceOf[BoundVal]))\
// ^ Note: this will succeed even if there are some non-BoundVal, because BoundVal is eliminated by erasure
// it's actually wrong (in AST, readVal(_:BoundVal) adds a Rep wrapper!
//hopHole(name, typ, vars, visible.toSet -- vars.flatten toList)
throw new UnsupportedOperationException("Higher-order patterns")
}

/** Pattern hole in type position */
def typeHole(name: String): TypeRep
Expand All @@ -62,6 +72,8 @@ self: Base =>
/* if (defs isEmpty) r else */ // <- This "optimization" is not welcome, as some IRs (ANF) may relie on `substitute` being called for all insertions
substitute(r, defs.toMap)

final def insertAfterTransformation(r: => Rep, defs: (String, Rep)*): Rep = insertAfterTransformation(r, defs.toMap)

protected def mkIR[T,C](r: Rep): IR[T,C] = new IR[T,C] {
val rep = r
override def equals(that: Any): Boolean = that match {
Expand Down Expand Up @@ -291,6 +303,8 @@ self: Base =>
res
}

protected def mergeAll(as: Extract*): Option[Extract] = mergeAll(as.map(Some(_)))

def mergeableReps(a: Rep, b: Rep): Boolean = a =~= b

def mergeTypes(a: TypeRep, b: TypeRep): Option[TypeRep] =
Expand Down Expand Up @@ -320,11 +334,14 @@ self: Base =>
def $Code[T](q: Code[T]): T = ??? // TODO B/E -- also, rename to 'unquote'?
def $Code[A,B](q: Code[A] => Code[B]): A => B = ???

/* To support hole syntax `xs?` (old syntax `$$xs`) (in ction) or `$xs` (in xtion) */
/* To support hole syntax `?xs` (old syntax `$$xs`) (in ction) or `$xs` (in xtion) */
def $$[T](name: Symbol): T = ???
/* To support hole syntax `$$xs: _*` (in ction) or `$xs: _*` (in xtion) */
def $$_*[T](name: Symbol): Seq[T] = ???

/** Higher-order pattern */
def $$_hop[T](name: Symbol)(args: Any*): T = ???


implicit def liftFun[A:IRType,B,C](qf: IR[A,C] => IR[B,C]): IR[A => B,C] = {
val bv = bindVal("lifted", typeRepOf[A], Nil) // add TODO annotation recording the lifting?
Expand Down
128 changes: 63 additions & 65 deletions core/src/main/scala/squid/quasi/QuasiEmbedder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,11 @@ class QuasiEmbedder[C <: whitebox.Context](val c: C) {

/** holes: Seq(either term or type); splicedHoles: which holes are spliced term holes (eg: List($xs*))
* holes in ction mode are interpreted as free variables (and are never spliced)
* unquotedTypes contains the types unquoted in (in ction mode with $ and in xtion mode with $$)
* TODO: actually use `unquotedTypes`!
* TODO maybe this should go in QuasiMacros... */
def applyQQ(Base: Tree, tree: c.Tree, holes: Seq[Either[TermName,TypeName]],
splicedHoles: collection.Set[TermName], hopvHoles: collection.Map[TermName,List[List[TermName]]],
typeBounds: Map[TypeName,EitherOrBoth[Tree,Tree]],
unquotedTypes: Seq[(TypeName, Type, Tree)], unapply: Option[c.Tree], config: QuasiConfig): c.Tree = {
* unquotedTypes contains the types that are inserted (in ction mode with $ and in xtion mode with $$) */
def applyQQ(Base: Tree, tree: c.Tree, holes: Seq[Either[TermName,TypeName]],
splicedHoles: collection.Set[TermName], hopHoles: collection.Set[TermName],
typeBounds: Map[TypeName,EitherOrBoth[Tree,Tree]],
unquotedTypes: Seq[(TypeName, Type, Tree)], unapply: Option[c.Tree], config: QuasiConfig): c.Tree = {

//debug("HOLES:",holes)

Expand Down Expand Up @@ -226,7 +224,7 @@ class QuasiEmbedder[C <: whitebox.Context](val c: C) {


apply(Base, finalTree, termScope, config, unapply,
typeSymbols, holeSymbols, holes, splicedHoles, hopvHoles, termHoles, typeHoles, typedTree, typedTreeType, stmts, convNames, unquotedTypes)
typeSymbols, holeSymbols, holes, splicedHoles, hopHoles, termHoles, typeHoles, typedTree, typedTreeType, stmts, convNames, unquotedTypes)

}

Expand All @@ -242,7 +240,7 @@ class QuasiEmbedder[C <: whitebox.Context](val c: C) {
def apply(
baseTree: Tree, rawTree: c.Tree, termScopeParam: List[Type], config: QuasiConfig, unapply: Option[c.Tree],
typeSymbols: Map[TypeName, Symbol], holeSymbols: Set[Symbol],
holes: Seq[Either[TermName,TypeName]], splicedHoles: collection.Set[TermName], hopvHoles: collection.Map[TermName,List[List[TermName]]],
holes: Seq[Either[TermName,TypeName]], splicedHoles: collection.Set[TermName], hopHoles: collection.Set[TermName],
termHoles: Set[TermName], typeHoles: Set[TypeName], typedTree: Tree, typedTreeType: Type, stmts: List[Tree],
convNames: Set[TermName], unquotedTypes: Seq[(TypeName, Type, Tree)]
): c.Tree = {
Expand Down Expand Up @@ -322,6 +320,23 @@ class QuasiEmbedder[C <: whitebox.Context](val c: C) {

override def liftTerm(x: Tree, parent: Tree, expectedType: Option[Type], inVarargsPos: Boolean)(implicit ctx: Map[TermSymbol, b.BoundVal]): b.Rep = {
object HoleName { def unapply(tr: Tree) = Some(holeName(tr,x)) }
def mkHoleType(name: String, tpt: Tree) = expectedType match {
case None if tpt.tpe <:< Nothing => throw EmbeddingException(s"No type info for hole '$name'" + (
if (debug.debugOptionEnabled) s", in: $parent" else "" )) // TODO: check only after we have explored all repetitions of the hole? (not sure if possible)
case Some(tp) =>
assert(!SCALA_REPEATED(tp.typeSymbol.fullName.toString))

if (tp <:< Nothing) parent match {
case q"$_: $_" => // this hole is ascribed explicitly; the Nothing type must be desired
case _ => macroContext.warning(macroContext.enclosingPosition,
s"Type inferred for hole '$name' was Nothing. Ascribe the hole explicitly to remove this warning.") // TODO show real hole in its original form
}

val mergedTp = if (tp <:< tpt.tpe || tpt.tpe <:< Nothing) tp else tpt.tpe
debug(s"[Hole '$name'] Expected",tp," required",tpt.tpe," merged",mergedTp)

mergedTp
}
x match {


Expand Down Expand Up @@ -465,74 +480,57 @@ class QuasiEmbedder[C <: whitebox.Context](val c: C) {
throw QuasiException("Unknown use of free variable syntax operator `?`.")


/** Handling of higher-order patterns: */
case q"$baseTree.$$$$_hop[$tpt](${nameTree @ HoleName(name)})(..$args)" => // TODO check baseTree
// TODO remove _extracted_ binders (as in `val $x = ...`) from 'visible' bindings?; add them to context requirements...
debug("HOP",tpt,nameTree,args)

val holeType = mkHoleType(name, tpt)

// TODO handle contexts and FVs...
// TODO make sure HOPV holes with the same name are not repeated? or at least have the same param types
// Q: handle HOPV holes in spliced position?

val termName = TermName(name)

val hopvType = FunctionType(args map (_.tpe) : _*)(holeType)
termHoleInfo(termName) = Map() -> hopvType

val largs = args map (arg => b.byName(liftTerm(arg,x,None,false)))

b.hopHole2(name, liftType(holeType), (largs)::Nil, ctx.values.toList)


/** Replaces calls to $$(name) with actual holes */
case q"$baseTree.$$$$[$tpt]($nameTree)" => // TODO check baseTree

val name = holeName(nameTree, x)

val holeType = expectedType match {
case None if tpt.tpe <:< Nothing => throw EmbeddingException(s"No type info for hole '$name'" + (
if (debug.debugOptionEnabled) s", in: $parent" else "" )) // TODO: check only after we have explored all repetitions of the hole? (not sure if possible)
case Some(tp) =>
assert(!SCALA_REPEATED(tp.typeSymbol.fullName.toString))

if (tp <:< Nothing) parent match {
case q"$_: $_" => // this hole is ascribed explicitly; the Nothing type must be desired
case _ => macroContext.warning(macroContext.enclosingPosition,
s"Type inferred for hole '$name' was Nothing. Ascribe the hole explicitly to remove this warning.") // TODO show real hole in its original form
}

val mergedTp = if (tp <:< tpt.tpe || tpt.tpe <:< Nothing) tp else tpt.tpe
debug(s"[Hole '$name'] Expected",tp," required",tpt.tpe," merged",mergedTp)

mergedTp
}

val holeType = mkHoleType(name, tpt)

//if (splicedHoles(TermName(name))) throw EmbeddingException(s"Misplaced spliced hole: '$name'") // used to be: q"$Base.splicedHole[${_expectedType}](${name.toString})"

val termName = TermName(name)

hopvHoles get TermName(name) match {
case Some(idents) =>

// TODO make sure HOPV holes withb the same name are not repeated? or at least have the same param types
// TODO handle HOPV holes in spliced position?

val scp = ctx map { case k -> v => k.name -> (k -> v) }
val identVals = idents map (_ map scp)
val yes = identVals map (_ map (_._2))
val keys = idents.flatten.toSet
val no = scp.filterKeys(!keys(_)).values.map(_._2).toList
debug(s"HOPV: yes=$yes; no=$no")
val List(identVals2) = identVals // FIXME generalize
val hopvType = FunctionType(identVals2 map (_._1.typeSignature) : _*)(holeType)
termHoleInfo(termName) = Map() -> hopvType
b.hopHole(name, liftType(holeType), yes, no)

case _ =>
if (unapply isEmpty) {
debug(s"Free variable: $name: $tpt")
freeVariableInstances ::= name -> holeType
// TODO maybe aggregate glb type beforehand so we can pass the precise type here... could even pass the _same_ hole!
} else {
//val termName = TermName(name)
val scp = ctx.keys map (k => k.name -> k.typeSignature) toMap;
termHoleInfo get termName map { case (scp0, holeType0) =>
val newScp = scp0 ++ scp.map { case (n,t) => lub(t :: scp0.getOrElse(n, Any) :: Nil) }
newScp -> lub(holeType :: holeType0 :: Nil)
} getOrElse {
termHoleInfo(termName) = scp -> holeType
}
}

if (splicedHoles(TermName(name)))
b.splicedHole(name, liftType(holeType))
else b.hole(name, liftType(holeType))

if (unapply isEmpty) {
debug(s"Free variable: $name: $tpt")
freeVariableInstances ::= name -> holeType
// TODO maybe aggregate glb type beforehand so we can pass the precise type here... could even pass the _same_ hole!
} else {
//val termName = TermName(name)
val scp = ctx.keys map (k => k.name -> k.typeSignature) toMap;
termHoleInfo get termName map { case (scp0, holeType0) =>
val newScp = scp0 ++ scp.map { case (n,t) => lub(t :: scp0.getOrElse(n, Any) :: Nil) }
newScp -> lub(holeType :: holeType0 :: Nil)
} getOrElse {
termHoleInfo(termName) = scp -> holeType
}
}

if (splicedHoles(TermName(name)))
b.splicedHole(name, liftType(holeType))
else b.hole(name, liftType(holeType))

/** Removes implicit conversions that were generated in order to apply the subtyping knowledge extracted from pattern matching */
case q"${Ident(name:TermName)}.apply($x)" if convNames(name) =>
liftTerm(x, parent, typeIfNotNothing(x.tpe))
Expand Down Expand Up @@ -642,7 +640,7 @@ class QuasiEmbedder[C <: whitebox.Context](val c: C) {
val typeTypesToExtract = typeSymbols mapValues { sym => tq"$baseTree.IRType[$sym]" }

val extrTyps = holes.map {
case Left(vname) => termTypesToExtract(vname)
case Left(vname) => termTypesToExtract(vname) // TODO B/E
case Right(tname) => typeTypesToExtract(tname) // TODO B/E
}
debug("Extracted Types: "+extrTyps.map(showCode(_)).mkString(", "))
Expand Down
23 changes: 11 additions & 12 deletions core/src/main/scala/squid/quasi/QuasiMacros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class QuasiMacros(val c: whitebox.Context) {
holeSymbols = Set(),
holes = Seq(),
splicedHoles = Set(),
hopvHoles = Map(),
hopHoles = Set(),
termHoles = Set(),
typeHoles = Set(),
typedTree = code,
Expand Down Expand Up @@ -200,7 +200,7 @@ class QuasiMacros(val c: whitebox.Context) {

var holes: List[(Either[TermName,TypeName], Tree)] = Nil // (Left(value-hole) | Right(type-hole), original-hole-tree)
val splicedHoles = mutable.Set[TermName]()
val hopvHoles = mutable.Map[TermName,List[List[TermName]]]()
val hopvHoles = mutable.Set[TermName]()
var typeBounds: List[(TypeName, EitherOrBoth[Tree,Tree])] = Nil

// Keeps track of which holes still have not been found in the source code
Expand Down Expand Up @@ -302,18 +302,17 @@ class QuasiMacros(val c: whitebox.Context) {
case Ident(name: TermName) if builder.holes.contains(name) =>
mkTermHole(name, false)

// Identify and treat Higher-Order Pattern Variables (HOPV)
case q"${Ident(name: TermName)}(...$argss)" if isUnapply && builder.holes.contains(name) =>
val idents = argss map (_ map {
case Ident(name:TermName) => name
case e => throw EmbeddingException(s"Unexpected expression in higher-order pattern variable argument: ${showCode(e)}")
})
val hole = builder.holes(name)
val n = hole.name filter (_.toString != "_") getOrElse (
// Identify and treat Higher-Order Patterns (HOP)
case q"${Ident(nme: TermName)}(...$argss)" if isUnapply && builder.holes.contains(nme) =>
val List(args) = argss // TODO handle ...$argss
val hole = builder.holes(nme)
val name = hole.name filter (_.toString != "_") getOrElse (
throw QuasiException("All higher-order holes should be named.") // Q: necessary restriction?
) toTermName;
hopvHoles += n -> idents
mkTermHole(name, false)
hopvHoles += name
remainingHoles -= nme
holes ::= Left(name) -> hole.tree
q"$base.$$$$_hop(${Symbol(name toString)})(..$args)"

// Interprets bounds on extracted types, like in: `case List[$t where (Null <:< t <:< AnyRef)]`:
case tq"${Ident(name: TypeName)} where $bounds" if isUnapply && builder.holes.contains(name.toTermName) =>
Expand Down
6 changes: 6 additions & 0 deletions src/main/scala/squid/ir/AST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ trait AST extends InspectableBase with ScalaTyping with ASTReinterpreter with Ru
override def hopHole(name: String, typ: TypeRep, yes: List[List[Val]], no: List[Val]) = rep(new HOPHole(name, typ, yes, no))
class HOPHole(name: String, typ: TypeRep, val yes: List[List[Val]], val no: List[Val]) extends HoleClass(name, typ)()

override def hopHole2(name: String, typ: TypeRep, args: List[List[Rep]], visible: List[BoundVal]): Rep = {
// TODO replace `hopHole`
val vars = args map (_ map (r => dfn(r).asInstanceOf[BoundVal]))
hopHole(name, typ, vars, visible.toSet -- vars.flatten toList)
}

case class Constant(value: Any) extends Def {
lazy val typ = value match {
case () => TypeRep(ruh.Unit)
Expand Down
Loading