diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala index 82dddf6b28..89a2ee18e1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/deforest/Rewrite.scala @@ -14,9 +14,6 @@ import hkmc2.codegen.flowAnalysis.* class DeforestRewriter(val solver: DeforestFusionSolver)(using Raise): - def apply(): Program = - if newBody is pre.pgrm.main then pre.pgrm - else Program(pre.pgrm.imports, newBody) val collector = solver.constraintSolver.collector given tl: TraceLogger = solver.tl @@ -180,10 +177,8 @@ class DeforestRewriter(val solver: DeforestFusionSolver)(using Raise): val branchName = whichBranch.fold("_dflt")(c => s"_${c.ctorClsName}") val scrutName = dest._1.getReferredSym.nme val branchFnNme = s"${dest.instId.mkFunName}$$$scrutName$branchName" - val owner = pre.res.matchScrutToCtxOfMatch(dest._1).collectFirst: - case pre.InCtx.Cls(cls) => cls.isym new BlockMemberSymbol(branchFnNme, Nil, true) - -> new TermSymbol(Fun, owner, Tree.Ident(branchFnNme)) + -> new TermSymbol(Fun, N, Tree.Ident(branchFnNme)) ) // compute the function parameters corresponding to ctor fields of branch funs branchFunParamFieldSyms.getOrElseUpdate( @@ -211,15 +206,8 @@ class DeforestRewriter(val solver: DeforestFusionSolver)(using Raise): restFunId, locally: val restFunName = dest.instId.mkFunName + s"$$${nme}_rest" - val owner = matchOrLabelId match - case label: LabelSymbol => - pre.res.labelSymToCtxOfLabel(label).collectFirst: - case pre.InCtx.Cls(cls) => cls.isym - case dtorId: ResultId => - pre.res.matchScrutToCtxOfMatch(dtorId).collectFirst: - case pre.InCtx.Cls(cls) => cls.isym new BlockMemberSymbol(restFunName, Nil, true) - -> new TermSymbol(Fun, owner, Tree.Ident(restFunName)) + -> new TermSymbol(Fun, N, Tree.Ident(restFunName)) ) val (ps, restBeforeParent) = getParentLabelOrMatchesAndRestBefore(matchOrLabelId) restOriginalBodiesAndParentRest.getOrElseUpdate( @@ -359,242 +347,235 @@ class DeforestRewriter(val solver: DeforestFusionSolver)(using Raise): allBranchesOfDtor.keysIterator.foreach(fvsForDtor) } - // compute new program body - val newBody = - - def mkFunRef(target: (BlockMemberSymbol, TermSymbol)): Path = - val (bms, tSym) = target - tSym.owner match - case Some(owner) => - Select(owner.asThis, Tree.Ident(bms.nme))(S(tSym)) - case None => - bms.asMemberRef(tSym) - def mkCall(target: (BlockMemberSymbol, TermSymbol), args: Ls[ValueSymbol]): Call = - Call( - mkFunRef(target), - args.map(a => Arg(N, a.asPath)) ne_:: Nil - )(true, false, false) - def mkReturnCall(target: (BlockMemberSymbol, TermSymbol), args: Ls[ValueSymbol]): Block = - Return(mkCall(target, args)) - - class Rewriter(instId: InstantiationId) extends BlockTransformer(_symSubst): - extension (resId: ResultId) def concreteId = ConcreteId(resId, instId) - - private def newRefId(refId: ResultId, refSym: TermSymbol) = - instId match - case Nil => refId :: Nil - case pathTo :+ called => - val lastRefedSymbol = called.getReferredFun.get - val funToSccRepMap = collector.funToSccRep - (funToSccRepMap(lastRefedSymbol), funToSccRepMap(refSym)) match - case (Some(a), Some(b)) if a is b => instId - case _ => instId :+ refId - case _ => die - override def applyResult(r: Result)(k: Result => Block): Block = - r match - case s@TrackableSelect(from, _, _) => - if branchSelSyms.isDefinedAt(s.uid.concreteId) then - k(branchSelSyms(s.uid.concreteId).asSimpleRef) - else if solver.finalDtorSrcs.contains(s.uid.concreteId) then - applyPath(from)(k) - else - super.applyResult(r)(k) - case ctor@CtorCall(cls, args) => - def mkCtorFieldSyms(ctorDtorId: CtorDtorId): Ls[TempSymbol] = - val ctorInfo = solver.fusingCtorInfo(ctorDtorId) - val clsNme = ctorInfo.ctor.ctorClsName - ctorInfo.args.unzip._1.map: f => - new TempSymbol(N, s"${clsNme}_${f.fieldName}") - end mkCtorFieldSyms + + def apply(): Program = + if solver.finalCtorDests.isEmpty && solver.finalDtorSrcs.isEmpty then + pre.pgrm + else + // compute new program body + val newBody = + + def mkCall(target: (BlockMemberSymbol, TermSymbol), args: Ls[ValueSymbol]): Call = + Call( + Value.Ref(target._1, S(target._2)), + args.map(a => Arg(N, a.asPath)) ne_:: Nil + )(true, false, false) + + // Rewrites the program under a specific instantiation id + // from the polymorphic analysis + class Rewriter(instId: InstantiationId) extends BlockTransformer(_symSubst): + extension (resId: ResultId) def concreteId = ConcreteId(resId, instId) + + private def newRefId(refId: ResultId, refSym: TermSymbol) = + instId match + case Nil => refId :: Nil + case pathTo :+ called => + val lastRefedSymbol = called.getReferredFun.get + val funToSccRepMap = collector.funToSccRep + (funToSccRepMap(lastRefedSymbol), funToSccRepMap(refSym)) match + case (Some(a), Some(b)) if a is b => instId + case _ => instId :+ refId + case _ => die + override def applyResult(r: Result)(k: Result => Block): Block = + r match + case s@TrackableSelect(from, _, _) => + if branchSelSyms.isDefinedAt(s.uid.concreteId) then + k(branchSelSyms(s.uid.concreteId).asSimpleRef) + else if solver.finalDtorSrcs.contains(s.uid.concreteId) then + applyPath(from)(k) + else + super.applyResult(r)(k) + case ctor@CtorProducer(cls, args) => + def mkCtorFieldSyms(ctorDtorId: CtorDtorId): Ls[TempSymbol] = + val ctorInfo = solver.fusingCtorInfo(ctorDtorId) + val clsNme = ctorInfo.ctor.ctorClsName + ctorInfo.args.unzip._1.map: f => + new TempSymbol(N, s"${clsNme}_${f.fieldName}") + end mkCtorFieldSyms + + solver.finalCtorDests.get(ctor.uid.concreteId) match + case None => super.applyResult(ctor)(k) + case Some(FinalDestSel(_, field)) => + val ctorInfo = solver.fusingCtorInfo(ctor.uid.concreteId) + val idx = ctorInfo.args.unzip._1.indexOf(field) + val fieldSyms = mkCtorFieldSyms(ctor.uid.concreteId) + args.zip(fieldSyms).foldRight(k(fieldSyms(idx).asSimpleRef)): + case (Arg(N, a) -> s, rest) => + applyPath(a): fusedField => + Scoped(Set.single(s), Assign(s, fusedField, rest)) + case _ => TODO("spread args are not supported") + case Some(_: FinalDestMatch) => + val fieldSyms = mkCtorFieldSyms(ctor.uid.concreteId) + val callBranchFun = mkCall(branchFunSyms(ctorWhichBranch(ctor.uid.concreteId)), fieldSyms) + args.zip(fieldSyms).foldRight(k(callBranchFun)): + case (Arg(N, a) -> fieldSym, rest) => + applyPath(a): fusedField => + Scoped(Set.single(fieldSym), Assign(fieldSym, fusedField, rest)) + case _ => TODO("spread args are not supported") + case _ => super.applyResult(r)(k) - solver.finalCtorDests.get(ctor.uid.concreteId) match - case None => super.applyResult(ctor)(k) - case Some(FinalDestSel(_, field)) => - val ctorInfo = solver.fusingCtorInfo(ctor.uid.concreteId) - val idx = ctorInfo.args.unzip._1.indexOf(field) - val fieldSyms = mkCtorFieldSyms(ctor.uid.concreteId) - args.zip(fieldSyms).foldRight(k(fieldSyms(idx).asSimpleRef)): - case (Arg(N, a) -> s, rest) => - applyPath(a): fusedField => - Scoped(Set.single(s), Assign(s, fusedField, rest)) - case _ => TODO("spread args are not supported") - case Some(_: FinalDestMatch) => - val fieldSyms = mkCtorFieldSyms(ctor.uid.concreteId) - val callBranchFun = mkCall(branchFunSyms(ctorWhichBranch(ctor.uid.concreteId)), fieldSyms) - args.zip(fieldSyms).foldRight(k(callBranchFun)): - case (Arg(N, a) -> fieldSym, rest) => - applyPath(a): fusedField => - Scoped(Set.single(fieldSym), Assign(fieldSym, fusedField, rest)) - case _ => TODO("spread args are not supported") - case _ => super.applyResult(r)(k) - - override def applyPath(p: Path)(k: Path => Block): Block = - p match - case ref@FunRef(f) if newPolyFnSyms.isDefinedAt(newRefId(ref.uid, f)) => - val (bms, tSym) = newPolyFnSyms(newRefId(ref.uid, f))(f) - k(bms.asMemberRef(tSym)) - case ctor@CtorCall(_, args) if solver.finalCtorDests.isDefinedAt(ctor.uid.concreteId) => - assert(args.isEmpty) - val callBranchFun = mkCall(branchFunSyms(ctorWhichBranch(ctor.uid.concreteId)), Nil) - val lambdaSym = new TempSymbol(N, "deforest$lam") - Scoped( - Set.single(lambdaSym), - Assign( - lambdaSym, - callBranchFun, - k(lambdaSym.asSimpleRef)) - ) - case s@TrackableSelect(from, _, _) => - if branchSelSyms.isDefinedAt(s.uid.concreteId) then - k(branchSelSyms(s.uid.concreteId).asSimpleRef) - else if solver.finalDtorSrcs.contains(s.uid.concreteId) then - applyPath(from)(k) - else - super.applyPath(s)(k) - case _ => super.applyPath(p)(k) - - override def applyBlock(b: Block): Block = - b match - case m@Match(scrut, _, _, _) if solver.finalDtorSrcs.isDefinedAt(scrut.uid.concreteId) => - val callWithFvs = dtorBranchFnFvs(scrut.uid.concreteId) - applyPath(scrut): newScrut => - Return( - Call(newScrut, callWithFvs.map(s => Arg(N, s.asPath)) ne_:: Nil)(true, false, false)) - case Break(label) => - val labelRestFunId = label.withInstId(instId) - restFunSyms.get(labelRestFunId) match - case None => super.applyBlock(b) - case Some(labelRestFunSym) => - val labelRestFunFvs = restFnFvs(labelRestFunId) - mkReturnCall(labelRestFunSym, labelRestFunFvs) - case _ => super.applyBlock(b) - end Rewriter - - class RefreshSymbol(existingMapping: Map[ValueSymbol, ValueSymbol]) extends SymbolRefresher(existingMapping.toMap): - override def applyScopedBlock(b: Block): Block = - b match - case Scoped(syms, body) => - syms.foreach: sym => - sym match - case bms: BlockMemberSymbol => - assert(bms.tsym.forall(_.owner.isEmpty)) - case _ => - case _ => - super.applyScopedBlock(b) - override def applyBlock(b: Block): Block = - b match - case Label(label, loop, body, rest) => - assert(!loop) - case Continue(label) => TODO("unsupported `continue` instruction during rewriting") - case _ => - super.applyBlock(b) - override def applyValue(v: Value)(k: Value => Block): Block = v match - case Value.This(l) => - pre.res.modSymToBms.get(l) match - case Some(bms) => - k(bms.asMemberRef(l.asMod.get)) - case None => super.applyValue(v)(k) - case _ => super.applyValue(v)(k) - end RefreshSymbol - - val newPolyFuns = - for - (instId, funSymMap) <- newPolyFnSyms - (referringFun, (bms, tSym)) <- funSymMap.toList.sortBy(_._1.uid) - yield - val fDefn = pre.res.funSymToFunDefn(referringFun) - val transformedBody = new Rewriter(instId).applyBlock(fDefn.body) - // refresh other local symbols: for funs, we can check existing scoped blocks and - // there is no need to add scoped blocks, because function bodies now already are scoped - val refreshParamMap = MutMap.empty[VarSymbol, VarSymbol] - val refreshedParams = fDefn.params.map: pl => - ParamList( - pl.flags, - pl.params.map: p => - val newSym = new VarSymbol(Tree.Ident(p.sym.name)) - refreshParamMap(p.sym) = newSym - Param(p.flags, newSym, p.sign, p.modulefulness), - pl.restParam) - val bodyWithCorrectSymbols = new RefreshSymbol(refreshParamMap.toMap).applyBlock(transformedBody) - FunDefn( - N, bms, tSym, refreshedParams, - bodyWithCorrectSymbols)(N, PrivateModifier :: fDefn.annotations) - end newPolyFuns - - val newBranchFuns = - for (branchId@(dtorId, whichBranch), (bms, tSym)) <- branchFunSyms yield - val instId = dtorId.getInstId - val ogBody = branchOriginalBodies(dtorId.exprId -> whichBranch) - val restFunSym = restFunSyms(dtorId) - val restFunArgs = restFnFvs(dtorId) - val actualBody = Begin( - new Rewriter(instId).applyBlock(ogBody), - mkReturnCall(restFunSym, restFunArgs)) - val refreshedFvSymbols = dtorBranchFnFvs(branchId._1).map(s => s -> new VarSymbol(Tree.Ident(s"fv_${s.nme}"))) - val bodyWithCorrectSymbols = new RefreshSymbol(refreshedFvSymbols.toMap).applyBlock(actualBody) - FunDefn(tSym.owner, bms, tSym, - branchFunParamFieldSyms(branchId).asParamList :: refreshedFvSymbols.unzip._2.asParamList :: Nil, - bodyWithCorrectSymbols - )(N, annotations = AffineAnnotForBranchFns :: PrivateModifier :: Nil) - end newBranchFuns - - val newRestFuns = - for (restFunId, (bms, tsym)) <- restFunSyms yield - val instId = restFunId.getInstId - val (ogBody, parent) = restOriginalBodiesAndParentRest(restFunId.withoutInstId) - val transformedOgBody = new Rewriter(instId).applyBlock(ogBody) - val actualBody = parent match - case Some(parentRestId) => - val parentRestFunId = parentRestId.withInstId(instId) - val parentFunSym = restFunSyms(parentRestFunId) - val parentFunFvs = restFnFvs(parentRestFunId) - Begin( - transformedOgBody, - mkReturnCall(parentFunSym, parentFunFvs)) - case None => - Begin(transformedOgBody, Return(Value.Lit(Tree.UnitLit(true)))) - val refreshedFvSymbols = restFnFvs(restFunId).map(s => s -> new VarSymbol(Tree.Ident(s"fv_${s.nme}"))) - val bodyWithCorrectSymbols = new RefreshSymbol(refreshedFvSymbols.toMap).applyBlock(actualBody) - FunDefn(tsym.owner, bms, tsym, refreshedFvSymbols.unzip._2.asParamList :: Nil, bodyWithCorrectSymbols)(N, annotations = PrivateModifier :: Nil) - end newRestFuns + override def applyPath(p: Path)(k: Path => Block): Block = + p match + case ref@FunRef(f) if newPolyFnSyms.isDefinedAt(newRefId(ref.uid, f)) => + val (bms, tSym) = newPolyFnSyms(newRefId(ref.uid, f))(f) + k(bms.asMemberRef(tSym)) + case ctor@CtorProducer(_, args) if solver.finalCtorDests.isDefinedAt(ctor.uid.concreteId) => + assert(args.isEmpty) + val callBranchFun = mkCall(branchFunSyms(ctorWhichBranch(ctor.uid.concreteId)), Nil) + val lambdaSym = new TempSymbol(N, "deforest$lam") + Scoped( + Set.single(lambdaSym), + Assign( + lambdaSym, + callBranchFun, + k(lambdaSym.asSimpleRef) + )) + case s@TrackableSelect(from, _, _) => + if branchSelSyms.isDefinedAt(s.uid.concreteId) then + k(branchSelSyms(s.uid.concreteId).asSimpleRef) + else if solver.finalDtorSrcs.contains(s.uid.concreteId) then + applyPath(from)(k) + else + super.applyPath(s)(k) + case _ => super.applyPath(p)(k) + + override def applyBlock(b: Block): Block = + b match + case m@Match(scrut, _, _, _) if solver.finalDtorSrcs.isDefinedAt(scrut.uid.concreteId) => + val callWithFvs = dtorBranchFnFvs(scrut.uid.concreteId) + applyPath(scrut): newScrut => + Return( + Call( + newScrut, + callWithFvs.map(s => Arg(N, s.asPath)) ne_:: Nil + )(true, false, false)) + case Break(label) => + val labelRestFunId = label.withInstId(instId) + restFunSyms.get(labelRestFunId) match + case None => super.applyBlock(b) + case Some(labelRestFunSym) => + val labelRestFunFvs = restFnFvs(labelRestFunId) + Return(mkCall(labelRestFunSym, labelRestFunFvs)) + case _ => super.applyBlock(b) + end Rewriter + + // Rebuilds instantiated branch body and rest functions with fresh symbols + // to keep the invariant in the IR that a symbol is never reused for multiple definitions + class RefreshSymbol(existingMapping: Map[Symbol, Symbol]) extends SymbolRefresher(existingMapping): + override def applyScopedBlock(b: Block): Block = + b match + case Scoped(syms, body) => + syms.foreach: sym => + sym match + case bms: BlockMemberSymbol => + assert(bms.tsym.forall(_.owner.isEmpty)) + case _ => + case _ => + super.applyScopedBlock(b) + override def applyBlock(b: Block): Block = + b match + case Label(label, loop, body, rest) => + assert(!loop) + case Continue(label) => TODO("unsupported `continue` instruction during rewriting") + case _ => + super.applyBlock(b) + override def applyValue(v: Value)(k: Value => Block): Block = v match + case Value.This(l) => + pre.res.modSymToBms.get(l) match + case Some(bms) => + k(bms.asMemberRef(l.asMod.get)) + case None => super.applyValue(v)(k) + case _ => super.applyValue(v)(k) + end RefreshSymbol + + // Instantiated polymorphic functions + val newPolyFuns = + for + (instId, funSymMap) <- newPolyFnSyms + (referringFun, (bms, tSym)) <- funSymMap.toList.sortBy(_._1.uid) + yield + val fDefn = pre.res.funSymToFunDefn(referringFun) + val transformedBody = new Rewriter(instId).applyBlock(fDefn.body) + // refresh other local symbols: for funs, we can check existing scoped blocks and + // there is no need to add scoped blocks, because function bodies now already are scoped + val refreshParamMap = MutMap.empty[VarSymbol, VarSymbol] + val refreshedParams = fDefn.params.map: pl => + ParamList( + pl.flags, + pl.params.map: p => + val newSym = new VarSymbol(Tree.Ident(p.sym.name)) + refreshParamMap(p.sym) = newSym + Param(p.flags, newSym, p.sign, p.modulefulness), + pl.restParam) + val bodyWithCorrectSymbols = new RefreshSymbol(refreshParamMap.toMap).applyBlock(transformedBody) + FunDefn( + N, bms, tSym, refreshedParams, + bodyWithCorrectSymbols)(N, PrivateModifier :: fDefn.annotations) + end newPolyFuns + + // Functions for fused match branches; each runs one arm and then its rest + val newBranchFuns = + for (branchId@(dtorId, whichBranch), (bms, tSym)) <- branchFunSyms yield + val instId = dtorId.getInstId + val ogBody = branchOriginalBodies(dtorId.exprId -> whichBranch) + val restFunSym = restFunSyms(dtorId) + val restFunArgs = restFnFvs(dtorId) + val actualBody = Begin( + new Rewriter(instId).applyBlock(ogBody), + Return(mkCall(restFunSym, restFunArgs))) + val refreshedFvSymbols = dtorBranchFnFvs(branchId._1).map(s => s -> new VarSymbol(Tree.Ident(s"fv_${s.nme}"))) + val bodyWithCorrectSymbols = new RefreshSymbol(refreshedFvSymbols.toMap).applyBlock(actualBody) + FunDefn(N, bms, tSym, + branchFunParamFieldSyms(branchId).asParamList :: refreshedFvSymbols.unzip._2.asParamList :: Nil, + bodyWithCorrectSymbols + )(N, annotations = AffineAnnotForBranchFns :: PrivateModifier :: Nil) + end newBranchFuns + + // Continuation functions for the code after fused matches or labels + val newRestFuns = + for (restFunId, (bms, tsym)) <- restFunSyms yield + val instId = restFunId.getInstId + val (ogBody, parent) = restOriginalBodiesAndParentRest(restFunId.withoutInstId) + val transformedOgBody = new Rewriter(instId).applyBlock(ogBody) + val actualBody = parent match + case Some(parentRestId) => + val parentRestFunId = parentRestId.withInstId(instId) + val parentFunSym = restFunSyms(parentRestFunId) + val parentFunFvs = restFnFvs(parentRestFunId) + Begin( + transformedOgBody, + Return(mkCall(parentFunSym, parentFunFvs))) + case None => + Begin(transformedOgBody, Return(Value.Lit(Tree.UnitLit(true)))) + val refreshedFvSymbols = restFnFvs(restFunId).map(s => s -> new VarSymbol(Tree.Ident(s"fv_${s.nme}"))) + val bodyWithCorrectSymbols = new RefreshSymbol(refreshedFvSymbols.toMap).applyBlock(actualBody) + FunDefn(N, bms, tsym, refreshedFvSymbols.unzip._2.asParamList :: Nil, bodyWithCorrectSymbols)(N, annotations = PrivateModifier :: Nil) + end newRestFuns - val inplaceRewrittenFunBodies = Map.from[TermSymbol, Block]: - for (selfInstId, funSym) <- collector.synthesizedInstIdToFunSym yield - val fDefn = pre.res.funSymToFunDefn(funSym) - funSym -> new Rewriter(selfInstId).applyBlock(fDefn.body) - - val newTopLevelBranchFuns = newBranchFuns.filter(_.owner.isEmpty) - val newTopLevelRestFuns = newRestFuns.filter(_.owner.isEmpty) - val newClassMethods = (newBranchFuns ++ newRestFuns) - .groupBy(_.owner) - .collect: - case (Some(owner), methods) => owner -> methods.toList + // Functions are also rewritten in-place for purely internal fusions + // that do not rely on the inputs + val inplaceRewrittenFunBodies = Map.from[TermSymbol, Block]: + for (selfInstId, funSym) <- collector.synthesizedInstIdToFunSym yield + val fDefn = pre.res.funSymToFunDefn(funSym) + funSym -> new Rewriter(selfInstId).applyBlock(fDefn.body) - val newMainBody = - object mainRewriter extends Rewriter(Nil): - override def applyFunDefn(fun: FunDefn): FunDefn = - inplaceRewrittenFunBodies.get(fun.dSym) match - case Some(rewrittenBody) => - FunDefn(fun.owner, fun.sym, fun.dSym, fun.params, rewrittenBody)(fun.configOverride, fun.annotations) - case None => super.applyFunDefn(fun) - override def applyClsLikeDefn(defn: ClsLikeDefn)(k: Defn => Block): Block = - super.applyClsLikeDefn(defn): transformed => - transformed match - case cls: ClsLikeDefn => - newClassMethods.get(cls.isym) match - case Some(methods) => - k(cls.copy(methods = cls.methods ++ methods)(cls.configOverride, cls.annotations)) - case None => - k(cls) - case _ => - k(transformed) - Scoped( - Set.from(newPolyFuns.map(_.sym) ++ newTopLevelBranchFuns.map(_.sym) ++ newTopLevelRestFuns.map(_.sym)), - mainRewriter.applyBlock(pre.pgrm.main)) - - (newPolyFuns ++ newTopLevelBranchFuns ++ newTopLevelRestFuns).foldRight(newMainBody): (fdef, rest) => - Define(fdef, rest) - - end newBody + val newMainBody = + object mainRewriter extends Rewriter(Nil): + override def applyFunDefn(fun: FunDefn): FunDefn = + inplaceRewrittenFunBodies.get(fun.dSym) match + case Some(rewrittenBody) => + FunDefn(fun.owner, fun.sym, fun.dSym, fun.params, rewrittenBody)(fun.configOverride, fun.annotations) + case None => super.applyFunDefn(fun) + Scoped( + Set.from(newPolyFuns.map(_.sym) ++ newBranchFuns.map(_.sym) ++ newRestFuns.map(_.sym)), + mainRewriter.applyBlock(pre.pgrm.main)) + + (newPolyFuns ++ newBranchFuns ++ newRestFuns).foldRight(newMainBody): (fdef, rest) => + Define(fdef, rest) + + end newBody + + Program(pre.pgrm.imports, newBody) + end apply end DeforestRewriter diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala index 40d400e4a4..f7c54e58f1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/flowAnalysis/FlowAnalysis.scala @@ -5,6 +5,7 @@ package flowAnalysis import scala.jdk.CollectionConverters.MapHasAsScala import utils.* import mlscript.utils.*, shorthands.* +import hkmc2.Message.MessageContext import semantics.* import syntax.Tree import scala.collection.mutable @@ -87,18 +88,6 @@ type SelField = TermSymbol | Int type FunId = (funSym: Symbol, whichParamList: Int) | ResultId type OriginId = ResultId | FunId -/** Extracts the underlying symbol of a variable-like reference, for flow-tracking use. */ -object TrackedSymOf: - def unapply(p: Value.RefLike | Select)(using Elaborator.State): Opt[Symbol] = p match - case Value.SimpleRef(sym) => S(sym) - case Value.MemberRef(_, disamb) => S(disamb) - case Value.This(sym) => S(sym) - case s: Select => s.symbol.flatMap: selSym => - for - selTermSym <- selSym.asTrm - owner <- selTermSym.owner - _ <- owner.asMod - yield selTermSym object TrackableFieldSelect: def unapply(s: Select): Opt[Path -> (field: TermSymbol, owner: ClassSymbol)] = @@ -133,38 +122,24 @@ object TrackableSelect: Some((qual, field, owner)) case _ => N -object CtorRef: - /** Resolves an object reference or a class-ctor `TermSymbol` to its corresponding class/object symbol. */ - private def classCtorSymbol(sym: Symbol)(using Elaborator.State): Opt[ClassSymbol | ModuleOrObjectSymbol] = - sym.asObj orElse - sym.asTrm.flatMap: tSym => - for - cls <- tSym.owner.flatMap(_.asCls) - clsDef <- cls.irClsLikeDefn - ctorSym <- clsDef.ctorSym - if ctorSym is tSym - yield cls - - def unapply(p: Path)(using Elaborator.State): Opt[ClassSymbol | ModuleOrObjectSymbol] = p match - case Value.SimpleRef(sym) => classCtorSymbol(sym) - case Value.MemberRef(_, disamb) => classCtorSymbol(disamb) orElse disamb.asCls orElse disamb.asObj - case Value.This(sym) => classCtorSymbol(sym) orElse sym.asCls - case s: Select => s.symbol.flatMap(classCtorSymbol) - case _ => N +object MemberRefTo: + def unapply(p: Path) = p.targetSymbol -object CtorCall: - def unapply(r: Result)(using Elaborator.State): Option[(ClassSymbol | ModuleOrObjectSymbol | Int) -> Ls[Arg]] = +object CtorProducer: + /** Extracts result forms that produce a concrete `Ctor` flow strategy. */ + def unapply(r: Result)(using Elaborator.State): Opt[CtorCls -> Ls[Arg]] = r match - case Instantiate(_, CtorRef(ctor), argss) => Some(ctor -> argss.flatten) - case Call(CtorRef(ctor), argss) => Some(ctor -> argss.flatten) - case CtorRef(ctor) if ctor.asObj.isDefined => Some(ctor -> Nil) - case Tuple(_, args) => Some(args.size, args) - case _ => None + case Instantiate(_, MemberRefTo(cls: ClassSymbol), argss) => S(cls -> argss.flatten) + case Call(MemberRefTo(cls: ClassCtorSymbol), argss) => S(cls.owner.get -> argss.flatten) + case MemberRefTo(ctor: ModuleOrObjectSymbol) => S(ctor -> Nil) + case Tuple(_, args) => S(args.size, args) + case _ => N object FunRef: def unapply(s: Path)(using Elaborator.State): Option[TermSymbol] = s match - case TrackedSymOf(tSym: TermSymbol) if tSym.k is syntax.Fun => Some(tSym) - case _ => None + case MemberRefTo(tSym: TermSymbol) + if (tSym.k is syntax.Fun) && tSym.owner.forall(_.asMod.isDefined) => S(tSym) + case _ => N type StratVarId = Uid[StratVar] @@ -957,7 +932,7 @@ class FlowConstraintsCollector( fromStrat, new FieldSel(sel.uid, instId)(field, owner, selRes.asConsStrat)) selRes.asProdStrat - case c@CtorCall(ctor, args) if args.forall(_.spread.isEmpty) => + case c@CtorProducer(ctor, args) if args.forall(_.spread.isEmpty) => val argsStrat = args.map: case Arg(_, a) => processResult(a) ctor match @@ -970,14 +945,14 @@ class FlowConstraintsCollector( new Ctor(c.uid, instId)(ctor, clsParams.zip(argsStrat)) case _ => // - the size of 0 means we don't know the cls param symbols, - // so we constrain args with NoCons and this CtorCall gives NoProd + // so we constrain args with NoCons and this CtorProducer gives NoProd // - if size > 1, we cannot handle multiple parameter class flow now, - // constrain args with NoCons and this CtorCall gives NoProd + // constrain args with NoCons and this CtorProducer gives NoProd for a <- argsStrat do cc.constrain(a, UnknownCons) UnknownProd case _: ModuleOrObjectSymbol => new Ctor(c.uid, instId)(ctor, Nil) case tupSize: Int => new Ctor(c.uid, instId)(tupSize, (0 until tupSize).zip(argsStrat).toList) - case c@CtorCall(_, args) => + case c@CtorProducer(_, args) => args.foreach(arg => cc.constrain(processResult(arg.value), UnknownCons)) UnknownProd case c@Call(fun, argss) => @@ -998,7 +973,7 @@ class FlowConstraintsCollector( case i@Instantiate(_, cls, argss) => handleCallLike(i.uid, cls, argss.flatten) case lam@Lambda(ps, body) => mkFunProdStrat("lam_res", ps :: Nil, body, lam.uid) - case _: Tuple => lastWords("should be handled in CtorCall") + case _: Tuple => lastWords("should be handled in CtorProducer") case Record(_, fields) => fields.foreach: case RcdArg(idx, value) => @@ -1007,25 +982,22 @@ class FlowConstraintsCollector( UnknownProd case p: Path => p match - case CtorRef(ctor) => UnknownProd case refSite@FunRef(f) => funsToProdStratScheme.get(f) match case Some(fScheme) => fScheme.instantiate(refSite.uid, f) case None => generatedProdVars(f).asProdStrat - case refLk@TrackedSymOf(sym) => - refLk match - case Select(p, _) => cc.constrain(processResult(p), UnknownCons) - case _ => () - generatedProdVars(sym).asProdStrat - case _: Value.RefLike => lastWords("already handled in `TrackedSymOf` case") - case Select(qual, name) => + case s@Select(qual, name) => cc.constrain(processResult(qual), UnknownCons) - UnknownProd + s.symbol.fold(UnknownProd): selSym => + generatedProdVars(selSym).asProdStrat case DynSelect(qual, fld, arrayIdx) => cc.constrain(processResult(qual), UnknownCons) cc.constrain(processResult(fld), UnknownCons) UnknownProd + case Value.MemberRef(_, disamb) => generatedProdVars(disamb).asProdStrat + case Value.SimpleRef(sym) => generatedProdVars(sym).asProdStrat + case Value.This(_) => UnknownProd case Value.Lit(lit) => UnknownProd } end FlowConstraintsCollector diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala index bb8d23b0f1..e139026c54 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala @@ -677,7 +677,7 @@ class JSBuilder(using Config, TL, State, Ctx) extends CodeBuilder: case Elaborator.ctx.builtins.Bool => doc"typeof $sd === 'boolean'" case Elaborator.ctx.builtins.Int => doc"globalThis.Number.isInteger($sd)" case Elaborator.ctx.builtins.BigInt => doc"typeof $sd === 'bigint'" - case Elaborator.ctx.builtins.Symbol.module => doc"typeof $sd === 'symbol'" + case Elaborator.ctx.builtins.Symbol => doc"typeof $sd === 'symbol'" case Elaborator.ctx.builtins.TypedArray => doc"globalThis.ArrayBuffer.isView($sd) && !($sd instanceof globalThis.DataView)" case _: ModuleOrObjectSymbol => doc"$sd instanceof ${result(pth)}.class" diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index d712c4db9e..821a3af666 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -231,6 +231,7 @@ object Elaborator: val Object = assumeBuiltinCls("Object") val Array = assumeBuiltinCls("Array") val TypedArray = assumeBuiltinCls("TypedArray") + val Symbol = assumeBuiltinCls("Symbol") // println(s"Builtins: $Int, $Num, $Str, $untyped") class VirtualModule(val module: ModuleOrObjectSymbol): val bms = getBuiltin(module.nme) match @@ -240,7 +241,7 @@ object Elaborator: module.tree.definedSymbols.get(nme).getOrElse: throw new NoSuchElementException( s"builtin module symbol source.$nme") - object Symbol extends VirtualModule(assumeBuiltinObj("Symbol")): + object SymbolModule extends VirtualModule(assumeBuiltinMod("Symbol")): val `for` = assumeObject("for") val iterator = assumeObject("iterator") object source extends VirtualModule(assumeBuiltinMod("source")): diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala index 19f9456b68..c5315d0616 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala @@ -28,8 +28,16 @@ enum Annot extends AutoLocated: case TailCall case Inline case Config(modify: hkmc2.Config => hkmc2.Config) - // marks if a function or lambda is affine, i.e. called at most once. - // for functions with multiple parameter lists, `whichParamList` is the zero-based parameter-list index. + // Marks if a function or lambda is one-shot, i.e. called at most once. + // Functions with multiple parameter lists are considered here as a chain of + // function values. `whichParamList` is the zero-based index of the parameter + // list whose corresponding function value is one-shot. + // For example, on `fun f(a)(b)`, + // - its list of annotations containing `Affine(0)` says that `f` is one-shot; + // - its list of annotations containing `Affine(1)` says that + // each function value produced by `f(a)` is one-shot; + // - its list of annotations containing both `Affine(0)` and `Affine(1)` says that + // `f` is one-shot and each function value produced by `f(a)` is also one-shot. case Affine(whichParamList: Int) def symbol: Opt[Symbol] = this match diff --git a/hkmc2/shared/src/test/mlscript/codegen/ConfigDirective.mls b/hkmc2/shared/src/test/mlscript/codegen/ConfigDirective.mls index 5017612995..3d1bd23943 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ConfigDirective.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ConfigDirective.mls @@ -199,12 +199,12 @@ fun fst(p) = if p is Pair(x, y) then x fun applyTwice(f, x) = f(x) + f(x) applyTwice(fst, Pair(1, 2)) //│ deforest > >>> non-affine syms >>> -//│ deforest > cap_ub_(term:fst,0)_for_fst@36 -//│ deforest > f_for_applyTwice@25 -//│ deforest > f_for_applyTwice@58 -//│ deforest > fst_for_fst@33 +//│ deforest > cap_ub_(term:fst,0)_for_fst@35 +//│ deforest > f_for_applyTwice@24 +//│ deforest > f_for_applyTwice@55 +//│ deforest > fst_for_fst@32 //│ deforest > tmp@1 -//│ deforest > x_for_applyTwice@24 -//│ deforest > x_for_applyTwice@57 +//│ deforest > x_for_applyTwice@23 +//│ deforest > x_for_applyTwice@54 //│ deforest > <<< non-affine syms <<< //│ = 2 diff --git a/hkmc2/shared/src/test/mlscript/decls/Prelude.mls b/hkmc2/shared/src/test/mlscript/decls/Prelude.mls index 7ec21d84bb..dc603ba6b6 100644 --- a/hkmc2/shared/src/test/mlscript/decls/Prelude.mls +++ b/hkmc2/shared/src/test/mlscript/decls/Prelude.mls @@ -111,7 +111,8 @@ declare module Array with isArray prototype -declare object Symbol with +declare class Symbol +declare module Symbol with // The `TermDef` needs `rhs` to be defined to be recognized as `isMLsFun`. // Otherwise, it would be wrapped in `runtime.safeCall`, which accesses the // uninitialized `runtime` in the `Rendering` module. @@ -211,9 +212,10 @@ declare val Infinity declare class Promise declare val Promise declare object WebAssembly with - declare object Instance + declare class Instance declare class Memory - declare object Module with + declare class Module + declare module Module with fun exports imports diff --git a/hkmc2/shared/src/test/mlscript/deforest/basic.mls b/hkmc2/shared/src/test/mlscript/deforest/basic.mls index 85c8152b27..0dda1c5e43 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/basic.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/basic.mls @@ -76,38 +76,38 @@ f(p()) //│ deforest > fields: arg$X$0$⁰.b¹ //│ deforest > <<< fusing <<< //│ ———————————————| Lowered IR |——————————————————————————————————————————————————————————————————————— -//│ let p⁰, f⁰, tmp, p_10$p⁰, f_12$f⁰, f_12$x_X⁰, f_12$x_rest⁰, f_12$arg$X$0$_Y⁰, f_12$arg$X$0$_rest⁰; +//│ let p⁰, f⁰, tmp, p_8$p⁰, f_10$f⁰, f_10$x_X⁰, f_10$x_rest⁰, f_10$arg$X$0$_Y⁰, f_10$arg$X$0$_rest⁰; //│ @private -//│ define p_10$p⁰ as fun p_10$p¹()(eta$0$0, eta$0$1, eta$0$2) { +//│ define p_8$p⁰ as fun p_8$p¹()(eta$0$0, eta$0$1, eta$0$2) { //│ let tmp1, Y_b, X_a; //│ set Y_b = O⁰; -//│ set tmp1 = f_12$arg$X$0$_Y¹(Y_b); +//│ set tmp1 = f_10$arg$X$0$_Y¹(Y_b); //│ set X_a = tmp1; -//│ return f_12$x_X¹(X_a)(eta$0$0, eta$0$1, eta$0$2) +//│ return f_10$x_X¹(X_a)(eta$0$0, eta$0$1, eta$0$2) //│ }; //│ @private -//│ define f_12$f⁰ as fun f_12$f¹(x) { +//│ define f_10$f⁰ as fun f_10$f¹(x) { //│ let y, arg$X$0$, arg$Y$0$; //│ return x(y, arg$X$0$, arg$Y$0$) //│ }; //│ @affine(1) @private -//│ define f_12$x_X⁰ as fun f_12$x_X¹(X_a)(fv_y, fv_arg$X$0$, fv_arg$Y$0$) { +//│ define f_10$x_X⁰ as fun f_10$x_X¹(X_a)(fv_y, fv_arg$X$0$, fv_arg$Y$0$) { //│ set fv_arg$X$0$ = X_a; //│ return fv_arg$X$0$(fv_y, fv_arg$Y$0$) //│ }; //│ @affine(1) @private -//│ define f_12$arg$X$0$_Y⁰ as fun f_12$arg$X$0$_Y¹(Y_b)(fv_y, fv_arg$Y$0$) { +//│ define f_10$arg$X$0$_Y⁰ as fun f_10$arg$X$0$_Y¹(Y_b)(fv_y, fv_arg$Y$0$) { //│ set fv_arg$Y$0$ = Y_b; //│ set fv_y = fv_arg$Y$0$; //│ return fv_y //│ }; //│ @private -//│ define f_12$x_rest⁰ as fun f_12$x_rest¹() { +//│ define f_10$x_rest⁰ as fun f_10$x_rest¹() { //│ return null //│ }; //│ @private -//│ define f_12$arg$X$0$_rest⁰ as fun f_12$arg$X$0$_rest¹() { -//│ return f_12$x_rest¹() +//│ define f_10$arg$X$0$_rest⁰ as fun f_10$arg$X$0$_rest¹() { +//│ return f_10$x_rest¹() //│ }; //│ define p⁰ as fun p¹() { //│ let tmp1; @@ -131,8 +131,8 @@ f(p()) //│ throw new globalThis⁰.Error⁰("match error") //│ end //│ }; -//│ set tmp = p_10$p¹(); -//│ return f_12$f¹(tmp) +//│ set tmp = p_8$p¹(); +//│ return f_10$f¹(tmp) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = O @@ -192,7 +192,7 @@ fun c(x, d) = if x is //│ deforest > match: x⁴ //│ deforest > fields: x⁴.a¹ //│ deforest > <<< fusing <<< -//│ = fun lambda_8$lambda +//│ = fun lambda_7$lambda :expect 2 diff --git a/hkmc2/shared/src/test/mlscript/deforest/cyclic.mls b/hkmc2/shared/src/test/mlscript/deforest/cyclic.mls index 7f502174cc..a672f11698 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/cyclic.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/cyclic.mls @@ -84,14 +84,14 @@ modSome(Some(17), 3) //│ deforest > fields: x⁰.x¹ //│ deforest > <<< fusing <<< //│ ———————————————| Lowered IR |——————————————————————————————————————————————————————————————————————— -//│ let modSome⁰, tmp, modSome_12$modSome⁰, modSome_12$x_Some⁰, modSome_12$x_rest⁰, Some_x; +//│ let modSome⁰, tmp, modSome_11$modSome⁰, modSome_11$x_Some⁰, modSome_11$x_rest⁰, Some_x; //│ @private -//│ define modSome_12$modSome⁰ as fun modSome_12$modSome¹(x, m) { +//│ define modSome_11$modSome⁰ as fun modSome_11$modSome¹(x, m) { //│ let n, scrut, arg$Some$0$, tmp1, tmp2; //│ return x(m, n, scrut, arg$Some$0$, tmp1, tmp2) //│ }; //│ @affine(1) @private -//│ define modSome_12$x_Some⁰ as fun modSome_12$x_Some¹(Some_x1)(fv_m, fv_n, fv_scrut, fv_arg$Some$0$, fv_tmp, fv_tmp1) { +//│ define modSome_11$x_Some⁰ as fun modSome_11$x_Some¹(Some_x1)(fv_m, fv_n, fv_scrut, fv_arg$Some$0$, fv_tmp, fv_tmp1) { //│ set fv_arg$Some$0$ = Some_x1; //│ set fv_n = fv_arg$Some$0$; //│ set fv_scrut = >=⁰(fv_n, fv_m); @@ -100,14 +100,14 @@ modSome(Some(17), 3) //│ let Some_x2; //│ set fv_tmp = -⁰(fv_n, fv_m); //│ set Some_x2 = fv_tmp; -//│ set fv_tmp1 = modSome_12$x_Some¹(Some_x2); -//│ return modSome_12$modSome¹(fv_tmp1, fv_m) +//│ set fv_tmp1 = modSome_11$x_Some¹(Some_x2); +//│ return modSome_11$modSome¹(fv_tmp1, fv_m) //│ else //│ return Some⁰(fv_n) //│ end //│ }; //│ @private -//│ define modSome_12$x_rest⁰ as fun modSome_12$x_rest¹() { +//│ define modSome_11$x_rest⁰ as fun modSome_11$x_rest¹() { //│ return null //│ }; //│ define modSome⁰ as fun modSome¹(x, m) { @@ -135,8 +135,8 @@ modSome(Some(17), 3) //│ end //│ }; //│ set Some_x = 17; -//│ set tmp = modSome_12$x_Some¹(Some_x); -//│ return modSome_12$modSome¹(tmp, 3) +//│ set tmp = modSome_11$x_Some¹(Some_x); +//│ return modSome_11$modSome¹(tmp, 3) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = Some(2) diff --git a/hkmc2/shared/src/test/mlscript/deforest/determinism.mls b/hkmc2/shared/src/test/mlscript/deforest/determinism.mls index 04b0318493..3d63cbf98f 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/determinism.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/determinism.mls @@ -75,66 +75,66 @@ c2 of A(A(A(A(A(A(1)))))) //│ deforest > fields: arg$A$0$⁴.a² //│ deforest > <<< fusing <<< //│ ———————————————| Lowered IR |——————————————————————————————————————————————————————————————————————— -//│ let c2⁰, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, c2_25$c2⁰, c2_25$x_A⁰, c2_25$x_rest⁰, c2_25$arg$A$0$_A⁰, c2_25$arg$A$0$_rest⁰, c2_25$arg$A$0$_A¹, c2_25$arg$A$0$_rest¹, c2_25$arg$A$0$_A², c2_25$arg$A$0$_rest², c2_25$arg$A$0$_A³, c2_25$arg$A$0$_rest³, c2_25$arg$A$0$_A⁴, c2_25$arg$A$0$_rest⁴, A_a, A_a1, A_a2, A_a3, A_a4, A_a5; +//│ let c2⁰, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, c2_19$c2⁰, c2_19$x_A⁰, c2_19$x_rest⁰, c2_19$arg$A$0$_A⁰, c2_19$arg$A$0$_rest⁰, c2_19$arg$A$0$_A¹, c2_19$arg$A$0$_rest¹, c2_19$arg$A$0$_A², c2_19$arg$A$0$_rest², c2_19$arg$A$0$_A³, c2_19$arg$A$0$_rest³, c2_19$arg$A$0$_A⁴, c2_19$arg$A$0$_rest⁴, A_a, A_a1, A_a2, A_a3, A_a4, A_a5; //│ @private -//│ define c2_25$c2⁰ as fun c2_25$c2¹(x) { +//│ define c2_19$c2⁰ as fun c2_19$c2¹(x) { //│ let a, arg$A$0$, arg$A$0$1, arg$A$0$2, arg$A$0$3, arg$A$0$4, arg$A$0$5; //│ return x(a, arg$A$0$, arg$A$0$1, arg$A$0$2, arg$A$0$3, arg$A$0$4, arg$A$0$5) //│ }; //│ @affine(1) @private -//│ define c2_25$x_A⁰ as fun c2_25$x_A¹(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3, fv_arg$A$0$4, fv_arg$A$0$5) { +//│ define c2_19$x_A⁰ as fun c2_19$x_A¹(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3, fv_arg$A$0$4, fv_arg$A$0$5) { //│ set fv_arg$A$0$ = A_a6; //│ return fv_arg$A$0$(fv_a, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3, fv_arg$A$0$4, fv_arg$A$0$5) //│ }; //│ @affine(1) @private -//│ define c2_25$arg$A$0$_A⁰ as fun c2_25$arg$A$0$_A⁵(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3, fv_arg$A$0$4) { +//│ define c2_19$arg$A$0$_A⁰ as fun c2_19$arg$A$0$_A⁵(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3, fv_arg$A$0$4) { //│ set fv_arg$A$0$ = A_a6; //│ return fv_arg$A$0$(fv_a, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3, fv_arg$A$0$4) //│ }; //│ @affine(1) @private -//│ define c2_25$arg$A$0$_A¹ as fun c2_25$arg$A$0$_A⁶(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3) { +//│ define c2_19$arg$A$0$_A¹ as fun c2_19$arg$A$0$_A⁶(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3) { //│ set fv_arg$A$0$ = A_a6; //│ return fv_arg$A$0$(fv_a, fv_arg$A$0$1, fv_arg$A$0$2, fv_arg$A$0$3) //│ }; //│ @affine(1) @private -//│ define c2_25$arg$A$0$_A² as fun c2_25$arg$A$0$_A⁷(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2) { +//│ define c2_19$arg$A$0$_A² as fun c2_19$arg$A$0$_A⁷(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1, fv_arg$A$0$2) { //│ set fv_arg$A$0$ = A_a6; //│ return fv_arg$A$0$(fv_a, fv_arg$A$0$1, fv_arg$A$0$2) //│ }; //│ @affine(1) @private -//│ define c2_25$arg$A$0$_A³ as fun c2_25$arg$A$0$_A⁸(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1) { +//│ define c2_19$arg$A$0$_A³ as fun c2_19$arg$A$0$_A⁸(A_a6)(fv_a, fv_arg$A$0$, fv_arg$A$0$1) { //│ set fv_arg$A$0$ = A_a6; //│ return fv_arg$A$0$(fv_a, fv_arg$A$0$1) //│ }; //│ @affine(1) @private -//│ define c2_25$arg$A$0$_A⁴ as fun c2_25$arg$A$0$_A⁹(A_a6)(fv_a, fv_arg$A$0$) { +//│ define c2_19$arg$A$0$_A⁴ as fun c2_19$arg$A$0$_A⁹(A_a6)(fv_a, fv_arg$A$0$) { //│ set fv_arg$A$0$ = A_a6; //│ set fv_a = fv_arg$A$0$; //│ return fv_a //│ }; //│ @private -//│ define c2_25$x_rest⁰ as fun c2_25$x_rest¹() { +//│ define c2_19$x_rest⁰ as fun c2_19$x_rest¹() { //│ return null //│ }; //│ @private -//│ define c2_25$arg$A$0$_rest⁰ as fun c2_25$arg$A$0$_rest⁵() { -//│ return c2_25$x_rest¹() +//│ define c2_19$arg$A$0$_rest⁰ as fun c2_19$arg$A$0$_rest⁵() { +//│ return c2_19$x_rest¹() //│ }; //│ @private -//│ define c2_25$arg$A$0$_rest¹ as fun c2_25$arg$A$0$_rest⁶() { -//│ return c2_25$arg$A$0$_rest⁵() +//│ define c2_19$arg$A$0$_rest¹ as fun c2_19$arg$A$0$_rest⁶() { +//│ return c2_19$arg$A$0$_rest⁵() //│ }; //│ @private -//│ define c2_25$arg$A$0$_rest² as fun c2_25$arg$A$0$_rest⁷() { -//│ return c2_25$arg$A$0$_rest⁶() +//│ define c2_19$arg$A$0$_rest² as fun c2_19$arg$A$0$_rest⁷() { +//│ return c2_19$arg$A$0$_rest⁶() //│ }; //│ @private -//│ define c2_25$arg$A$0$_rest³ as fun c2_25$arg$A$0$_rest⁸() { -//│ return c2_25$arg$A$0$_rest⁷() +//│ define c2_19$arg$A$0$_rest³ as fun c2_19$arg$A$0$_rest⁸() { +//│ return c2_19$arg$A$0$_rest⁷() //│ }; //│ @private -//│ define c2_25$arg$A$0$_rest⁴ as fun c2_25$arg$A$0$_rest⁹() { -//│ return c2_25$arg$A$0$_rest⁸() +//│ define c2_19$arg$A$0$_rest⁴ as fun c2_19$arg$A$0$_rest⁹() { +//│ return c2_19$arg$A$0$_rest⁸() //│ }; //│ define c2⁰ as fun c2¹(x) { //│ let a, arg$A$0$, arg$A$0$1, arg$A$0$2, arg$A$0$3, arg$A$0$4, arg$A$0$5; @@ -178,17 +178,17 @@ c2 of A(A(A(A(A(A(1)))))) //│ end //│ }; //│ set A_a = 1; -//│ set tmp = c2_25$arg$A$0$_A⁹(A_a); +//│ set tmp = c2_19$arg$A$0$_A⁹(A_a); //│ set A_a1 = tmp; -//│ set tmp1 = c2_25$arg$A$0$_A⁸(A_a1); +//│ set tmp1 = c2_19$arg$A$0$_A⁸(A_a1); //│ set A_a2 = tmp1; -//│ set tmp2 = c2_25$arg$A$0$_A⁷(A_a2); +//│ set tmp2 = c2_19$arg$A$0$_A⁷(A_a2); //│ set A_a3 = tmp2; -//│ set tmp3 = c2_25$arg$A$0$_A⁶(A_a3); +//│ set tmp3 = c2_19$arg$A$0$_A⁶(A_a3); //│ set A_a4 = tmp3; -//│ set tmp4 = c2_25$arg$A$0$_A⁵(A_a4); +//│ set tmp4 = c2_19$arg$A$0$_A⁵(A_a4); //│ set A_a5 = tmp4; -//│ set tmp5 = c2_25$x_A¹(A_a5); -//│ return c2_25$c2¹(tmp5) +//│ set tmp5 = c2_19$x_A¹(A_a5); +//│ return c2_19$c2¹(tmp5) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = 1 diff --git a/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/basic.mls b/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/basic.mls index c7a80e59f1..ffb4545054 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/basic.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/basic.mls @@ -29,7 +29,7 @@ c(p(3)) //│ deforest > fields: x¹.a⁰ //│ deforest > <<< fusing <<< //│ eta-expansion > >>> eta-expansion targets shapes >>> -//│ eta-expansion > p_5$p: [1, 2] +//│ eta-expansion > p_4$p: [1, 2] //│ eta-expansion > <<< eta-expansion targets shapes <<< //│ = 3 @@ -49,7 +49,7 @@ c(p(true)) //│ deforest > match: x² //│ deforest > <<< fusing <<< //│ eta-expansion > >>> eta-expansion targets shapes >>> -//│ eta-expansion > p_6$p: [1, 0] +//│ eta-expansion > p_5$p: [1, 0] //│ eta-expansion > <<< eta-expansion targets shapes <<< //│ = 1 @@ -70,9 +70,9 @@ g(f(p())) //│ deforest > fields: y⁰.b⁰ //│ deforest > <<< fusing <<< //│ eta-expansion > >>> eta-expansion targets shapes >>> -//│ eta-expansion > f_12$f: [1, 2] -//│ eta-expansion > p_10$p: [0, 2, 2] -//│ eta-expansion > f_12$x_X: [1, 2, 2] +//│ eta-expansion > f_10$f: [1, 2] +//│ eta-expansion > p_8$p: [0, 2, 2] +//│ eta-expansion > f_10$x_X: [1, 2, 2] //│ eta-expansion > <<< eta-expansion targets shapes <<< //│ = O @@ -99,7 +99,7 @@ c(p(true)) //│ deforest > fields: arg$X$0$⁰.b⁰ //│ deforest > <<< fusing <<< //│ eta-expansion > >>> eta-expansion targets shapes >>> -//│ eta-expansion > p_12$p: [1, 3] +//│ eta-expansion > p_10$p: [1, 3] //│ eta-expansion > <<< eta-expansion targets shapes <<< //│ = 22 diff --git a/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/recursive.mls b/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/recursive.mls index 7c9ee5fe6a..71ab610458 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/recursive.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/eta-expansion/recursive.mls @@ -30,12 +30,12 @@ sum(enum(5), 0) //│ deforest > match: ls⁰ //│ deforest > <<< fusing <<< //│ eta-expansion > >>> eta-expansion targets shapes >>> -//│ eta-expansion > enum_13$enum: [1, 6] +//│ eta-expansion > enum_12$enum: [1, 6] //│ eta-expansion > <<< eta-expansion targets shapes <<< //│ ——————————————| Optimized IR |—————————————————————————————————————————————————————————————————————— -//│ let sum⁰, enum⁰, enum_13$enum$worker⁰; +//│ let sum⁰, enum⁰, enum_12$enum$worker⁰; //│ @private -//│ define enum_13$enum$worker⁰ as fun enum_13$enum$worker¹(x, eta$0$0, eta$0$5) { +//│ define enum_12$enum$worker⁰ as fun enum_12$enum$worker¹(x, eta$0$0, eta$0$5) { //│ let scrut, tmp; //│ set scrut = <⁰(x, 0); //│ match scrut @@ -46,7 +46,7 @@ sum(enum(5), 0) //│ set tmp = -⁰(x, 1); //│ set fv_tmp = eta$0$5; //│ set fv_tmp = +⁰(x, eta$0$0); -//│ return enum_13$enum$worker¹(tmp, fv_tmp, undefined) +//│ return enum_12$enum$worker¹(tmp, fv_tmp, undefined) //│ end //│ }; //│ define enum⁰ as fun enum¹(x) { @@ -79,7 +79,7 @@ sum(enum(5), 0) //│ end //│ unreachable /* Rest of abortive labelled block */ //│ }; -//│ return enum_13$enum$worker¹(5, 0, undefined) +//│ return enum_12$enum$worker¹(5, 0, undefined) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = 15 @@ -105,17 +105,17 @@ len(flatten(id((1 :: 2 :: Nil) :: (3 :: Nil) :: Nil))) //│ deforest > fields: ls¹.t⁰ //│ deforest > <<< fusing <<< //│ eta-expansion > >>> eta-expansion targets shapes >>> -//│ eta-expansion > flatten_30_append_18$append: [2, 5] -//│ eta-expansion > flatten_30$flatten: [1, 5] +//│ eta-expansion > flatten_27_append_16$append: [2, 5] +//│ eta-expansion > flatten_27$flatten: [1, 5] //│ eta-expansion > <<< eta-expansion targets shapes <<< //│ ——————————————| Optimized IR |—————————————————————————————————————————————————————————————————————— -//│ let flatten⁰, len⁰, append⁰, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, flatten_30$flatten⁰, flatten_30_append_18$append$worker⁰, flatten_30$flatten$worker⁰; +//│ let flatten⁰, len⁰, append⁰, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, flatten_27$flatten⁰, flatten_27_append_16$append$worker⁰, flatten_27$flatten$worker⁰; //│ @inline @private -//│ define flatten_30$flatten⁰ as fun flatten_30$flatten¹(xss)() { -//│ return flatten_30$flatten$worker¹(xss) +//│ define flatten_27$flatten⁰ as fun flatten_27$flatten¹(xss)() { +//│ return flatten_27$flatten$worker¹(xss) //│ }; //│ @private -//│ define flatten_30$flatten$worker⁰ as fun flatten_30$flatten$worker¹(xss) { +//│ define flatten_27$flatten$worker⁰ as fun flatten_27$flatten$worker¹(xss) { //│ let arg$Cons$0$, arg$Cons$1$, tmp6; //│ match xss //│ Nil⁰ => @@ -123,14 +123,14 @@ len(flatten(id((1 :: 2 :: Nil) :: (3 :: Nil) :: Nil))) //│ Cons¹ => //│ set arg$Cons$0$ = xss.h⁰; //│ set arg$Cons$1$ = xss.t⁰; -//│ set tmp6 = flatten_30$flatten¹(arg$Cons$1$); -//│ return flatten_30_append_18$append$worker¹(arg$Cons$0$, tmp6) +//│ set tmp6 = flatten_27$flatten¹(arg$Cons$1$); +//│ return flatten_27_append_16$append$worker¹(arg$Cons$0$, tmp6) //│ else //│ throw new globalThis⁰.Error⁰("match error") //│ end //│ }; //│ @private -//│ define flatten_30_append_18$append$worker⁰ as fun flatten_30_append_18$append$worker¹(xs, ys) { +//│ define flatten_27_append_16$append$worker⁰ as fun flatten_27_append_16$append$worker¹(xs, ys) { //│ let arg$Cons$1$; //│ match xs //│ Nil⁰ => @@ -138,7 +138,7 @@ len(flatten(id((1 :: 2 :: Nil) :: (3 :: Nil) :: Nil))) //│ Cons¹ => //│ let inlinedVal; //│ set arg$Cons$1$ = xs.t⁰; -//│ set inlinedVal = flatten_30_append_18$append$worker¹(arg$Cons$1$, ys); +//│ set inlinedVal = flatten_27_append_16$append$worker¹(arg$Cons$1$, ys); //│ return +⁰(1, inlinedVal) //│ else //│ throw new globalThis⁰.Error⁰("match error") @@ -191,7 +191,7 @@ len(flatten(id((1 :: 2 :: Nil) :: (3 :: Nil) :: Nil))) //│ set tmp3 = Cons⁰(tmp2, Nil⁰); //│ set tmp4 = Cons⁰(tmp1, tmp3); //│ set tmp5 = Predef⁰.id⁰(tmp4); -//│ return flatten_30$flatten$worker¹(tmp5) +//│ return flatten_27$flatten$worker¹(tmp5) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = 3 diff --git a/hkmc2/shared/src/test/mlscript/deforest/fusibility.mls b/hkmc2/shared/src/test/mlscript/deforest/fusibility.mls index c8218763a7..6d5d2df582 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/fusibility.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/fusibility.mls @@ -58,14 +58,14 @@ fun c(p) = cl() + cl() c(AA(7)) //│ deforest > >>> non-affine syms >>> -//│ deforest > cap_ub_(term:lambda,0)_for_c@31 -//│ deforest > cap_ub_(term:lambda,0)_for_c@49 -//│ deforest > cl_for_c@20 -//│ deforest > cl_for_c@38 -//│ deforest > lambda_for_c@29 -//│ deforest > lambda_for_c@47 -//│ deforest > p_for_c@21 -//│ deforest > p_for_c@39 +//│ deforest > cap_ub_(term:lambda,0)_for_c@30 +//│ deforest > cap_ub_(term:lambda,0)_for_c@47 +//│ deforest > cl_for_c@19 +//│ deforest > cl_for_c@36 +//│ deforest > lambda_for_c@28 +//│ deforest > lambda_for_c@45 +//│ deforest > p_for_c@20 +//│ deforest > p_for_c@37 //│ deforest > tmp@1 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> fusing >>> @@ -109,13 +109,13 @@ fun c(p) = if p is AA(v) then v fun apply(f, x) = f(x) + f(x) apply(c, AA(3)) //│ deforest > >>> non-affine syms >>> -//│ deforest > c_for_c@30 -//│ deforest > cap_ub_(term:c,0)_for_c@33 -//│ deforest > f_for_apply@22 -//│ deforest > f_for_apply@49 +//│ deforest > c_for_c@29 +//│ deforest > cap_ub_(term:c,0)_for_c@32 +//│ deforest > f_for_apply@21 +//│ deforest > f_for_apply@46 //│ deforest > tmp@1 -//│ deforest > x_for_apply@21 -//│ deforest > x_for_apply@48 +//│ deforest > x_for_apply@20 +//│ deforest > x_for_apply@45 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> fusing >>> //│ deforest > <<< fusing <<< @@ -127,8 +127,8 @@ fun c(k, x) = if k is AA(_) then x.AA#x + x.AA#x + x.AA#x c(AA(0), AA(3)) //│ deforest > >>> non-affine syms >>> //│ deforest > tmp@2 -//│ deforest > x_for_c@18 -//│ deforest > x_for_c@33 +//│ deforest > x_for_c@17 +//│ deforest > x_for_c@31 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> fusing >>> //│ deforest > AA⁰(0) -> @@ -148,8 +148,8 @@ fun c(y) = if y is AA(_) then c(AA(1)) //│ deforest > >>> non-affine syms >>> //│ deforest > tmp@1 -//│ deforest > y_for_c@14 -//│ deforest > y_for_c@26 +//│ deforest > y_for_c@13 +//│ deforest > y_for_c@24 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> fusing >>> //│ deforest > <<< fusing <<< @@ -162,9 +162,9 @@ fun c2(x) = if x is AA(AA(_)) then 1 else 0 let p = AA(AA(AA(10))) c1(p) + c2(p) //│ deforest > >>> non-affine syms >>> -//│ deforest > p@3 -//│ deforest > tmp@2 -//│ deforest > tmp@4 +//│ deforest > p@2 +//│ deforest > tmp@1 +//│ deforest > tmp@3 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> fusing >>> //│ deforest > <<< fusing <<< @@ -180,8 +180,8 @@ fun c2(p) = if p is Many(Once(v)) then v fun apply(f, g, p) = f(p) + g(p) apply(c1, c2, Many(Once(10))) //│ deforest > >>> non-affine syms >>> -//│ deforest > p_for_apply@33 -//│ deforest > p_for_apply@81 +//│ deforest > p_for_apply@30 +//│ deforest > p_for_apply@72 //│ deforest > tmp@1 //│ deforest > tmp@2 //│ deforest > <<< non-affine syms <<< @@ -197,18 +197,18 @@ fun nest_consume(f, p) = if p is AA(i) then f(i) + f(i) fun nest_pickB(p) = if p is BB(b) then b + 1 nest_consume(nest_pickB, nest_prod(10)) //│ deforest > >>> non-affine syms >>> -//│ deforest > arg$AA$0$_for_nest_consume@48 -//│ deforest > arg$AA$0$_for_nest_consume@77 -//│ deforest > cap_ub_(term:nest_pickB,0)_for_nest_pickB@53 -//│ deforest > f_for_nest_consume@37 -//│ deforest > f_for_nest_consume@66 -//│ deforest > i_for_nest_consume@38 -//│ deforest > i_for_nest_consume@67 -//│ deforest > nest_pickB_for_nest_pickB@50 -//│ deforest > sel_res_for_nest_consume@49 -//│ deforest > sel_res_for_nest_consume@78 -//│ deforest > tmp_for_nest_prod@34 -//│ deforest > x_for_nest_prod@31 +//│ deforest > arg$AA$0$_for_nest_consume@45 +//│ deforest > arg$AA$0$_for_nest_consume@72 +//│ deforest > cap_ub_(term:nest_pickB,0)_for_nest_pickB@50 +//│ deforest > f_for_nest_consume@36 +//│ deforest > f_for_nest_consume@63 +//│ deforest > i_for_nest_consume@35 +//│ deforest > i_for_nest_consume@62 +//│ deforest > nest_pickB_for_nest_pickB@47 +//│ deforest > sel_res_for_nest_consume@46 +//│ deforest > sel_res_for_nest_consume@73 +//│ deforest > tmp_for_nest_prod@32 +//│ deforest > x_for_nest_prod@29 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> fusing >>> //│ deforest > AA⁰(tmp⁰) -> @@ -226,16 +226,16 @@ fun length(ls) = if ls is fun from(n, acc) = if n == 0 then acc else from(n - 1, n :: acc) length(from(5, Nil)) //│ deforest > >>> non-affine syms >>> -//│ deforest > call_res_for_from@35 -//│ deforest > call_res_for_from@76 -//│ deforest > n_for_from@28 -//│ deforest > n_for_from@69 -//│ deforest > tmp_for_from@33 -//│ deforest > tmp_for_from@74 +//│ deforest > call_res_for_from@34 +//│ deforest > call_res_for_from@73 +//│ deforest > n_for_from@27 +//│ deforest > n_for_from@66 +//│ deforest > tmp_for_from@32 +//│ deforest > tmp_for_from@71 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> accumulator syms >>> -//│ deforest > acc_for_from@29 -//│ deforest > acc_for_from@70 +//│ deforest > acc_for_from@28 +//│ deforest > acc_for_from@67 //│ deforest > <<< accumulator syms <<< //│ deforest > >>> fusing >>> //│ deforest > <<< fusing <<< @@ -351,8 +351,8 @@ length(flatten(id((1 :: Nil) :: Nil))) //│ deforest > >>> non-affine syms >>> //│ deforest > <<< non-affine syms <<< //│ deforest > >>> accumulator syms >>> -//│ deforest > ys_for_append_for_flatten@150 -//│ deforest > ys_for_append_for_flatten@78 +//│ deforest > ys_for_append_for_flatten@140 +//│ deforest > ys_for_append_for_flatten@73 //│ deforest > <<< accumulator syms <<< //│ deforest > >>> fusing >>> //│ deforest > <<< fusing <<< @@ -367,8 +367,8 @@ fun alias_then_patmat(x) = alias_then_patmat(Cons(12, 13)) //│ deforest > >>> non-affine syms >>> //│ deforest > tmp@1 -//│ deforest > x_for_alias_then_patmat@19 -//│ deforest > x_for_alias_then_patmat@36 +//│ deforest > x_for_alias_then_patmat@18 +//│ deforest > x_for_alias_then_patmat@34 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> accumulator syms >>> //│ deforest > <<< accumulator syms <<< @@ -404,12 +404,12 @@ fun foo(a) = f() + f() foo of AA of () => 1 //│ deforest > >>> non-affine syms >>> -//│ deforest > cap_ub_(term:lambda,0)_for_lambda@19 -//│ deforest > f_for_foo@21 -//│ deforest > f_for_foo@34 -//│ deforest > lambda_for_lambda@17 -//│ deforest > sel_res_for_foo@31 -//│ deforest > sel_res_for_foo@44 +//│ deforest > cap_ub_(term:lambda,0)_for_lambda@18 +//│ deforest > f_for_foo@20 +//│ deforest > f_for_foo@32 +//│ deforest > lambda_for_lambda@16 +//│ deforest > sel_res_for_foo@29 +//│ deforest > sel_res_for_foo@41 //│ deforest > <<< non-affine syms <<< //│ deforest > >>> accumulator syms >>> //│ deforest > <<< accumulator syms <<< diff --git a/hkmc2/shared/src/test/mlscript/deforest/recursive.mls b/hkmc2/shared/src/test/mlscript/deforest/recursive.mls index 70d01f0571..be81d13153 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/recursive.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/recursive.mls @@ -755,7 +755,7 @@ f //│ deforest > B⁰ -> //│ deforest > match: B⁰ //│ deforest > <<< fusing <<< -//│ = fun f_9$f +//│ = fun f_8$f :deforest diff --git a/hkmc2/shared/src/test/mlscript/deforest/relaxedPrograms.mls b/hkmc2/shared/src/test/mlscript/deforest/relaxedPrograms.mls index 9cef7f8d78..392c8113da 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/relaxedPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/relaxedPrograms.mls @@ -28,6 +28,7 @@ store.foo(AA(4)) :deforest :expect 5 :noInline +:fixme data class AA(x) class Store(n) with fun get() = @@ -42,8 +43,11 @@ store.foo(AA(4)) //│ deforest > match: scrut¹ //│ deforest > fields: scrut¹.x¹ //│ deforest > <<< fusing <<< -//│ = 5 -//│ store = Store(_) +//│ ═══[INTERNAL ERROR] `this` not in scope: class:Store +//│ > let AA3, Store3, store1, tmp2, tmp3, $scrut_AA;try { const n$accessorSymbol = globalThis.Symbol("n"); $scrut_AA = function $scrut_AA(AA_x) { runtime.checkArgs("$scrut_AA", 1, true, arguments.length); return (fv_x, fv_arg$AA$0$) => { fv_arg$AA$0$ = AA_x; fv_x = AA_x; return AA_x + ‹MISSING_THIS›[n$accessorSymbol] } }; AA3 = function AA(x) { return globalThis.Object.freeze(new AA.class(x)); }; globalThis.Object.freeze(class AA2 { static { AA3.class = this } constructor(x) { this.x = x; } toString() { return runtime.render(this); } static [definitionMetadata] = ["class", "AA", ["x"]]; }); Store3 = function Store(n) { return globalThis.Object.freeze(new Store.class(n)); }; globalThis.Object.freeze(class Store2 { static { Store3.class = this } constructor(n) { this.#n = n; } #n; get [n$accessorSymbol]() { return this.#n; } set [n$accessorSymbol](value) { this.#n = value; } get get$__checkNotMethod() { runtime.deboundMethod("get", "Store"); } get foo$__checkNotMethod() { runtime.deboundMethod("foo", "Store"); } get() { runtime.checkArgs("get", 0, true, arguments.length); let AA_x; AA_x = this.#n; return runtime.checkCall($scrut_AA(AA_x)(undefined, undefined)) } foo(x) { runtime.checkArgs("foo", 1, true, arguments.length); let arg$AA$0$; if (x instanceof AA3.class) { arg$AA$0$ = x.x; return arg$AA$0$ + this.#n } throw globalThis.Object.freeze(new globalThis.Error("match error")); } toString() { return runtime.render(this); } static [definitionMetadata] = ["class", "Store", [null]]; }); tmp2 = runtime.checkCall(Store3(1)); store1 = tmp2; tmp3 = runtime.checkCall(AA3(4)); block$res2 = runtime.safeCall(store1.foo(tmp3));; undefined } catch (e) { console.log('\u200B' + e + '\u200B'); } +//│ ═══[COMPILATION ERROR] [Uncaught SyntaxError] Invalid or unexpected token +//│ ═══[RUNTIME ERROR] Expected: '5', got: 'undefined' +//│ ═══[RUNTIME ERROR] ReferenceError: store1 is not defined @@ -53,6 +57,7 @@ store.foo(AA(4)) :deforest :expect 3 +:fixme // requires the block above to succeed fun classMethodSibling() = if AA(1) is AA(x) then x + store.get() @@ -65,7 +70,8 @@ classMethodSibling() //│ deforest > match: scrut² //│ deforest > fields: scrut².x¹ //│ deforest > <<< fusing <<< -//│ = 3 +//│ ═══[RUNTIME ERROR] ReferenceError: store1 is not defined +//│ ═══[RUNTIME ERROR] Expected: '3', got: 'undefined' :deforest diff --git a/hkmc2/shared/src/test/mlscript/deforest/simple.mls b/hkmc2/shared/src/test/mlscript/deforest/simple.mls index 3c98705d2a..d815ae16ed 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/simple.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/simple.mls @@ -569,17 +569,17 @@ f(id(A)) + f(A) //│ deforest > match: x²² //│ deforest > <<< fusing <<< //│ ———————————————| Lowered IR |——————————————————————————————————————————————————————————————————————— -//│ let f⁰, tmp, tmp1, tmp2, f_7$f⁰, f_7$x_A⁰, f_7$x_rest⁰, deforest$lam; +//│ let f⁰, tmp, tmp1, tmp2, f_6$f⁰, f_6$x_A⁰, f_6$x_rest⁰, deforest$lam; //│ @private -//│ define f_7$f⁰ as fun f_7$f¹(x) { +//│ define f_6$f⁰ as fun f_6$f¹(x) { //│ return x() //│ }; //│ @affine(1) @private -//│ define f_7$x_A⁰ as fun f_7$x_A¹()() { +//│ define f_6$x_A⁰ as fun f_6$x_A¹()() { //│ return 1 //│ }; //│ @private -//│ define f_7$x_rest⁰ as fun f_7$x_rest¹() { +//│ define f_6$x_rest⁰ as fun f_6$x_rest¹() { //│ return null //│ }; //│ define f⁰ as fun f¹(x) { @@ -592,8 +592,8 @@ f(id(A)) + f(A) //│ }; //│ set tmp = Predef⁰.id⁰(A⁰); //│ set tmp1 = f¹(tmp); -//│ set deforest$lam = f_7$x_A¹(); -//│ set tmp2 = f_7$f¹(deforest$lam); +//│ set deforest$lam = f_6$x_A¹(); +//│ set tmp2 = f_6$f¹(deforest$lam); //│ return +⁰(tmp1, tmp2) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = 2 diff --git a/hkmc2/shared/src/test/mlscript/deforest/todos.mls b/hkmc2/shared/src/test/mlscript/deforest/todos.mls index e955005d31..f57b526328 100644 --- a/hkmc2/shared/src/test/mlscript/deforest/todos.mls +++ b/hkmc2/shared/src/test/mlscript/deforest/todos.mls @@ -52,41 +52,41 @@ test(p) + f(p) + test(AA(AA(AA(10)))) + test(B) //│ deforest > fields: arg$AA$0$¹.x¹ //│ deforest > <<< fusing <<< //│ ———————————————| Lowered IR |——————————————————————————————————————————————————————————————————————— -//│ let test⁰, f⁰, p⁰, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, test_31$test⁰, test_31$x_dflt⁰, test_31$x_rest⁰, test_28$test⁰, test_28$x_AA⁰, test_28$x_rest⁰, test_28$arg$AA$0$_AA⁰, test_28$arg$AA$0$_rest⁰, test_28$arg$AA$0$_AA¹, test_28$arg$AA$0$_rest¹, AA_x, AA_x1, AA_x2, deforest$lam; +//│ let test⁰, f⁰, p⁰, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, test_29$test⁰, test_29$x_dflt⁰, test_29$x_rest⁰, test_26$test⁰, test_26$x_AA⁰, test_26$x_rest⁰, test_26$arg$AA$0$_AA⁰, test_26$arg$AA$0$_rest⁰, test_26$arg$AA$0$_AA¹, test_26$arg$AA$0$_rest¹, AA_x, AA_x1, AA_x2, deforest$lam; //│ @private -//│ define test_31$test⁰ as fun test_31$test¹(x) { +//│ define test_29$test⁰ as fun test_29$test¹(x) { //│ let t, a, arg$AA$0$, arg$AA$0$1, arg$AA$0$2, tmp11, tmp12, tmp13, tmp14, tmp15; //│ return x(tmp11, t, tmp11, tmp12, tmp13, tmp14, tmp15) //│ }; //│ @private -//│ define test_28$test⁰ as fun test_28$test¹(x) { +//│ define test_26$test⁰ as fun test_26$test¹(x) { //│ let t, a, arg$AA$0$, arg$AA$0$1, arg$AA$0$2, tmp11, tmp12, tmp13, tmp14, tmp15; //│ return x(t, a, arg$AA$0$, arg$AA$0$1, arg$AA$0$2, tmp11, tmp12, tmp13, tmp14, tmp15, t, tmp11, tmp12, tmp13, tmp14, tmp15) //│ }; //│ @affine(1) @private -//│ define test_31$x_dflt⁰ as fun test_31$x_dflt¹()(fv_tmp, fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) { +//│ define test_29$x_dflt⁰ as fun test_29$x_dflt¹()(fv_tmp, fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) { //│ set fv_tmp1 = 4; -//│ return test_31$x_rest¹(fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) +//│ return test_29$x_rest¹(fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) //│ }; //│ @affine(1) @private -//│ define test_28$x_AA⁰ as fun test_28$x_AA¹(AA_x3)(fv_t, fv_a, fv_arg$AA$0$, fv_arg$AA$0$1, fv_arg$AA$0$2, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_t1, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9) { +//│ define test_26$x_AA⁰ as fun test_26$x_AA¹(AA_x3)(fv_t, fv_a, fv_arg$AA$0$, fv_arg$AA$0$1, fv_arg$AA$0$2, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_t1, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9) { //│ set fv_arg$AA$0$ = AA_x3; //│ return fv_arg$AA$0$(fv_t1, fv_a, fv_arg$AA$0$1, fv_arg$AA$0$2, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9, fv_t1, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9) //│ }; //│ @affine(1) @private -//│ define test_28$arg$AA$0$_AA⁰ as fun test_28$arg$AA$0$_AA²(AA_x3)(fv_t, fv_a, fv_arg$AA$0$, fv_arg$AA$0$1, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_t1, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9) { +//│ define test_26$arg$AA$0$_AA⁰ as fun test_26$arg$AA$0$_AA²(AA_x3)(fv_t, fv_a, fv_arg$AA$0$, fv_arg$AA$0$1, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_t1, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9) { //│ set fv_arg$AA$0$ = AA_x3; //│ return fv_arg$AA$0$(fv_a, fv_arg$AA$0$1, fv_tmp5, fv_t1, fv_tmp5, fv_tmp6, fv_tmp7, fv_tmp8, fv_tmp9) //│ }; //│ @affine(1) @private -//│ define test_28$arg$AA$0$_AA¹ as fun test_28$arg$AA$0$_AA³(AA_x3)(fv_a, fv_arg$AA$0$, fv_tmp, fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) { +//│ define test_26$arg$AA$0$_AA¹ as fun test_26$arg$AA$0$_AA³(AA_x3)(fv_a, fv_arg$AA$0$, fv_tmp, fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) { //│ set fv_arg$AA$0$ = AA_x3; //│ set fv_a = fv_arg$AA$0$; //│ set fv_tmp1 = fv_a; -//│ return test_28$arg$AA$0$_rest²(fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) +//│ return test_26$arg$AA$0$_rest²(fv_t, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4, fv_tmp5) //│ }; //│ @private -//│ define test_31$x_rest⁰ as fun test_31$x_rest¹(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { +//│ define test_29$x_rest⁰ as fun test_29$x_rest¹(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { //│ set fv_t = fv_tmp; //│ set fv_tmp1 = *⁰(5, 4); //│ set fv_tmp2 = +⁰(fv_t, fv_tmp1); @@ -95,7 +95,7 @@ test(p) + f(p) + test(AA(AA(AA(10)))) + test(B) //│ return -⁰(fv_tmp4, 1) //│ }; //│ @private -//│ define test_28$x_rest⁰ as fun test_28$x_rest¹(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { +//│ define test_26$x_rest⁰ as fun test_26$x_rest¹(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { //│ set fv_t = fv_tmp; //│ set fv_tmp1 = *⁰(5, 4); //│ set fv_tmp2 = +⁰(fv_t, fv_tmp1); @@ -104,12 +104,12 @@ test(p) + f(p) + test(AA(AA(AA(10)))) + test(B) //│ return -⁰(fv_tmp4, 1) //│ }; //│ @private -//│ define test_28$arg$AA$0$_rest⁰ as fun test_28$arg$AA$0$_rest³(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { -//│ return test_28$x_rest¹(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) +//│ define test_26$arg$AA$0$_rest⁰ as fun test_26$arg$AA$0$_rest³(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { +//│ return test_26$x_rest¹(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) //│ }; //│ @private -//│ define test_28$arg$AA$0$_rest¹ as fun test_28$arg$AA$0$_rest²(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { -//│ return test_28$arg$AA$0$_rest³(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) +//│ define test_26$arg$AA$0$_rest¹ as fun test_26$arg$AA$0$_rest²(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) { +//│ return test_26$arg$AA$0$_rest³(fv_t, fv_tmp, fv_tmp1, fv_tmp2, fv_tmp3, fv_tmp4) //│ }; //│ define test⁰ as fun test¹(x) { //│ let t, a, arg$AA$0$, arg$AA$0$1, arg$AA$0$2, tmp11, tmp12, tmp13, tmp14, tmp15; @@ -165,15 +165,15 @@ test(p) + f(p) + test(AA(AA(AA(10)))) + test(B) //│ set tmp3 = f¹(p⁰); //│ set tmp4 = +⁰(tmp2, tmp3); //│ set AA_x = 10; -//│ set tmp5 = test_28$arg$AA$0$_AA³(AA_x); +//│ set tmp5 = test_26$arg$AA$0$_AA³(AA_x); //│ set AA_x1 = tmp5; -//│ set tmp6 = test_28$arg$AA$0$_AA²(AA_x1); +//│ set tmp6 = test_26$arg$AA$0$_AA²(AA_x1); //│ set AA_x2 = tmp6; -//│ set tmp7 = test_28$x_AA¹(AA_x2); -//│ set tmp8 = test_28$test¹(tmp7); +//│ set tmp7 = test_26$x_AA¹(AA_x2); +//│ set tmp8 = test_26$test¹(tmp7); //│ set tmp9 = +⁰(tmp4, tmp8); -//│ set deforest$lam = test_31$x_dflt¹(); -//│ set tmp10 = test_31$test¹(deforest$lam); +//│ set deforest$lam = test_29$x_dflt¹(); +//│ set tmp10 = test_29$test¹(deforest$lam); //│ return +⁰(tmp9, tmp10) //│ —————————————————| Output |————————————————————————————————————————————————————————————————————————— //│ = 78 @@ -225,3 +225,17 @@ f(A) + f(A) //│ deforest > <<< fusing <<< //│ = 2 + +:todo +module Test with + module Test2 with + let x = 1 + fun foo(a) = if a is + AA(y) then x + y +Test.Test2.foo(AA(2)) +//│ deforest > >>> fusing >>> +//│ deforest > AA⁰(2) -> +//│ deforest > match: a⁰ +//│ deforest > fields: a⁰.x¹ +//│ deforest > <<< fusing <<< +//│ ═══[RUNTIME ERROR] ReferenceError: Test2 is not defined diff --git a/hkmc2/shared/src/test/mlscript/invalml/InvalMLPrelude.mls b/hkmc2/shared/src/test/mlscript/invalml/InvalMLPrelude.mls index 94a9aac7fd..2dc958a536 100644 --- a/hkmc2/shared/src/test/mlscript/invalml/InvalMLPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/invalml/InvalMLPrelude.mls @@ -44,7 +44,8 @@ declare module source with declare class Array[T](val length: Int): Array[T] -declare object Symbol with +declare class Symbol +declare module Symbol with // The `TermDef` needs `rhs` to be defined to be recognized as `isMLsFun`. // Otherwise, it would be wrapped in `runtime.safeCall`, which accesses the // uninitialized `runtime` in the `Rendering` module. diff --git a/hkmc2/shared/src/test/mlscript/wasm/Binaryen.mls b/hkmc2/shared/src/test/mlscript/wasm/Binaryen.mls index f533ef4566..e97bc0c05b 100644 --- a/hkmc2/shared/src/test/mlscript/wasm/Binaryen.mls +++ b/hkmc2/shared/src/test/mlscript/wasm/Binaryen.mls @@ -13,8 +13,8 @@ fun compileWatToWasm(wat) = modBuf fun instantiateWasm(wasm, importObj) = assert WebAssembly.validate(wasm) - let mod = new! WebAssembly.Module(wasm) - let inst = new! WebAssembly.Instance(mod, importObj) + let mod = new WebAssembly.Module(wasm) + let inst = new WebAssembly.Instance(mod, importObj) inst