From de66f553bb71837818524c0b0a145a9ad789737c Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 12 Jul 2022 12:13:16 +0800 Subject: [PATCH] Fix the res running variable is not consistent with DiffTests --- .../src/main/scala/mlscript/JSBackend.scala | 16 +++-- .../main/scala/mlscript/codegen/Scope.scala | 5 ++ shared/src/test/diff/codegen/Classes.mls | 13 +--- shared/src/test/diff/codegen/Declare.mls | 3 - shared/src/test/diff/codegen/Inheritance.mls | 1 - shared/src/test/diff/codegen/Parentheses.mls | 1 - shared/src/test/diff/codegen/Polyfill.mls | 2 - shared/src/test/diff/codegen/Recursion.mls | 3 - shared/src/test/diff/codegen/Res.mls | 5 +- shared/src/test/diff/codegen/Terms.mls | 9 --- shared/src/test/diff/codegen/TraitMethods.mls | 16 ++--- .../src/test/diff/codegen/TrickyShadowing.mls | 16 +---- shared/src/test/diff/codegen/TrickyTerms.mls | 4 -- shared/src/test/diff/codegen/TrickyWiths.mls | 2 - shared/src/test/diff/mlscript/BadInherit2.mls | 4 +- .../src/test/diff/mlscript/BadInherit2Co.mls | 4 +- shared/src/test/diff/mlscript/MLTuples.mls | 37 +++++------ shared/src/test/diff/mlscript/Mohammad.mls | 8 +-- shared/src/test/diff/mlscript/Under.mls | 12 ++-- shared/src/test/diff/mlscript/i65.mls | 65 +++++++++++++++++++ .../src/test/scala/mlscript/DiffTests.scala | 25 +++---- 21 files changed, 140 insertions(+), 111 deletions(-) create mode 100644 shared/src/test/diff/mlscript/i65.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 1fc099c7b..17baca432 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -594,9 +594,8 @@ class JSTestBackend extends JSBackend { ((JSIdent("globalThis").member(sym.runtimeName) := (expr match { case t: JSArrowFn => t.toFuncExpr(S(sym.runtimeName)) case t => t - })) :: - (resultIdent := JSIdent(sym.runtimeName)) :: - Nil) + })) :: Nil), + sym.runtimeName ) case L(reason) => JSTestBackend.AbortedQuery(reason) } @@ -606,7 +605,9 @@ class JSTestBackend extends JSBackend { case term: Term => try { val body = translateTerm(term)(scope) - JSTestBackend.CodeQuery(scope.tempVars.emit(), (resultIdent := body) :: Nil) + val res = JSTestBackend.CodeQuery(scope.tempVars.emit(), (resultIdent := body) :: Nil) + scope.refreshRes() + res } catch { case e: UnimplementedError => JSTestBackend.AbortedQuery(e.getMessage()) case e: Throwable => throw e @@ -641,18 +642,19 @@ object JSTestBackend { /** * The entry generates meaningful code. */ - final case class CodeQuery(prelude: Ls[Str], code: Ls[Str]) extends Query { + final case class CodeQuery(prelude: Ls[Str], code: Ls[Str], res: Str) extends Query { } object CodeQuery { - def apply(decls: Opt[JSLetDecl], stmts: Ls[JSStmt]): CodeQuery = + def apply(decls: Opt[JSLetDecl], stmts: Ls[JSStmt], res: Str = "res"): CodeQuery = CodeQuery( decls match { case S(stmt) => stmt.toSourceCode.toLines case N => Nil }, - SourceCode.fromStmts(stmts).toLines + SourceCode.fromStmts(stmts).toLines, + res ) } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index f8ec76f2d..95820f733 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -7,6 +7,7 @@ import scala.reflect.ClassTag import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls} import mlscript.MethodDef import mlscript.Term +import mlscript.utils.AnyOps class Scope(name: Str, enclosing: Opt[Scope]) { private val lexicalTypeSymbols = scala.collection.mutable.HashMap[Str, TypeSymbol]() @@ -301,6 +302,10 @@ class Scope(name: Str, enclosing: Opt[Scope]) { * Shorthands for deriving function scopes. */ def derive(name: Str, params: Ls[Str]): Scope = Scope(name, params, this) + + def refreshRes(): Unit = { + lexicalValueSymbols("res") = ValueSymbol("res", "res") + } } object Scope { diff --git a/shared/src/test/diff/codegen/Classes.mls b/shared/src/test/diff/codegen/Classes.mls index 0e1f98121..b06063292 100644 --- a/shared/src/test/diff/codegen/Classes.mls +++ b/shared/src/test/diff/codegen/Classes.mls @@ -33,7 +33,6 @@ def Box value = Box { inner = value } //│ globalThis.Box1 = function Box1(value) { //│ return new Box({ inner: value }); //│ }; -//│ res = Box1; //│ // End of generated code //│ Box: 'inner -> Box['inner] //│ = [Function: Box1] @@ -43,10 +42,8 @@ def box1 = Box 1 def box2 = box1.Map (fun x -> add x 1) //│ // Query 1 //│ globalThis.box1 = Box1(1); -//│ res = box1; //│ // Query 2 //│ globalThis.box2 = box1.Map((x) => add(x)(1)); -//│ res = box2; //│ // End of generated code //│ box1: Box[1] //│ = Box { inner: 1 } @@ -92,7 +89,6 @@ def MyBox inner info = MyBox { inner; info } //│ info: info //│ })); //│ }; -//│ res = MyBox1; //│ // End of generated code //│ MyBox: (int & 'inner) -> (string & 'info) -> (MyBox with {info: 'info, inner: 'inner}) //│ = [Function: MyBox1] @@ -105,15 +101,12 @@ mb2 = mb.Map (fun x -> x * 3) mb2.Get //│ // Query 1 //│ globalThis.mb = MyBox1(1)("hello"); -//│ res = mb; //│ // Query 2 //│ globalThis.mb1 = mb.Inc; -//│ res = mb1; //│ // Query 3 //│ res = mb1.Get; //│ // Query 4 //│ globalThis.mb2 = mb1.Map((x) => x * 3); -//│ res = mb2; //│ // Query 5 //│ res = mb2.Get; //│ // End of generated code @@ -168,13 +161,13 @@ def f: Box[?] -> int :e f(Box{}) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.169: f(Box{}) +//│ ║ l.162: f(Box{}) //│ ║ ^^^^^^^^ //│ ╟── record literal of type `anything` does not match type `nothing` -//│ ║ l.169: f(Box{}) +//│ ║ l.162: f(Box{}) //│ ║ ^^ //│ ╟── Note: constraint arises from type wildcard: -//│ ║ l.164: def f: Box[?] -> int +//│ ║ l.157: def f: Box[?] -> int //│ ╙── ^ //│ res: error | int //│ = diff --git a/shared/src/test/diff/codegen/Declare.mls b/shared/src/test/diff/codegen/Declare.mls index 2fbc0096c..d0e77d783 100644 --- a/shared/src/test/diff/codegen/Declare.mls +++ b/shared/src/test/diff/codegen/Declare.mls @@ -26,7 +26,6 @@ def q = 0 //│ // Query 1 aborted: b and a are not implemented //│ // Query 2 //│ globalThis.q = 0; -//│ res = q; //│ // End of generated code //│ c: int //│ = @@ -87,10 +86,8 @@ def break = 1 def str = "str" //│ // Query 1 //│ globalThis.break1 = 1; -//│ res = break1; //│ // Query 2 //│ globalThis.str = "str"; -//│ res = str; //│ // End of generated code //│ break: 1 //│ = 1 diff --git a/shared/src/test/diff/codegen/Inheritance.mls b/shared/src/test/diff/codegen/Inheritance.mls index 0f872d167..cb6d34068 100644 --- a/shared/src/test/diff/codegen/Inheritance.mls +++ b/shared/src/test/diff/codegen/Inheritance.mls @@ -230,7 +230,6 @@ checkS p && checkR p && checkQ p && checkP p //│ r: 0, //│ p: 0 //│ }); -//│ res = p; //│ // Query 2 //│ res = checkS(p) && checkR(p) && checkQ(p) && checkP(p); //│ // End of generated code diff --git a/shared/src/test/diff/codegen/Parentheses.mls b/shared/src/test/diff/codegen/Parentheses.mls index 725619096..1332a4238 100644 --- a/shared/src/test/diff/codegen/Parentheses.mls +++ b/shared/src/test/diff/codegen/Parentheses.mls @@ -33,7 +33,6 @@ x = 0 x > 0 && x < 0 //│ // Query 1 //│ globalThis.x = 0; -//│ res = x; //│ // Query 2 //│ res = x > 0 && x < 0; //│ // End of generated code diff --git a/shared/src/test/diff/codegen/Polyfill.mls b/shared/src/test/diff/codegen/Polyfill.mls index 998cc538d..5d3af37f5 100644 --- a/shared/src/test/diff/codegen/Polyfill.mls +++ b/shared/src/test/diff/codegen/Polyfill.mls @@ -42,7 +42,6 @@ def add x y = x + y + x + y //│ globalThis.add = function add(x) { //│ return (y) => x + y + x + y; //│ }; -//│ res = add; //│ // End of generated code //│ add: int -> int -> int //│ = [Function: add] @@ -86,7 +85,6 @@ n = 123 with { x = 1 } //│ } //│ // Query 1 //│ globalThis.n = withConstruct(123, { x: 1 }); -//│ res = n; //│ // End of generated code //│ n: 123 & {x: 1} //│ = [Number: 123] { x: 1 } diff --git a/shared/src/test/diff/codegen/Recursion.mls b/shared/src/test/diff/codegen/Recursion.mls index 5bab891e0..67e91587a 100644 --- a/shared/src/test/diff/codegen/Recursion.mls +++ b/shared/src/test/diff/codegen/Recursion.mls @@ -8,7 +8,6 @@ rec def pow0 n x = //│ globalThis.pow0 = function pow0(n) { //│ return (x) => n > 0 ? pow0(n - 1)(x) * x : 1; //│ }; -//│ res = pow0; //│ // End of generated code //│ pow0: int -> int -> int //│ = [Function: pow0] @@ -31,7 +30,6 @@ def pow1 x = //│ return n > 0 ? go(n - 1) * x : 1; //│ })); //│ }; -//│ res = pow1; //│ // End of generated code //│ pow1: int -> int -> int //│ = [Function: pow1] @@ -46,7 +44,6 @@ rec def pow2 n = { call = fun x -> if n > 0 then (pow2 (n - 1)).call x * x else //│ globalThis.pow2 = function pow2(n) { //│ return { call: (x) => n > 0 ? pow2(n - 1).call(x) * x : 1 }; //│ }; -//│ res = pow2; //│ // End of generated code //│ pow2: int -> {call: int -> int} //│ = [Function: pow2] diff --git a/shared/src/test/diff/codegen/Res.mls b/shared/src/test/diff/codegen/Res.mls index db458e7b1..1a011cded 100644 --- a/shared/src/test/diff/codegen/Res.mls +++ b/shared/src/test/diff/codegen/Res.mls @@ -56,7 +56,6 @@ res == 4 def res = 0 //│ // Query 1 //│ globalThis.res1 = 0; -//│ res = res1; //│ // End of generated code //│ res: 0 //│ = 0 @@ -74,7 +73,7 @@ res + 1 :js res + 1 //│ // Query 1 -//│ res = res1 + 1; +//│ res = res + 1; //│ // End of generated code //│ res: int -//│ = 1 +//│ = 2 diff --git a/shared/src/test/diff/codegen/Terms.mls b/shared/src/test/diff/codegen/Terms.mls index c2498ad9c..7a1e3fad6 100644 --- a/shared/src/test/diff/codegen/Terms.mls +++ b/shared/src/test/diff/codegen/Terms.mls @@ -131,7 +131,6 @@ f 0 //│ globalThis.f = function f(x) { //│ return x; //│ }; -//│ res = f; //│ // Query 2 //│ res = f(0); //│ // End of generated code @@ -248,7 +247,6 @@ def f x = case x of { } //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ }; -//│ res = f1; //│ // End of generated code //│ f: nothing -> nothing //│ = [Function: f1] @@ -358,13 +356,11 @@ rcd2 = rcd1 with { x = 1; z = 2 } //│ x: "a", //│ y: "b" //│ }; -//│ res = rcd1; //│ // Query 2 //│ globalThis.rcd2 = withConstruct(rcd1, { //│ x: 1, //│ z: 2 //│ }); -//│ res = rcd2; //│ // Query 3 //│ res = [ //│ rcd1.x, @@ -390,7 +386,6 @@ a1.x <- 666 a1.x //│ // Query 1 //│ globalThis.a1 = new M({ x: 233 }); -//│ res = a1; //│ // Query 2 //│ res = (a1.x = 666, []); //│ // Query 3 @@ -412,7 +407,6 @@ t1 = (mut "hello", mut true) //│ "hello", //│ true //│ ]; -//│ res = t1; //│ // End of generated code //│ t1: (mut 'a, mut 'b,) //│ where @@ -443,7 +437,6 @@ muta1 = (mut 1, mut 2, mut 3, mut 4) //│ 3, //│ 4 //│ ]; -//│ res = muta1; //│ // End of generated code //│ muta1: MutArray[int] //│ = @@ -476,7 +469,6 @@ xpp a1 //│ globalThis.xpp = function xpp(rc) { //│ return ((_) => rc)((rc.x = rc.x + 1, [])); //│ }; -//│ res = xpp; //│ // Query 2 //│ res = xpp(a1); //│ // End of generated code @@ -495,7 +487,6 @@ tu._2 //│ [], //│ 2 //│ ]; -//│ res = tu; //│ // Query 2 //│ res = (tu["_1"] = (tu["_2"] = 3, []), []); //│ // Query 3 diff --git a/shared/src/test/diff/codegen/TraitMethods.mls b/shared/src/test/diff/codegen/TraitMethods.mls index 7b096ec75..5c011bc2c 100644 --- a/shared/src/test/diff/codegen/TraitMethods.mls +++ b/shared/src/test/diff/codegen/TraitMethods.mls @@ -101,7 +101,6 @@ class B: A & T1 a = A{} //│ // Query 1 //│ globalThis.a = new A({}); -//│ res = a; //│ // End of generated code //│ ╔══[ERROR] Instantiation of an abstract type is forbidden //│ ║ l.101: a = A{} @@ -129,7 +128,6 @@ b = B{} foo b //│ // Query 1 //│ globalThis.b = new B({}); -//│ res = b; //│ // Query 2 //│ res = foo(b); //│ // End of generated code @@ -153,16 +151,16 @@ class BBB: AAA method F: int method G: 'a -> 'a //│ ╔══[ERROR] Overriding method AAA.F without an overriding definition is not allowed. -//│ ║ l.153: method F: int +//│ ║ l.151: method F: int //│ ║ ^^^^^^ //│ ╟── Note: method definition inherited from -//│ ║ l.149: method F = 1 +//│ ║ l.147: method F = 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Overriding method AAA.G without an overriding definition is not allowed. -//│ ║ l.154: method G: 'a -> 'a +//│ ║ l.152: method G: 'a -> 'a //│ ║ ^^^^^^^^^^^ //│ ╟── Note: method definition inherited from -//│ ║ l.151: method G x = x +//│ ║ l.149: method G x = x //│ ╙── ^^^^^^^ //│ Defined type alias Id[+X] //│ Defined class AAA @@ -193,7 +191,7 @@ C.Foo :e fun x -> x.Foo //│ ╔══[ERROR] Implicit call to method Foo is forbidden because it is ambiguous. -//│ ║ l.194: fun x -> x.Foo +//│ ║ l.192: fun x -> x.Foo //│ ║ ^^^^^ //│ ╟── Unrelated methods named Foo are defined by: //│ ╟── • trait T0 @@ -203,10 +201,10 @@ fun x -> x.Foo //│ ║ l.41: trait T1 //│ ║ ^^ //│ ╟── • trait T3 -//│ ║ l.178: trait T3 +//│ ║ l.176: trait T3 //│ ║ ^^ //│ ╟── • trait T4 -//│ ║ l.180: trait T4 +//│ ║ l.178: trait T4 //│ ╙── ^^ //│ res: anything -> error //│ = [Function: res] diff --git a/shared/src/test/diff/codegen/TrickyShadowing.mls b/shared/src/test/diff/codegen/TrickyShadowing.mls index 1f1df4726..ff256171d 100644 --- a/shared/src/test/diff/codegen/TrickyShadowing.mls +++ b/shared/src/test/diff/codegen/TrickyShadowing.mls @@ -11,7 +11,6 @@ A = 2 //│ res = ((x) => new A(x)); //│ // Query 2 //│ globalThis.A1 = 2; -//│ res = A1; //│ // End of generated code //│ res: anything -> A //│ = [Function: res] @@ -26,7 +25,7 @@ A :js class add //│ ╔══[ERROR] Type names must start with a capital letter -//│ ║ l.27: class add +//│ ║ l.26: class add //│ ╙── ^^^ //│ // Prelude //│ class add1 {} @@ -58,7 +57,6 @@ x = Test //│ globalThis.x = function x(x) { //│ return new Test1(x); //│ }; -//│ res = x; //│ // End of generated code //│ x: anything -> Test //│ = [Function: x] @@ -78,7 +76,6 @@ x = Test2 //│ globalThis.x1 = function x1(x) { //│ return new Test2(x); //│ }; -//│ res = x1; //│ // End of generated code //│ x: anything -> Test2 //│ = [Function: x1] @@ -93,7 +90,7 @@ type B = Test2 :js class C: B //│ ╔══[ERROR] cannot inherit from a type alias -//│ ║ l.94: class C: B +//│ ║ l.91: class C: B //│ ╙── ^^^^ //│ Code generation encountered an error: //│ cannot inherit from type alias B @@ -102,7 +99,6 @@ class C: B B = 1 //│ // Query 1 //│ globalThis.B = 1; -//│ res = B; //│ // End of generated code //│ B: 1 //│ = 1 @@ -122,10 +118,8 @@ def f = 2 def f = 3 //│ // Query 1 //│ globalThis.f = 2; -//│ res = f; //│ // Query 2 //│ globalThis.f1 = 3; -//│ res = f1; //│ // End of generated code //│ 2 //│ <: f: @@ -156,7 +150,6 @@ def g: string g = "a" //│ // Query 1 //│ globalThis.g1 = "a"; -//│ res = g1; //│ // End of generated code //│ "a" //│ <: g: @@ -178,11 +171,9 @@ def i: string i = "a" //│ // Query 1 //│ globalThis.i = 1; -//│ res = i; //│ // Query 2 is empty //│ // Query 3 //│ globalThis.i1 = "a"; -//│ res = i1; //│ // End of generated code //│ i: 1 //│ = 1 @@ -205,7 +196,6 @@ class C1 C1 = "a" //│ // Query 1 //│ globalThis.C11 = "a"; -//│ res = C11; //│ // End of generated code //│ C1: "a" //│ = 'a' @@ -231,7 +221,7 @@ type Lol = 1 :js Lol //│ ╔══[ERROR] identifier not found: Lol -//│ ║ l.232: Lol +//│ ║ l.222: Lol //│ ╙── ^^^ //│ res: error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/codegen/TrickyTerms.mls b/shared/src/test/diff/codegen/TrickyTerms.mls index 3ebcef9e6..efc30fd76 100644 --- a/shared/src/test/diff/codegen/TrickyTerms.mls +++ b/shared/src/test/diff/codegen/TrickyTerms.mls @@ -37,7 +37,6 @@ def f x = case 1 of { 1 -> x } //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ }; -//│ res = f; //│ // End of generated code //│ f: 'a -> 'a //│ = [Function: f] @@ -48,10 +47,8 @@ def tmp = 1 def tmp = succ tmp //│ // Query 1 //│ globalThis.tmp = 1; -//│ res = tmp; //│ // Query 2 //│ globalThis.tmp1 = succ(tmp); -//│ res = tmp1; //│ // End of generated code //│ tmp: 1 //│ = 1 @@ -67,7 +64,6 @@ let t = tmp in let tmp = 1 in t tmp //│ globalThis.tmp2 = function tmp2(tmp) { //│ return tmp; //│ }; -//│ res = tmp2; //│ // Query 2 //│ res = tmp2((function (tmp) { //│ return tmp; diff --git a/shared/src/test/diff/codegen/TrickyWiths.mls b/shared/src/test/diff/codegen/TrickyWiths.mls index 4dfc89c1e..efbfec1d1 100644 --- a/shared/src/test/diff/codegen/TrickyWiths.mls +++ b/shared/src/test/diff/codegen/TrickyWiths.mls @@ -8,7 +8,6 @@ n = 42 with { x = 1 } n + n.x //│ // Query 1 //│ globalThis.n = withConstruct(42, { x: 1 }); -//│ res = n; //│ // Query 2 //│ res = n + n.x; //│ // End of generated code @@ -28,7 +27,6 @@ a = (1,2,3) with {} //│ 2, //│ 3 //│ ], {}); -//│ res = a; //│ // End of generated code //│ a: (1, 2, 3,) //│ = [ 1, 2, 3 ] diff --git a/shared/src/test/diff/mlscript/BadInherit2.mls b/shared/src/test/diff/mlscript/BadInherit2.mls index 11f9251c3..95cbcb5d8 100644 --- a/shared/src/test/diff/mlscript/BadInherit2.mls +++ b/shared/src/test/diff/mlscript/BadInherit2.mls @@ -214,11 +214,11 @@ def f = 0 def f' = 1 //│ f': 1 -//│ = 0 +//│ = 1 f' //│ res: 1 -//│ = 0 +//│ = A1 { Foo1: [Function (anonymous)] } diff --git a/shared/src/test/diff/mlscript/BadInherit2Co.mls b/shared/src/test/diff/mlscript/BadInherit2Co.mls index c39f01ce3..79905a0ab 100644 --- a/shared/src/test/diff/mlscript/BadInherit2Co.mls +++ b/shared/src/test/diff/mlscript/BadInherit2Co.mls @@ -175,9 +175,9 @@ def f = 0 def f' = 1 //│ f': 1 -//│ = 0 +//│ = 1 f' //│ res: 1 -//│ = 0 +//│ = A1 {} diff --git a/shared/src/test/diff/mlscript/MLTuples.mls b/shared/src/test/diff/mlscript/MLTuples.mls index 8e4cd6e98..6cf364b4e 100644 --- a/shared/src/test/diff/mlscript/MLTuples.mls +++ b/shared/src/test/diff/mlscript/MLTuples.mls @@ -11,7 +11,6 @@ t = (1, 2, 3) tx = t with { x = 1 } //│ // Query 1 //│ globalThis.tx = withConstruct(t, { x: 1 }); -//│ res = tx; //│ // End of generated code //│ tx: (1, 2, 3,) & {x: 1} //│ = [ 1, 2, 3, x: 1 ] @@ -26,16 +25,16 @@ trait Hey: { x: int } :e Hey t //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.27: Hey t +//│ ║ l.26: Hey t //│ ║ ^^^^^ //│ ╟── tuple literal of type `{_1: 1, _2: 2, _3: 3}` does not have field 'x' //│ ║ l.2: t = (1, 2, 3) //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{x: int}` -//│ ║ l.27: Hey t +//│ ║ l.26: Hey t //│ ║ ^ //│ ╟── Note: constraint arises from record type: -//│ ║ l.23: trait Hey: { x: int } +//│ ║ l.22: trait Hey: { x: int } //│ ╙── ^^^^^^^^^^ //│ res: (1, 2, 3,) & hey | error //│ = [ 1, 2, 3 ] @@ -73,44 +72,44 @@ f t f tx f htx //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: f t +//│ ║ l.71: f t //│ ║ ^^^ //│ ╟── tuple literal of type `(1, 2, 3,)` does not match type `(?a, ?b,)` //│ ║ l.2: t = (1, 2, 3) //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(?c, ?d,)` -//│ ║ l.72: f t +//│ ║ l.71: f t //│ ║ ^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.67: f ((a, b)) = add a b +//│ ║ l.66: f ((a, b)) = add a b //│ ╙── ^^^^^^ //│ res: error | int //│ = 3 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.73: f tx +//│ ║ l.72: f tx //│ ║ ^^^^ //│ ╟── `with` extension of type `(1, 2, 3,) & {x: 1}` is not a 2-element tuple //│ ║ l.11: tx = t with { x = 1 } //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(?a, ?b,)` -//│ ║ l.73: f tx +//│ ║ l.72: f tx //│ ║ ^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.67: f ((a, b)) = add a b +//│ ║ l.66: f ((a, b)) = add a b //│ ╙── ^^^^^^ //│ res: error | int //│ = 3 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.74: f htx +//│ ║ l.73: f htx //│ ║ ^^^^^ //│ ╟── `with` extension of type `(1, 2, 3,) & {x: 1}` does not match type `(?a, ?b,) | ~hey` //│ ║ l.11: tx = t with { x = 1 } //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(?c, ?d,) | ~hey` -//│ ║ l.74: f htx +//│ ║ l.73: f htx //│ ║ ^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.67: f ((a, b)) = add a b +//│ ║ l.66: f ((a, b)) = add a b //│ ╙── ^^^^^^ //│ res: error | int //│ = 3 @@ -142,11 +141,11 @@ g (tx with { y = 2 }) :e g tx //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.143: g tx +//│ ║ l.142: g tx //│ ║ ^^^^ //│ ╟── expression of type `(1, 2, 3,) & {x: 1} & ~hey` does not have field 'y' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.131: g arg = case arg of { Hey -> arg.x | _ -> arg.y } +//│ ║ l.130: g arg = case arg of { Hey -> arg.x | _ -> arg.y } //│ ╙── ^^^^^ //│ res: 1 | error //│ = 1 @@ -210,16 +209,16 @@ t = (1, 2, 3) with {_1 = "oops"} :e (t: ("oops",int,int,))._1 //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.211: (t: ("oops",int,int,))._1 +//│ ║ l.210: (t: ("oops",int,int,))._1 //│ ║ ^ //│ ╟── `with` extension of type `{_1: "oops", _2: 2, _3: 3}` is not a 3-element tuple -//│ ║ l.205: t = (1, 2, 3) with {_1 = "oops"} +//│ ║ l.204: t = (1, 2, 3) with {_1 = "oops"} //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `("oops", int, int,)` -//│ ║ l.211: (t: ("oops",int,int,))._1 +//│ ║ l.210: (t: ("oops",int,int,))._1 //│ ║ ^ //│ ╟── Note: constraint arises from tuple type: -//│ ║ l.211: (t: ("oops",int,int,))._1 +//│ ║ l.210: (t: ("oops",int,int,))._1 //│ ╙── ^^^^^^^^^^^^^^^^^ //│ res: "oops" //│ = 'oops' diff --git a/shared/src/test/diff/mlscript/Mohammad.mls b/shared/src/test/diff/mlscript/Mohammad.mls index c059465d0..52955a32a 100644 --- a/shared/src/test/diff/mlscript/Mohammad.mls +++ b/shared/src/test/diff/mlscript/Mohammad.mls @@ -26,7 +26,6 @@ def useCls c = case c of { Class -> c.x | int -> "oops" } //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ }; -//│ res = useCls; //│ // End of generated code //│ useCls: ((Class with {x: 'x}) | int) -> ("oops" | 'x) //│ = [Function: useCls] @@ -101,14 +100,14 @@ def useTrt t = case t of { T -> t.y | Class -> t.x } :e useTrt c //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.102: useTrt c +//│ ║ l.101: useTrt c //│ ║ ^^^^^^^^ //│ ╟── expression of type `Class & {x: ?x} & t | Class & {x: ?x} & ~?a` does not have field 'y' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.97: def useTrt t = case t of { T -> t.y | Class -> t.x } +//│ ║ l.96: def useTrt t = case t of { T -> t.y | Class -> t.x } //│ ║ ^^^ //│ ╟── from refined scrutinee: -//│ ║ l.97: def useTrt t = case t of { T -> t.y | Class -> t.x } +//│ ║ l.96: def useTrt t = case t of { T -> t.y | Class -> t.x } //│ ╙── ^ //│ res: 1 | error //│ = 1 @@ -228,7 +227,6 @@ trait Oops oo = Oops 2 //│ // Query 1 //│ globalThis.oo = Oops.build(2); -//│ res = oo; //│ // End of generated code //│ oo: 2 & oops //│ = [Number: 2] diff --git a/shared/src/test/diff/mlscript/Under.mls b/shared/src/test/diff/mlscript/Under.mls index ca9ec94ab..76e3b5844 100644 --- a/shared/src/test/diff/mlscript/Under.mls +++ b/shared/src/test/diff/mlscript/Under.mls @@ -44,24 +44,26 @@ def foo { _ } = { _ } //│ res: 1 //│ = 1 +// * This code leads to a syntax error in NodeJS: "Duplicate parameter name not allowed in this context", +// * so we got an undefined result here. :e def foo { _ ; _ } = 1 //│ ╔══[ERROR] Multiple declarations of field name _ in record literal -//│ ║ l.48: def foo { _ ; _ } = 1 +//│ ║ l.50: def foo { _ ; _ } = 1 //│ ║ ^^^^^^^^^ //│ ╟── Declared at -//│ ║ l.48: def foo { _ ; _ } = 1 +//│ ║ l.50: def foo { _ ; _ } = 1 //│ ║ ^ //│ ╟── Declared at -//│ ║ l.48: def foo { _ ; _ } = 1 +//│ ║ l.50: def foo { _ ; _ } = 1 //│ ╙── ^ //│ foo: {_: anything, _: anything} -> 1 -//│ = 1 +//│ = undefined // :js def foo { _ = _ ; __ = _ } = 1 //│ foo: {_: anything, __: anything} -> 1 -//│ = 1 +//│ = undefined rec def _ = 1 //│ _: 1 diff --git a/shared/src/test/diff/mlscript/i65.mls b/shared/src/test/diff/mlscript/i65.mls new file mode 100644 index 000000000..dab329a4d --- /dev/null +++ b/shared/src/test/diff/mlscript/i65.mls @@ -0,0 +1,65 @@ +:js +42 +//│ // Prelude +//│ let res; +//│ // Query 1 +//│ res = 42; +//│ // End of generated code +//│ res: 42 +//│ = 42 + +:js +def foo = "oops" +//│ // Query 1 +//│ globalThis.foo = "oops"; +//│ // End of generated code +//│ foo: "oops" +//│ = 'oops' + +:js +res +//│ // Query 1 +//│ res = res; +//│ // End of generated code +//│ res: 42 +//│ = 42 + +:js +res = 5 +//│ // Query 1 +//│ globalThis.res1 = 5; +//│ // End of generated code +//│ res: 5 +//│ = 5 + +res +//│ res: 5 +//│ = 5 + +:js +foo +//│ // Query 1 +//│ res = foo; +//│ // End of generated code +//│ res: "oops" +//│ = 'oops' + +:js +res +//│ // Query 1 +//│ res = res; +//│ // End of generated code +//│ res: "oops" +//│ = 'oops' + +def res: bool +//│ res: bool +//│ = + +42 +//│ res: 42 +//│ = 42 + +res +//│ res: 42 +//│ = 42 diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 5921f6c0f..1ddc0dfa0 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -431,7 +431,7 @@ class DiffTests extends org.scalatest.funsuite.AnyFunSuite with org.scalatest.Pa } } queries.zipWithIndex foreach { - case (JSTestBackend.CodeQuery(prelude, code), i) => + case (JSTestBackend.CodeQuery(prelude, code, _), i) => output(s"// Query ${i + 1}") prelude foreach { output(_) } code foreach { output(_) } @@ -455,7 +455,7 @@ class DiffTests extends org.scalatest.funsuite.AnyFunSuite with org.scalatest.Pa } // Send queries to the host. ExecutedResult(queries.zipWithIndex.map { - case (JSTestBackend.CodeQuery(preludeLines, codeLines), i) => + case (JSTestBackend.CodeQuery(preludeLines, codeLines, res), i) => val prelude = preludeLines.mkString val code = codeLines.mkString if (mode.showRepl) { @@ -463,7 +463,7 @@ class DiffTests extends org.scalatest.funsuite.AnyFunSuite with org.scalatest.Pa println(s"│ ├── Prelude: ${if (preludeLines.isEmpty) "" else prelude}") println(s"│ └── Code: ${code}") } - val reply = host.query(prelude, code) + val reply = host.query(prelude, code, res) if (mode.showRepl) { val prefix = if (i + 1 == queries.length) "└──" else "├──" println(s"$prefix Reply ${i + 1}/${queries.length}: $reply") @@ -753,14 +753,17 @@ object DiffTests { stdin.flush() } - def query(prelude: Str, code: Str): ReplHost.Reply = { - val wrapped = s"$prelude try { $code } catch (e) { console.log('\\u200B' + e + '\\u200B'); }" - send(wrapped) - consumeUntilPrompt() match { - case _: ReplHost.Result => - send("res") - consumeUntilPrompt() - case t => t + def query(prelude: Str, code: Str, res: Str): ReplHost.Reply = { + if (prelude.isEmpty && code.isEmpty) ReplHost.Empty + else { + val wrapped = s"$prelude try { $code } catch (e) { console.log('\\u200B' + e + '\\u200B'); }" + send(wrapped) + consumeUntilPrompt() match { + case _: ReplHost.Result => + send(if (res =:= "res") res else s"globalThis[\"${res}\"]") + consumeUntilPrompt() + case t => t + } } }