Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/tests/NonstrictMode.test.cpp
2723 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/Scope.h"
3
#include "Luau/TypeInfer.h"
4
#include "Luau/Type.h"
5
6
#include "Fixture.h"
7
8
#include "ScopedFlags.h"
9
#include "doctest.h"
10
11
#include <algorithm>
12
13
using namespace Luau;
14
15
16
LUAU_FASTFLAG(DebugLuauMagicTypes)
17
LUAU_FASTFLAG(DebugLuauForceOldSolver)
18
19
TEST_SUITE_BEGIN("NonstrictModeTests");
20
21
TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
22
{
23
DOES_NOT_PASS_NEW_SOLVER_GUARD();
24
CheckResult result = check(R"(
25
--!nonstrict
26
function foo(x, y) end
27
)");
28
29
TypeId fooType = requireType("foo");
30
REQUIRE(fooType);
31
32
const FunctionType* ftv = get<FunctionType>(fooType);
33
REQUIRE_MESSAGE(ftv != nullptr, "Expected a function, got " << toString(fooType));
34
35
auto args = flatten(ftv->argTypes).first;
36
REQUIRE_EQ(2, args.size());
37
REQUIRE_EQ("any", toString(args[0]));
38
REQUIRE_EQ("any", toString(args[1]));
39
40
auto rets = flatten(ftv->retTypes).first;
41
REQUIRE_EQ(0, rets.size());
42
}
43
44
TEST_CASE_FIXTURE(Fixture, "infer_the_maximum_number_of_values_the_function_could_return")
45
{
46
DOES_NOT_PASS_NEW_SOLVER_GUARD();
47
CheckResult result = check(R"(
48
--!nonstrict
49
function getMinCardCountForWidth(width)
50
if width < 513 then
51
return 3
52
else
53
return 8, 'jellybeans'
54
end
55
end
56
)");
57
58
TypeId t = requireType("getMinCardCountForWidth");
59
REQUIRE(t);
60
61
REQUIRE_EQ("(any) -> (...any)", toString(t));
62
}
63
64
TEST_CASE_FIXTURE(Fixture, "return_annotation_is_still_checked")
65
{
66
CheckResult result = check(R"(
67
function foo(x): number return 'hello' end
68
)");
69
70
LUAU_REQUIRE_ERROR_COUNT(1, result);
71
72
CHECK("any" != toString(requireType("foo")));
73
}
74
75
TEST_CASE_FIXTURE(Fixture, "function_parameters_are_any")
76
{
77
CheckResult result = check(R"(
78
--!nonstrict
79
function f(arg)
80
arg = 9
81
arg:concat(4)
82
end
83
)");
84
85
LUAU_REQUIRE_NO_ERRORS(result);
86
}
87
88
TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok")
89
{
90
CheckResult result = check(R"(
91
--!nonstrict
92
function f()
93
if 1 then
94
return 4
95
else
96
return 'hello'
97
end
98
return 'one', 'two'
99
end
100
)");
101
102
LUAU_REQUIRE_NO_ERRORS(result);
103
}
104
105
TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default")
106
{
107
DOES_NOT_PASS_NEW_SOLVER_GUARD();
108
CheckResult result = check(R"(
109
--!nonstrict
110
local m = 55
111
)");
112
113
LUAU_REQUIRE_NO_ERRORS(result);
114
115
CHECK("any" == toString(requireType("m")));
116
}
117
118
TEST_CASE_FIXTURE(Fixture, "parameters_having_type_any_are_optional")
119
{
120
CheckResult result = check(R"(
121
--!nonstrict
122
local function f(a, b)
123
return a
124
end
125
126
f(5)
127
)");
128
129
LUAU_REQUIRE_NO_ERRORS(result);
130
}
131
132
TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
133
{
134
DOES_NOT_PASS_NEW_SOLVER_GUARD();
135
CheckResult result = check(R"(
136
--!nonstrict
137
local T = {}
138
function T:method() end
139
function T.staticmethod() end
140
141
T.method()
142
T:staticmethod()
143
)");
144
145
LUAU_REQUIRE_ERROR_COUNT(1, result);
146
147
CHECK_EQ("This function does not take self. Did you mean to use a dot instead of a colon?", toString(result.errors[0]));
148
}
149
150
TEST_CASE_FIXTURE(Fixture, "offer_a_hint_if_you_use_a_dot_instead_of_a_colon")
151
{
152
DOES_NOT_PASS_NEW_SOLVER_GUARD();
153
CheckResult result = check(R"(
154
--!nonstrict
155
local T = {}
156
function T:method(x: number) end
157
T.method(5)
158
)");
159
160
LUAU_REQUIRE_ERROR_COUNT(1, result);
161
162
CHECK_EQ("This function must be called with self. Did you mean to use a colon instead of a dot?", toString(result.errors[0]));
163
}
164
165
TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
166
{
167
DOES_NOT_PASS_NEW_SOLVER_GUARD();
168
CheckResult result = check(R"(
169
--!nonstrict
170
local T = {}
171
T.foo = 55
172
)");
173
174
LUAU_REQUIRE_NO_ERRORS(result);
175
176
TableType* ttv = getMutable<TableType>(requireType("T"));
177
178
REQUIRE(ttv != nullptr);
179
180
REQUIRE(ttv->props.count("foo"));
181
TypeId fooProp = ttv->props["foo"].type_DEPRECATED();
182
REQUIRE(fooProp != nullptr);
183
184
CHECK("any" == toString(fooProp));
185
}
186
187
TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
188
{
189
DOES_NOT_PASS_NEW_SOLVER_GUARD();
190
CheckResult result = check(R"(
191
--!nonstrict
192
local T = {
193
one = 1,
194
two = 'two',
195
three = function() return 3 end
196
}
197
)");
198
199
LUAU_REQUIRE_NO_ERRORS(result);
200
201
TableType* ttv = getMutable<TableType>(requireType("T"));
202
REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(requireType("T")));
203
204
CHECK("any" == toString(ttv->props["one"].type_DEPRECATED()));
205
CHECK("any" == toString(ttv->props["two"].type_DEPRECATED()));
206
CHECK_MESSAGE(
207
get<FunctionType>(follow(ttv->props["three"].type_DEPRECATED())), "Should be a function: " << *ttv->props["three"].type_DEPRECATED()
208
);
209
}
210
211
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any")
212
{
213
CheckResult result = check(R"(
214
--!nonstrict
215
function requires_a_table(arg: {}) end
216
function requires_a_number(arg: number) end
217
218
local T = {}
219
for a, b in pairs(T) do
220
requires_a_table(a)
221
requires_a_table(b)
222
requires_a_number(a)
223
requires_a_number(b)
224
end
225
)");
226
227
LUAU_REQUIRE_NO_ERRORS(result);
228
}
229
230
TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls")
231
{
232
CheckResult result = check(R"(
233
--!nonstrict
234
function populateListFromIds(list, normalizedData)
235
local newList = {}
236
237
for _, value in ipairs(list) do
238
if type(value) == "table" then
239
table.insert(newList, populateListFromIds(value, normalizedData))
240
else
241
table.insert(newList, normalizedData[value])
242
end
243
end
244
245
return newList
246
end
247
)");
248
249
LUAU_REQUIRE_NO_ERRORS(result);
250
}
251
252
TEST_CASE_FIXTURE(Fixture, "delay_function_does_not_require_its_argument_to_return_anything")
253
{
254
CheckResult result = check(R"(
255
--!nonstrict
256
257
function delay(ms: number?, cb: () -> ()): () end
258
259
delay(50, function() end)
260
)");
261
262
LUAU_REQUIRE_NO_ERRORS(result);
263
}
264
265
TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
266
{
267
DOES_NOT_PASS_NEW_SOLVER_GUARD();
268
CheckResult result = check(R"(
269
--!nonstrict
270
271
local FFlag: any
272
273
if FFlag.get('SomeFlag') then
274
return {foo='bar'}
275
else
276
return function(prop)
277
return 'bar'
278
end
279
end
280
)");
281
282
LUAU_REQUIRE_NO_ERRORS(result);
283
284
REQUIRE_EQ("any", toString(getMainModule()->returnType));
285
}
286
287
TEST_CASE_FIXTURE(Fixture, "returning_insufficient_return_values")
288
{
289
CheckResult result = check(R"(
290
--!nonstrict
291
292
function foo(): (boolean, string?)
293
if true then
294
return true, "hello"
295
else
296
return false
297
end
298
end
299
)");
300
301
LUAU_REQUIRE_NO_ERRORS(result);
302
}
303
304
TEST_CASE_FIXTURE(Fixture, "returning_too_many_values")
305
{
306
CheckResult result = check(R"(
307
--!nonstrict
308
309
function foo(): boolean
310
if true then
311
return true, "hello"
312
else
313
return false
314
end
315
end
316
)");
317
318
LUAU_REQUIRE_NO_ERRORS(result);
319
}
320
321
TEST_CASE_FIXTURE(Fixture, "standalone_constraint_solving_incomplete_is_hidden_nonstrict")
322
{
323
ScopedFastFlag sffs[] = {
324
{FFlag::DebugLuauForceOldSolver, false},
325
{FFlag::DebugLuauMagicTypes, true},
326
// This debug flag is normally on, but we turn it off as we're testing
327
// the exact behavior it enables.
328
{FFlag::DebugLuauAlwaysShowConstraintSolvingIncomplete, false},
329
};
330
331
CheckResult results = check(R"(
332
--!nonstrict
333
local function _f(_x: _luau_force_constraint_solving_incomplete) end
334
)");
335
336
LUAU_REQUIRE_NO_ERRORS(results);
337
}
338
339
TEST_CASE_FIXTURE(BuiltinsFixture, "non_standalone_constraint_solving_incomplete_is_hidden_nonstrict")
340
{
341
ScopedFastFlag sffs[] = {
342
{FFlag::DebugLuauForceOldSolver, false},
343
{FFlag::DebugLuauMagicTypes, true},
344
};
345
346
CheckResult results = check(R"(
347
--!nonstrict
348
local function _f(_x: _luau_force_constraint_solving_incomplete) end
349
math.abs("pls")
350
)");
351
352
LUAU_REQUIRE_ERROR_COUNT(2, results);
353
CHECK(get<CheckedFunctionCallError>(results.errors[0]));
354
CHECK(get<ConstraintSolvingIncompleteError>(results.errors[1]));
355
}
356
357
TEST_SUITE_END();
358
359