mlscript icon indicating copy to clipboard operation
mlscript copied to clipboard

UCS/UPS tracking issue

Open LPTK opened this issue 3 years ago • 14 comments

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 Block and Break.

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 is test has a single pattern Though maybe we shouldn't warn when it's conjuncted with other things, as then the is may be used to bind expressions, as in if xs is x :: xs and mapPartition(f, xs) is (as, bs) and ...

LPTK avatar Nov 22 '22 15:11 LPTK

  • [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]
    

LPTK avatar Feb 25 '23 16:02 LPTK

  • [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

LPTK avatar Mar 03 '23 06:03 LPTK

  • [ ] 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 or in shared/src/test/diff/ucs/Or.mls
  • [x] Leading and in shared/src/test/diff/ucs/LeadingAnd.mls
  • [x] Incomplete example in shared/src/test/diff/ucs/JSON.mls

chengluyu avatar May 05 '23 06:05 chengluyu

  • [ ] 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

chengluyu avatar May 12 '23 18:05 chengluyu

  • [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 x to y which shadows parameter y, 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

chengluyu avatar May 17 '23 09:05 chengluyu

  • [ ] 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

LPTK avatar Jul 18 '23 03:07 LPTK

  • [ ] 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
    //│ ╙──          ^^^^
    

LPTK avatar Feb 19 '24 14:02 LPTK