Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/include/Luau/Frontend.h
2727 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#pragma once
3
4
#include "Luau/Config.h"
5
#include "Luau/ConfigResolver.h"
6
#include "Luau/GlobalTypes.h"
7
#include "Luau/Module.h"
8
#include "Luau/ModuleResolver.h"
9
#include "Luau/RequireTracer.h"
10
#include "Luau/Scope.h"
11
#include "Luau/Set.h"
12
#include "Luau/TypeCheckLimits.h"
13
14
#include <mutex>
15
#include <string>
16
#include <vector>
17
#include <optional>
18
19
namespace Luau
20
{
21
22
class AstStat;
23
class ParseError;
24
struct Frontend;
25
struct TypeError;
26
struct LintWarning;
27
struct GlobalTypes;
28
struct TypeChecker;
29
struct FileResolver;
30
struct ModuleResolver;
31
struct ParseResult;
32
struct HotComment;
33
struct BuildQueueItem;
34
struct BuildQueueWorkState;
35
struct FrontendCancellationToken;
36
37
struct LoadDefinitionFileResult
38
{
39
bool success;
40
ParseResult parseResult;
41
SourceModule sourceModule;
42
ModulePtr module;
43
};
44
45
std::optional<Mode> parseMode(const std::vector<HotComment>& hotcomments);
46
47
struct SourceNode
48
{
49
bool hasDirtySourceModule() const
50
{
51
return dirtySourceModule;
52
}
53
54
bool hasDirtyModule(bool forAutocomplete) const
55
{
56
return forAutocomplete ? dirtyModuleForAutocomplete : dirtyModule;
57
}
58
59
bool hasInvalidModuleDependency(bool forAutocomplete) const
60
{
61
return forAutocomplete ? invalidModuleDependencyForAutocomplete : invalidModuleDependency;
62
}
63
64
void setInvalidModuleDependency(bool value, bool forAutocomplete)
65
{
66
if (forAutocomplete)
67
invalidModuleDependencyForAutocomplete = value;
68
else
69
invalidModuleDependency = value;
70
}
71
72
ModuleName name;
73
std::string humanReadableName;
74
DenseHashSet<ModuleName> requireSet{{}};
75
std::vector<std::pair<ModuleName, Location>> requireLocations;
76
Set<ModuleName> dependents{{}};
77
78
bool dirtySourceModule = true;
79
bool dirtyModule = true;
80
bool dirtyModuleForAutocomplete = true;
81
82
bool invalidModuleDependency = true;
83
bool invalidModuleDependencyForAutocomplete = true;
84
85
double autocompleteLimitsMult = 1.0;
86
};
87
88
struct FrontendOptions
89
{
90
// When true, we retain full type information about every term in the AST.
91
// Setting this to false cuts back on RAM and is a good idea for batch
92
// jobs where the type graph is not deeply inspected after typechecking
93
// is complete.
94
bool retainFullTypeGraphs = false;
95
96
// Run typechecking only in mode required for autocomplete (strict mode in
97
// order to get more precise type information)
98
bool forAutocomplete = false;
99
100
bool runLintChecks = false;
101
102
// If not empty, randomly shuffle the constraint set before attempting to
103
// solve. Use this value to seed the random number generator.
104
std::optional<unsigned> randomizeConstraintResolutionSeed;
105
106
std::optional<LintOptions> enabledLintWarnings;
107
108
std::shared_ptr<FrontendCancellationToken> cancellationToken;
109
110
// Time limit for typechecking a single module
111
std::optional<double> moduleTimeLimitSec;
112
113
// When true, some internal complexity limits will be scaled down for modules that miss the limit set by moduleTimeLimitSec
114
bool applyInternalLimitScaling = false;
115
116
// An optional callback which is called for every *dirty* module was checked
117
// If multi-threaded typechecking is used, this callback might be called
118
// from multiple threads and has to be thread-safe
119
std::function<void(const SourceModule& sourceModule, const Luau::Module& module)> customModuleCheck;
120
121
bool collectTypeAllocationStats = false;
122
};
123
124
struct CheckResult
125
{
126
std::vector<TypeError> errors;
127
128
LintResult lintResult;
129
130
std::vector<ModuleName> timeoutHits;
131
};
132
133
struct FrontendModuleResolver : ModuleResolver
134
{
135
FrontendModuleResolver(Frontend* frontend);
136
137
const ModulePtr getModule(const ModuleName& moduleName) const override;
138
bool moduleExists(const ModuleName& moduleName) const override;
139
std::optional<ModuleInfo> resolveModuleInfo(const ModuleName& currentModuleName, const AstExpr& pathExpr) override;
140
std::string getHumanReadableModuleName(const ModuleName& moduleName) const override;
141
142
bool setModule(const ModuleName& moduleName, ModulePtr module);
143
void clearModules();
144
145
146
private:
147
Frontend* frontend;
148
149
mutable std::mutex moduleMutex;
150
std::unordered_map<ModuleName, ModulePtr> modules;
151
};
152
153
struct Frontend
154
{
155
struct Stats
156
{
157
size_t files = 0;
158
size_t lines = 0;
159
160
size_t filesStrict = 0;
161
size_t filesNonstrict = 0;
162
163
size_t typesAllocated = 0;
164
size_t typePacksAllocated = 0;
165
166
size_t boolSingletonsMinted = 0;
167
size_t strSingletonsMinted = 0;
168
size_t uniqueStrSingletonsMinted = 0;
169
170
double timeRead = 0;
171
double timeParse = 0;
172
double timeCheck = 0;
173
double timeLint = 0;
174
175
size_t dynamicConstraintsCreated = 0;
176
};
177
Frontend(SolverMode mode, FileResolver* fileResolver, ConfigResolver* configResolver, FrontendOptions options = {});
178
Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {});
179
180
void setLuauSolverMode(SolverMode mode);
181
SolverMode getLuauSolverMode() const;
182
// The default value assuming there is no workspace setup yet
183
std::atomic<SolverMode> useNewLuauSolver;
184
// Parse module graph and prepare SourceNode/SourceModule data, including required dependencies without running typechecking
185
void parse(const ModuleName& name);
186
void parseModules(const std::vector<ModuleName>& name);
187
188
// Parse and typecheck module graph
189
CheckResult check(const ModuleName& name, std::optional<FrontendOptions> optionOverride = {}); // new shininess
190
191
bool allModuleDependenciesValid(const ModuleName& name, bool forAutocomplete = false) const;
192
193
bool isDirty(const ModuleName& name, bool forAutocomplete = false) const;
194
void markDirty(const ModuleName& name, std::vector<ModuleName>* markedDirty = nullptr);
195
196
void traverseDependents(const ModuleName& name, std::function<bool(SourceNode&)> processSubtree);
197
198
/** Borrow a pointer into the SourceModule cache.
199
*
200
* Returns nullptr if we don't have it. This could mean that the script
201
* doesn't exist, or simply that its contents have changed since the previous
202
* check, in which case we do not have its AST.
203
*
204
* IMPORTANT: this pointer is only valid until the next call to markDirty. Do not retain it.
205
*/
206
SourceModule* getSourceModule(const ModuleName& name);
207
const SourceModule* getSourceModule(const ModuleName& name) const;
208
209
void clearStats();
210
void clear();
211
void clearBuiltinEnvironments();
212
213
ScopePtr addEnvironment(const std::string& environmentName);
214
ScopePtr getEnvironmentScope(const std::string& environmentName) const;
215
216
void registerBuiltinDefinition(const std::string& name, std::function<void(Frontend&, GlobalTypes&, ScopePtr)>);
217
void applyBuiltinDefinitionToEnvironment(const std::string& environmentName, const std::string& definitionName);
218
219
LoadDefinitionFileResult loadDefinitionFile(
220
GlobalTypes& globals,
221
ScopePtr targetScope,
222
std::string_view source,
223
const std::string& packageName,
224
bool captureComments,
225
bool typeCheckForAutocomplete = false
226
);
227
228
// Batch module checking. Queue modules and check them together, retrieve results with 'getCheckResult'
229
// If provided, 'executeTasks' function is allowed to call any item in 'tasks' on any thread and return without waiting for them to complete
230
void queueModuleCheck(const std::vector<ModuleName>& names);
231
void queueModuleCheck(const ModuleName& name);
232
std::vector<ModuleName> checkQueuedModules(
233
std::optional<FrontendOptions> optionOverride = {},
234
std::function<void(std::vector<std::function<void()>> tasks)> executeTasks = {},
235
std::function<bool(size_t done, size_t total)> progress = {}
236
);
237
238
std::optional<CheckResult> getCheckResult(const ModuleName& name, bool accumulateNested, bool forAutocomplete = false);
239
std::vector<ModuleName> getRequiredScripts(const ModuleName& name, const TypeCheckLimits& limits);
240
241
TypeId parseType(
242
NotNull<Allocator> allocator,
243
NotNull<AstNameTable> nameTable,
244
NotNull<InternalErrorReporter> iceHandler,
245
TypeCheckLimits limits,
246
NotNull<TypeArena> arena,
247
std::string_view source
248
);
249
250
private:
251
ModulePtr check(
252
const SourceModule& sourceModule,
253
Mode mode,
254
std::vector<RequireCycle> requireCycles,
255
std::optional<ScopePtr> environmentScope,
256
bool forAutocomplete,
257
bool recordJsonLog,
258
Frontend::Stats& stats,
259
TypeCheckLimits typeCheckLimits
260
);
261
262
std::pair<SourceNode*, SourceModule*> getSourceNode(const ModuleName& name, const TypeCheckLimits& limits);
263
SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions);
264
265
bool parseGraph(
266
std::vector<ModuleName>& buildQueue,
267
const ModuleName& root,
268
const TypeCheckLimits& limits,
269
bool forAutocomplete,
270
std::function<bool(const ModuleName&)> canSkip = {}
271
);
272
273
void addBuildQueueItems(
274
std::vector<BuildQueueItem>& items,
275
std::vector<ModuleName>& buildQueue,
276
bool cycleDetected,
277
DenseHashSet<Luau::ModuleName>& seen,
278
const FrontendOptions& frontendOptions
279
);
280
void checkBuildQueueItem(BuildQueueItem& item);
281
void checkBuildQueueItems(std::vector<BuildQueueItem>& items);
282
void recordItemResult(const BuildQueueItem& item);
283
void performQueueItemTask(std::shared_ptr<BuildQueueWorkState> state, size_t itemPos);
284
void sendQueueItemTasks(std::shared_ptr<BuildQueueWorkState> state, const std::vector<size_t>& items);
285
void sendQueueCycleItemTask(std::shared_ptr<BuildQueueWorkState> state);
286
287
static LintResult classifyLints(const std::vector<LintWarning>& warnings, const Config& config);
288
289
ScopePtr getModuleEnvironment(const SourceModule& module, const Config& config, bool forAutocomplete) const;
290
std::unordered_map<std::string, ScopePtr> environments;
291
std::unordered_map<std::string, std::function<void(Frontend&, GlobalTypes&, ScopePtr)>> builtinDefinitions;
292
293
BuiltinTypes builtinTypes_;
294
295
public:
296
const NotNull<BuiltinTypes> builtinTypes;
297
298
FileResolver* fileResolver;
299
300
FrontendModuleResolver moduleResolver;
301
FrontendModuleResolver moduleResolverForAutocomplete;
302
303
GlobalTypes globals;
304
GlobalTypes globalsForAutocomplete;
305
306
ConfigResolver* configResolver;
307
FrontendOptions options;
308
InternalErrorReporter iceHandler;
309
std::function<void(const ModuleName& name, const ScopePtr& scope, bool forAutocomplete)> prepareModuleScope;
310
std::function<void(const ModuleName& name, std::string log)> writeJsonLog = {};
311
312
std::unordered_map<ModuleName, std::shared_ptr<SourceNode>> sourceNodes;
313
std::unordered_map<ModuleName, std::shared_ptr<SourceModule>> sourceModules;
314
std::unordered_map<ModuleName, RequireTraceResult> requireTrace;
315
316
Stats stats = {};
317
318
std::vector<ModuleName> moduleQueue;
319
};
320
321
ModulePtr check(
322
const SourceModule& sourceModule,
323
Mode mode,
324
const std::vector<RequireCycle>& requireCycles,
325
NotNull<BuiltinTypes> builtinTypes,
326
NotNull<InternalErrorReporter> iceHandler,
327
NotNull<ModuleResolver> moduleResolver,
328
NotNull<FileResolver> fileResolver,
329
const ScopePtr& globalScope,
330
const ScopePtr& typeFunctionScope,
331
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
332
FrontendOptions options,
333
TypeCheckLimits limits
334
);
335
336
ModulePtr check(
337
const SourceModule& sourceModule,
338
Mode mode,
339
const std::vector<RequireCycle>& requireCycles,
340
NotNull<BuiltinTypes> builtinTypes,
341
NotNull<InternalErrorReporter> iceHandler,
342
NotNull<ModuleResolver> moduleResolver,
343
NotNull<FileResolver> fileResolver,
344
const ScopePtr& parentScope,
345
const ScopePtr& typeFunctionScope,
346
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
347
FrontendOptions options,
348
TypeCheckLimits limits,
349
bool recordJsonLog,
350
Frontend::Stats& stats,
351
std::function<void(const ModuleName&, std::string)> writeJsonLog
352
);
353
354
} // namespace Luau
355
356