diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 47a717919d..d3aa3a5908 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -29,6 +29,19 @@ sealed abstract class Block extends Product: case _: End => true case _ => false + lazy val isAbortive: Bool = this match + case _: End => false + case _: Throw | _: Break | _: Continue => true + case ret: Return => !ret.implct + case Begin(sub, rst) => sub.isAbortive || rst.isAbortive + case Assign(_, _, rst) => rst.isAbortive + case AssignField(_, _, _, rst) => rst.isAbortive + case AssignDynField(_, _, _, _, rst) => rst.isAbortive + case Match(_, arms, dflt, rst) => rst.isAbortive + case Define(_, rst) => rst.isAbortive + case TryBlock(sub, fin, rst) => rst.isAbortive || sub.isAbortive || fin.isAbortive + case Label(_, _, bod, rst) => rst.isAbortive + case HandleBlock(_, _, _, _, _, handlers, body, rst) => rst.isAbortive lazy val definedVars: Set[Local] = this match case _: Return | _: Throw => Set.empty @@ -287,6 +300,23 @@ case class AssignDynField(lhs: Path, fld: Path, arrayIdx: Bool, rhs: Result, res case class Define(defn: Defn, rest: Block) extends Block with ProductWithTail +object Match: + def apply(scrut: Path, arms: Ls[Case -> Block], dflt: Opt[Block], rest: Block): Block = dflt match + case S(Match(`scrut`, arms2, dflt2, _: End)) => // TODO: also handle non-End rest (may require a join point) + // * Currently, this branch does not seem used, because the UCS already does a good job at merging matches + Match(scrut, arms ::: arms2, dflt2, rest) + case _ => + if !rest.isEmpty && arms.forall(_._2.isAbortive) && dflt.exists(_.isAbortive) + then new Match(scrut, arms, dflt, End("unreachable")) + else new Match(scrut, arms, dflt, rest) + +object Begin: + def apply(sub: Block, rest: Block): Block = + if sub.isEmpty then rest + else if sub.isAbortive then sub + else new Begin(sub, rest) + + case class HandleBlock( lhs: Local, res: Local, 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 b5fb6e9176..56f46eaec5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala @@ -447,6 +447,17 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder: case S(el) => returningTerm(el, endSemi = true) case N => doc"" e :: returningTerm(rest, endSemi) + case Match(scrut, arms, els, rest) + if arms.sizeCompare(1) > 0 && arms.forall(_._1.isInstanceOf[Case.Lit]) => + val l = arms.foldLeft(doc""): (acc, arm) => + acc :: doc" # case ${arm._1.asInstanceOf[Case.Lit].lit.idStr}: #{ ${ + returningTerm(arm._2, endSemi = true) + } # break; #} " + val e = els match + case S(el) => + doc" # default: #{ ${ returningTerm(el, endSemi = true) } # break; #} " + case N => doc"" + doc" # switch (${result(scrut)}) { #{ ${l :: e} #} # }" :: returningTerm(rest, endSemi) case Match(scrut, hd :: tl, els, rest) => val sd = result(scrut) def cond(cse: Case) = cse match diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls b/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls index 19e96e6493..11b3fb765b 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbCodeGen.mls @@ -176,12 +176,16 @@ fun nott = case //│ nott = function nott() { //│ let lambda1; //│ lambda1 = (undefined, function (caseScrut) { -//│ if (caseScrut === true) { -//│ return false -//│ } else if (caseScrut === false) { -//│ return true -//│ } else { -//│ throw globalThis.Object.freeze(new globalThis.Error("match error")) +//│ switch (caseScrut) { +//│ case true: +//│ return false; +//│ break; +//│ case false: +//│ return true; +//│ break; +//│ default: +//│ throw globalThis.Object.freeze(new globalThis.Error("match error")); +//│ break; //│ } //│ }); //│ return lambda1 diff --git a/hkmc2/shared/src/test/mlscript/codegen/IfThenElse.mls b/hkmc2/shared/src/test/mlscript/codegen/IfThenElse.mls index a440378432..5c783aded4 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/IfThenElse.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/IfThenElse.mls @@ -9,12 +9,12 @@ if true then 1 else 0 :sjs let f = x => if x then print("ok") else print("ko") //│ JS (unsanitized): -//│ let f, lambda; -//│ lambda = (undefined, function (x) { +//│ let f, f1; +//│ f1 = function f(x) { //│ if (x === true) { return Predef.print("ok") } else { return Predef.print("ko") } -//│ }); -//│ f = lambda; -//│ f = fun +//│ }; +//│ f = f1; +//│ f = fun f f(true) //│ > ok @@ -26,8 +26,8 @@ f(false) :sjs let f = x => print((if x then "ok" else "ko") + "!") //│ JS (unsanitized): -//│ let f1, lambda1; -//│ lambda1 = (undefined, function (x) { +//│ let f2, lambda; +//│ lambda = (undefined, function (x) { //│ let tmp, tmp1; //│ if (x === true) { //│ tmp = "ok"; @@ -35,14 +35,14 @@ let f = x => print((if x then "ok" else "ko") + "!") //│ tmp1 = tmp + "!"; //│ return Predef.print(tmp1) //│ }); -//│ f1 = lambda1; +//│ f2 = lambda; //│ f = fun :sjs let f = x => print((if x and x then "ok" else "ko") + "!") //│ JS (unsanitized): -//│ let f2, lambda2; -//│ lambda2 = (undefined, function (x) { +//│ let f3, lambda1; +//│ lambda1 = (undefined, function (x) { //│ let tmp, tmp1; //│ if (x === true) { //│ tmp = "ok"; @@ -50,7 +50,7 @@ let f = x => print((if x and x then "ok" else "ko") + "!") //│ tmp1 = tmp + "!"; //│ return Predef.print(tmp1) //│ }); -//│ f2 = lambda2; +//│ f3 = lambda1; //│ f = fun // --- TODO: What we want --- // this.f = (x) => { diff --git a/hkmc2/shared/src/test/mlscript/codegen/PartialApps.mls b/hkmc2/shared/src/test/mlscript/codegen/PartialApps.mls index f3930a6543..f206a5bf8d 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/PartialApps.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/PartialApps.mls @@ -225,17 +225,17 @@ _ - _ of 1, 2 :sjs 1 \ (_ - 2) //│ JS (unsanitized): -//│ let lambda38; lambda38 = (undefined, function (_0) { return _0 - 2 }); Predef.passTo(1, lambda38) +//│ let lambda37; lambda37 = (undefined, function (_0) { return _0 - 2 }); Predef.passTo(1, lambda37) //│ = fun :sjs 1 \ (_ - 2)() //│ JS (unsanitized): -//│ let lambda39, tmp19; -//│ lambda39 = (undefined, function (_0) { +//│ let lambda38, tmp19; +//│ lambda38 = (undefined, function (_0) { //│ return _0 - 2 //│ }); -//│ tmp19 = Predef.passTo(1, lambda39); +//│ tmp19 = Predef.passTo(1, lambda38); //│ runtime.safeCall(tmp19()) //│ = -1 diff --git a/hkmc2/shared/src/test/mlscript/codegen/Throw.mls b/hkmc2/shared/src/test/mlscript/codegen/Throw.mls index 4ef0cd898a..4636263464 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/Throw.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/Throw.mls @@ -47,3 +47,19 @@ f(false) //│ }; //│ f3(false) //│ ═══[RUNTIME ERROR] Error: y + + +:re +:sjs +if false then throw 0 +throw 1 +//│ JS (unsanitized): +//│ let scrut; +//│ scrut = false; +//│ if (scrut === true) { +//│ throw 0 +//│ } else { throw globalThis.Object.freeze(new globalThis.Error("match error")) } +//│ /* unreachable */ +//│ ═══[RUNTIME ERROR] Error: match error + + diff --git a/hkmc2/shared/src/test/mlscript/codegen/While.mls b/hkmc2/shared/src/test/mlscript/codegen/While.mls index a916c4e47a..76e87c7a78 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/While.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/While.mls @@ -17,7 +17,7 @@ //│ } else { //│ throw globalThis.Object.freeze(new globalThis.Error("match error")) //│ } -//│ return runtime.LoopEnd +//│ /* unreachable */ //│ }); //│ tmp1 = while1(); //│ tmp2 = tmp1 !== runtime.LoopEnd; diff --git a/hkmc2/shared/src/test/mlscript/handlers/Debugging.mls b/hkmc2/shared/src/test/mlscript/handlers/Debugging.mls index 853a00e414..8c0165de0d 100644 --- a/hkmc2/shared/src/test/mlscript/handlers/Debugging.mls +++ b/hkmc2/shared/src/test/mlscript/handlers/Debugging.mls @@ -53,44 +53,53 @@ fun f() = //│ this.pc = pc; //│ } //│ resume(value$) { -//│ if (this.pc === 1) { -//│ scrut = value$; -//│ } else if (this.pc === 2) { -//│ tmp = value$; -//│ } else if (this.pc === 3) { -//│ tmp1 = value$; +//│ switch (this.pc) { +//│ case 1: +//│ scrut = value$; +//│ break; +//│ case 2: +//│ tmp = value$; +//│ break; +//│ case 3: +//│ tmp1 = value$; +//│ break; //│ } //│ contLoop: while (true) { -//│ if (this.pc === 4) { -//│ return j / i -//│ } else if (this.pc === 1) { -//│ if (scrut === true) { -//│ tmp = Predef.raiseUnhandledEffect(); -//│ if (tmp instanceof runtime.EffectSig.class) { -//│ return this.doUnwind(tmp, 2) +//│ switch (this.pc) { +//│ case 4: +//│ return j / i; +//│ break; +//│ case 1: +//│ if (scrut === true) { +//│ tmp = Predef.raiseUnhandledEffect(); +//│ if (tmp instanceof runtime.EffectSig.class) { +//│ return this.doUnwind(tmp, 2) +//│ } +//│ this.pc = 2; +//│ continue contLoop +//│ } else { +//│ tmp1 = runtime.Unit; +//│ this.pc = 4; +//│ continue contLoop //│ } -//│ this.pc = 2; -//│ continue contLoop -//│ } else { -//│ tmp1 = runtime.Unit; +//│ /* unreachable */ +//│ break; +//│ case 5: +//│ tmp1 = Predef.print(tmp); +//│ if (tmp1 instanceof runtime.EffectSig.class) { +//│ return this.doUnwind(tmp1, 3) +//│ } +//│ this.pc = 3; +//│ continue contLoop; +//│ break; +//│ case 2: +//│ this.pc = 5; +//│ continue contLoop; +//│ break; +//│ case 3: //│ this.pc = 4; -//│ continue contLoop -//│ } -//│ this.pc = 4; -//│ continue contLoop -//│ } else if (this.pc === 5) { -//│ tmp1 = Predef.print(tmp); -//│ if (tmp1 instanceof runtime.EffectSig.class) { -//│ return this.doUnwind(tmp1, 3) -//│ } -//│ this.pc = 3; -//│ continue contLoop -//│ } else if (this.pc === 2) { -//│ this.pc = 5; -//│ continue contLoop -//│ } else if (this.pc === 3) { -//│ this.pc = 4; -//│ continue contLoop +//│ continue contLoop; +//│ break; //│ } //│ break; //│ } @@ -99,12 +108,16 @@ fun f() = //│ return getLocals3(); //│ } //│ get getLoc() { -//│ if (this.pc === 1) { -//│ return "Debugging.mls:16:6" -//│ } else if (this.pc === 2) { -//│ return "Debugging.mls:17:14" -//│ } else if (this.pc === 3) { -//│ return "Debugging.mls:17:5" +//│ switch (this.pc) { +//│ case 1: +//│ return "Debugging.mls:16:6"; +//│ break; +//│ case 2: +//│ return "Debugging.mls:17:14"; +//│ break; +//│ case 3: +//│ return "Debugging.mls:17:5"; +//│ break; //│ } //│ } //│ toString() { return runtime.render(this); } @@ -148,8 +161,8 @@ lambda_test(() => raiseUnhandledEffect() 100) //│ ═══[RUNTIME ERROR] Error: Unhandled effect FatalEffect -//│ at lambda (Debugging.mls:148:3) -//│ at lambda_test (Debugging.mls:145:3) +//│ at lambda (Debugging.mls:161:3) +//│ at lambda_test (Debugging.mls:158:3) import "../../mlscript-compile/Runtime.mls" @@ -228,9 +241,9 @@ fun f() = f() //│ > [FnLocalsInfo("‹top level›", [LocalVarInfo("i", 100)]), FnLocalsInfo("f", [LocalVarInfo("j", 200)])] //│ > Stack Trace: -//│ > at f (Debugging.mls:221:3) with locals: j=200 +//│ > at f (Debugging.mls:234:3) with locals: j=200 //│ > Stack Trace: -//│ > at f (Debugging.mls:223:3) +//│ > at f (Debugging.mls:236:3) //│ > Stack Trace: -//│ > at f (Debugging.mls:224:3) with locals: j=300 +//│ > at f (Debugging.mls:237:3) with locals: j=300 //│ > [FnLocalsInfo("‹top level›", [LocalVarInfo("i", 100)]), FnLocalsInfo("f", [LocalVarInfo("j", 300)])] diff --git a/hkmc2/shared/src/test/mlscript/handlers/EffectsInClasses.mls b/hkmc2/shared/src/test/mlscript/handlers/EffectsInClasses.mls index fbef803763..803fd3577c 100644 --- a/hkmc2/shared/src/test/mlscript/handlers/EffectsInClasses.mls +++ b/hkmc2/shared/src/test/mlscript/handlers/EffectsInClasses.mls @@ -31,27 +31,35 @@ data class Lol(h) with //│ this.pc = pc; //│ } //│ resume(value$) { -//│ if (this.pc === 1) { -//│ tmp = value$; -//│ } else if (this.pc === 2) { -//│ res = value$; +//│ switch (this.pc) { +//│ case 1: +//│ tmp = value$; +//│ break; +//│ case 2: +//│ res = value$; +//│ break; //│ } //│ contLoop: while (true) { -//│ if (this.pc === 3) { -//│ return this$Lol -//│ } else if (this.pc === 4) { -//│ res = Predef.print(tmp); -//│ if (res instanceof runtime.EffectSig.class) { -//│ return this.doUnwind(res, 2) -//│ } -//│ this.pc = 2; -//│ continue contLoop -//│ } else if (this.pc === 1) { -//│ this.pc = 4; -//│ continue contLoop -//│ } else if (this.pc === 2) { -//│ this.pc = 3; -//│ continue contLoop +//│ switch (this.pc) { +//│ case 3: +//│ return this$Lol; +//│ break; +//│ case 4: +//│ res = Predef.print(tmp); +//│ if (res instanceof runtime.EffectSig.class) { +//│ return this.doUnwind(res, 2) +//│ } +//│ this.pc = 2; +//│ continue contLoop; +//│ break; +//│ case 1: +//│ this.pc = 4; +//│ continue contLoop; +//│ break; +//│ case 2: +//│ this.pc = 3; +//│ continue contLoop; +//│ break; //│ } //│ break; //│ } diff --git a/hkmc2/shared/src/test/mlscript/handlers/RecursiveHandlers.mls b/hkmc2/shared/src/test/mlscript/handlers/RecursiveHandlers.mls index 74770fcc40..0ecaf9b42a 100644 --- a/hkmc2/shared/src/test/mlscript/handlers/RecursiveHandlers.mls +++ b/hkmc2/shared/src/test/mlscript/handlers/RecursiveHandlers.mls @@ -183,11 +183,11 @@ str //│ this.pc = pc; //│ } //│ resume(value$) { -//│ if (this.pc === 7) { +//│ if (this.pc === 6) { //│ tmp13 = value$; //│ } //│ contLoop: while (true) { -//│ if (this.pc === 7) { +//│ if (this.pc === 6) { //│ tmp14 = str + "A"; //│ str = tmp14; //│ return runtime.Unit @@ -207,7 +207,7 @@ str //│ str = tmp12; //│ tmp13 = runtime.safeCall(k(arg)); //│ if (tmp13 instanceof runtime.EffectSig.class) { -//│ return doUnwind1(tmp13, 7) +//│ return doUnwind1(tmp13, 6) //│ } //│ tmp14 = str + "A"; //│ str = tmp14; @@ -229,11 +229,11 @@ str //│ this.pc = pc; //│ } //│ resume(value$) { -//│ if (this.pc === 6) { +//│ if (this.pc === 5) { //│ tmp11 = value$; //│ } //│ contLoop: while (true) { -//│ if (this.pc === 6) { +//│ if (this.pc === 5) { //│ return tmp11 //│ } //│ break; @@ -319,21 +319,27 @@ str //│ this.pc = pc; //│ } //│ resume(value$) { -//│ if (this.pc === 1) { -//│ tmp12 = value$; -//│ } else if (this.pc === 2) { -//│ res7 = value$; +//│ switch (this.pc) { +//│ case 1: +//│ tmp12 = value$; +//│ break; +//│ case 2: +//│ res7 = value$; +//│ break; //│ } //│ contLoop: while (true) { -//│ if (this.pc === 1) { -//│ res7 = runtime.safeCall(h1.perform(runtime.Unit)); -//│ if (res7 instanceof runtime.EffectSig.class) { -//│ return this.doUnwind(res7, 2) -//│ } -//│ this.pc = 2; -//│ continue contLoop -//│ } else if (this.pc === 2) { -//│ return res7 +//│ switch (this.pc) { +//│ case 1: +//│ res7 = runtime.safeCall(h1.perform(runtime.Unit)); +//│ if (res7 instanceof runtime.EffectSig.class) { +//│ return this.doUnwind(res7, 2) +//│ } +//│ this.pc = 2; +//│ continue contLoop; +//│ break; +//│ case 2: +//│ return res7; +//│ break; //│ } //│ break; //│ } @@ -357,7 +363,7 @@ str //│ }; //│ tmp11 = handleBlock$8(); //│ if (tmp11 instanceof runtime.EffectSig.class) { -//│ return doUnwind(tmp11, 6) +//│ return doUnwind(tmp11, 5) //│ } //│ return tmp11 //│ }; diff --git a/hkmc2/shared/src/test/mlscript/handlers/StackSafety.mls b/hkmc2/shared/src/test/mlscript/handlers/StackSafety.mls index 3b67e7af1e..7fbe35f933 100644 --- a/hkmc2/shared/src/test/mlscript/handlers/StackSafety.mls +++ b/hkmc2/shared/src/test/mlscript/handlers/StackSafety.mls @@ -97,10 +97,13 @@ sum(10000) //│ } //│ contLoop: while (true) { //│ runtime.stackDepth = curDepth1; -//│ if (this.pc === 0) { -//│ return sum1(n) -//│ } else if (this.pc === 1) { -//│ return n + tmp1 +//│ switch (this.pc) { +//│ case 0: +//│ return sum1(n); +//│ break; +//│ case 1: +//│ return n + tmp1; +//│ break; //│ } //│ break; //│ } @@ -149,6 +152,8 @@ fun sum(n) = sum(10000) //│ ═══[RUNTIME ERROR] RangeError: Maximum call stack size exceeded + + :effectHandlers :stackSafe 100 mut val ctr = 0 diff --git a/hkmc2/shared/src/test/mlscript/lifter/StackSafetyLift.mls b/hkmc2/shared/src/test/mlscript/lifter/StackSafetyLift.mls index 075ed11084..e5bd090cd1 100644 --- a/hkmc2/shared/src/test/mlscript/lifter/StackSafetyLift.mls +++ b/hkmc2/shared/src/test/mlscript/lifter/StackSafetyLift.mls @@ -134,10 +134,13 @@ sum(10000) //│ } //│ contLoop: while (true) { //│ runtime.stackDepth = curDepth; -//│ if (this.pc === 0) { -//│ return sum1(this.n) -//│ } else if (this.pc === 1) { -//│ return this.n + this.tmp +//│ switch (this.pc) { +//│ case 0: +//│ return sum1(this.n); +//│ break; +//│ case 1: +//│ return this.n + this.tmp; +//│ break; //│ } //│ break; //│ } diff --git a/hkmc2/shared/src/test/mlscript/tailrec/TailRecOpt.mls b/hkmc2/shared/src/test/mlscript/tailrec/TailRecOpt.mls index ea4a8d459c..327ee65680 100644 --- a/hkmc2/shared/src/test/mlscript/tailrec/TailRecOpt.mls +++ b/hkmc2/shared/src/test/mlscript/tailrec/TailRecOpt.mls @@ -20,31 +20,34 @@ f(10000, 20000, 0) //│ g_f = function g_f(id, param0, param1, param2, param3) { //│ let scrut, scrut1, tmp, tmp1, tmp2; //│ loopLabel: while (true) { -//│ if (id === 0) { -//│ tmp = param2 + param3; -//│ param2 = tmp; -//│ id = 1; -//│ continue loopLabel -//│ } else if (id === 1) { -//│ scrut = param0 > 0; -//│ if (scrut === true) { -//│ tmp1 = param0 - 1; -//│ param0 = tmp1; -//│ param3 = 1; -//│ id = 0; -//│ continue loopLabel -//│ } else { -//│ scrut1 = param1 > 0; -//│ if (scrut1 === true) { -//│ tmp2 = param1 - 1; -//│ param1 = tmp2; -//│ param3 = 2; +//│ switch (id) { +//│ case 0: +//│ tmp = param2 + param3; +//│ param2 = tmp; +//│ id = 1; +//│ continue loopLabel; +//│ break; +//│ case 1: +//│ scrut = param0 > 0; +//│ if (scrut === true) { +//│ tmp1 = param0 - 1; +//│ param0 = tmp1; +//│ param3 = 1; //│ id = 0; //│ continue loopLabel //│ } else { -//│ return param2 +//│ scrut1 = param1 > 0; +//│ if (scrut1 === true) { +//│ tmp2 = param1 - 1; +//│ param1 = tmp2; +//│ param3 = 2; +//│ id = 0; +//│ continue loopLabel +//│ } else { +//│ return param2 +//│ } //│ } -//│ } +//│ break; //│ } //│ break; //│ } @@ -143,7 +146,7 @@ fun f(x) = @tailcall f(x) @tailcall g() //│ ╔══[ERROR] This call is not in tail position. -//│ ║ l.142: @tailcall f(x) +//│ ║ l.145: @tailcall f(x) //│ ╙── ^ :lift @@ -161,10 +164,10 @@ module A with @tailcall g(x - 1) A.f(10000) //│ ╔══[ERROR] This tail call exits the current scope is not optimized. -//│ ║ l.160: fun g(x) = if x < 0 then 0 else @tailcall f(x) +//│ ║ l.163: fun g(x) = if x < 0 then 0 else @tailcall f(x) //│ ╙── ^^^ //│ ╔══[ERROR] This tail call exits the current scope is not optimized. -//│ ║ l.161: @tailcall g(x - 1) +//│ ║ l.164: @tailcall g(x - 1) //│ ╙── ^^^^^^^^ //│ ═══[RUNTIME ERROR] RangeError: Maximum call stack size exceeded @@ -191,12 +194,12 @@ class A with fun g(x) = if x == 0 then 1 else @tailcall f(x - 1) (new A).f(10) //│ ╔══[ERROR] Calls from class methods cannot yet be marked @tailcall. -//│ ║ l.190: @tailrec fun f(x) = if x == 0 then 0 else @tailcall g(x - 1) +//│ ║ l.193: @tailrec fun f(x) = if x == 0 then 0 else @tailcall g(x - 1) //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Class methods may not yet be marked @tailrec. -//│ ║ l.190: @tailrec fun f(x) = if x == 0 then 0 else @tailcall g(x - 1) +//│ ║ l.193: @tailrec fun f(x) = if x == 0 then 0 else @tailcall g(x - 1) //│ ╙── ^ //│ ╔══[ERROR] Calls from class methods cannot yet be marked @tailcall. -//│ ║ l.191: fun g(x) = if x == 0 then 1 else @tailcall f(x - 1) +//│ ║ l.194: fun g(x) = if x == 0 then 1 else @tailcall f(x - 1) //│ ╙── ^^^^^^^^ //│ = 0 diff --git a/hkmc2/shared/src/test/mlscript/ucs/normalization/Deduplication.mls b/hkmc2/shared/src/test/mlscript/ucs/normalization/Deduplication.mls index 4bba48a888..0cf3ea14b5 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/normalization/Deduplication.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/normalization/Deduplication.mls @@ -41,27 +41,41 @@ if x is //│ let tmp2; //│ split_root$: { //│ split_1$: { -//│ if (x === 0) { -//│ if (y === 0) { -//│ if (z === 0) { -//│ tmp2 = "000"; -//│ break split_root$ -//│ } else if (z === 1) { -//│ tmp2 = "001"; -//│ break split_root$ -//│ } else { -//│ break split_1$ +//│ switch (x) { +//│ case 0: +//│ switch (y) { +//│ case 0: +//│ switch (z) { +//│ case 0: +//│ tmp2 = "000"; +//│ break split_root$; +//│ break; +//│ case 1: +//│ tmp2 = "001"; +//│ break split_root$; +//│ break; +//│ default: +//│ break split_1$; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp2 = "01"; +//│ break split_root$; +//│ break; +//│ default: +//│ break split_1$; +//│ break; //│ } -//│ } else if (y === 1) { -//│ tmp2 = "01"; -//│ break split_root$ -//│ } else { -//│ break split_1$ -//│ } -//│ } else if (x === 1) { -//│ tmp2 = "1"; -//│ break split_root$ -//│ } else { break split_1$ } +//│ break; +//│ case 1: +//│ tmp2 = "1"; +//│ break split_root$; +//│ break; +//│ default: +//│ break split_1$; +//│ break; +//│ } //│ } //│ tmp2 = ""; //│ } @@ -81,27 +95,41 @@ let qqq = if x is //│ let qqq, tmp3; //│ split_root$1: { //│ split_1$1: { -//│ if (x === 0) { -//│ if (y === 0) { -//│ if (z === 0) { -//│ tmp3 = "000"; -//│ break split_root$1 -//│ } else if (z === 1) { -//│ tmp3 = "001"; -//│ break split_root$1 -//│ } else { -//│ break split_1$1 +//│ switch (x) { +//│ case 0: +//│ switch (y) { +//│ case 0: +//│ switch (z) { +//│ case 0: +//│ tmp3 = "000"; +//│ break split_root$1; +//│ break; +//│ case 1: +//│ tmp3 = "001"; +//│ break split_root$1; +//│ break; +//│ default: +//│ break split_1$1; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp3 = "01"; +//│ break split_root$1; +//│ break; +//│ default: +//│ break split_1$1; +//│ break; //│ } -//│ } else if (y === 1) { -//│ tmp3 = "01"; -//│ break split_root$1 -//│ } else { -//│ break split_1$1 -//│ } -//│ } else if (x === 1) { -//│ tmp3 = "1"; -//│ break split_root$1 -//│ } else { break split_1$1 } +//│ break; +//│ case 1: +//│ tmp3 = "1"; +//│ break split_root$1; +//│ break; +//│ default: +//│ break split_1$1; +//│ break; +//│ } //│ } //│ tmp3 = ""; //│ } @@ -121,27 +149,41 @@ print of if x is //│ let tmp4; //│ split_root$2: { //│ split_1$2: { -//│ if (x === 0) { -//│ if (y === 0) { -//│ if (z === 0) { -//│ tmp4 = "000"; -//│ break split_root$2 -//│ } else if (z === 1) { -//│ tmp4 = "001"; -//│ break split_root$2 -//│ } else { -//│ break split_1$2 +//│ switch (x) { +//│ case 0: +//│ switch (y) { +//│ case 0: +//│ switch (z) { +//│ case 0: +//│ tmp4 = "000"; +//│ break split_root$2; +//│ break; +//│ case 1: +//│ tmp4 = "001"; +//│ break split_root$2; +//│ break; +//│ default: +//│ break split_1$2; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp4 = "01"; +//│ break split_root$2; +//│ break; +//│ default: +//│ break split_1$2; +//│ break; //│ } -//│ } else if (y === 1) { -//│ tmp4 = "01"; -//│ break split_root$2 -//│ } else { -//│ break split_1$2 -//│ } -//│ } else if (x === 1) { -//│ tmp4 = "1"; -//│ break split_root$2 -//│ } else { break split_1$2 } +//│ break; +//│ case 1: +//│ tmp4 = "1"; +//│ break split_root$2; +//│ break; +//│ default: +//│ break split_1$2; +//│ break; +//│ } //│ } //│ tmp4 = ""; //│ } @@ -164,27 +206,41 @@ fun foo(x, y, z) = //│ let tmp5; //│ split_root$3: { //│ split_1$3: { -//│ if (x1 === 0) { -//│ if (y1 === 0) { -//│ if (z1 === 0) { -//│ tmp5 = "000"; -//│ break split_root$3 -//│ } else if (z1 === 1) { -//│ tmp5 = "001"; -//│ break split_root$3 -//│ } else { -//│ break split_1$3 +//│ switch (x1) { +//│ case 0: +//│ switch (y1) { +//│ case 0: +//│ switch (z1) { +//│ case 0: +//│ tmp5 = "000"; +//│ break split_root$3; +//│ break; +//│ case 1: +//│ tmp5 = "001"; +//│ break split_root$3; +//│ break; +//│ default: +//│ break split_1$3; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp5 = "01"; +//│ break split_root$3; +//│ break; +//│ default: +//│ break split_1$3; +//│ break; //│ } -//│ } else if (y1 === 1) { -//│ tmp5 = "01"; -//│ break split_root$3 -//│ } else { -//│ break split_1$3 -//│ } -//│ } else if (x1 === 1) { -//│ tmp5 = "1"; -//│ break split_root$3 -//│ } else { break split_1$3 } +//│ break; +//│ case 1: +//│ tmp5 = "1"; +//│ break split_root$3; +//│ break; +//│ default: +//│ break split_1$3; +//│ break; +//│ } //│ } //│ tmp5 = ""; //│ } @@ -210,39 +266,51 @@ print of if //│ split_1$3: { //│ split_2$: { //│ split_3$: { -//│ if (x === 0) { -//│ if (y === 0) { -//│ if (z === 0) { -//│ tmp5 = "000"; -//│ break split_root$3 -//│ } else if (z === 1) { -//│ break split_1$3 -//│ } else { -//│ break split_2$ +//│ switch (x) { +//│ case 0: +//│ switch (y) { +//│ case 0: +//│ switch (z) { +//│ case 0: +//│ tmp5 = "000"; +//│ break split_root$3; +//│ break; +//│ case 1: +//│ break split_1$3; +//│ break; +//│ default: +//│ break split_2$; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp5 = "01_"; +//│ break split_root$3; +//│ break; +//│ default: +//│ if (z === 1) { +//│ break split_1$3 +//│ } else { +//│ if (y === 2) { +//│ break split_3$ +//│ } else { +//│ break split_2$ +//│ } +//│ } +//│ break; //│ } -//│ } else if (y === 1) { -//│ tmp5 = "01_"; -//│ break split_root$3 -//│ } else { -//│ if (z === 1) { -//│ break split_1$3 +//│ break; +//│ case 1: +//│ tmp5 = "1__"; +//│ break split_root$3; +//│ break; +//│ default: +//│ if (y === 2) { +//│ break split_3$ //│ } else { -//│ if (y === 2) { -//│ break split_3$ -//│ } else { -//│ break split_2$ -//│ } +//│ break split_2$ //│ } -//│ } -//│ } else if (x === 1) { -//│ tmp5 = "1__"; -//│ break split_root$3 -//│ } else { -//│ if (y === 2) { -//│ break split_3$ -//│ } else { -//│ break split_2$ -//│ } +//│ break; //│ } //│ } //│ tmp5 = "_2_"; @@ -274,39 +342,51 @@ fun foo(x, y, z) = if //│ split_1$4: { //│ split_2$1: { //│ split_3$1: { -//│ if (x1 === 0) { -//│ if (y1 === 0) { -//│ if (z1 === 0) { -//│ tmp6 = "000"; -//│ break split_root$4 -//│ } else if (z1 === 1) { -//│ break split_1$4 -//│ } else { -//│ break split_2$1 +//│ switch (x1) { +//│ case 0: +//│ switch (y1) { +//│ case 0: +//│ switch (z1) { +//│ case 0: +//│ tmp6 = "000"; +//│ break split_root$4; +//│ break; +//│ case 1: +//│ break split_1$4; +//│ break; +//│ default: +//│ break split_2$1; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp6 = "01_"; +//│ break split_root$4; +//│ break; +//│ default: +//│ if (z1 === 1) { +//│ break split_1$4 +//│ } else { +//│ if (y1 === 2) { +//│ break split_3$1 +//│ } else { +//│ break split_2$1 +//│ } +//│ } +//│ break; //│ } -//│ } else if (y1 === 1) { -//│ tmp6 = "01_"; -//│ break split_root$4 -//│ } else { -//│ if (z1 === 1) { -//│ break split_1$4 +//│ break; +//│ case 1: +//│ tmp6 = "1__"; +//│ break split_root$4; +//│ break; +//│ default: +//│ if (y1 === 2) { +//│ break split_3$1 //│ } else { -//│ if (y1 === 2) { -//│ break split_3$1 -//│ } else { -//│ break split_2$1 -//│ } +//│ break split_2$1 //│ } -//│ } -//│ } else if (x1 === 1) { -//│ tmp6 = "1__"; -//│ break split_root$4 -//│ } else { -//│ if (y1 === 2) { -//│ break split_3$1 -//│ } else { -//│ break split_2$1 -//│ } +//│ break; //│ } //│ } //│ tmp6 = "_2_"; @@ -339,27 +419,41 @@ fun foo(x, y, z) = if x is //│ let value, tmp6; //│ split_root$4: { //│ split_1$4: { -//│ if (x1 === 0) { -//│ if (y1 === 0) { -//│ if (z1 === 0) { -//│ tmp6 = "000"; -//│ break split_root$4 -//│ } else if (z1 === 1) { -//│ tmp6 = "001"; -//│ break split_root$4 -//│ } else { -//│ break split_1$4 +//│ switch (x1) { +//│ case 0: +//│ switch (y1) { +//│ case 0: +//│ switch (z1) { +//│ case 0: +//│ tmp6 = "000"; +//│ break split_root$4; +//│ break; +//│ case 1: +//│ tmp6 = "001"; +//│ break split_root$4; +//│ break; +//│ default: +//│ break split_1$4; +//│ break; +//│ } +//│ break; +//│ case 1: +//│ tmp6 = "01"; +//│ break split_root$4; +//│ break; +//│ default: +//│ break split_1$4; +//│ break; //│ } -//│ } else if (y1 === 1) { -//│ tmp6 = "01"; -//│ break split_root$4 -//│ } else { -//│ break split_1$4 -//│ } -//│ } else if (x1 === 1) { -//│ tmp6 = "1"; -//│ break split_root$4 -//│ } else { break split_1$4 } +//│ break; +//│ case 1: +//│ tmp6 = "1"; +//│ break split_root$4; +//│ break; +//│ default: +//│ break split_1$4; +//│ break; +//│ } //│ } //│ value = "hello"; //│ tmp6 = expensive_call(value);