diff --git a/effekt/shared/src/main/scala/effekt/Compiler.scala b/effekt/shared/src/main/scala/effekt/Compiler.scala index 074590214..d7062642c 100644 --- a/effekt/shared/src/main/scala/effekt/Compiler.scala +++ b/effekt/shared/src/main/scala/effekt/Compiler.scala @@ -2,7 +2,7 @@ package effekt import effekt.PhaseResult.{ AllTransformed, CoreTransformed } import effekt.context.Context -import effekt.core.{ DirectStyleMutableState, Transformer } +import effekt.core.Transformer import effekt.namer.Namer import effekt.source.{ AnnotateCaptures, ExplicitCapabilities, ResolveExternDefs, ModuleDecl } import effekt.symbols.Module diff --git a/effekt/shared/src/main/scala/effekt/core/Deadcode.scala b/effekt/shared/src/main/scala/effekt/core/Deadcode.scala index e6f142a2f..8765d570a 100644 --- a/effekt/shared/src/main/scala/effekt/core/Deadcode.scala +++ b/effekt/shared/src/main/scala/effekt/core/Deadcode.scala @@ -36,144 +36,3 @@ object Deadcode { remove(Set(entrypoint), m) } -/** - * A simple reachability analysis for toplevel definitions - * - * TODO this could also be extended to cover record and interface declarations. - */ -class Reachable( - var reachable: Map[Id, Usage], - var stack: List[Id], - var seen: Set[Id] -) { - - def within(id: Id)(f: => Unit): Unit = { - stack = id :: stack - f - stack = stack.tail - } - - def process(d: Definition)(using defs: Map[Id, Definition]): Unit = - if stack.contains(d.id) then - reachable = reachable.updated(d.id, Usage.Recursive) - else d match { - case Definition.Def(id, block) => - seen = seen + id - within(id) { process(block) } - - case Definition.Let(id, _, binding) => - seen = seen + id - process(binding) - } - - def process(id: Id)(using defs: Map[Id, Definition]): Unit = - if (stack.contains(id)) { - reachable = reachable.updated(id, Usage.Recursive) - return; - } - - val count = reachable.get(id) match { - case Some(Usage.Once) => Usage.Many - case Some(Usage.Many) => Usage.Many - case Some(Usage.Recursive) => Usage.Recursive - case None => Usage.Once - } - reachable = reachable.updated(id, count) - if (!seen.contains(id)) { - defs.get(id).foreach(process) - } - - def process(b: Block)(using defs: Map[Id, Definition]): Unit = - b match { - case Block.BlockVar(id, annotatedTpe, annotatedCapt) => process(id) - case Block.BlockLit(tparams, cparams, vparams, bparams, body) => process(body) - case Block.Member(block, field, annotatedTpe) => process(block) - case Block.Unbox(pure) => process(pure) - case Block.New(impl) => process(impl) - } - - def process(s: Stmt)(using defs: Map[Id, Definition]): Unit = s match { - case Stmt.Scope(definitions, body) => - var currentDefs = defs - definitions.foreach { - case d: Definition.Def => - currentDefs += d.id -> d // recursive - process(d)(using currentDefs) - case d: Definition.Let => - process(d)(using currentDefs) - currentDefs += d.id -> d // non-recursive - } - process(body)(using currentDefs) - case Stmt.Return(expr) => process(expr) - case Stmt.Val(id, tpe, binding, body) => process(binding); process(body) - case Stmt.App(callee, targs, vargs, bargs) => - process(callee) - vargs.foreach(process) - bargs.foreach(process) - case Stmt.If(cond, thn, els) => process(cond); process(thn); process(els) - case Stmt.Match(scrutinee, clauses, default) => - process(scrutinee) - clauses.foreach { case (id, value) => process(value) } - default.foreach(process) - case Stmt.Alloc(id, init, region, body) => - process(init) - process(region) - process(body) - case Stmt.Var(id, init, capture, body) => - process(init) - process(body) - case Stmt.Get(id, capt, tpe) => process(id) - case Stmt.Put(id, tpe, value) => process(id); process(value) - case Stmt.Reset(body) => process(body) - case Stmt.Shift(prompt, body) => process(prompt); process(body) - case Stmt.Resume(k, body) => process(k); process(body) - case Stmt.Region(body) => process(body) - case Stmt.Hole() => () - } - - def process(e: Expr)(using defs: Map[Id, Definition]): Unit = e match { - case DirectApp(b, targs, vargs, bargs) => - process(b); - vargs.foreach(process) - bargs.foreach(process) - case Run(s) => process(s) - case Pure.ValueVar(id, annotatedType) => process(id) - case Pure.Literal(value, annotatedType) => () - case Pure.PureApp(b, targs, vargs) => process(b); vargs.foreach(process) - case Pure.Make(data, tag, vargs) => process(tag); vargs.foreach(process) - case Pure.Select(target, field, annotatedType) => process(target) - case Pure.Box(b, annotatedCapture) => process(b) - } - - def process(i: Implementation)(using defs: Map[Id, Definition]): Unit = - i.operations.foreach { op => process(op.body) } - -} - -object Reachable { - def apply(entrypoints: Set[Id], definitions: Map[Id, Definition]): Map[Id, Usage] = { - val analysis = new Reachable(Map.empty, Nil, Set.empty) - entrypoints.foreach(d => analysis.process(d)(using definitions)) - analysis.reachable - } - - def apply(m: ModuleDecl): Map[Id, Usage] = { - val analysis = new Reachable(Map.empty, Nil, Set.empty) - val defs = m.definitions.map(d => d.id -> d).toMap - m.definitions.foreach(d => analysis.process(d)(using defs)) - analysis.reachable - } - - def apply(s: Stmt.Scope): Map[Id, Usage] = { - val analysis = new Reachable(Map.empty, Nil, Set.empty) - analysis.process(s)(using Map.empty) - analysis.reachable - } -} - -enum Usage { - case Once - case Many - case Recursive -} - diff --git a/effekt/shared/src/main/scala/effekt/core/DirectStyleMutableState.scala b/effekt/shared/src/main/scala/effekt/core/DirectStyleMutableState.scala deleted file mode 100644 index 7242ad731..000000000 --- a/effekt/shared/src/main/scala/effekt/core/DirectStyleMutableState.scala +++ /dev/null @@ -1,74 +0,0 @@ -package effekt.core - -import effekt.PhaseResult.CoreTransformed -import effekt.context.Context -import effekt.symbols -import effekt.symbols.builtins.{ TState, TUnit } -import effekt.symbols.{ TmpBlock, TmpValue } -import effekt.{ CoreTransformed, Phase } - -import scala.annotation.targetName - -/** - * [[Phase]] on [[CoreTransformed]] to translate access to mutable state cells to - * direct style. - * - * e.g. val a = x.get(); s will become: let a = x.get(); s - * - * This is necessary for backends like JS, where we want to represent state using host language - * reference cells, without paying for the monadic abstraction. - */ -object DirectStyleMutableState extends Phase[CoreTransformed, CoreTransformed] { - - override val phaseName: String = "direct style mutable state" - - override def run(input: CoreTransformed)(using Context): Option[CoreTransformed] = input match { - case CoreTransformed(source, tree, mod, core) => - val direct = Context.timed(phaseName, source.name) { directStyle.rewrite(core) } - Some(CoreTransformed(source, tree, mod, direct)) - } - - object directStyle extends Tree.Rewrite { - override def stmt: PartialFunction[Stmt, Stmt] = { - - case Stmt.Val(y, ytpe, Get(x, tpe), s) => Let(y, ytpe, Get(rewrite(x), tpe), rewrite(s)) - - case Stmt.Val(y, ytpe, Put(x, tpe, v), s) => Let(y, ytpe, Put(x, tpe, rewrite(v)), rewrite(s)) - - case Get(x, tpe) => - val id = Id("tmp_get") - val binding = Get(x, tpe) - Let(id, binding.tpe, binding, Stmt.Return(Pure.ValueVar(id, tpe.result))) - - case Put(x, tpe, v) => - val id = Id("tmp_put") - val binding = Put(x, tpe, v) - Let(id, binding.tpe, binding, Stmt.Return(Pure.ValueVar(id, Type.TUnit))) - } - } - - object Get { - def unapply(s: Stmt): Option[(Block, BlockType.Function)] = s match { - case Stmt.App(Block.Member(x, TState.get, tpe: BlockType.Function), Nil, Nil, Nil) => Some((x, tpe)) - case Stmt.Get(id, capt, tpe) => - val stateType = Type.TState(tpe) - Some(BlockVar(id, stateType, capt), BlockType.Function(Nil, Nil, Nil, Nil, tpe)) - case _ => None - } - def apply(x: Block, tpe: BlockType): Expr = - DirectApp(Block.Member(x, TState.get, tpe), Nil, Nil, Nil) - } - - object Put { - def unapply(s: Stmt): Option[(Block, BlockType.Function, Pure)] = s match { - case Stmt.App(Block.Member(x, TState.put, tpe: BlockType.Function), Nil, List(v), Nil) => Some((x, tpe, v)) - case Stmt.Put(id, capt, value) => - val tpe = value.tpe - val stateType = Type.TState(tpe) - Some(BlockVar(id, stateType, capt), BlockType.Function(Nil, Nil, List(tpe), Nil, Type.TUnit), value) - case _ => None - } - def apply(x: Block, tpe: BlockType, value: Pure): Expr = - DirectApp(Block.Member(x, TState.put, tpe), Nil, List(value), Nil) - } -} diff --git a/effekt/shared/src/main/scala/effekt/core/Inline.scala b/effekt/shared/src/main/scala/effekt/core/Inline.scala index 77c857c04..18f91c607 100644 --- a/effekt/shared/src/main/scala/effekt/core/Inline.scala +++ b/effekt/shared/src/main/scala/effekt/core/Inline.scala @@ -128,6 +128,9 @@ object Inline { case Stmt.App(b, targs, vargs, bargs) => app(rewrite(b), targs, vargs.map(rewrite), bargs.map(rewrite)) + case Stmt.Invoke(b, method, methodTpe, targs, vargs, bargs) => + invoke(rewrite(b), method, methodTpe, targs, vargs.map(rewrite), bargs.map(rewrite)) + case Stmt.Reset(body) => rewrite(body) match { case BlockLit(tparams, cparams, vparams, List(prompt), body) if !used(prompt.id) => body @@ -173,7 +176,6 @@ object Inline { // congruences case b @ Block.BlockLit(tparams, cparams, vparams, bparams, body) => rewrite(b) - case Block.Member(block, field, annotatedTpe) => member(rewrite(block), field, annotatedTpe) case Block.Unbox(pure) => unbox(rewrite(pure)) case Block.New(impl) => New(rewrite(impl)) } @@ -224,6 +226,7 @@ object Inline { case Stmt.Return(expr) => false case Stmt.Val(id, annotatedTpe, binding, body) => tailResumptive(k, body) && !freeInStmt(binding) case Stmt.App(callee, targs, vargs, bargs) => false + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => false case Stmt.If(cond, thn, els) => !freeInExpr(cond) && tailResumptive(k, thn) && tailResumptive(k, els) // Interestingly, we introduce a join point making this more difficult to implement properly case Stmt.Match(scrutinee, clauses, default) => !freeInExpr(scrutinee) && clauses.forall { @@ -261,6 +264,7 @@ object Inline { case Stmt.Hole() => stmt case Stmt.Return(expr) => stmt case Stmt.App(callee, targs, vargs, bargs) => stmt + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => stmt case Stmt.Get(id, annotatedCapt, annotatedTpe) => stmt case Stmt.Put(id, annotatedCapt, value) => stmt } diff --git a/effekt/shared/src/main/scala/effekt/core/Parser.scala b/effekt/shared/src/main/scala/effekt/core/Parser.scala index cced7ef0e..7d80f3607 100644 --- a/effekt/shared/src/main/scala/effekt/core/Parser.scala +++ b/effekt/shared/src/main/scala/effekt/core/Parser.scala @@ -124,7 +124,10 @@ class CoreParsers(positions: Positions, names: Names) extends EffektLexers(posit | `val` ~> id ~ maybeTypeAnnotation ~ (`=` ~> stmt) ~ (`;` ~> stmt) ^^ { case id ~ tpe ~ binding ~ body => Stmt.Val(id, tpe.getOrElse(binding.tpe), binding, body) } - | block ~ maybeTypeArgs ~ valueArgs ~ blockArgs ^^ Stmt.App.apply + | block ~ (`.` ~> id ~ (`:` ~> blockType)).? ~ maybeTypeArgs ~ valueArgs ~ blockArgs ^^ { + case (recv ~ Some(method ~ tpe) ~ targs ~ vargs ~ bargs) => Invoke(recv, method, tpe, targs, vargs, bargs) + case (recv ~ None ~ targs ~ vargs ~ bargs) => App(recv, targs, vargs, bargs) + } | (`if` ~> `(` ~/> pure <~ `)`) ~ stmt ~ (`else` ~> stmt) ^^ Stmt.If.apply | `region` ~> blockLit ^^ Stmt.Region.apply | `var` ~> id ~ (`in` ~> id) ~ (`=` ~> pure) ~ (`;` ~> stmt) ^^ { case id ~ region ~ init ~ body => Alloc(id, init, region, body) } @@ -195,15 +198,6 @@ class CoreParsers(positions: Positions, names: Names) extends EffektLexers(posit // Blocks // ------ lazy val block: P[Block] = - ( blockNonMember ~ many((`.` ~> id) ~ (`:` ~> blockType)) ^^ { - case firstReceiver ~ fields => fields.foldLeft(firstReceiver) { - case (receiver, field ~ tpe) => Block.Member(receiver, field, tpe) - } - } - | blockNonMember - ) - - lazy val blockNonMember: P[Block] = ( id ~ (`:` ~> blockType) ~ (`@` ~> captures) ^^ Block.BlockVar.apply | `unbox` ~> pure ^^ Block.Unbox.apply | `new` ~> implementation ^^ Block.New.apply diff --git a/effekt/shared/src/main/scala/effekt/core/PolymorphismBoxing.scala b/effekt/shared/src/main/scala/effekt/core/PolymorphismBoxing.scala index c033ee772..c2057425c 100644 --- a/effekt/shared/src/main/scala/effekt/core/PolymorphismBoxing.scala +++ b/effekt/shared/src/main/scala/effekt/core/PolymorphismBoxing.scala @@ -215,17 +215,6 @@ object PolymorphismBoxing extends Phase[CoreTransformed, CoreTransformed] { case Block.BlockVar(id, annotatedTpe, annotatedCapt) => Block.BlockVar(id, transform(annotatedTpe), annotatedCapt) case b: Block.BlockLit => transform(b) - case Block.Member(block, field, annotatedTpe) => // TODO properly box/unbox arguments and result - val tpe = block.tpe.asInstanceOf[core.BlockType.Interface] - PContext.findInterface(tpe.name) match { - case None => // assume it's an external interface and will be handled elsewhere - Block.Member(transform(block), field, transform(annotatedTpe)) - case Some(ifce) => - val prop = ifce.properties.find { p => p.id == field }.getOrElse { Context.abort(s"Cannot find field ${field} in declaration ${ifce}") } - val propTpe = Type.substitute(prop.tpe.asInstanceOf[BlockType.Function], (ifce.tparams zip (tpe.targs.map(transformArg))).toMap, Map.empty) - val coerce = coercer[Block](transform(propTpe), transform(annotatedTpe)) - coerce(Block.Member(transform(block), field, transform(propTpe))) - } case Block.Unbox(pure) => Block.Unbox(transform(pure)) case Block.New(impl) => @@ -277,6 +266,56 @@ object PolymorphismBoxing extends Phase[CoreTransformed, CoreTransformed] { val bcoercers = (tBargs zip itpe.bparams).map { (a, p) => coercer[Block](a.tpe, p) } val fcoercer = coercer[Block](tpe, itpe, targs) fcoercer.call(calleeT, (vcoercers zip tVargs).map(_(_)), (bcoercers zip tBargs).map(_(_))) + + // [S](S) => (Int, S) + case Stmt.Invoke(callee, method, methodTpe: BlockType.Function, targs, vargs, bargs) => + // Double + + val calleeT = transform(callee) + + // [S](S) => (T, S) + val (tpe: BlockType.Function, interfaceParams, interfaceArgs) = calleeT.tpe match { + // [Int] + case BlockType.Interface(name, targs) => + PContext.findInterface(name) match { + // [T] + case Some(Interface(id, tparams, properties)) => + // op: [S](S) => (T, S) + val prop = properties.find { p => p.id == method }.getOrElse { Context.panic(pp"Cannot find field ${method} in declaration of ${id}") } + + (prop.tpe.asInstanceOf[BlockType.Function], tparams, targs) + case _ => + Context.panic(pp"Should not happen. Method call on extern interface: ${stmt}") + } + case _ => + Context.panic("Should not happen. Method call on non-interface") + } + + // [S](S) => (BoxedInt, S) + val boxedTpe = Type.substitute(tpe, (interfaceParams zip interfaceArgs.map(transformArg)).toMap, Map.empty).asInstanceOf[BlockType.Function] + + // duplicated from App + val itpe = Type.instantiate(methodTpe, targs, methodTpe.cparams.map(Set(_))) + val tVargs = vargs map transform + val tBargs = bargs map transform + val vcoercers = (tVargs zip boxedTpe.vparams).map { (a, p) => coercer(a.tpe, p) } + val bcoercers = (tBargs zip boxedTpe.bparams).map { (a, p) => coercer[Block](a.tpe, p) } + // (T, S) (Int, Double) + val rcoercer = coercer(tpe.result, itpe.result) + + val result = Invoke(calleeT, method, boxedTpe, targs.map(transformArg), (vcoercers zip tVargs).map(_(_)), (bcoercers zip tBargs).map(_(_))) + + // (BoxedInt, BoxedDouble) + val out = result.tpe + if (rcoercer.isIdentity) { + result + } else { + val orig = TmpValue("result") + Stmt.Val(orig, out, result, + Stmt.Return(rcoercer(Pure.ValueVar(orig, out)))) + } + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => ??? + case Stmt.Get(id, capt, tpe) => Stmt.Get(id, capt, transform(tpe)) case Stmt.Put(id, capt, value) => Stmt.Put(id, capt, transform(value)) case Stmt.If(cond, thn, els) => @@ -344,6 +383,8 @@ object PolymorphismBoxing extends Phase[CoreTransformed, CoreTransformed] { case Stmt.Hole() => Stmt.Hole() } + + def transform(expr: Expr)(using PContext): Expr = expr match { case DirectApp(b, targs, vargs, bargs) => val callee = transform(b) diff --git a/effekt/shared/src/main/scala/effekt/core/PrettyPrinter.scala b/effekt/shared/src/main/scala/effekt/core/PrettyPrinter.scala index 4bedd296e..96d11ed33 100644 --- a/effekt/shared/src/main/scala/effekt/core/PrettyPrinter.scala +++ b/effekt/shared/src/main/scala/effekt/core/PrettyPrinter.scala @@ -81,8 +81,6 @@ object PrettyPrinter extends ParenPrettyPrinter { case BlockVar(id, _, _) => toDoc(id) case BlockLit(tps, cps, vps, bps, body) => braces { space <> paramsToDoc(tps, vps, bps) <+> "=>" <+> nest(line <> toDoc(body)) <> line } - case Member(b, id, _) => - toDoc(b) <> "." <> id.name.toString case Unbox(e) => parens("unbox" <+> toDoc(e)) case New(handler) => "new" <+> toDoc(handler) } @@ -181,6 +179,9 @@ object PrettyPrinter extends ParenPrettyPrinter { case App(b, targs, vargs, bargs) => toDoc(b) <> argsToDoc(targs, vargs, bargs) + case Invoke(b, method, methodTpe, targs, vargs, bargs) => + toDoc(b) <> "." <> method.name.toString <> argsToDoc(targs, vargs, bargs) + case If(cond, thn, els) => "if" <+> parens(toDoc(cond)) <+> block(toDoc(thn)) <+> "else" <+> block(toDoc(els)) diff --git a/effekt/shared/src/main/scala/effekt/core/Reachable.scala b/effekt/shared/src/main/scala/effekt/core/Reachable.scala new file mode 100644 index 000000000..3d51c94f0 --- /dev/null +++ b/effekt/shared/src/main/scala/effekt/core/Reachable.scala @@ -0,0 +1,142 @@ +package effekt +package core + +/** + * A simple reachability analysis. + */ +class Reachable( + var reachable: Map[Id, Usage], + var stack: List[Id], + var seen: Set[Id] +) { + + def process(d: Definition)(using defs: Map[Id, Definition]): Unit = + if stack.contains(d.id) then + reachable = reachable.updated(d.id, Usage.Recursive) + else d match { + case Definition.Def(id, block) => + seen = seen + id + val before = stack + stack = id :: stack + process(block) + stack = before + + case Definition.Let(id, _, binding) => + seen = seen + id + process(binding) + } + + def process(id: Id)(using defs: Map[Id, Definition]): Unit = + if (stack.contains(id)) { + reachable = reachable.updated(id, Usage.Recursive) + return; + } + + val count = reachable.get(id) match { + case Some(Usage.Once) => Usage.Many + case Some(Usage.Many) => Usage.Many + case Some(Usage.Recursive) => Usage.Recursive + case None => Usage.Once + } + reachable = reachable.updated(id, count) + if (!seen.contains(id)) { + defs.get(id).foreach(process) + } + + def process(b: Block)(using defs: Map[Id, Definition]): Unit = + b match { + case Block.BlockVar(id, annotatedTpe, annotatedCapt) => process(id) + case Block.BlockLit(tparams, cparams, vparams, bparams, body) => process(body) + case Block.Unbox(pure) => process(pure) + case Block.New(impl) => process(impl) + } + + def process(s: Stmt)(using defs: Map[Id, Definition]): Unit = s match { + case Stmt.Scope(definitions, body) => + var currentDefs = defs + definitions.foreach { + case d: Definition.Def => + currentDefs += d.id -> d // recursive + process(d)(using currentDefs) + case d: Definition.Let => + process(d)(using currentDefs) + currentDefs += d.id -> d // non-recursive + } + process(body)(using currentDefs) + case Stmt.Return(expr) => process(expr) + case Stmt.Val(id, tpe, binding, body) => process(binding); process(body) + case Stmt.App(callee, targs, vargs, bargs) => + process(callee) + vargs.foreach(process) + bargs.foreach(process) + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => + process(callee) + process(method) + vargs.foreach(process) + bargs.foreach(process) + case Stmt.If(cond, thn, els) => process(cond); process(thn); process(els) + case Stmt.Match(scrutinee, clauses, default) => + process(scrutinee) + clauses.foreach { case (id, value) => process(value) } + default.foreach(process) + case Stmt.Alloc(id, init, region, body) => + process(init) + process(region) + process(body) + case Stmt.Var(id, init, capture, body) => + process(init) + process(body) + case Stmt.Get(id, capt, tpe) => process(id) + case Stmt.Put(id, tpe, value) => process(id); process(value) + case Stmt.Reset(body) => process(body) + case Stmt.Shift(prompt, body) => process(prompt); process(body) + case Stmt.Resume(k, body) => process(k); process(body) + case Stmt.Region(body) => process(body) + case Stmt.Hole() => () + } + + def process(e: Expr)(using defs: Map[Id, Definition]): Unit = e match { + case DirectApp(b, targs, vargs, bargs) => + process(b); + vargs.foreach(process) + bargs.foreach(process) + case Run(s) => process(s) + case Pure.ValueVar(id, annotatedType) => process(id) + case Pure.Literal(value, annotatedType) => () + case Pure.PureApp(b, targs, vargs) => process(b); vargs.foreach(process) + case Pure.Make(data, tag, vargs) => process(tag); vargs.foreach(process) + case Pure.Select(target, field, annotatedType) => process(field); process(target) + case Pure.Box(b, annotatedCapture) => process(b) + } + + def process(i: Implementation)(using defs: Map[Id, Definition]): Unit = + i.operations.foreach { op => process(op.body) } + +} + +object Reachable { + def apply(entrypoints: Set[Id], definitions: Map[Id, Definition]): Map[Id, Usage] = { + val analysis = new Reachable(Map.empty, Nil, Set.empty) + entrypoints.foreach(d => analysis.process(d)(using definitions)) + analysis.reachable + } + + def apply(m: ModuleDecl): Map[Id, Usage] = { + val analysis = new Reachable(Map.empty, Nil, Set.empty) + val defs = m.definitions.map(d => d.id -> d).toMap + m.definitions.foreach(d => analysis.process(d)(using defs)) + analysis.reachable + } + + def apply(s: Stmt.Scope): Map[Id, Usage] = { + val analysis = new Reachable(Map.empty, Nil, Set.empty) + analysis.process(s)(using Map.empty) + analysis.reachable + } +} + +enum Usage { + case Once + case Many + case Recursive +} diff --git a/effekt/shared/src/main/scala/effekt/core/Transformer.scala b/effekt/shared/src/main/scala/effekt/core/Transformer.scala index 890463b74..c32774a1f 100644 --- a/effekt/shared/src/main/scala/effekt/core/Transformer.scala +++ b/effekt/shared/src/main/scala/effekt/core/Transformer.scala @@ -224,11 +224,15 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { } } - def transformUnbox(tree: source.Term)(implicit C: Context): Block = - Unbox(transformAsPure(tree)) + def transformUnbox(tree: source.Term)(implicit C: Context): Block = tree match { + case source.Unbox(b) => Unbox(transformAsPure(b)) + case _ => Unbox(transformAsPure(tree)) + } - def transformBox(tree: source.Term)(implicit C: Context): Pure = - Box(transformAsBlock(tree), transform(Context.inferredCapture(tree))) + def transformBox(tree: source.Term)(implicit C: Context): Pure = tree match { + case source.Box(capt, block) => Box(transformAsBlock(tree), transform(Context.inferredCapture(block))) + case _ => Box(transformAsBlock(tree), transform(Context.inferredCapture(tree))) + } /** * Transforms the source to a function (expecting to be called using [[core.Stmt.App]] or an interface. @@ -242,18 +246,9 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { } case _: source.BlockLiteral => transformAsControlBlock(tree) case _: source.New => transformAsObject(tree) - case _ => transformUnboxOrSelect(tree) + case _ => transformUnbox(tree) } - private def transformUnboxOrSelect(tree: source.Term)(using Context): Block = tree match { - case s @ source.Select(receiver, id) => - Member(transformAsObject(receiver), s.definition, transform(Context.inferredBlockTypeOf(tree))) - - case source.Unbox(b) => - Unbox(transformAsPure(b)) - case _ => - transformUnbox(tree) - } /** * Transforms the source to an interface block */ @@ -267,7 +262,7 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { case source.New(impl) => New(transform(impl, None)) - case _ => transformUnboxOrSelect(tree) + case _ => transformUnbox(tree) } /** * Transforms the source to a function block that expects to be called using [[core.Stmt.App]]. @@ -336,7 +331,7 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { case s @ source.New(impl) => Context.abort(s"Expected a function but got an object instantiation: ${s}") - case _ => transformUnboxOrSelect(tree) + case _ => transformUnbox(tree) } def transformAsPure(tree: source.Term)(using Context): Pure = transformAsExpr(tree) match { @@ -346,14 +341,10 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { def transformAsExpr(tree: source.Term)(using Context): Expr = tree match { case v: source.Var => v.definition match { - case sym: VarBinder => + case sym: RefBinder => val stateType = Context.blockTypeOf(sym) val tpe = TState.extractType(stateType) - Context.bind(Get(sym, Set(sym.capture), transform(tpe))) - case sym: RegBinder => - val stateType = Context.blockTypeOf(sym) - val getType = operationAtCallsite(stateType, TState.get) - Context.bind(App(Member(BlockVar(sym), TState.get, transform(getType)), Nil, Nil, Nil)) + Context.bind(Get(sym, transform(Context.captureOf(sym)), transform(tpe))) case sym: ValueSymbol => ValueVar(sym) case sym: BlockSymbol => transformBox(tree) } @@ -467,15 +458,9 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { case source.Hole(stmts) => Context.bind(Hole()) - case a @ source.Assign(id, expr) => a.definition match { - case sym: VarBinder => Context.bind(Put(sym, Set(sym.capture), transformAsPure(expr))) - case sym: RegBinder => - val e = transformAsPure(expr) - val sym = a.definition - val stateType = Context.blockTypeOf(sym) - val putType = operationAtCallsite(stateType, TState.put) - Context.bind(App(Member(BlockVar(sym), TState.put, transform(putType)), Nil, List(e), Nil)) - } + case a @ source.Assign(id, expr) => + val sym = a.definition + Context.bind(Put(sym, transform(Context.captureOf(sym)), transformAsPure(expr))) // methods are dynamically dispatched, so we have to assume they are `control`, hence no PureApp. case c @ source.MethodCall(receiver, id, targs, vargs, bargs) => @@ -494,7 +479,7 @@ object Transformer extends Phase[Typechecked, CoreTransformed] { // Do not pass type arguments for the type constructor of the receiver. val remainingTypeArgs = typeArgs.drop(operation.interface.tparams.size) - Context.bind(App(Member(rec, operation, opType), remainingTypeArgs, valueArgs, blockArgs)) + Context.bind(Invoke(rec, operation, opType, remainingTypeArgs, valueArgs, blockArgs)) case c @ source.Call(source.ExprTarget(source.Unbox(expr)), targs, vargs, bargs) => diff --git a/effekt/shared/src/main/scala/effekt/core/Tree.scala b/effekt/shared/src/main/scala/effekt/core/Tree.scala index 13f489181..485c56e67 100644 --- a/effekt/shared/src/main/scala/effekt/core/Tree.scala +++ b/effekt/shared/src/main/scala/effekt/core/Tree.scala @@ -27,6 +27,10 @@ import effekt.util.messages.ErrorReporter * │ │─ [[ Def ]] * │ │─ [[ Include ]] * │ + * │─ [[ ExternBody ]] + * │ │─ [[ StringExternBody ]] + * │ │─ [[ Unsupported ]] + * │ * │─ [[ Definition ]] * │ │─ [[ Def ]] * │ │─ [[ Let ]] @@ -39,7 +43,6 @@ import effekt.util.messages.ErrorReporter * │─ [[ Block ]] * │ │─ [[ BlockVar ]] * │ │─ [[ BlockLit ]] - * │ │─ [[ Member ]] * │ │─ [[ Unbox ]] * │ │─ [[ New ]] * │ @@ -52,6 +55,7 @@ import effekt.util.messages.ErrorReporter * │ │─ [[ Return ]] * │ │─ [[ Val ]] * │ │─ [[ App ]] + * │ │─ [[ Invoke ]] * │ │─ [[ If ]] * │ │─ [[ Match ]] * │ │─ [[ Region ]] @@ -59,7 +63,9 @@ import effekt.util.messages.ErrorReporter * │ │─ [[ Var ]] * │ │─ [[ Get ]] * │ │─ [[ Put ]] - * │ │─ [[ Try ]] + * │ │─ [[ Reset ]] + * │ │─ [[ Shift ]] + * │ │─ [[ Resume ]] * │ │─ [[ Hole ]] * │ * │─ [[ Implementation ]] @@ -233,7 +239,6 @@ export Pure.* * ─ [[ Block ]] * │─ [[ BlockVar ]] * │─ [[ BlockLit ]] - * │─ [[ Member ]] * │─ [[ Unbox ]] * │─ [[ New ]] * @@ -242,7 +247,6 @@ export Pure.* enum Block extends Tree { case BlockVar(id: Id, annotatedTpe: BlockType, annotatedCapt: Captures) case BlockLit(tparams: List[Id], cparams: List[Id], vparams: List[Param.ValueParam], bparams: List[Param.BlockParam], body: Stmt) - case Member(block: Block, field: Id, annotatedTpe: BlockType) case Unbox(pure: Pure) case New(impl: Implementation) @@ -269,6 +273,7 @@ export Param.* * │─ [[ Return ]] * │─ [[ Val ]] * │─ [[ App ]] + * │─ [[ Invoke ]] * │─ [[ If ]] * │─ [[ Match ]] * │─ [[ Region ]] @@ -276,7 +281,9 @@ export Param.* * │─ [[ Var ]] * │─ [[ Get ]] * │─ [[ Put ]] - * │─ [[ Try ]] + * │─ [[ Reset ]] + * │─ [[ Shift ]] + * │─ [[ Resume ]] * │─ [[ Hole ]] * * ------------------------------------------- @@ -289,6 +296,7 @@ enum Stmt extends Tree { case Return(expr: Pure) case Val(id: Id, annotatedTpe: ValueType, binding: Stmt, body: Stmt) case App(callee: Block, targs: List[ValueType], vargs: List[Pure], bargs: List[Block]) + case Invoke(callee: Block, method: Id, methodTpe: BlockType, targs: List[ValueType], vargs: List[Pure], bargs: List[Block]) // Local Control Flow case If(cond: Pure, thn: Stmt, els: Stmt) @@ -365,17 +373,6 @@ object normal { case _ => if (definitions.isEmpty) body else Stmt.Scope(definitions, body) } - // new { def f = BLOCK }.f = BLOCK - def member(b: Block, field: Id, annotatedTpe: BlockType): Block = b match { - case Block.New(impl) => - val Operation(name, tps, cps, vps, bps, body) = - impl.operations.find(op => op.name == field).getOrElse { - INTERNAL_ERROR("Should not happen") - } - BlockLit(tps, cps, vps, bps, body) - case _ => Block.Member(b, field, annotatedTpe) - } - // TODO perform record selection here, if known def select(target: Pure, field: Id, annotatedType: ValueType): Pure = Select(target, field, annotatedType) @@ -386,6 +383,17 @@ object normal { case other => Stmt.App(callee, targs, vargs, bargs) } + def invoke(callee: Block, method: Id, methodTpe: BlockType, targs: List[ValueType], vargs: List[Pure], bargs: List[Block]): Stmt = + callee match { + case Block.New(impl) => + val Operation(name, tps, cps, vps, bps, body) = + impl.operations.find(op => op.name == method).getOrElse { + INTERNAL_ERROR("Should not happen") + } + reduce(BlockLit(tps, cps, vps, bps, body), targs, vargs, bargs) + case other => Invoke(callee, method, methodTpe, targs, vargs, bargs) + } + def reset(body: BlockLit): Stmt = body match { // case BlockLit(tparams, cparams, vparams, List(prompt), // Stmt.Shift(prompt2, body) if prompt.id == prompt2.id => ??? @@ -591,7 +599,7 @@ object Tree { } def rewrite(matchClause: (Id, BlockLit)): (Id, BlockLit) = matchClause match { - case (p, b) => (p, rewrite(b).asInstanceOf[BlockLit]) + case (p, b) => (p, rewrite(b)) } } } @@ -656,8 +664,6 @@ object Variables { case Block.BlockVar(id, annotatedTpe, annotatedCapt) => Variables.block(id, annotatedTpe, annotatedCapt) case Block.BlockLit(tparams, cparams, vparams, bparams, body) => free(body) -- all(vparams, bound) -- all(bparams, bound) - - case Block.Member(block, field, annotatedTpe) => free(block) case Block.Unbox(pure) => free(pure) case Block.New(impl) => free(impl) } @@ -690,6 +696,7 @@ object Variables { case Stmt.Return(expr) => free(expr) case Stmt.Val(id, tpe, binding, body) => free(binding) ++ (free(body) -- Variables.value(id, binding.tpe)) case Stmt.App(callee, targs, vargs, bargs) => free(callee) ++ all(vargs, free) ++ all(bargs, free) + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => free(callee) ++ all(vargs, free) ++ all(bargs, free) case Stmt.If(cond, thn, els) => free(cond) ++ free(thn) ++ free(els) case Stmt.Match(scrutinee, clauses, default) => free(scrutinee) ++ all(default, free) ++ all(clauses, { case (id, lit) => free(lit) @@ -790,6 +797,9 @@ object substitutions { case App(callee, targs, vargs, bargs) => App(substitute(callee), targs.map(substitute), vargs.map(substitute), bargs.map(substitute)) + case Invoke(callee, method, methodTpe, targs, vargs, bargs) => + Invoke(substitute(callee), method, substitute(methodTpe), targs.map(substitute), vargs.map(substitute), bargs.map(substitute)) + case If(cond, thn, els) => If(substitute(cond), substitute(thn), substitute(els)) @@ -845,9 +855,6 @@ object substitutions { bparams.map(p => substitute(p)(using shadowedTypelevel)), substitute(body)(using shadowedTypelevel shadowParams (vparams ++ bparams))) - case Member(block, field, annotatedTpe) => - Member(substitute(block), field, substitute(annotatedTpe)) - case Unbox(pure) => Unbox(substitute(pure)) diff --git a/effekt/shared/src/main/scala/effekt/core/Type.scala b/effekt/shared/src/main/scala/effekt/core/Type.scala index 64e433268..0d8fc1f04 100644 --- a/effekt/shared/src/main/scala/effekt/core/Type.scala +++ b/effekt/shared/src/main/scala/effekt/core/Type.scala @@ -176,7 +176,6 @@ object Type { val bparams = bps.map { p => p.tpe } BlockType.Function(tparams, cparams, vparams, bparams, body.tpe) - case Block.Member(b, field, tpe) => tpe case Block.Unbox(pure) => pure.tpe.asInstanceOf[ValueType.Boxed].tpe case Block.New(impl) => impl.tpe } @@ -184,7 +183,6 @@ object Type { case Block.BlockVar(id, tpe, capt) => capt case Block.BlockLit(tparams, cparams, vparams, bparams, body) => body.capt -- cparams - case Block.Member(block, field, tpe) => block.capt case Block.Unbox(pure) => pure.tpe.asInstanceOf[ValueType.Boxed].capt case Block.New(impl) => impl.capt } @@ -195,7 +193,8 @@ object Type { case Stmt.Val(id, tpe, binding, body) => body.tpe case Stmt.App(callee, targs, vargs, bargs) => instantiate(callee.functionType, targs, bargs.map(_.capt)).result - + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => + instantiate(methodTpe.asInstanceOf, targs, bargs.map(_.capt)).result case Stmt.If(cond, thn, els) => merge(thn.tpe, els.tpe, covariant = true) case Stmt.Match(scrutinee, clauses, default) => val allTypes = clauses.map { case (_, cl) => cl.returnType } ++ default.map(_.tpe).toList @@ -229,6 +228,7 @@ object Type { case Stmt.Return(expr) => Set.empty case Stmt.Val(id, tpe, binding, body) => binding.capt ++ body.capt case Stmt.App(callee, targs, vargs, bargs) => callee.capt ++ bargs.flatMap(_.capt).toSet + case Stmt.Invoke(callee, method, methodTpe, targs, vargs, bargs) => callee.capt ++ bargs.flatMap(_.capt).toSet case Stmt.If(cond, thn, els) => thn.capt ++ els.capt case Stmt.Match(scrutinee, clauses, default) => clauses.flatMap { (_, cl) => cl.capt }.toSet ++ default.toSet.flatMap(s => s.capt) case Stmt.Alloc(id, init, region, body) => Set(region) ++ body.capt diff --git a/effekt/shared/src/main/scala/effekt/cps/Transformer.scala b/effekt/shared/src/main/scala/effekt/cps/Transformer.scala index 299da2df5..0b7ffc54c 100644 --- a/effekt/shared/src/main/scala/effekt/cps/Transformer.scala +++ b/effekt/shared/src/main/scala/effekt/cps/Transformer.scala @@ -95,20 +95,11 @@ object Transformer { binding(id, value) { transform(body, ks, k) } }) - case core.Stmt.App(core.Block.Member(ref: core.Block.BlockVar, TState.get, tpe), Nil, Nil, Nil) => - val x = Id("x") - cps.Get(ref.id, x, k(ValueVar(x), ks)) - - case core.Stmt.App(core.Block.Member(ref: core.Block.BlockVar, TState.put, tpe), Nil, List(value), Nil) => - cps.Put(ref.id, transform(value), k(cps.Pure.Literal(()), ks)) + case core.Stmt.App(callee, targs, vargs, bargs) => + App(transform(callee), vargs.map(transform), bargs.map(transform), MetaCont(ks), k.reify) - case core.Stmt.App(callee, targs, vargs, bargs) => callee match { - case core.Block.Member(block, field, tpe) => - Invoke(transform(block), field, vargs.map(transform), bargs.map(transform), MetaCont(ks), k.reify) - - case _ => - App(transform(callee), vargs.map(transform), bargs.map(transform), MetaCont(ks), k.reify) - } + case core.Stmt.Invoke(callee, method, tpe, targs, vargs, bargs) => + Invoke(transform(callee), method, vargs.map(transform), bargs.map(transform), MetaCont(ks), k.reify) case core.Stmt.If(cond, thn, els) => withJoinpoint(k) { k2 => @@ -219,7 +210,6 @@ object Transformer { def transform(block: core.Block)(using C: TransformationContext): Block = block match { case core.Block.BlockVar(id, annotatedTpe, annotatedCapt) => C.lookupBlock(id) case b @ core.Block.BlockLit(tparams, cparams, vparams, bparams, body) => transformBlockLit(b) - case core.Block.Member(block, field, annotatedTpe) => sys error "shouldn't happen" case core.Block.Unbox(pure) => Unbox(transform(pure)) case core.Block.New(impl) => New(transform(impl)) } diff --git a/effekt/shared/src/main/scala/effekt/generator/chez/Transformer.scala b/effekt/shared/src/main/scala/effekt/generator/chez/Transformer.scala index 18c31b495..ab983ef7b 100644 --- a/effekt/shared/src/main/scala/effekt/generator/chez/Transformer.scala +++ b/effekt/shared/src/main/scala/effekt/generator/chez/Transformer.scala @@ -77,6 +77,8 @@ trait Transformer { def toChezExpr(stmt: Stmt): chez.Expr = stmt match { case Return(e) => pure(toChez(e)) case App(b, targs, vargs, bargs) => chez.Call(toChez(b), vargs.map(toChez) ++ bargs.map(toChez)) + case Invoke(b, method, methodTpe, targs, vargs, bargs) => + chez.Call(chez.Call(chez.Variable(nameRef(method)), List(toChez(b))), vargs.map(toChez) ++ bargs.map(toChez)) case If(cond, thn, els) => chez.If(toChez(cond), toChezExpr(thn), toChezExpr(els)) case Val(id, tpe, binding, body) => bind(toChezExpr(binding), nameDef(id), toChez(body)) // empty matches are translated to a hole in chez scheme @@ -190,9 +192,6 @@ trait Transformer { case b @ BlockLit(tps, cps, vps, bps, body) => toChez(b) - case Member(b, field, tpe) => - chez.Call(chez.Variable(nameRef(field)), List(toChez(b))) - case Unbox(e) => toChez(e) case New(impl) => toChez(impl) diff --git a/effekt/shared/src/main/scala/effekt/generator/js/JavaScript.scala b/effekt/shared/src/main/scala/effekt/generator/js/JavaScript.scala index 9421df95a..ded31be25 100644 --- a/effekt/shared/src/main/scala/effekt/generator/js/JavaScript.scala +++ b/effekt/shared/src/main/scala/effekt/generator/js/JavaScript.scala @@ -4,7 +4,6 @@ package js import effekt.PhaseResult.CoreTransformed import effekt.context.Context -import effekt.core.DirectStyleMutableState import kiama.output.PrettyPrinterTypes.Document import kiama.util.Source diff --git a/effekt/shared/src/main/scala/effekt/machine/Transformer.scala b/effekt/shared/src/main/scala/effekt/machine/Transformer.scala index 51ce30ce9..eb6a182ae 100644 --- a/effekt/shared/src/main/scala/effekt/machine/Transformer.scala +++ b/effekt/shared/src/main/scala/effekt/machine/Transformer.scala @@ -2,7 +2,7 @@ package effekt package machine import effekt.context.Context -import effekt.core.{ DeclarationContext, Definition, Id, given } +import effekt.core.{ Block, DeclarationContext, Definition, Id, given } import effekt.symbols.{ Symbol, TermSymbol } import effekt.symbols.builtins.TState import effekt.util.messages.ErrorReporter @@ -129,7 +129,7 @@ object Transformer { case (core.Definition.Def(id, core.New(impl)), rest) => New(Variable(transform(id), transform(impl.interface)), transform(impl), rest) - case (d @ core.Definition.Def(_, _: core.BlockVar | _: core.Member | _: core.Unbox), rest) => + case (d @ core.Definition.Def(_, _: core.BlockVar | _: core.Unbox), rest) => ErrorReporter.abort(s"block definition: $d") } @@ -142,47 +142,52 @@ object Transformer { transform(binding) ) - // hardcoded translation for get and put. - // TODO remove this when interfaces are correctly translated - case core.App(core.Member(core.BlockVar(x, core.Type.TState(stateType), _), TState.get, _), targs, Nil, Nil) => - if (targs.exists(requiresBoxing)) { ErrorReporter.abort(s"Types ${targs} are used as type parameters but would require boxing.") } - - val tpe = transform(stateType) - val variable = Variable(freshName(x.name.name + "_value"), tpe) - val reference = Variable(transform(x), Type.Reference(tpe)) - LoadVar(variable, reference, Return(List(variable))) - - case core.App(core.Member(core.BlockVar(x, core.Type.TState(stateType), _), TState.put, _), targs, List(arg), Nil) => - if (targs.exists(requiresBoxing)) { ErrorReporter.abort(s"Types ${targs} are used as type parameters but would require boxing.") } - - val tpe = transform(stateType) - val variable = Variable(freshName("ignored"), Positive()); - val reference = Variable(transform(x), Type.Reference(tpe)) - transform(arg).run { value => - StoreVar(reference, value, - Construct(variable, builtins.Unit, List(), - Return(List(variable)))) + case core.App(callee, targs, vargs, bargs) => + if (targs.exists(requiresBoxing)) { ErrorReporter.panic(s"Types ${targs} are used as type parameters but would require boxing.") } + transform(vargs, bargs).run { (values, blocks) => + callee match { + case Block.BlockVar(id, annotatedTpe, annotatedCapt) => + BPC.info.getOrElse(id, sys.error(s"Cannot find block info for ${id}.\n${BPC.info}")) match { + // Unknown Jump to function + case BlockInfo.Parameter(tpe: core.BlockType.Function) => + Invoke(Variable(transform(id), transform(tpe)), builtins.Apply, values ++ blocks) + + // Known Jump + case BlockInfo.Definition(freeParams, blockParams) => + val label = machine.Label(transform(id), blockParams ++ freeParams) + Substitute(label.environment.zip(values ++ blocks), Jump(label)) + + case _ => ErrorReporter.panic("Applying an object") + } + + case Block.Unbox(pure) => + transform(pure).run { callee => Invoke(callee, builtins.Apply, values ++ blocks) } + + case Block.New(impl) => + ErrorReporter.panic("Applying an object") + + case Block.BlockLit(tparams, cparams, vparams, bparams, body) => + ErrorReporter.panic("Call to block literal should have been reduced") + } } - case core.App(callee, targs, vargs, bargs) => + case core.Invoke(callee, method, methodTpe, targs, vargs, bargs) => if (targs.exists(requiresBoxing)) { ErrorReporter.abort(s"Types ${targs} are used as type parameters but would require boxing.") } - transformCallee(callee).run { callee => - transform(vargs, bargs).run { (values, blocks) => - callee match { - // Here we actually need a substitution to prepare the environment for the jump - case Callee.Known(label) => - Substitute(label.environment.zip(values ++ blocks), Jump(label)) + val opTag = DeclarationContext.getPropertyTag(method) + transform(vargs, bargs).run { (values, blocks) => + callee match { + case Block.BlockVar(id, tpe, capt) => + Invoke(Variable(transform(id), transform(tpe)), opTag, values ++ blocks) - case Callee.UnknownFunction(variable, tpe) => - Invoke(variable, builtins.Apply, values ++ blocks) + case Block.Unbox(pure) => + transform(pure).run { callee => Invoke(callee, opTag, values ++ blocks) } - case Callee.Method(receiver, tpe, tag) => - Invoke(receiver, tag, values ++ blocks) + case Block.New(impl) => + ErrorReporter.panic("Method call to known object should have been reduced") - case Callee.UnknownObject(variable, tpe) => - E.panic("Cannot call an object.") - } + case Block.BlockLit(tparams, cparams, vparams, bparams, body) => + ErrorReporter.panic("Invoking a method on a function") } } @@ -292,49 +297,6 @@ object Transformer { blocks <- traverse(bargs)(transformBlockArg) } yield (values, blocks) - enum Callee { - case Known(label: machine.Label) - case UnknownFunction(variable: machine.Variable, tpe: core.BlockType.Function) - case UnknownObject(variable: machine.Variable, tpe: core.BlockType.Interface) - case Method(receiver: machine.Variable, tpe: core.BlockType.Interface, tag: Int) - } - - def transformCallee(block: core.Block)(using BPC: BlocksParamsContext, DC: DeclarationContext, E: ErrorReporter): Binding[Callee] = block match { - case core.BlockVar(id, tpe, capt) => - BPC.info.getOrElse(id, sys.error(s"Cannot find block info for ${id}.\n${BPC.info}")) match { - // Unknown Jump to function - case BlockInfo.Parameter(tpe: core.BlockType.Function) => - pure(Callee.UnknownFunction(Variable(transform(id), transform(tpe)), tpe)) - - // Unknown object as a receiver - case BlockInfo.Parameter(tpe: core.BlockType.Interface) => - pure(Callee.UnknownObject(Variable(transform(id), transform(tpe)), tpe)) - - // Known Jump - case BlockInfo.Definition(freeParams, blockParams) => - pure(Callee.Known(machine.Label(transform(id), blockParams ++ freeParams))) - } - case core.Member(block, op, annotatedTpe) => transformCallee(block).flatMap { - case Callee.UnknownObject(id, tpe) => - val opTag = DeclarationContext.getPropertyTag(op) - pure(Callee.Method(id, tpe, opTag)) - case _ => - E.panic("Receiver of a method call needs to be an object") - } - case core.BlockLit(tparams, cparams, vparams, bparams, body) => - E.panic("Optimizer / normalizer should have removed the beta reduction ({() => ...}())!") - case core.Unbox(pure) => - transform(pure).map { f => - pure.tpe match { - case core.ValueType.Boxed(tpe: core.BlockType.Function, capt) => Callee.UnknownFunction(f, tpe) - case core.ValueType.Boxed(tpe: core.BlockType.Interface, capt) => Callee.UnknownObject(f, tpe) - case _ => E.panic("Can only unbox boxed types") - } - } - case core.New(impl) => - E.panic("Optimizer / normalizer should have removed the beta reduction ({() => ...}())!") - } - def transformBlockArg(block: core.Block)(using BPC: BlocksParamsContext, DC: DeclarationContext, E: ErrorReporter): Binding[Variable] = block match { case core.BlockVar(id, tpe, capt) if isDefinition(id) => // Passing a top-level function directly, so we need to eta-expand turning it into a closure @@ -366,9 +328,6 @@ object Transformer { New(variable, transform(impl), k(variable)) } - case core.Member(b, field, annotatedTpe) => - E.panic("Cannot pass member selection as argument") - case core.Unbox(pure) => transform(pure) } diff --git a/effekt/shared/src/main/scala/effekt/machine/Tree.scala b/effekt/shared/src/main/scala/effekt/machine/Tree.scala index 31b81188d..8f1020665 100644 --- a/effekt/shared/src/main/scala/effekt/machine/Tree.scala +++ b/effekt/shared/src/main/scala/effekt/machine/Tree.scala @@ -90,14 +90,14 @@ case class Clause(parameters: Environment, body: Statement) * │─ [[ Switch ]] * │─ [[ New ]] * │─ [[ Invoke ]] - * │─ [[ Allocate ]] - * │─ [[ Load ]] - * │─ [[ Store ]] + * │─ [[ Var ]] + * │─ [[ LoadVar ]] + * │─ [[ StoreVar ]] * │─ [[ PushFrame ]] * │─ [[ Return ]] - * │─ [[ NewStack ]] - * │─ [[ PushStack ]] - * │─ [[ PopStacks ]] + * │─ [[ Reset ]] + * │─ [[ Resume ]] + * │─ [[ Shift ]] * │─ [[ ForeignCall ]] * │─ [[ LiteralInt ]] * │─ [[ LiteralDouble ]] diff --git a/effekt/shared/src/main/scala/effekt/source/Tree.scala b/effekt/shared/src/main/scala/effekt/source/Tree.scala index dacffce9d..194b551e2 100644 --- a/effekt/shared/src/main/scala/effekt/source/Tree.scala +++ b/effekt/shared/src/main/scala/effekt/source/Tree.scala @@ -12,6 +12,15 @@ import effekt.symbols.Symbol * ─ [[ Tree ]] * │─ [[ NoSource ]] * │─ [[ Comment ]] + * │─ [[ FeatureFlag ]] + * │ │─ [[ NamedFeatureFlag ]] + * │ │─ [[ Default ]] + * │ + * │─ [[ ExternBody ]] + * │ │─ [[ StringExternBody ]] + * │ │─ [[ EffektExternBody ]] + * │ │─ [[ Unsupported ]] + * │ * │─ [[ Id ]] * │ │─ [[ IdDef ]] * │ │─ [[ IdRef ]] @@ -52,6 +61,10 @@ import effekt.symbols.Symbol * │ │─ [[ ExprTarget ]] * │ * │─ [[ MatchClause ]] + * │─ [[ MatchGuard ]] + * │ │─ [[ BooleanGuard ]] + * │ │─ [[ PatternGuard ]] + * │ * │─ [[ MatchPattern ]] * │ │─ [[ AnyPattern ]] * │ │─ [[ TagPattern ]] @@ -205,6 +218,7 @@ export Param.* * │─ [[ RegDef ]] * │─ [[ VarDef ]] * │─ [[ DefDef ]] + * │─ [[ NamespaceDef ]] * │─ [[ InterfaceDef ]] * │─ [[ DataDef ]] * │─ [[ RecordDef ]] diff --git a/effekt/shared/src/main/scala/effekt/symbols/symbols.scala b/effekt/shared/src/main/scala/effekt/symbols/symbols.scala index 34a773993..6ddbb68aa 100644 --- a/effekt/shared/src/main/scala/effekt/symbols/symbols.scala +++ b/effekt/shared/src/main/scala/effekt/symbols/symbols.scala @@ -124,7 +124,6 @@ object TrackedParam { case class BlockParam(name: Name, tpe: Option[BlockType]) extends TrackedParam case class ResumeParam(module: Module) extends TrackedParam { val name = Name.local("resume") } case class ExternResource(name: Name, tpe: BlockType) extends TrackedParam - } export TrackedParam.*