UCS/UPS tracking issue
Issue to track the parts of the UCS implementation that are still incomplete or wrong – please update with more cases as you find them.
Translation
- [x] Support virtual constructors for pattern matching against tuples. Note as of Jan 2024: We implemented simple tuple pattern in #194 and we will support advanced tuple patterns, for example, splice tuple patterns, in the near future.
- [x] Do not duplicate default cases and insert local function definitions instead.
- Note as of Jan 2024: We paved the road for this in #194 and we will implement this feature in the near future.
- Note as of Nov 2025: This has been solved in #336. Instead of using local functions, we use
BlockandBreak.
Locations
-
~~Track scrutinee locations with
Scrutinee.Source~~. (Note: it was removed in new desugarer.) -
[x] No location reported in:
fun testF(x) = if x is Foo(a) then a Foo(a) then a //│ ╔══[WARNING] duplicated branch //│ ╙──
Reporting
- [ ] Warn when an
istest has a single pattern Though maybe we shouldn't warn when it's conjuncted with other things, as then theismay be used to bind expressions, as inif xs is x :: xs and mapPartition(f, xs) is (as, bs) and ...
-
[x] hygiene
:NewParser :NewDefs :NoJS class Union<Region>(a: Region, b: Region) //│ class Union[Region](a: Region, b: Region) // * [FIXME:UCS] unhygienically desugars to: // | | | | Desugared term: case x of { Union => let x = (x).a in let y = (x).b in x } fun hmm(x) = if x is Union(x, y) then x //│ fun hmm: Union[{b: anything} & 'a] -> 'a fun hmm(x) = if x is Union(z, y) then x //│ fun hmm: Union['Region] -> Union['Region]
- [x] There's a problem witth he builtin true/false in the current UCS impl
:NewParser
:NewDefs
module Nil
class Cons[A](head: A, tail: Cons[A] | Nil)
//│ module Nil()
//│ class Cons[A](head: A, tail: Cons[A] | Nil)
// FIXME
fun filtermap(f, xs) = if xs is
Nil then Nil
Cons(y, ys) and f(ys) is
false then filtermap(f, ys)
true then Cons(y, filtermap(f, ys))
[true, z] then Cons(y, filtermap(f, ys))
//│ ╔══[ERROR] identifier not found: ys
//│ ║ l.26: Cons(y, ys) and f(ys) is
//│ ╙── ^^
//│ ╔══[ERROR] Type mismatch in application:
//│ ║ l.26: Cons(y, ys) and f(ys) is
//│ ║ ^^^^^^^^
//│ ║ l.27: false then filtermap(f, ys)
//│ ║ ^^^^^^^^^
//│ ╟── reference of type `false` is not an instance of type `number`
//│ ║ l.27: false then filtermap(f, ys)
//│ ╙── ^^^^^
//│ ╔══[ERROR] Type mismatch in application:
//│ ║ l.26: Cons(y, ys) and f(ys) is
//│ ║ ^^^^^^^^
//│ ║ l.27: false then filtermap(f, ys)
//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//│ ║ l.28: true then Cons(y, filtermap(f, ys))
//│ ║ ^^^^^^^^
//│ ╟── reference of type `true` is not an instance of type `number`
//│ ║ l.28: true then Cons(y, filtermap(f, ys))
//│ ╙── ^^^^
//│ ╔══[ERROR] type identifier not found: Tuple#2
//│ ╙──
//│ fun filtermap: ((error | Cons['A] | Nil) -> number & (Cons['A] | Nil) -> error, Cons['A0] | Nil,) -> (Cons['A1] | Nil | error)
//│ where
//│ 'A := 'A0
//│ 'A0 <: nothing
//│ Code generation encountered an error:
//│ unknown match case: Tuple#2
module True
module False
//│ module True()
//│ module False()
class Pair[A, B](lhs: A, rhs: B)
//│ class Pair[A, B](lhs: A, rhs: B)
fun filtermap(f, xs) = if xs is
Nil then Nil
Cons(y, ys) then if f(y) is
True then filtermap(f, ys)
False then Cons(y, filtermap(f, ys))
Pair(True, z) then Cons(z, filtermap(f, ys))
//│ fun filtermap: ('head -> (False | Pair[anything, 'A] | True), Cons['head] | Nil,) -> (Cons['A] | Nil)
//│ where
//│ 'head <: 'A
- [ ] Fix unhygienic bindings in HygienicBindings.mls and shared/src/test/diff/ucs/Hygiene.mls
- [ ] Should report warnings in shared/src/test/diff/ucs/Wildcard.mls
- [ ] Proper errors in shared/src/test/diff/ucs/PlainConditionals.mls
- [x] Some parser failures in shared/src/test/diff/ucs/ParseFailures.mls
- [ ] Support
orin shared/src/test/diff/ucs/Or.mls - [x] Leading
andin shared/src/test/diff/ucs/LeadingAnd.mls - [x] Incomplete example in shared/src/test/diff/ucs/JSON.mls
- [ ] Warning message regression. It should report the first duplicated branch. https://github.com/chengluyu/mlscript/blob/ee1ab193234e9d59ad0ce3fa82e2c922efd8d56e/shared/src/test/diff/ucs/DirectLines.mls#L50-L63
- [ ] Show terms properly, not using the internal debug string. https://github.com/chengluyu/mlscript/blob/ee1ab193234e9d59ad0ce3fa82e2c922efd8d56e/shared/src/test/diff/ucs/Exhaustiveness.mls#L51
-
[x] Give warnings for non-conditional UCS. See https://github.com/hkust-taco/mlscript/blob/ee1ab193234e9d59ad0ce3fa82e2c922efd8d56e/shared/src/test/diff/nu/BadUCS.mls#L75
Update as of the introduction of new desugarer in Jan 2024: This case is interesting, it means that we bind
xtoywhich shadows parametery, but someone may think it means if x == y then 0. -
[ ] Precise scrutinee tracking and merge explicit let bindings: https://github.com/hkust-taco/mlscript/blob/66d41f279648dd67507d442fa96330bec17075e7/shared/src/test/diff/ucs/HygienicBindings.mls#L31
-
[ ] One more hygienic bindings thing to make sure and address
https://github.com/hkust-taco/mlscript/blob/687f39d8ebf4d649622e40ecba2af6ac09c3400f/shared/src/test/diff/ucs/CrossBranchCapture.mls#L8-L12
-
[ ] Warn against shadowing pattern variables
https://github.com/hkust-taco/mlscript/blob/687f39d8ebf4d649622e40ecba2af6ac09c3400f/shared/src/test/diff/ucs/CrossBranchCapture.mls#L49-L52
- [ ] It seems that this should work, but is currently warned about due to an overly restrictive implementation:
fun fold(opt, k, d) = if opt is None then d refined(Some) then k(opt) else k(opt) //│ ╔══[WARNING] inconsistent refined pattern //│ ║ l.67: None then d //│ ║ ^^^^ //│ ╟── pattern `Some` is refined //│ ║ l.68: refined(Some) then k(opt) //│ ║ ^^^^ //│ ╟── but pattern `None` is not refined //│ ║ l.67: None then d //│ ╙── ^^^^