Skip to content

Commit 00d22fb

Browse files
authored
Merge pull request brownplt#1242 from brownplt/type-check-tests
Fixes brownplt#1233
2 parents 4d3ee4d + 163e577 commit 00d22fb

File tree

5 files changed

+147
-27
lines changed

5 files changed

+147
-27
lines changed

src/arr/compiler/type-check.arr

Lines changed: 105 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -472,18 +472,7 @@ fun _checking(e :: Expr, expect-type :: Type, top-level :: Boolean, context :: C
472472
end)
473473
else:
474474
shadow context = misc-collect-example(e, context)
475-
476-
synthesis(l, false, context).bind(lam(_, left-type, shadow context):
477-
cases(Option<Expr>) r:
478-
| some(shadow r) =>
479-
synthesis(r, false, context).bind(lam(_, right-type, shadow-context):
480-
shadow context = context.add-constraint(left-type, right-type)
481-
typing-result(e, expect-type, context)
482-
end)
483-
| none =>
484-
typing-result(e, expect-type, context)
485-
end
486-
end)
475+
synthesis-s-check-test(e, loc, op, refinement, l, r, context)
487476
end
488477
| s-check-expr(l, expr, ann) =>
489478
synthesis(expr, false, context) # XXX: this should probably use the annotation instead
@@ -748,21 +737,7 @@ fun _synthesis(e :: Expr, top-level :: Boolean, context :: Context) -> TypingRes
748737
end)
749738
else:
750739
shadow context = misc-collect-example(e, context)
751-
synthesis(l, false, context).bind(lam(_, left-type, shadow context):
752-
cases(Option<Expr>) r:
753-
| some(shadow r) =>
754-
synthesis(r, false, context).bind(lam(_, right-type, shadow-context):
755-
shadow context = context.add-constraint(left-type, right-type)
756-
result-type = new-existential(loc, false)
757-
shadow context = context.add-variable(result-type)
758-
typing-result(e, result-type, context)
759-
end)
760-
| none =>
761-
result-type = new-existential(loc, false)
762-
shadow context = context.add-variable(result-type)
763-
typing-result(e, result-type, context)
764-
end
765-
end)
740+
synthesis-s-check-test(e, loc, op, refinement, l, r, context)
766741
end
767742
| s-check-expr(l, expr, ann) =>
768743
synthesis(expr, false, context) # XXX: this should probably use the annotation instead
@@ -2366,6 +2341,109 @@ fun ignore-checker(l :: Loc, binds :: List<A.LetBind>, body :: Expr, blocky, con
23662341
handler(l, binds, body, context)
23672342
end
23682343
end
2344+
fun synthesis-s-check-test(e :: Expr, loc :: Loc, op :: A.CheckOp, refinement :: Option<Expr>, left :: Expr, right :: Option<Expr>, context :: Context) -> TypingResult:
2345+
fun create-result(shadow context :: Context) -> TypingResult:
2346+
result-type = new-existential(loc, false)
2347+
shadow context = context.add-variable(result-type)
2348+
typing-result(e, result-type, context)
2349+
end
2350+
2351+
fun synthesis-equivalent(l :: Loc) -> TypingResult:
2352+
cases(Option<Expr>) right:
2353+
| some(shadow right) =>
2354+
synthesis(left, false, context).bind(lam(_, left-type, shadow context):
2355+
synthesis(right, false, context).bind(lam(_, right-type, shadow context):
2356+
shadow context = context.add-constraint(left-type, right-type)
2357+
create-result(context)
2358+
end)
2359+
end)
2360+
| none =>
2361+
raise("Expected test to have a right hand side")
2362+
end
2363+
end
2364+
2365+
fun synthesis-refinement(l :: Loc) -> TypingResult:
2366+
cases(Option<Expr>) refinement:
2367+
| some(shadow refinement) =>
2368+
cases(Option<Expr>) right:
2369+
| some(shadow right) =>
2370+
synthesis(left, false, context).bind(lam(_, left-type, shadow context):
2371+
synthesis(right, false, context).bind(lam(_, right-type, shadow context):
2372+
synthesis(refinement, false, context).bind(lam(_, refinement-type, shadow context):
2373+
shadow context = context.add-constraint(refinement-type, t-arrow([list: left-type, right-type], t-boolean(loc), l, false))
2374+
create-result(context)
2375+
end)
2376+
end)
2377+
end)
2378+
| none =>
2379+
raise("Expected test to have a right hand side")
2380+
end
2381+
| none =>
2382+
synthesis-equivalent(l)
2383+
end
2384+
end
2385+
2386+
fun synthesis-predicate(l :: Loc) -> TypingResult:
2387+
cases(Option<Expr>) right:
2388+
| some(shadow right) =>
2389+
synthesis(left, false, context).bind(lam(_, left-type, shadow context):
2390+
synthesis(right, false, context).bind(lam(_, pred-type, shadow context):
2391+
shadow context = context.add-constraint(pred-type, t-arrow([list: left-type], t-boolean(loc), l, false))
2392+
create-result(context)
2393+
end)
2394+
end)
2395+
| none =>
2396+
raise("Expected test to have a right hand side")
2397+
end
2398+
end
2399+
2400+
fun synthesis-string(l :: Loc) -> TypingResult:
2401+
cases(Option<Expr>) right:
2402+
| some(shadow right) =>
2403+
synthesis(left, false, context).bind(lam(_, left-type, shadow context):
2404+
checking(right, t-string(loc), false, context).bind(lam(_, _, shadow context):
2405+
create-result(context)
2406+
end)
2407+
end)
2408+
| none =>
2409+
raise("Expected test to have a right hand side")
2410+
end
2411+
end
2412+
2413+
fun synthesis-exception(l :: Loc) -> TypingResult:
2414+
cases(Option<Expr>) right:
2415+
| some(shadow right) =>
2416+
synthesis(left, false, context).bind(lam(_, left-type, shadow context):
2417+
synthesis(right, false, context).bind(lam(_, pred-type, shadow context):
2418+
shadow context = context.add-constraint(pred-type, t-arrow([list: t-top(l, false)], t-boolean(loc), l, false))
2419+
create-result(context)
2420+
end)
2421+
end)
2422+
| none =>
2423+
raise("Expected test to have a right hand side")
2424+
end
2425+
end
2426+
2427+
cases(A.CheckOp) op:
2428+
| s-op-is(l) => synthesis-refinement(l)
2429+
| s-op-is-roughly(l) => synthesis-equivalent(l)
2430+
| s-op-is-op(l, _) => synthesis-equivalent(l)
2431+
| s-op-is-not(l) => synthesis-refinement(l)
2432+
| s-op-is-not-op(l, _) => synthesis-equivalent(l)
2433+
| s-op-satisfies(l) => synthesis-predicate(l)
2434+
| s-op-satisfies-not(l) => synthesis-predicate(l)
2435+
| s-op-raises(l) => synthesis-string(l)
2436+
| s-op-raises-other(l) => synthesis-string(l)
2437+
| s-op-raises-not(l) =>
2438+
synthesis(left, false, context).bind(lam(_, left-type, shadow context):
2439+
create-result(context)
2440+
end)
2441+
| s-op-raises-satisfies(l) =>
2442+
synthesis-exception(l)
2443+
| s-op-raises-violates(l) =>
2444+
synthesis-exception(l)
2445+
end
2446+
end
23692447

23702448
################### Test Inference ####################
23712449

tests/type-check/bad/test-is.arr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun func() -> Number:
2+
0
3+
where:
4+
func() is false
5+
end

tests/type-check/bad/test-raises.arr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun func() -> Number:
2+
0
3+
where:
4+
func() raises 1
5+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun func() -> Number:
2+
0
3+
where:
4+
func() is%({(x :: Number): false}) 0
5+
end

tests/type-check/good/tests.arr

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import is-invalid-array-index from error
2+
3+
fun func() -> Number: 0
4+
where:
5+
fun pred-fun(a :: Number, b :: Number):
6+
a == 4
7+
end
8+
9+
func() is 0
10+
func() is-roughly 0.0000000000001
11+
func() is-not 10
12+
func() is%(pred-fun) 4
13+
func() is-not%(pred-fun) 5
14+
func() is== 0
15+
func() is-not== 5
16+
func() is=~ 0
17+
func() is-not=~ 5
18+
func() is<=> 0
19+
func() is-not<=> 5
20+
func() satisfies {(x): true}
21+
func() violates {(x): false}
22+
1 / 0 raises "zero"
23+
1 / 0 raises-other-than "field"
24+
func() does-not-raise
25+
raw-array-get([raw-array: 1, 2], 4) raises-satisfies is-invalid-array-index
26+
1 / 0 raises-violates is-invalid-array-index
27+
end

0 commit comments

Comments
 (0)