Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/include/Luau/OverloadResolution.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/Ast.h"
5
#include "Luau/Error.h"
6
#include "Luau/InsertionOrderedMap.h"
7
#include "Luau/Location.h"
8
#include "Luau/NotNull.h"
9
#include "Luau/Subtyping.h"
10
#include "Luau/TypeFwd.h"
11
12
namespace Luau
13
{
14
15
struct BuiltinTypes;
16
struct TypeArena;
17
struct Scope;
18
struct InternalErrorReporter;
19
struct TypeCheckLimits;
20
struct Subtyping;
21
22
class Normalizer;
23
24
// There are essentially two reasons why we might consider an overload
25
// to be unsuitable:
26
//
27
// First, subtyping might fail. This also includes cases where we
28
// cannot find a generic substitution scheme that results in a
29
// callable function.
30
//
31
// Second, subtyping might succeed, but it might result in the
32
// presence of an unreducible type function. (eg add<string, string>)
33
//
34
// TODO: Subtyping should probably also be the thing that checks for
35
// unreducible type functions. This would be nice because it would
36
// mean that overload resolution would not have to talk about type
37
// functions at all.
38
using IncompatibilityReason = Variant<SubtypingReasonings, ErrorVec>;
39
40
/**
41
* Struct representing "selecting" an overload from `OverloadResolution::resolveOverload`.
42
*/
43
struct SelectedOverload
44
{
45
/**
46
* An unambiguous overload, if one can be selected. This is _not_ necessarily
47
* an overload that is valid for the argument pack provided. For example:
48
*
49
* local f: ((string) -> "one") & ((string, string) -> "two")
50
*
51
* -- We will select `(string) -> "one"` here based on arity. Type checking
52
* -- will later inform us that `42` is not a string, but that's ok.
53
* f(42)
54
*/
55
std::optional<TypeId> overload;
56
57
/**
58
* Any associated constraints with selecting this overload. For example, in
59
* the code block:
60
*
61
* local f: ((string, number) -> string) & ((number, boolean) -> number)
62
* local function g(x)
63
* -- When selecting an overload at this point, we'll reject the
64
* -- second overload, and claim that this is the only possible
65
* -- overload with a constraint of `x <: string`.
66
* f(x, 42)
67
* end
68
*/
69
std::vector<ConstraintV> assumedConstraints;
70
71
/**
72
* Whether we should potentially defer selecting an overload, such as in:
73
*
74
* local f: ((string) -> string) & ((number) -> number)
75
* local function g(x)
76
* -- There *may* be another constraint on `x` later that allows us to
77
* -- unambiguously select an overload.
78
* f(x)
79
* end
80
*/
81
bool shouldRetry;
82
};
83
84
struct OverloadResolution
85
{
86
// Overloads that will work
87
std::vector<TypeId> ok;
88
89
// "Overloads" that aren't callable.
90
std::vector<TypeId> nonFunctions;
91
92
// Overloads that could match, but require that other constraints also be satisfied.
93
std::vector<std::pair<TypeId, std::vector<ConstraintV>>> potentialOverloads;
94
95
// Overloads that have the correct arity, but do not work.
96
std::vector<std::pair<TypeId, IncompatibilityReason>> incompatibleOverloads;
97
98
// Overloads that will never work specifically because of an arity mismatch.
99
std::vector<TypeId> arityMismatches;
100
101
// If a particular overload is a __call metamethod, then type inference
102
// needs to know so that it can prepend the self argument to the argument
103
// list when it infers.
104
DenseHashSet<TypeId> metamethods{nullptr};
105
106
/**
107
* Try to determine an unambiguous overload. See `SelectedOverload` for
108
* documentation.
109
*/
110
SelectedOverload getUnambiguousOverload() const;
111
};
112
113
struct OverloadResolver
114
{
115
OverloadResolver(
116
NotNull<BuiltinTypes> builtinTypes,
117
NotNull<TypeArena> arena,
118
NotNull<Normalizer> normalizer,
119
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
120
NotNull<Scope> scope,
121
NotNull<InternalErrorReporter> reporter,
122
NotNull<TypeCheckLimits> limits,
123
Location callLocation
124
);
125
126
NotNull<BuiltinTypes> builtinTypes;
127
NotNull<TypeArena> arena;
128
NotNull<Normalizer> normalizer;
129
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
130
NotNull<Scope> scope;
131
NotNull<InternalErrorReporter> ice;
132
NotNull<TypeCheckLimits> limits;
133
Subtyping subtyping;
134
Location callLoc;
135
136
// Given a (potentially overloaded) function and a set of arguments, test each overload.
137
OverloadResolution resolveOverload(
138
TypeId fnTy,
139
TypePackId args,
140
Location fnLocation,
141
NotNull<DenseHashSet<TypeId>> uniqueTypes,
142
bool useFreeTypeBounds
143
);
144
145
void reportErrors(
146
ErrorVec& errors,
147
TypeId fnTy,
148
Location fnLocation,
149
const ModuleName& moduleName,
150
TypePackId argPack,
151
const std::vector<AstExpr*>& argExprs,
152
const SubtypingReasoning& reason
153
) const;
154
155
private:
156
void testFunctionOrUnion(
157
OverloadResolution& result,
158
TypeId fnTy,
159
TypePackId argsPack,
160
Location fnLocation,
161
NotNull<DenseHashSet<TypeId>> uniqueTypes
162
);
163
164
void testFunction(OverloadResolution& result, TypeId fnTy, TypePackId argsPack, Location fnLocation, NotNull<DenseHashSet<TypeId>> uniqueTypes);
165
166
void testFunctionOrCallMetamethod(
167
OverloadResolution& result,
168
TypeId fnTy,
169
TypePackId argsPack,
170
Location fnLocation,
171
NotNull<DenseHashSet<TypeId>> uniqueTypes
172
);
173
174
void maybeEmplaceError(
175
ErrorVec* errors,
176
Location argLocation,
177
const SubtypingReasoning* reason,
178
std::optional<TypeId> wantedTy,
179
std::optional<TypeId> givenTy
180
) const;
181
182
void maybeEmplaceError(
183
ErrorVec* errors,
184
Location argLocation,
185
const ModuleName& moduleName,
186
const SubtypingReasoning* reason,
187
std::optional<TypeId> wantedTy,
188
std::optional<TypeId> givenTy
189
) const;
190
191
void maybeEmplaceError(
192
ErrorVec* errors,
193
Location argLocation,
194
const ModuleName& moduleName,
195
const SubtypingReasoning* reason,
196
std::optional<TypePackId> wantedTp,
197
std::optional<TypePackId> givenTp
198
) const;
199
200
void maybeEmplaceError(
201
ErrorVec* errors,
202
Location argLocation,
203
const ModuleName& moduleName,
204
const SubtypingReasoning* reason,
205
std::optional<TypeOrPack> wantedType,
206
std::optional<TypeOrPack> givenType
207
) const;
208
209
// Checks if the candidate args are arity-compatible with the desired parameters.
210
// Used during overload selection to do arity-based filtering of overloads.
211
// We do not accept nil in place of a generic unless that generic is explicitly optional.
212
bool isArityCompatible(TypePackId candidate, TypePackId desired, NotNull<BuiltinTypes> builtinTypes) const;
213
};
214
215
// Helper utility, presently used for binary operator type functions.
216
//
217
// Given a function and a set of arguments, select a suitable overload.
218
219
} // namespace Luau
220
221