-
Notifications
You must be signed in to change notification settings - Fork 11
/
TypeCheckerTests.swift
239 lines (192 loc) · 7.16 KB
/
TypeCheckerTests.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
import XCTest
import SwiftcTest
class TypeCheckerTests: XCTestCase {
func testClosureExpr() throws {
let s = try Parser(source: """
{ (x: Int) in
x
}
"""
).parse()
let cl1 = try XCTCast(XCTArrayGet(s.statements, 0), ClosureExpr.self)
let _ = try XCTCast(XCTArrayGet(cl1.body, 0), UnresolvedDeclRefExpr.self)
let tc = TypeChecker(source: s)
try tc.typeCheck()
let cl2 = try XCTCast(XCTArrayGet(s.statements, 0), ClosureExpr.self)
let vd = cl2.parameter
let dr = try XCTCast(XCTArrayGet(cl2.body, 0), DeclRefExpr.self)
XCTAssertTrue(dr.target === vd)
}
func testClosureExprError() throws {
let s = try Parser(source: """
{ (x) in
x
}
"""
).parse()
let tc = TypeChecker(source: s)
XCTAssertThrowsError(try tc.typeCheck())
}
func testFunctionApplication() throws {
let s = try Parser(source: """
func f(a: Int) -> String { }
f(3)
"""
).parse()
let ca1 = try XCTCast(XCTArrayGet(s.statements, 1), CallExpr.self)
XCTAssertNil(ca1.type)
let tc = TypeChecker(source: s)
try tc.typeCheck()
let ca2 = try XCTCast(XCTArrayGet(s.statements, 1), CallExpr.self)
XCTAssertEqual(ca2.type, PrimitiveType.string)
}
func testClosureArgInfer() throws {
let code = """
{ (x) -> Int in 4 }(3)
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let ap = try XCTCast(XCTArrayGet(s.statements, 0), CallExpr.self)
XCTAssertEqual(ap.type, PrimitiveType.int)
let cl = try XCTCast(ap.callee, ClosureExpr.self)
XCTAssertEqual(cl.type, FunctionType(parameter: PrimitiveType.int, result: PrimitiveType.int))
XCTAssertEqual(cl.parameter.type, PrimitiveType.int)
let ag = try XCTCast(ap.argument, IntegerLiteralExpr.self)
XCTAssertEqual(ag.type, PrimitiveType.int)
}
func testClosureReturnInfer() throws {
let code = """
{ (x) in x }(3)
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let ap = try XCTCast(XCTArrayGet(s.statements, 0), CallExpr.self)
XCTAssertEqual(ap.type, PrimitiveType.int)
let cl = try XCTCast(ap.callee, ClosureExpr.self)
XCTAssertEqual(cl.type, FunctionType(parameter: PrimitiveType.int, result: PrimitiveType.int))
XCTAssertEqual(cl.parameter.type, PrimitiveType.int)
let ag = try XCTCast(ap.argument, IntegerLiteralExpr.self)
XCTAssertEqual(ag.type, PrimitiveType.int)
}
func testOverload() throws {
let code = """
func f(_ a: Int) { }
func f(_ a: String) { }
f(3)
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
}
func testAssignNoType() throws {
let code = """
let a = 3
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let vd = try XCTCast(XCTArrayGet(s.statements, 0), VariableDecl.self)
XCTAssertEqual(vd.type, PrimitiveType.int)
}
func testAssignInt() throws {
let code = """
let a: Int = 3
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let vd = try XCTCast(XCTArrayGet(s.statements, 0), VariableDecl.self)
XCTAssertEqual(vd.type, PrimitiveType.int)
}
func testAssignError() throws {
let code = """
let a: String = 3
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
XCTAssertThrowsError(try tc.typeCheck())
}
func testArgConv() throws {
// it does not generate conv typevar inference
let s = try Parser(source: """
func f(a: Int?) { }
f(3)
"""
).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let call = try XCTCast(XCTArrayGet(s.statements, 1), CallExpr.self)
_ = try XCTCast(call.argument, InjectIntoOptionalExpr.self)
}
func testClosureConvBodyReturn() throws {
let code = """
{ (x: Int) -> Int? in 4 }
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let clr = try XCTCast(XCTArrayGet(s.statements, 0), ClosureExpr.self)
_ = try XCTCast(XCTArrayGet(clr.body, 0), InjectIntoOptionalExpr.self)
}
// [TODO] enable this. need coercion between functions. ses CSApply
func _testClosureConvBodyNoReturnSig() throws {
let code = """
func f(_ g: (Int) -> Int?) { }
f({ (x: Int) in 4 })
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
// There are 2 solutions theoretically.
// [0] closure: (Int) -> Int
// [1] closure: (Int) -> Int?
// Current implementation find only [1] solution.
// So it test application of VtoO _inside_ of closure
let call = try XCTCast(XCTArrayGet(s.statements, 1), CallExpr.self)
let clr = try XCTCast(call.argument, ClosureExpr.self)
_ = try XCTCast(XCTArrayGet(clr.body, 0), InjectIntoOptionalExpr.self)
}
func testAssignConv() throws {
let code = """
let a: Int? = 3
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let vd = try XCTCast(XCTArrayGet(s.statements, 0), VariableDecl.self)
_ = try XCTCast(XCTUnwrap(vd.initializer), InjectIntoOptionalExpr.self)
}
func testAssignOptionalOptionalConv() throws {
let code = """
let a: Int?? = 3
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let vd = try XCTCast(XCTArrayGet(s.statements, 0), VariableDecl.self)
let initializer = try XCTCast(XCTUnwrap(vd.initializer), InjectIntoOptionalExpr.self)
_ = try XCTCast(initializer.subExpr, InjectIntoOptionalExpr.self)
}
func testArgConvAssignConvInfer() throws {
let code = """
let a: Int? = { (x) in x }(3)
"""
let s = try Parser(source: code).parse()
let tc = TypeChecker(source: s)
try tc.typeCheck()
let vd = try XCTCast(XCTArrayGet(s.statements, 0), VariableDecl.self)
// Actually there are multiple solutions
// 1. (Int) -> Int
// 2. (Int) -> Int?
// 3. (Int?) -> Int?
// but current implementation does not have stable logic.
let iio = try XCTCast(XCTUnwrap(vd.initializer), InjectIntoOptionalExpr.self)
let call = try XCTCast(iio.subExpr, CallExpr.self)
let clr = try XCTCast(call.callee, ClosureExpr.self)
XCTAssertEqual(try clr.typeOrThrow(),
FunctionType(parameter: PrimitiveType.int,
result: PrimitiveType.int))
}
}