From d266c17da4c38ea9db6798f480518bb3131a56d1 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 6 Nov 2024 10:16:19 +0800 Subject: [PATCH 1/9] No need to turn off type checking globally --- hkmc2/shared/src/test/mlscript/ucs/examples/EitherOrBoth.mls | 3 --- hkmc2/shared/src/test/mlscript/ucs/examples/ListFold.mls | 3 --- hkmc2/shared/src/test/mlscript/ucs/examples/Permutations.mls | 4 ---- .../test/mlscript/ucs/normalization/OverlapOfPrimitives.mls | 1 - .../test/mlscript/ucs/normalization/UnifySubScrutinees.mls | 1 - 5 files changed, 12 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/ucs/examples/EitherOrBoth.mls b/hkmc2/shared/src/test/mlscript/ucs/examples/EitherOrBoth.mls index 3d742c5e4..82b1898f4 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/examples/EitherOrBoth.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/examples/EitherOrBoth.mls @@ -1,6 +1,3 @@ -:global -:!typeCheck - :import ../prelude/String.mls //│ Imported 2 member(s) diff --git a/hkmc2/shared/src/test/mlscript/ucs/examples/ListFold.mls b/hkmc2/shared/src/test/mlscript/ucs/examples/ListFold.mls index 08b893add..8d626575f 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/examples/ListFold.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/examples/ListFold.mls @@ -1,6 +1,3 @@ -:global -:!typeCheck - :import ../prelude/List.mls //│ Imported 4 member(s) diff --git a/hkmc2/shared/src/test/mlscript/ucs/examples/Permutations.mls b/hkmc2/shared/src/test/mlscript/ucs/examples/Permutations.mls index 103ac12b2..b9317f6af 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/examples/Permutations.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/examples/Permutations.mls @@ -1,7 +1,3 @@ -:global -:!typeCheck - - :import ../prelude/List.mls //│ Imported 4 member(s) :import ../prelude/String.mls diff --git a/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls b/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls index 995604369..41b839fbe 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls @@ -1,5 +1,4 @@ :global -:!typeCheck :ucs desugared fun test(x, p) = if x is diff --git a/hkmc2/shared/src/test/mlscript/ucs/normalization/UnifySubScrutinees.mls b/hkmc2/shared/src/test/mlscript/ucs/normalization/UnifySubScrutinees.mls index 067c7a333..a83f3adcc 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/normalization/UnifySubScrutinees.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/normalization/UnifySubScrutinees.mls @@ -5,7 +5,6 @@ //│ Imported 3 member(s) :global -:!typeCheck :ucs desugared normalized class Pair[A, B](x: A, y: B) From 5dc38ac751d4481f594a64221b2311299630e7b3 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 6 Nov 2024 10:54:43 +0800 Subject: [PATCH 2/9] Fix a typo --- hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala index b2357c644..94af9135b 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala @@ -82,7 +82,7 @@ abstract class DiffTestRunner(state: DiffTestRunner.State) "\n\tNote: you can increase this limit by changing DiffTests.TimeLimit") // * Thread.stop() is considered bad practice because normally it's better to implement proper logic // * to terminate threads gracefully, avoiding leaving applications in a bad state. - // * But here we DGAF since all the test is doing is runnign a type checker and some Node REPL, + // * But here we DGAF since all the test is doing is running a type checker and some Node REPL, // * which would be a much bigger pain to make receptive to "gentle" interruption. // * It would feel extremely wrong to intersperse the pure type checker algorithms // * with ugly `Thread.isInterrupted` checks everywhere... From 22a7476694f0bb150167f83db114424c9e5ec68a Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 6 Nov 2024 14:35:43 +0800 Subject: [PATCH 3/9] Fix getting modified files from `git status` --- hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala index 94af9135b..3a5e7ca71 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala @@ -55,8 +55,9 @@ object DiffTestRunner: else if filePath.ext =/= "mls" then N else S(filePath) }.toSet catch - case err: Throwable => System.err.println("/!\\ git command failed with: " + err) - Set.empty + case err: Throwable => + System.err.println("/!\\ git command failed with: " + err) + Set.empty end State From 2be4a22c9420880ca41fc50a8da3382e0bc4a109 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 6 Nov 2024 15:01:12 +0800 Subject: [PATCH 4/9] Port test files about patterns --- .../mlscript/ucs/patterns/AliasPattern.mls | 47 ++++++ .../test/mlscript/ucs/patterns/Literals.mls | 67 ++++++++ .../mlscript/ucs/patterns/NamePattern.mls | 9 ++ .../mlscript/ucs/patterns/RecordPattern.mls | 15 ++ .../test/mlscript/ucs/patterns/Refinement.mls | 46 ++++++ .../mlscript/ucs/patterns/SimpleTuple.mls | 83 ++++++++++ .../ucs/staging/patterns/AliasPattern.mls | 57 ------- .../ucs/staging/patterns/Literals.mls | 127 --------------- .../ucs/staging/patterns/NamePattern.mls | 9 -- .../ucs/staging/patterns/RecordPattern.mls | 26 ---- .../ucs/staging/patterns/Refinement.mls | 74 --------- .../ucs/staging/patterns/SimpleTuple.mls | 145 ------------------ 12 files changed, 267 insertions(+), 438 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls create mode 100644 hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls create mode 100644 hkmc2/shared/src/test/mlscript/ucs/patterns/NamePattern.mls create mode 100644 hkmc2/shared/src/test/mlscript/ucs/patterns/RecordPattern.mls create mode 100644 hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls create mode 100644 hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls delete mode 100644 hkmc2/shared/src/test/mlscript/ucs/staging/patterns/AliasPattern.mls delete mode 100644 hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Literals.mls delete mode 100644 hkmc2/shared/src/test/mlscript/ucs/staging/patterns/NamePattern.mls delete mode 100644 hkmc2/shared/src/test/mlscript/ucs/staging/patterns/RecordPattern.mls delete mode 100644 hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Refinement.mls delete mode 100644 hkmc2/shared/src/test/mlscript/ucs/staging/patterns/SimpleTuple.mls diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls new file mode 100644 index 000000000..d1ae7c914 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls @@ -0,0 +1,47 @@ +:import ../prelude/Option.mls +//│ Imported 3 member(s) + +:todo +fun map(f) = case + Some(x) then Some(f(x)) + None as n then n +//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here +//│ ║ l.7: None as n then n +//│ ╙── ^^ +//│ ╔══[ERROR] Unsupported default case branch. +//│ ║ l.6: Some(x) then Some(f(x)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: None as n then n +//│ ╙── ^^^^^^ + +:todo +fun map(f) = case + Some(x as n) then Some of f(n) + None as n then n +//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here +//│ ║ l.19: Some(x as n) then Some of f(n) +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here +//│ ║ l.20: None as n then n +//│ ╙── ^^ +//│ ╔══[ERROR] Unsupported default case branch. +//│ ║ l.19: Some(x as n) then Some of f(n) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.20: None as n then n +//│ ╙── ^^^^^^ + +:todo +fun foo = case + Some(Some(a as b) as c) as d then [a, b, c, d] +//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here +//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here +//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here +//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] +//│ ╙── ^^ +//│ ╔══[ERROR] Unsupported default case branch. +//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls new file mode 100644 index 000000000..4ac3248e3 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls @@ -0,0 +1,67 @@ +:import ../prelude/Option.mls +//│ Imported 3 member(s) + +class Pair[A, B](x: A, y: B) + +fun f(x) = if x is Some(1) then true else false + +[f(Some(1)), f(None), f(Some(2)), f(Some(-1))] + +fun f(x) = if x is Some(1) then true + +fun f(x) = if x is + Some(1) then true + Some(2) then false + +[f(Some(1)), f(Some(2))] + +fun g(x) = if x then 1 else 2 + +// :e +fun test_must_be_boolean(x) = if 0 then 1 else 2 + +fun g(x) = if x is true then 1 else 2 + +[g(true), g(false), g(None)] + +fun g(x) = if x && true is true then 1 else 2 + +fun h(x) = if (x : Bool) then 1 else 2 + +// Currently post-processing cannot handle this case. The desugared term is not +// perfect. Also, is the inferred type wrong? +fun mix(x) = if x is + true then "true" + Some(value) then "Some" + 0 then "zero" + +[mix(true), mix(Some(1)), mix(0)] + +// :e +[mix(false), mix(None)] + +fun string_literals(x) = + if x is + "foo" then 0 + "bar" then 1 + "qax" then 2 + +class Foo + +fun mixed_patterns(x) = + if x is + Foo then 1 + 23 then 2 + "test" then 3 + +fun bool_patterns(x) = + if x is + true then 1 + false then 2 + +fun dual_patterns(x, y) = + if + x is "some" and y is "none" then 0 + x is "none" and y is "some" then 1 + x is "some" and y is "some" then 2 + x is "none" and y is "none" then 3 diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/NamePattern.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/NamePattern.mls new file mode 100644 index 000000000..1bedafdae --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/NamePattern.mls @@ -0,0 +1,9 @@ +fun id(x) = x + +:ucs desugared +if id(0) is t then t +//│ Desugared: +//│ > if +//│ > let $scrut@28 = globalThis:block#0.id#0(0) +//│ > let t@29 = $scrut@28#0 +//│ > else t@29#0 diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/RecordPattern.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/RecordPattern.mls new file mode 100644 index 000000000..6bce2709e --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/RecordPattern.mls @@ -0,0 +1,15 @@ +:pe +:e +fun take_1(p) = + if p is + { x, y } then x + y + else 0 +//│ ╔══[PARSE ERROR] Expected an expression; found block instead +//│ ║ l.6: else 0 +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Unexpected curly brace section here +//│ ║ l.5: { x, y } then x + y +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Unrecognized pattern split. +//│ ║ l.5: { x, y } then x + y +//│ ╙── ^^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls new file mode 100644 index 000000000..3ac78a8f5 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls @@ -0,0 +1,46 @@ +:import ../prelude/Option.mls +//│ Imported 3 member(s) + +:global +:e +:ucs normalized + +// OK +x => if x is + refined(None) then x +//│ ╔══[ERROR] Unknown constructor `refined`. +//│ ║ l.10: refined(None) then x +//│ ╙── ^^^^^^^ +//│ Normalized: +//│ > if + +// OK +x => if x is + refined(Some) then x +//│ ╔══[ERROR] Unknown constructor `refined`. +//│ ║ l.19: refined(Some) then x +//│ ╙── ^^^^^^^ +//│ Normalized: +//│ > if + +// Should warn about the inconsistent refinement +x => if x is + refined(None) then x + Some then x +//│ ╔══[ERROR] Unknown constructor `refined`. +//│ ║ l.28: refined(None) then x +//│ ╙── ^^^^^^^ +//│ Normalized: +//│ > if x@34 is Some then x@34#2 + +x => if x is + refined(None) then x + refined(Some) then x +//│ ╔══[ERROR] Unknown constructor `refined`. +//│ ║ l.38: refined(Some) then x +//│ ╙── ^^^^^^^ +//│ ╔══[ERROR] Unknown constructor `refined`. +//│ ║ l.37: refined(None) then x +//│ ╙── ^^^^^^^ +//│ Normalized: +//│ > if diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls new file mode 100644 index 000000000..e05a30325 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls @@ -0,0 +1,83 @@ +// We test the support for simple tuple patterns in this file. +// Splice tuple patterns will be implement in the future. + +fun sum(x, y) = x + y +sum(1, 2) + +:fixme +fun sum'([x, y]) = x + y +sum'([1, 2]) +//│ /!!!\ Uncaught error: scala.MatchError: Tup(List(Ident(x), Ident(y))) (of class hkmc2.syntax.Tree$Tup) + +:e +fun sum''(pair) = + if pair is [x, y] then x + y +sum'([1, 2]) +//│ ╔══[ERROR] Unrecognized pattern. +//│ ║ l.14: if pair is [x, y] then x + y +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Name not found: sum' +//│ ║ l.15: sum'([1, 2]) +//│ ╙── ^^^^ + +// We need native support for tuple patterns in MLscript syntax. +// Otherwise the following cases work. + +:e +fun test(thing) = + if thing is [] then 0 +test("") +test(12) +//│ ╔══[ERROR] Unrecognized pattern. +//│ ║ l.28: if thing is [] then 0 +//│ ╙── ^^ + +:e +// Since pattern destruction is desugared to let bindings, matching with other +// classes after the tuple pattern will not work. +class Point(x: Int, y: Int) +fun discarded_cases(thing) = + if thing is + [x, y] then x + y + Point(x, y) then x + y +//│ ╔══[ERROR] Unrecognized pattern. +//│ ║ l.41: [x, y] then x + y +//│ ╙── ^^^^^^ + +:e +:todo +discarded_cases(Point(0, 0)) + +// A workaround is to move the tuple pattern to the last case. +:e +fun working_cases(thing) = + if thing is + Point(x, y) then x + y + [x, y] then x + y +//│ ╔══[ERROR] Unrecognized pattern. +//│ ║ l.56: [x, y] then x + y +//│ ╙── ^^^^^^ + +working_cases(Point(0, 0)) + +// However, the `Object` type forbids tuples to be used. +:e +:todo +working_cases([0, 0]) + +:e +fun not_working(x) = + if x is + [a, b, c] then + a + b + c + else + 0 +//│ ╔══[ERROR] Unrecognized pattern. +//│ ║ l.71: [a, b, c] then +//│ ╙── ^^^^^^^^^ + +not_working([1, 2, 3]) + +:e +:todo +not_working([1, 2]) diff --git a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/AliasPattern.mls b/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/AliasPattern.mls deleted file mode 100644 index d18adc4b1..000000000 --- a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/AliasPattern.mls +++ /dev/null @@ -1,57 +0,0 @@ -:NewDefs - -abstract class Option[out A] -class Some[out A](val value: A) extends Option[A] -module None extends Option[nothing] -//│ abstract class Option[A] -//│ class Some[A](value: A) extends Option -//│ module None extends Option - -:ducs:postprocess.result -fun map(f) = case - Some(x) then Some(f(x)) - None as n then n -//│ Post-processed UCS term: -//│ case case$scrut*‡ of -//│ Some*◊ -> -//│ let ucs$args_case$scrut$Some*† = (Some).unapply(case$scrut,) -//│ let x*‡ = (ucs$args_case$scrut$Some).0 -//│ Some(f(x,),) -//│ None*† -> -//│ let n*† = case$scrut -//│ n -//│ fun map: forall 'a 'A. ('a -> 'A) -> (None | Some['a]) -> (None | Some['A]) - -:ducs:postprocess.result -fun map(f) = case - Some(x as n) then Some of f(n) - None as n then n -//│ Post-processed UCS term: -//│ case case$scrut*‡ of -//│ Some*◊ -> -//│ let ucs$args_case$scrut$Some*† = (Some).unapply(case$scrut,) -//│ let x*‡ = (ucs$args_case$scrut$Some).0 -//│ let n*‡ = x -//│ Some(f(n,),) -//│ None*† -> -//│ let n*† = case$scrut -//│ n -//│ fun map: forall 'a 'A. ('a -> 'A) -> (None | Some['a]) -> (None | Some['A]) - -:ducs:postprocess.result -fun foo = case - Some(Some(a as b) as c) as d then [a, b, c, d] -//│ Post-processed UCS term: -//│ let d*† = case$scrut -//│ case case$scrut*‡ of -//│ Some*◊ -> -//│ let ucs$args_case$scrut$Some*† = (Some).unapply(case$scrut,) -//│ let case$scrut$Some_0*‡ = (ucs$args_case$scrut$Some).0 -//│ case case$scrut$Some_0*‡ of -//│ Some*◊ -> -//│ let ucs$args_case$scrut$Some_0$Some*† = (Some).unapply(case$scrut$Some_0,) -//│ let a*‡ = (ucs$args_case$scrut$Some_0$Some).0 -//│ let b*‡ = a -//│ let c*‡ = case$scrut$Some_0 -//│ [a, b, c, d,] -//│ fun foo: forall 'A 'a. (Some[Some['A]] & 'a) -> ['A, 'A, Some['A], 'a] diff --git a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Literals.mls b/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Literals.mls deleted file mode 100644 index 1b89a4b19..000000000 --- a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Literals.mls +++ /dev/null @@ -1,127 +0,0 @@ -:NewDefs - -class Some[T](value: T) -module None -type Option[T] = Some[T] | None -class Pair[A, B](x: A, y: B) -//│ class Some[T](value: T) -//│ module None -//│ type Option[T] = None | Some[T] -//│ class Pair[A, B](x: A, y: B) - -fun f(x) = if x is Some(1) then true else false -//│ fun f: (Object & ~#Some | Some[Object]) -> Bool - -[f(Some(1)), f(None), f(Some(2)), f(Some(-1))] -//│ [Bool, Bool, Bool, Bool] -//│ res -//│ = [ true, false, false, false ] - -fun f(x) = if x is Some(1) then true -//│ fun f: Some[1] -> true - -fun f(x) = if x is - Some(1) then true - Some(2) then false -//│ fun f: Some[1 | 2] -> Bool - -[f(Some(1)), f(Some(2))] -//│ [Bool, Bool] -//│ res -//│ = [ true, false ] - -fun g(x) = if x then 1 else 2 -//│ fun g: Bool -> (1 | 2) - -:e -fun test_must_be_boolean(x) = if 0 then 1 else 2 -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.37: fun test_must_be_boolean(x) = if 0 then 1 else 2 -//│ ║ ^ -//│ ╙── integer literal of type `0` is not an instance of type `Bool` -//│ fun test_must_be_boolean: anything -> (1 | 2) - -fun g(x) = if x is true then 1 else 2 -//│ fun g: Object -> (1 | 2) - -[g(true), g(false), g(None)] -//│ [1 | 2, 1 | 2, 1 | 2] -//│ res -//│ = [ 1, 2, 2 ] - -fun g(x) = if x && true is true then 1 else 2 -//│ fun g: Bool -> (1 | 2) - -fun h(x) = if (x : Bool) then 1 else 2 -//│ fun h: Bool -> (1 | 2) - -// Currently post-processing cannot handle this case. The desugared term is not -// perfect. Also, is the inferred type wrong? -fun mix(x) = if x is - true then "true" - Some(value) then "Some" - 0 then "zero" -//│ fun mix: (0 | Some[anything] | true) -> ("Some" | "true" | "zero") - -[mix(true), mix(Some(1)), mix(0)] -//│ ["Some" | "true" | "zero", "Some" | "true" | "zero", "Some" | "true" | "zero"] -//│ res -//│ = [ 'true', 'Some', 'zero' ] - -:e -[mix(false), mix(None)] -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: [mix(false), mix(None)] -//│ ║ ^^^^^^^^^^ -//│ ╟── reference of type `false` does not match type `0 | Some[?T] | true` -//│ ║ l.72: [mix(false), mix(None)] -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.60: fun mix(x) = if x is -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: [mix(false), mix(None)] -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `None` does not match type `0 | Some[?T] | true` -//│ ║ l.72: [mix(false), mix(None)] -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.60: fun mix(x) = if x is -//│ ╙── ^ -//│ ["Some" | "true" | "zero" | error, "Some" | "true" | "zero" | error] -//│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression - -fun string_literals(x) = - if x is - "foo" then 0 - "bar" then 1 - "qax" then 2 -//│ fun string_literals: ("bar" | "foo" | "qax") -> (0 | 1 | 2) - -class Foo -//│ class Foo { -//│ constructor() -//│ } - -fun mixed_patterns(x) = - if x is - Foo then 1 - 23 then 2 - "test" then 3 -//│ fun mixed_patterns: ("test" | 23 | Foo) -> (1 | 2 | 3) - -fun bool_patterns(x) = - if x is - true then 1 - false then 2 -//│ fun bool_patterns: Bool -> (1 | 2) - -fun dual_patterns(x, y) = - if - x is "some" and y is "none" then 0 - x is "none" and y is "some" then 1 - x is "some" and y is "some" then 2 - x is "none" and y is "none" then 3 -//│ fun dual_patterns: ("none" | "some", "none" | "some") -> (0 | 1 | 2 | 3) diff --git a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/NamePattern.mls b/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/NamePattern.mls deleted file mode 100644 index 05aa66c77..000000000 --- a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/NamePattern.mls +++ /dev/null @@ -1,9 +0,0 @@ -:NewDefs - -fun id(x) = x -//│ fun id: forall 'a. 'a -> 'a - -if id(0) is t then t -//│ 0 -//│ res -//│ = 0 diff --git a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/RecordPattern.mls b/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/RecordPattern.mls deleted file mode 100644 index 68f99b1b5..000000000 --- a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/RecordPattern.mls +++ /dev/null @@ -1,26 +0,0 @@ -:NewDefs - -:e -:w -fun take_1(p) = - if p is - { x, y } then x + y - else 0 -//│ ╔══[ERROR] unknown pattern '{' {x: x, y: y} '}' -//│ ║ l.7: { x, y } then x + y -//│ ╙── ^^^^^^^^ -//│ ╔══[WARNING] this case is unreachable -//│ ║ l.8: else 0 -//│ ║ ^ -//│ ╟── because it is subsumed by the branch -//│ ║ l.7: { x, y } then x + y -//│ ╙── ^^^^^ -//│ ╔══[ERROR] identifier not found: x -//│ ║ l.7: { x, y } then x + y -//│ ╙── ^ -//│ ╔══[ERROR] identifier not found: y -//│ ║ l.7: { x, y } then x + y -//│ ╙── ^ -//│ fun take_1: anything -> Int -//│ Code generation encountered an error: -//│ unresolved symbol x diff --git a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Refinement.mls b/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Refinement.mls deleted file mode 100644 index c92832701..000000000 --- a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/Refinement.mls +++ /dev/null @@ -1,74 +0,0 @@ -:NewDefs - -module None -class Some[out A](val value: A) -//│ module None -//│ class Some[A](value: A) - -// OK -:ducs:desugar.result,postprocess.result -x => if x is - refined(None) then x -//│ Desugared UCS term: -//│ if x*‡ is refined None then x -//│ Post-processed UCS term: -//│ case x*‡ of -//│ refined None*† -> x -//│ forall 'a. (None & 'a) -> (None & 'a) -//│ res -//│ = [Function: res] - -// OK -:ducs:desugar.result,postprocess.result -x => if x is - refined(Some) then x -//│ Desugared UCS term: -//│ if x*‡ is refined Some then x -//│ Post-processed UCS term: -//│ case x*‡ of -//│ refined Some*◊ -> x -//│ forall 'a. (Some[anything] & 'a) -> (Some[anything] & 'a) -//│ res -//│ = [Function: res] - -:w -:ducs:desugar.result,postprocess.result -x => if x is - refined(None) then x - Some then x -//│ Desugared UCS term: -//│ if -//│ x*‡ is refined None then x -//│ x*‡ is Some then x -//│ Post-processed UCS term: -//│ case x*‡ of -//│ refined None*† -> x -//│ Some*◊ -> x -//│ ╔══[WARNING] inconsistent refined pattern -//│ ║ l.37: refined(None) then x -//│ ║ ^^^^ -//│ ╟── pattern `Some` is not refined -//│ ║ l.38: Some then x -//│ ║ ^^^^ -//│ ╟── but pattern `None` is refined -//│ ║ l.37: refined(None) then x -//│ ╙── ^^^^ -//│ (None | Some[anything]) -> Some[nothing] -//│ res -//│ = [Function: res] - -:ducs:desugar.result,postprocess.result -x => if x is - refined(None) then x - refined(Some) then x -//│ Desugared UCS term: -//│ if -//│ x*‡ is refined None then x -//│ x*‡ is refined Some then x -//│ Post-processed UCS term: -//│ case x*‡ of -//│ refined None*† -> x -//│ refined Some*◊ -> x -//│ (None | Some[anything]) -> nothing -//│ res -//│ = [Function: res] diff --git a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/SimpleTuple.mls b/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/SimpleTuple.mls deleted file mode 100644 index 57d37d53c..000000000 --- a/hkmc2/shared/src/test/mlscript/ucs/staging/patterns/SimpleTuple.mls +++ /dev/null @@ -1,145 +0,0 @@ -:NewDefs - -// We test the support for simple tuple patterns in this file. -// Splice tuple patterns will be implement in the future. - -fun sum(x, y) = x + y -sum(1, 2) -//│ fun sum: (Int, Int) -> Int -//│ Int -//│ res -//│ = 3 - -fun sum'([x, y]) = x + y -sum'([1, 2]) -//│ fun sum': ([Int, Int]) -> Int -//│ Int -//│ res -//│ = 3 - -fun sum''(pair) = - if pair is [x, y] then x + y -sum'([1, 2]) -//│ fun sum'': {0: Int, 1: Int} -> Int -//│ Int -//│ res -//│ = 3 - -// We need native support for tuple patterns in MLscript syntax. -// Otherwise the following cases work. - -fun test(thing) = - if thing is [] then 0 -test("") -test(12) -//│ fun test: anything -> 0 -//│ 0 -//│ res -//│ = 0 -//│ res -//│ = 0 - -:w -// Since pattern destruction is desugared to let bindings, matching with other -// classes after the tuple pattern will not work. -class Point(x: Int, y: Int) -fun discarded_cases(thing) = - if thing is - [x, y] then x + y - Point(x, y) then x + y -//│ ╔══[WARNING] this case is unreachable -//│ ║ l.47: if thing is -//│ ║ ^^^^^^^^ -//│ ║ l.48: [x, y] then x + y -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.49: Point(x, y) then x + y -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── because it is subsumed by the branch -//│ ║ l.48: [x, y] then x + y -//│ ╙── ^^^^^ -//│ class Point(x: Int, y: Int) -//│ fun discarded_cases: {0: Int, 1: Int} -> Int - -:e -discarded_cases(Point(0, 0)) -//│ ╔══[ERROR] Type `Point` does not contain member `1` -//│ ║ l.48: [x, y] then x + y -//│ ╙── ^ -//│ Int | error -//│ res -//│ = NaN - -// A workaround is to move the tuple pattern to the last case. -fun working_cases(thing) = - if thing is - Point(x, y) then x + y - [x, y] then x + y -//│ fun working_cases: (Object & {0: Int, 1: Int} & ~#Point | Point) -> Int - -working_cases(Point(0, 0)) -//│ Int -//│ res -//│ = 0 - -// However, the `Object` type forbids tuples to be used. -:e -working_cases([0, 0]) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.86: working_cases([0, 0]) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── tuple literal of type `[0, 0]` is not an instance of type `Object` -//│ ║ l.86: working_cases([0, 0]) -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from `case` expression: -//│ ║ l.74: if thing is -//│ ║ ^^^^^^^^ -//│ ║ l.75: Point(x, y) then x + y -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.76: [x, y] then x + y -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── from reference: -//│ ║ l.74: if thing is -//│ ╙── ^^^^^ -//│ Int | error -//│ res -//│ = 0 - -:w -fun not_working(x) = - if x is - [a, b, c] then - a + b + c - else - 0 -//│ ╔══[WARNING] this case is unreachable -//│ ║ l.113: 0 -//│ ║ ^ -//│ ╟── because it is subsumed by the branch -//│ ║ l.111: a + b + c -//│ ╙── ^^^^^^^^^ -//│ fun not_working: {0: Int, 1: Int, 2: Int} -> Int - -not_working([1, 2, 3]) -//│ Int -//│ res -//│ = 6 - -:e -not_working([1, 2]) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.128: not_working([1, 2]) -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── tuple literal of type `{0: 1, 1: 2}` does not have field '2' -//│ ║ l.128: not_working([1, 2]) -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from field selection: -//│ ║ l.109: if x is -//│ ║ ^^^^ -//│ ║ l.110: [a, b, c] then -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from reference: -//│ ║ l.109: if x is -//│ ╙── ^ -//│ Int | error -//│ res -//│ = NaN From b32b647e2a3924a5467d1720026e0e69eed54973 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 6 Nov 2024 16:36:41 +0800 Subject: [PATCH 5/9] Fix elaboration of `case` and support `as` patterns --- .../scala/hkmc2/semantics/Desugarer.scala | 12 ++++ .../scala/hkmc2/semantics/Elaborator.scala | 31 +++------- .../src/main/scala/hkmc2/syntax/Keyword.scala | 4 +- .../main/scala/hkmc2/syntax/ParseRule.scala | 1 + .../src/main/scala/hkmc2/syntax/Tree.scala | 1 - .../src/test/mlscript/bbml/bbBasics.mls | 10 +-- .../shared/src/test/mlscript/bbml/bbGPCE.mls | 16 ++--- .../test/mlscript/codegen/CaseShorthand.mls | 24 ++++---- .../src/test/mlscript/codegen/OptMatch.mls | 24 ++++++-- .../mlscript/ucs/patterns/AliasPattern.mls | 61 ++++++++----------- 10 files changed, 97 insertions(+), 87 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala index d612eb07d..0ed4d3901 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala @@ -14,6 +14,11 @@ object Desugarer: case InfixApp(lhs, Keyword.and, rhs) => S((lhs, rhs)) case _ => N + object as: + infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match + case InfixApp(lhs, Keyword.`as`, rhs) => S((lhs, rhs)) + case _ => N + object is: infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match case InfixApp(lhs, Keyword.is, rhs) => S((lhs, rhs)) @@ -380,6 +385,13 @@ class Desugarer(tl: TraceLogger, elaborator: Elaborator)(using raise: Raise, sta pattern match // A single wildcard pattern. case Ident("_") => _ => ctx => sequel(ctx) + // Alias pattern + case pat as (alias @ Ident(_)) => fallback => + val aliasSymbol = VarSymbol(alias, nextUid) + val inner = (ctx: Ctx) => + val ctxWithAlias = ctx + (alias.name -> aliasSymbol) + Split.Let(aliasSymbol, ref, sequel(ctxWithAlias)) + expandMatch(scrutSymbol, pat, inner)(fallback) // A single variable pattern or constructor pattern without parameters. case ctor: Ident => fallback => ctx => ctx.get(ctor.name) match case S(sym: ClassSymbol) => // TODO: refined diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index c13242910..2e267a1bb 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -200,27 +200,16 @@ extends Importer: Term.If(body)(body) case Tree.Quoted(body) => Term.Quoted(term(body)) case Tree.Unquoted(body) => Term.Unquoted(term(body)) - case Tree.Case(Block(branches)) => branches.lastOption match - case S(InfixApp(id: Ident, Keyword.`then`, dflt)) => - val sym = VarSymbol(id, nextUid) - val nestCtx = ctx.copy(locals = ctx.locals ++ Ls(id.name -> sym)) - val body = branches.dropRight(1).foldRight(Split.default(term(dflt)(using nestCtx))): - case (InfixApp(target, Keyword.`then`, cons), res) => - val scrutIdent = Ident("scrut"): Ident - val cond = term(App(Ident("=="), Tree.Tup(id :: target :: Nil)))(using nestCtx) - val scrut = TempSymbol(nextUid, S(cond), "scrut") - Split.Let(scrut, cond, Branch( - scrut.ref(), - Pattern.LitPat(Tree.BoolLit(true)), - Split.default(term(cons)(using nestCtx)) - ) :: res) - case _ => - raise(ErrorReport(msg"Unsupported case branch." -> tree.toLoc :: Nil)) - Split.default(Term.Error) - Term.Lam(Param(FldFlags.empty, sym, N) :: Nil, Term.If(body)(body)) - case _ => - raise(ErrorReport(msg"Unsupported default case branch." -> tree.toLoc :: Nil)) - Term.Error + case Tree.Case(branches) => + val scrut = VarSymbol(Ident("caseScrut"), nextUid) + val desugarer = new Desugarer(tl, this) + val des = desugarer.patternSplit(branches, scrut)(Split.Nil)(ctx) + scoped("ucs:desugared"): + log(s"Desugared:\n${Split.display(des)}") + val nor = new ucs.Normalization(tl)(des) + scoped("ucs:normalized"): + log(s"Normalized:\n${Split.display(nor)}") + Term.Lam(Param(FldFlags.empty, scrut, N) :: Nil, Term.If(des)(nor)) case Modified(Keyword.`return`, kwLoc, body) => Term.Ret(term(body)) case Tree.Region(id: Tree.Ident, body) => diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala index ad0e419bd..735e38cc5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Keyword.scala @@ -65,11 +65,11 @@ object Keyword: val `fun` = Keyword("fun", N, N) // val `val` = Keyword("val", N, N) val `var` = Keyword("var", N, N) - val `as` = Keyword("as", N, N) val `of` = Keyword("of", N, N) val `or` = Keyword("or", nextPrec, curPrec) val `and` = Keyword("and", nextPrec, nextPrec) val `is` = Keyword("is", nextPrec, curPrec, canStartInfixOnNewLine = false) + val `as` = Keyword("as", nextPrec, curPrec) val `let` = Keyword("let", nextPrec, curPrec) val `region` = Keyword("region", curPrec, curPrec) val `rec` = Keyword("rec", N, N) @@ -117,7 +117,7 @@ object Keyword: `abstract`, mut, virtual, `override`, declare, public, `private`) type Infix = `and`.type | `or`.type | `then`.type | `else`.type | `is`.type | `:`.type | `->`.type | - `=>`.type | `extends`.type | `restricts`.type + `=>`.type | `extends`.type | `restricts`.type | `as`.type type letLike = `let`.type | `set`.type diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala index a4e1fc748..9c594cd4c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/ParseRule.scala @@ -304,6 +304,7 @@ object ParseRule: genInfixRule(`and`, (rhs, _: Unit) => lhs => InfixApp(lhs, `and`, rhs)), genInfixRule(`or`, (rhs, _: Unit) => lhs => InfixApp(lhs, `or`, rhs)), genInfixRule(`is`, (rhs, _: Unit) => lhs => InfixApp(lhs, `is`, rhs)), + genInfixRule(`as`, (rhs, _: Unit) => lhs => InfixApp(lhs, `as`, rhs)), genInfixRule(`then`, (rhs, _: Unit) => lhs => InfixApp(lhs, `then`, rhs)), // genInfixRule(`else`, (rhs, _: Unit) => lhs => InfixApp(lhs, `else`, rhs)), genInfixRule(`:`, (rhs, _: Unit) => lhs => InfixApp(lhs, `:`, rhs)), diff --git a/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala b/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala index 66dffd94a..c1d45fde4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala @@ -66,7 +66,6 @@ enum Tree extends AutoLocated: case If(split: Tree) @deprecated("Use If instead", "hkmc2-ucs") case IfElse(cond: Tree, alt: Tree) - @deprecated("Use If instead", "hkmc2-ucs") case Case(branches: Tree) case Region(name: Tree, body: Tree) case RegRef(reg: Tree, value: Tree) diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls index 8990f44b7..7e6debed3 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbBasics.mls @@ -247,7 +247,7 @@ fact(1) fun fact2 = case 0 then 1 n then n * fact2(n - 1) -//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref($scrut@161),LitPat(BoolLit(true)),Else(Lit(IntLit(1)))),Else(App(Ref(.*),Tup(List(Fld(‹›,Ref(n@156),None), Fld(‹›,App(Ref(globalThis:block#52.fact2),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@156),None), Fld(‹›,Lit(IntLit(1)),None)))),None)))),None)))))) (of class hkmc2.semantics.Split$Cons) +//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref(caseScrut@156),LitPat(IntLit(0)),Else(Lit(IntLit(1)))),Let(n@157,Ref(caseScrut@156),Else(App(Ref(.*),Tup(List(Fld(‹›,Ref(n@157),None), Fld(‹›,App(Ref(globalThis:block#52.fact2),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@157),None), Fld(‹›,Lit(IntLit(1)),None)))),None)))),None))))))) (of class hkmc2.semantics.Split$Cons) fact2 //│ Type: ⊥ @@ -260,16 +260,16 @@ class Foo[A](x: A -> A) //│ Type: ⊤ new Foo(x => x) -//│ Type: Foo[α76_1] +//│ Type: Foo[α74_1] fun f(g) = new Foo(g) f -//│ Type: forall α79_2: (α79_2 -> α79_2) -> Foo[α79_2] +//│ Type: forall α77_2: (α77_2 -> α77_2) -> Foo[α77_2] f(x => x).Foo#x -//│ Type: (α81_1) ->{⊥} α81_1 +//│ Type: (α79_1) ->{⊥} α79_1 g => (new Foo(g)).Foo#x -//│ Type: (α86_1 -> α86_1) ->{⊥} (α86_1) ->{⊥} α86_1 +//│ Type: (α84_1 -> α84_1) ->{⊥} (α84_1) ->{⊥} α84_1 diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls index f59db3626..6f103f946 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGPCE.mls @@ -6,7 +6,7 @@ fun power(x) = case 0 then `1.0 n then x `*. power(x)(n - 1) power -//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref($scrut@48),LitPat(BoolLit(true)),Else(Quoted(Lit(DecLit(1.0))))),Else(Quoted(App(Ref(.*.),Tup(List(Fld(‹›,Unquoted(Ref(x@41)),None), Fld(‹›,Unquoted(App(App(Ref(globalThis:block#0.power),Tup(List(Fld(‹›,Ref(x@41),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@42),None), Fld(‹›,Lit(IntLit(1)),None)))),None))))),None))))))) (of class hkmc2.semantics.Split$Cons) +//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref(caseScrut@42),LitPat(IntLit(0)),Else(Quoted(Lit(DecLit(1.0))))),Let(n@43,Ref(caseScrut@42),Else(Quoted(App(Ref(.*.),Tup(List(Fld(‹›,Unquoted(Ref(x@41)),None), Fld(‹›,Unquoted(App(App(Ref(globalThis:block#0.power),Tup(List(Fld(‹›,Ref(x@41),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@43),None), Fld(‹›,Lit(IntLit(1)),None)))),None))))),None)))))))) (of class hkmc2.semantics.Split$Cons) fun id: [A] -> A -> A @@ -22,7 +22,7 @@ fun assertNotZero(x) = `if (x `== `0.0) then `error else x let checkedDiv = x `=> y `=> x `/. (assertNotZero(y)) run(checkedDiv) -//│ ═══[ERROR] Cannot quote If(Let($scrut@72,Unquoted(Quoted(App(Ref(.==),Tup(List(Fld(‹›,Unquoted(Ref(x@70)),None), Fld(‹›,Unquoted(Quoted(Lit(DecLit(0.0)))),None)))))),Cons(Branch(Ref($scrut@72),LitPat(BoolLit(true)),Else(Unquoted(Quoted(Ref(.error))))),Else(Unquoted(Ref(x@70)))))) +//│ ═══[ERROR] Cannot quote If(Let($scrut@71,Unquoted(Quoted(App(Ref(.==),Tup(List(Fld(‹›,Unquoted(Ref(x@69)),None), Fld(‹›,Unquoted(Quoted(Lit(DecLit(0.0)))),None)))))),Cons(Branch(Ref($scrut@71),LitPat(BoolLit(true)),Else(Unquoted(Quoted(Ref(.error))))),Else(Unquoted(Ref(x@69)))))) //│ Type: Num -> (Num -> Num) @@ -35,7 +35,7 @@ show fun inc(dbg) = x `=> let c = x `+ `1 in let t = dbg(c) in c inc -//│ Type: forall α65_2: (CodeBase[out Int, ?, ?] ->{α65_2} ⊤) ->{α65_2} CodeBase[out Int -> Int, ⊥, ?] +//│ Type: forall α63_2: (CodeBase[out Int, ?, ?] ->{α63_2} ⊤) ->{α63_2} CodeBase[out Int -> Int, ⊥, ?] inc(c => log(show(c))) //│ Type: CodeBase[out Int -> Int, ⊥, ?] @@ -49,11 +49,11 @@ fun body(x, y) = case fun gib_naive(n) = (x, y) `=> body(x, y)(n) let gn5 = run(gib_naive(5)) -//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref($scrut@111),LitPat(BoolLit(true)),Else(Ref(x@101))),Let($scrut@109,App(Ref(.==),Tup(List(Fld(‹›,Ref(n@103),None), Fld(‹›,Lit(IntLit(1)),None)))),Cons(Branch(Ref($scrut@109),LitPat(BoolLit(true)),Else(Ref(y@102))),Else(App(App(Ref(globalThis:block#7.body),Tup(List(Fld(‹›,Ref(y@102),None), Fld(‹›,Quoted(App(Ref(.+),Tup(List(Fld(‹›,Unquoted(Ref(x@101)),None), Fld(‹›,Unquoted(Ref(y@102)),None))))),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@103),None), Fld(‹›,Lit(IntLit(1)),None)))),None)))))))) (of class hkmc2.semantics.Split$Cons) +//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref(caseScrut@102),LitPat(IntLit(0)),Else(Ref(x@100))),Cons(Branch(Ref(caseScrut@102),LitPat(IntLit(1)),Else(Ref(y@101))),Let(n@103,Ref(caseScrut@102),Else(App(App(Ref(globalThis:block#7.body),Tup(List(Fld(‹›,Ref(y@101),None), Fld(‹›,Quoted(App(Ref(.+),Tup(List(Fld(‹›,Unquoted(Ref(x@100)),None), Fld(‹›,Unquoted(Ref(y@101)),None))))),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@103),None), Fld(‹›,Lit(IntLit(1)),None)))),None)))))))) (of class hkmc2.semantics.Split$Cons) fun bind(rhs, k) = `let x = rhs `in k(x) bind -//│ Type: forall α102_2, α103_2, α107_2, α110_2, α113_2, α114_2: (CodeBase[out α102_2, out α103_2, ?], CodeBase[in α107_2 out α107_2 ∨ α102_2, ?, ⊥] ->{α110_2} CodeBase[out α113_2, out α114_2, ?]) ->{α110_2} CodeBase[out α113_2, out α103_2 ∨ α114_2, ?] +//│ Type: forall α98_2, α99_2, α103_2, α106_2, α109_2, α110_2: (CodeBase[out α98_2, out α99_2, ?], CodeBase[in α103_2 out α103_2 ∨ α98_2, ?, ⊥] ->{α106_2} CodeBase[out α109_2, out α110_2, ?]) ->{α106_2} CodeBase[out α109_2, out α99_2 ∨ α110_2, ?] :e :fixme @@ -62,12 +62,12 @@ fun body(x, y) = case 0 then x 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out C, out Any] -//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref($scrut@145),LitPat(BoolLit(true)),Else(Ref(x@132))),Let($scrut@143,App(Ref(.==),Tup(List(Fld(‹›,Ref(n@134),None), Fld(‹›,Lit(IntLit(1)),None)))),Cons(Branch(Ref($scrut@143),LitPat(BoolLit(true)),Else(Ref(y@133))),Else(App(Ref(globalThis:block#8.bind),Tup(List(Fld(‹›,Quoted(App(Ref(.+),Tup(List(Fld(‹›,Unquoted(Ref(x@132)),None), Fld(‹›,Unquoted(Ref(y@133)),None))))),None), Fld(‹›,Lam(List(Param(‹›,z@137,None)),App(App(Ref(globalThis:block#9.body),Tup(List(Fld(‹›,Ref(y@133),None), Fld(‹›,Ref(z@137),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@134),None), Fld(‹›,Lit(IntLit(1)),None)))),None))))),Some(Forall(List(QuantVar(C@141,None,None)),FunTy(Tup(List(Fld(‹›,TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(class:Int))), WildcardTy(None,Some(Ref(C@141))), WildcardTy(None,Some(Ref(class:Any))))),None))),TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(C@141))), WildcardTy(None,Some(Ref(class:Any))))),None))))))))))) (of class hkmc2.semantics.Split$Cons) +//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref(caseScrut@130),LitPat(IntLit(0)),Else(Ref(x@128))),Cons(Branch(Ref(caseScrut@130),LitPat(IntLit(1)),Else(Ref(y@129))),Let(n@131,Ref(caseScrut@130),Else(App(Ref(globalThis:block#8.bind),Tup(List(Fld(‹›,Quoted(App(Ref(.+),Tup(List(Fld(‹›,Unquoted(Ref(x@128)),None), Fld(‹›,Unquoted(Ref(y@129)),None))))),None), Fld(‹›,Lam(List(Param(‹›,z@134,None)),App(App(Ref(globalThis:block#9.body),Tup(List(Fld(‹›,Ref(y@129),None), Fld(‹›,Ref(z@134),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@131),None), Fld(‹›,Lit(IntLit(1)),None)))),None))))),Some(Forall(List(QuantVar(C@138,None,None)),FunTy(Tup(List(Fld(‹›,TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(class:Int))), WildcardTy(None,Some(Ref(C@138))), WildcardTy(None,Some(Ref(class:Any))))),None))),TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(C@138))), WildcardTy(None,Some(Ref(class:Any))))),None))))))))))) (of class hkmc2.semantics.Split$Cons) fun bind: [G] -> (CodeBase[out Int, out G, out Any], [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out Int, out C | G, out Any]) -> CodeBase[out Int, out G, out Any] fun bind(rhs, k) = `let x = rhs `in k(x) bind -//│ Type: forall α127_2: (CodeBase[out Int, out α127_2, ?], forall α128_3: (CodeBase[out Int, out α128_3, ?]) ->{⊥} CodeBase[out Int, out α128_3 ∨ α127_2, ?]) ->{⊥} CodeBase[out Int, out α127_2, ?] +//│ Type: forall α121_2: (CodeBase[out Int, out α121_2, ?], forall α122_3: (CodeBase[out Int, out α122_3, ?]) ->{⊥} CodeBase[out Int, out α122_3 ∨ α121_2, ?]) ->{⊥} CodeBase[out Int, out α121_2, ?] :fixme @@ -77,7 +77,7 @@ fun body(x, y) = case 1 then y n then bind of x `+ y, (z => body(y, z)(n - 1)): [C] -> CodeBase[out Int, out C, out Any] -> CodeBase[out Int, out C, out Any] body -//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref($scrut@175),LitPat(BoolLit(true)),Else(Ref(x@162))),Let($scrut@173,App(Ref(.==),Tup(List(Fld(‹›,Ref(n@164),None), Fld(‹›,Lit(IntLit(1)),None)))),Cons(Branch(Ref($scrut@173),LitPat(BoolLit(true)),Else(Ref(y@163))),Else(App(Ref(globalThis:block#10.bind),Tup(List(Fld(‹›,Quoted(App(Ref(.+),Tup(List(Fld(‹›,Unquoted(Ref(x@162)),None), Fld(‹›,Unquoted(Ref(y@163)),None))))),None), Fld(‹›,Lam(List(Param(‹›,z@167,None)),App(App(Ref(globalThis:block#11.body),Tup(List(Fld(‹›,Ref(y@163),None), Fld(‹›,Ref(z@167),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@164),None), Fld(‹›,Lit(IntLit(1)),None)))),None))))),Some(Forall(List(QuantVar(C@171,None,None)),FunTy(Tup(List(Fld(‹›,TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(class:Int))), WildcardTy(None,Some(Ref(C@171))), WildcardTy(None,Some(Ref(class:Any))))),None))),TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(class:Int))), WildcardTy(None,Some(Ref(C@171))), WildcardTy(None,Some(Ref(class:Any))))),None))))))))))) (of class hkmc2.semantics.Split$Cons) +//│ /!!!\ Uncaught error: scala.MatchError: Cons(Branch(Ref(caseScrut@157),LitPat(IntLit(0)),Else(Ref(x@155))),Cons(Branch(Ref(caseScrut@157),LitPat(IntLit(1)),Else(Ref(y@156))),Let(n@158,Ref(caseScrut@157),Else(App(Ref(globalThis:block#10.bind),Tup(List(Fld(‹›,Quoted(App(Ref(.+),Tup(List(Fld(‹›,Unquoted(Ref(x@155)),None), Fld(‹›,Unquoted(Ref(y@156)),None))))),None), Fld(‹›,Lam(List(Param(‹›,z@161,None)),App(App(Ref(globalThis:block#11.body),Tup(List(Fld(‹›,Ref(y@156),None), Fld(‹›,Ref(z@161),None)))),Tup(List(Fld(‹›,App(Ref(.-),Tup(List(Fld(‹›,Ref(n@158),None), Fld(‹›,Lit(IntLit(1)),None)))),None))))),Some(Forall(List(QuantVar(C@165,None,None)),FunTy(Tup(List(Fld(‹›,TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(class:Int))), WildcardTy(None,Some(Ref(C@165))), WildcardTy(None,Some(Ref(class:Any))))),None))),TyApp(Ref(class:CodeBase),List(WildcardTy(None,Some(Ref(class:Int))), WildcardTy(None,Some(Ref(C@165))), WildcardTy(None,Some(Ref(class:Any))))),None))))))))))) (of class hkmc2.semantics.Split$Cons) fun gib(n) = (x, y) `=> body(x, y)(n) let g5 = run(gib(5)) diff --git a/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls b/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls index 95807c7de..9eb8d507c 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/CaseShorthand.mls @@ -11,7 +11,7 @@ case x then x :sjs case { x then x } //│ JS: -//│ (x) => { return x } +//│ (caseScrut) => { let x; x = caseScrut; return x } //│ = [Function (anonymous)] :sjs @@ -21,19 +21,19 @@ x => if x is //│ (x) => { if (x === 0) { return true } else { throw new this.Error("match error") } } //│ = [Function (anonymous)] -:fixme +:sjs case 0 then true -//│ ╔══[ERROR] Unsupported default case branch. -//│ ║ l.26: 0 then true -//│ ╙── ^ +//│ JS: +//│ (caseScrut) => { if (caseScrut === 0) { return true } else { throw new this.Error("match error") } } +//│ = [Function (anonymous)] :sjs case 0 then true _ then false //│ JS: -//│ (_) => { let scrut; scrut = _ == 0; if (scrut) { return true } else { return false } } +//│ (caseScrut) => { if (caseScrut === 0) { return true } else { return false } } //│ = [Function (anonymous)] class Some(value) @@ -45,13 +45,15 @@ val isDefined = case Some then true None then false //│ JS: -//│ this.isDefined = (None) => { -//│ let scrut; -//│ scrut = None == this.Some; -//│ if (scrut) { +//│ this.isDefined = (caseScrut) => { +//│ if (caseScrut instanceof this.Some) { //│ return true //│ } else { -//│ return false +//│ if (caseScrut === this.None) { +//│ return false +//│ } else { +//│ throw new this.Error("match error") +//│ } //│ } //│ }; //│ undefined diff --git a/hkmc2/shared/src/test/mlscript/codegen/OptMatch.mls b/hkmc2/shared/src/test/mlscript/codegen/OptMatch.mls index aa4dd230e..d26991673 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/OptMatch.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/OptMatch.mls @@ -30,18 +30,32 @@ isDefined(None) //│ = false -:fixme +:sjs val isDefined = case Some(_) then true None then false -//│ ╔══[ERROR] Name not found: _ -//│ ║ l.35: Some(_) then true -//│ ╙── ^ +//│ JS: +//│ this.isDefined = (caseScrut) => { +//│ let param0; +//│ if (caseScrut instanceof this.Some) { +//│ param0 = caseScrut.value; +//│ return true +//│ } else { +//│ if (caseScrut === this.None) { +//│ return false +//│ } else { +//│ throw new this.Error("match error") +//│ } +//│ } +//│ }; +//│ undefined //│ isDefined = [Function (anonymous)] isDefined(Some(1)) +//│ = true isDefined(None) +//│ = false val isDefined = x => if x is @@ -64,7 +78,7 @@ val isOther = x => if x is Foo.Other(_) then true None then false //│ ╔══[ERROR] Unrecognized pattern. -//│ ║ l.64: Foo.Other(_) then true +//│ ║ l.78: Foo.Other(_) then true //│ ╙── ^^^^^^^^^^^^ //│ isOther = [Function (anonymous)] diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls index d1ae7c914..070fee3b1 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/AliasPattern.mls @@ -1,47 +1,40 @@ :import ../prelude/Option.mls //│ Imported 3 member(s) -:todo +:global +:ucs desugared + fun map(f) = case Some(x) then Some(f(x)) None as n then n -//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here -//│ ║ l.7: None as n then n -//│ ╙── ^^ -//│ ╔══[ERROR] Unsupported default case branch. -//│ ║ l.6: Some(x) then Some(f(x)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: None as n then n -//│ ╙── ^^^^^^ +//│ Desugared: +//│ > if +//│ > caseScrut@31 is Some($param0@33) and +//│ > let x@34 = $param0@33#0 +//│ > else class:Some#1(f@30#0(x@34#0)) +//│ > caseScrut@31 is None and +//│ > let n@32 = caseScrut@31#1 +//│ > else n@32#0 -:todo fun map(f) = case Some(x as n) then Some of f(n) None as n then n -//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here -//│ ║ l.19: Some(x as n) then Some of f(n) -//│ ╙── ^^ -//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here -//│ ║ l.20: None as n then n -//│ ╙── ^^ -//│ ╔══[ERROR] Unsupported default case branch. -//│ ║ l.19: Some(x as n) then Some of f(n) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.20: None as n then n -//│ ╙── ^^^^^^ +//│ Desugared: +//│ > if +//│ > caseScrut@40 is Some($param0@42) and +//│ > let x@44 = $param0@42#0 +//│ > let n@43 = $param0@42#1 +//│ > else class:Some#3(f@39#0(n@43#0)) +//│ > caseScrut@40 is None and +//│ > let n@41 = caseScrut@40#1 +//│ > else n@41#0 -:todo fun foo = case Some(Some(a as b) as c) as d then [a, b, c, d] -//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here -//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] -//│ ╙── ^^ -//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here -//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] -//│ ╙── ^^ -//│ ╔══[PARSE ERROR] Unexpected 'as' keyword here -//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] -//│ ╙── ^^ -//│ ╔══[ERROR] Unsupported default case branch. -//│ ║ l.35: Some(Some(a as b) as c) as d then [a, b, c, d] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ +//│ Desugared: +//│ > if caseScrut@49 is Some($param0@51) and $param0@51 is Some($param0@53) and +//│ > let a@55 = $param0@53#0 +//│ > let b@54 = $param0@53#1 +//│ > let c@52 = $param0@51#1 +//│ > let d@50 = caseScrut@49#1 +//│ > else [a@55#0, b@54#0, c@52#0, d@50#0] From 15a72403d56caa1828ffa69f551f9f5382559eca Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 6 Nov 2024 17:03:47 +0800 Subject: [PATCH 6/9] Reduce the boilerplate of extractors --- .../scala/hkmc2/semantics/Desugarer.scala | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala index 0ed4d3901..162f7e642 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Desugarer.scala @@ -6,38 +6,19 @@ import mlscript.utils.*, shorthands.* import Message.MessageContext import utils.TraceLogger import hkmc2.syntax.Literal -import Keyword.`let` +import Keyword.{as, and, `else`, is, let, `then`} object Desugarer: - object and: + extension (op: Keyword.Infix) infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match - case InfixApp(lhs, Keyword.and, rhs) => S((lhs, rhs)) + case InfixApp(lhs, `op`, rhs) => S((lhs, rhs)) case _ => N - object as: - infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match - case InfixApp(lhs, Keyword.`as`, rhs) => S((lhs, rhs)) - case _ => N - - object is: - infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match - case InfixApp(lhs, Keyword.is, rhs) => S((lhs, rhs)) - case _ => N - - object `then`: - infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match - case InfixApp(lhs, Keyword.`then`, rhs) => S((lhs, rhs)) - case _ => N - - object `->`: + /** An extractor that accepts either `A and B` or `A then B`. */ + object `~>`: infix def unapply(tree: Tree): Opt[(Tree, Tree \/ Tree)] = tree match - case InfixApp(lhs, Keyword.and, rhs) => S((lhs, L(rhs))) - case InfixApp(lhs, Keyword.`then`, rhs) => S((lhs, R(rhs))) - case _ => N - - object `else`: - infix def unapply(tree: Tree): Opt[(Tree, Tree)] = tree match - case InfixApp(lhs, Keyword.`else`, rhs) => S((lhs, rhs)) + case lhs and rhs => S((lhs, L(rhs))) + case lhs `then` rhs => S((lhs, R(rhs))) case _ => N end Desugarer @@ -187,7 +168,7 @@ class Desugarer(tl: TraceLogger, elaborator: Elaborator)(using raise: Raise, sta case coda is rhs => fallback => ctx => nominate(ctx, finish(term(coda)(using ctx))): patternSplit(rhs, _)(fallback) - case matches -> consequent => fallback => + case matches ~> consequent => fallback => // There are N > 0 conjunct matches. We use `::[T]` instead of `List[T]`. // Each match is represented by a pair of a _coda_ and a _pattern_ // that is yet to be elaborated. @@ -348,7 +329,7 @@ class Desugarer(tl: TraceLogger, elaborator: Elaborator)(using raise: Raise, sta post = (res: Split) => s"patternSplit (alternative) >>> ${res.showDbg}" ): patternSplit(branch, scrutSymbol)(elabFallback(backup)(ctx))(ctx) - case patternAndMatches -> consequent => fallback => + case patternAndMatches ~> consequent => fallback => // There are N > 0 conjunct matches. We use `::[T]` instead of `List[T]`. // Each match is represented by a pair of a _coda_ and a _pattern_ // that is yet to be elaborated. From 79bb49d839d5afe4f08f4bc92be28b022377cffe Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 7 Nov 2024 11:38:16 +0800 Subject: [PATCH 7/9] Fix a misreference in a test of simple tuple patterns Co-authored-by: Lionel Parreaux --- hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls index e05a30325..e6885e7ca 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls @@ -12,7 +12,7 @@ sum'([1, 2]) :e fun sum''(pair) = if pair is [x, y] then x + y -sum'([1, 2]) +sum''([1, 2]) //│ ╔══[ERROR] Unrecognized pattern. //│ ║ l.14: if pair is [x, y] then x + y //│ ╙── ^^^^^^ From 72bf8eeaf448da979e379f497e175b8676068346 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 7 Nov 2024 11:40:15 +0800 Subject: [PATCH 8/9] Fix the commands of tests of patterns --- .../src/test/mlscript/ucs/patterns/Literals.mls | 2 -- .../src/test/mlscript/ucs/patterns/Refinement.mls | 2 +- .../src/test/mlscript/ucs/patterns/SimpleTuple.mls | 14 ++++++-------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls index 4ac3248e3..ba1b075b3 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/Literals.mls @@ -28,8 +28,6 @@ fun g(x) = if x && true is true then 1 else 2 fun h(x) = if (x : Bool) then 1 else 2 -// Currently post-processing cannot handle this case. The desugared term is not -// perfect. Also, is the inferred type wrong? fun mix(x) = if x is true then "true" Some(value) then "Some" diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls index 3ac78a8f5..a4d31206a 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/Refinement.mls @@ -2,7 +2,7 @@ //│ Imported 3 member(s) :global -:e +:todo :ucs normalized // OK diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls index e6885e7ca..6bdbe5eb2 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls @@ -9,7 +9,7 @@ fun sum'([x, y]) = x + y sum'([1, 2]) //│ /!!!\ Uncaught error: scala.MatchError: Tup(List(Ident(x), Ident(y))) (of class hkmc2.syntax.Tree$Tup) -:e +:todo fun sum''(pair) = if pair is [x, y] then x + y sum''([1, 2]) @@ -23,7 +23,7 @@ sum''([1, 2]) // We need native support for tuple patterns in MLscript syntax. // Otherwise the following cases work. -:e +:todo fun test(thing) = if thing is [] then 0 test("") @@ -32,7 +32,7 @@ test(12) //│ ║ l.28: if thing is [] then 0 //│ ╙── ^^ -:e +:todo // Since pattern destruction is desugared to let bindings, matching with other // classes after the tuple pattern will not work. class Point(x: Int, y: Int) @@ -49,7 +49,7 @@ fun discarded_cases(thing) = discarded_cases(Point(0, 0)) // A workaround is to move the tuple pattern to the last case. -:e +:todo fun working_cases(thing) = if thing is Point(x, y) then x + y @@ -61,11 +61,10 @@ fun working_cases(thing) = working_cases(Point(0, 0)) // However, the `Object` type forbids tuples to be used. -:e :todo working_cases([0, 0]) -:e +:todo fun not_working(x) = if x is [a, b, c] then @@ -73,11 +72,10 @@ fun not_working(x) = else 0 //│ ╔══[ERROR] Unrecognized pattern. -//│ ║ l.71: [a, b, c] then +//│ ║ l.70: [a, b, c] then //│ ╙── ^^^^^^^^^ not_working([1, 2, 3]) -:e :todo not_working([1, 2]) From 8ec13566af05b0c00466a2b9dc08ad51af246cbf Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 7 Nov 2024 11:47:26 +0800 Subject: [PATCH 9/9] Rerun test on SimpleTuple.mls --- .../src/test/mlscript/ucs/patterns/SimpleTuple.mls | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls index 6bdbe5eb2..bcddebf6a 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/patterns/SimpleTuple.mls @@ -16,9 +16,6 @@ sum''([1, 2]) //│ ╔══[ERROR] Unrecognized pattern. //│ ║ l.14: if pair is [x, y] then x + y //│ ╙── ^^^^^^ -//│ ╔══[ERROR] Name not found: sum' -//│ ║ l.15: sum'([1, 2]) -//│ ╙── ^^^^ // We need native support for tuple patterns in MLscript syntax. // Otherwise the following cases work. @@ -29,7 +26,7 @@ fun test(thing) = test("") test(12) //│ ╔══[ERROR] Unrecognized pattern. -//│ ║ l.28: if thing is [] then 0 +//│ ║ l.25: if thing is [] then 0 //│ ╙── ^^ :todo @@ -41,7 +38,7 @@ fun discarded_cases(thing) = [x, y] then x + y Point(x, y) then x + y //│ ╔══[ERROR] Unrecognized pattern. -//│ ║ l.41: [x, y] then x + y +//│ ║ l.38: [x, y] then x + y //│ ╙── ^^^^^^ :e @@ -55,7 +52,7 @@ fun working_cases(thing) = Point(x, y) then x + y [x, y] then x + y //│ ╔══[ERROR] Unrecognized pattern. -//│ ║ l.56: [x, y] then x + y +//│ ║ l.53: [x, y] then x + y //│ ╙── ^^^^^^ working_cases(Point(0, 0)) @@ -72,7 +69,7 @@ fun not_working(x) = else 0 //│ ╔══[ERROR] Unrecognized pattern. -//│ ║ l.70: [a, b, c] then +//│ ║ l.67: [a, b, c] then //│ ╙── ^^^^^^^^^ not_working([1, 2, 3])