Skip to content

Commit d168eb5

Browse files
committed
Add some examples of unhygienic let bindings
1 parent b7a7cd5 commit d168eb5

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
:NewDefs
2+
3+
type Option[out T] = None | Some[T]
4+
module None
5+
class Some[out T](value: T)
6+
//│ type Option[T] = Some[T] | None
7+
//│ module None()
8+
//│ class Some[T](value: T)
9+
10+
type Either[A, B] = Left[A] | Right[B]
11+
class Left[A](leftValue: A)
12+
class Right[B](rightValue: B)
13+
//│ type Either[A, B] = Left[A] | Right[B]
14+
//│ class Left[A](leftValue: A)
15+
//│ class Right[B](rightValue: B)
16+
17+
type List[out A] = Nil | Cons[A]
18+
module Nil
19+
class Cons[out A](head: A, tail: List[A])
20+
//│ type List[A] = Cons[A] | Nil
21+
//│ module Nil()
22+
//│ class Cons[A](head: A, tail: List[A])
23+
24+
fun h0(a) =
25+
if
26+
a is Some(Left(y)) then y
27+
a is Some(Right(z)) then z
28+
a is None then 0
29+
//│ fun h0: forall 'leftValue. (None | Some[Left['leftValue] | Right['leftValue]]) -> (0 | 'leftValue)
30+
31+
// FIXME: Precise scrutinee identification (easy)
32+
// This seems fine. But the subtrees are not merged.
33+
fun h1(a) =
34+
if
35+
a is Some(x) and x is Left(y) then y
36+
a is Some(y) and y is Right(z) then z
37+
a is None then 0
38+
//│ fun h1: forall 'leftValue. (None | Some[Right['leftValue]]) -> (0 | 'leftValue)
39+
40+
// FIXME: This is the desugared version of the test case above.
41+
fun h1'(a) =
42+
if a is
43+
Some then
44+
let x = a.value
45+
let y = a.value
46+
if x is
47+
Left then
48+
let y = x.leftValue
49+
y
50+
_ then
51+
if y is
52+
Right then
53+
let z = y.rightValue
54+
z
55+
None then 0
56+
//│ fun h1': forall 'leftValue. (None | Some[Right['leftValue]]) -> (0 | 'leftValue)
57+
58+
// FIXME This seems fine but the desugared term does not merge the cases.
59+
// See the example below.
60+
fun h1''(a) =
61+
if
62+
a is Some(x) and x is Left(y) then y
63+
a is Some(x) and x is Right(z) then z
64+
a is None then 0
65+
//│ fun h1'': forall 'leftValue. (None | Some[Left['leftValue] | Right['leftValue]]) -> (0 | 'leftValue)
66+
67+
// FIXME
68+
h1(Some(Left(0)))
69+
h1'(Some(Left(0)))
70+
h1''(Some(Left(0)))
71+
//│ ╔══[ERROR] Type mismatch in application:
72+
//│ ║ l.68: h1(Some(Left(0)))
73+
//│ ║ ^^^^^^^^^^^^^^^^^
74+
//│ ╟── application of type `Left[?A]` is not an instance of type `Right`
75+
//│ ║ l.68: h1(Some(Left(0)))
76+
//│ ║ ^^^^^^^
77+
//│ ╟── Note: constraint arises from class pattern:
78+
//│ ║ l.36: a is Some(y) and y is Right(z) then z
79+
//│ ║ ^^^^^
80+
//│ ╟── from reference:
81+
//│ ║ l.35: a is Some(x) and x is Left(y) then y
82+
//│ ║ ^
83+
//│ ╟── Note: type parameter T is defined at:
84+
//│ ║ l.5: class Some[out T](value: T)
85+
//│ ╙── ^
86+
//│ ╔══[ERROR] Type mismatch in application:
87+
//│ ║ l.69: h1'(Some(Left(0)))
88+
//│ ║ ^^^^^^^^^^^^^^^^^^
89+
//│ ╟── application of type `Left[?A]` is not an instance of type `Right`
90+
//│ ║ l.69: h1'(Some(Left(0)))
91+
//│ ║ ^^^^^^^
92+
//│ ╟── Note: constraint arises from class pattern:
93+
//│ ║ l.52: Right then
94+
//│ ║ ^^^^^
95+
//│ ╟── from field selection:
96+
//│ ║ l.45: let y = a.value
97+
//│ ║ ^^^^^^^
98+
//│ ╟── Note: type parameter T is defined at:
99+
//│ ║ l.5: class Some[out T](value: T)
100+
//│ ╙── ^
101+
//│ 0
102+
//│ res
103+
//│ = 0
104+
//│ res
105+
//│ = 0
106+
//│ res
107+
//│ = 0
108+
109+
// FIXME: Precise scrutinee identification (hard)
110+
fun h2(a) =
111+
if
112+
a is Some(x) and x is x' and x' is Left(y) then y
113+
a is Some(y) and
114+
let y' = y
115+
y' is Right(z) then z
116+
a is None then 0
117+
//│ ╔══[ERROR] identifier not found: y
118+
//│ ║ l.114: let y' = y
119+
//│ ╙── ^
120+
//│ ╔══[ERROR] identifier not found: y
121+
//│ ║ l.114: let y' = y
122+
//│ ╙── ^
123+
//│ fun h2: forall 'leftValue. (None | Some[Left['leftValue] | ~Left[anything]]) -> (0 | error | 'leftValue)
124+
//│ Code generation encountered an error:
125+
//│ unresolved symbol y
126+
127+
// FIXME
128+
fun h3(x, y, f, p) =
129+
if x is
130+
_ and f(x) is y and p(x) then y
131+
None then y
132+
_ then "anyway"
133+
h3("anything", "not me", _ => "should be me", _ => true)
134+
h3(None, "should be me", _ => "not me", _ => false)
135+
h3("anything", "anything", _ => "not me", _ => false)
136+
//│ fun h3: forall 'a 'b. (None | 'a & ~#None, 'b, (None | 'a) -> anything, (None | 'a) -> anything,) -> ("anyway" | 'b)
137+
//│ "anything" | "anyway"
138+
//│ res
139+
//│ = [Function: h3]
140+
//│ res
141+
//│ = 'not me'
142+
//│ res
143+
//│ = 'should be me'
144+
145+
// FIXME
146+
fun h4(x, y, p) =
147+
if x is
148+
y and p(x) then y
149+
None then y
150+
_ then "default"
151+
h4("should be me", "not me", _ => true) // WRONG!
152+
h4(None, "not me", _ => true) // WRONG!
153+
h4(None, "should be me", _ => false)
154+
h4("anything", "not me", _ => false)
155+
//│ fun h4: forall 'a 'b. (None | 'a & ~#None, 'b, (None | 'a) -> anything,) -> ("default" | 'b)
156+
//│ "default" | "not me"
157+
//│ res
158+
//│ = [Function: h4]
159+
//│ res
160+
//│ = 'not me'
161+
//│ res
162+
//│ = 'not me'
163+
//│ res
164+
//│ = 'should be me'

shared/src/test/diff/ucs/Wildcard.mls

+26
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,29 @@ w6("42", "42")
235235
//│ = 0
236236
//│ res
237237
//│ = '42'
238+
239+
// FIXME
240+
// Should report warnings.
241+
fun w7(x, f) =
242+
if x is
243+
_ and f(x) is
244+
Some(v) then v
245+
None then x
246+
Left(x) then x + 1
247+
Right(x) then x + 2
248+
//│ fun w7: forall 'a 'value. (Left[int] | Right[int] | 'a & ~#Left & ~#Right, 'a -> (None | Some['value]),) -> (int | 'value | 'a)
249+
250+
// The results are wrong:
251+
w7(Left(99), _ => Some(0)) // => 0
252+
w7(Left(99), _ => None) // => Left(99)
253+
w7(Right(99), _ => Some(0)) // => 0
254+
w7(Right(99), _ => None) // => Right(99)
255+
//│ int
256+
//│ res
257+
//│ = 100
258+
//│ res
259+
//│ = 100
260+
//│ res
261+
//│ = 101
262+
//│ res
263+
//│ = 101

0 commit comments

Comments
 (0)