Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/src/OverloadResolution.cpp
2725 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/OverloadResolution.h"
3
4
#include "Luau/Common.h"
5
#include "Luau/Instantiation2.h"
6
#include "Luau/Subtyping.h"
7
#include "Luau/TxnLog.h"
8
#include "Luau/Type.h"
9
#include "Luau/TypeFunction.h"
10
#include "Luau/TypePack.h"
11
#include "Luau/TypePath.h"
12
#include "Luau/TypeUtils.h"
13
#include "Luau/Unifier2.h"
14
15
namespace Luau
16
{
17
18
SelectedOverload OverloadResolution::getUnambiguousOverload() const
19
{
20
if (ok.size() == 1 && potentialOverloads.size() == 0)
21
{
22
// Unambiguously: there is exactly one overload that matches
23
// without dispatching any more constraints.
24
return {
25
ok.front(),
26
{},
27
false,
28
};
29
}
30
31
if (ok.size() == 0 && potentialOverloads.size() == 1)
32
{
33
// Unambiguously: there are _no_ overloads that match without
34
// dispatching constraints, but there's exactly one that does
35
// match without dispatching constraints.
36
return {potentialOverloads.front().first, potentialOverloads.front().second, false};
37
}
38
39
if (ok.size() > 1)
40
{
41
// FIXME CLI-180645: We should try to infer a union of return
42
// types here so that we get better autocomplete / type
43
// inference for the rest of the function.
44
return {std::nullopt, {}, false};
45
}
46
47
if (potentialOverloads.size() + ok.size() > 1)
48
{
49
// This is a first case of "ambiguous" overloads: we have at least
50
// one overload that matches without constraints, and one that matches
51
// with extra constraints.
52
//
53
// This is the one spot where we return `true`, which callers may use
54
// to determine whether they should emit an error or try again later.
55
if (ok.empty())
56
return {potentialOverloads.front().first, potentialOverloads.front().second, true};
57
else
58
{
59
LUAU_ASSERT(ok.size() == 1);
60
return {ok.front(), {}, true};
61
}
62
}
63
64
LUAU_ASSERT(potentialOverloads.size() + ok.size() == 0);
65
66
// In this case, no overloads are valid. Let's try to pick the one that
67
// will cause us to report the most legible errors.
68
if (incompatibleOverloads.size() == 1)
69
{
70
// There's exactly one incompatible overload, but it has
71
// the right arity, so just use that. We'll fail type checking
72
// but that's ok.
73
return {incompatibleOverloads.front().first, {}, false};
74
}
75
76
// FIXME: CLI-180645: if `incompatibleOverloads` is non-empty, return a
77
// union of all its type packs to the user to use as the inferred return
78
// type.
79
//
80
// FIXME CLI-180638: If we have exactly one function, but there is an
81
// arity mismatch, then use that and move on.
82
//
83
// This is the final case:
84
// - There are _no_ overloads whose arguments are clean supertypes, nor
85
// could be supertypes if constraints are dispatched.
86
// - There are no overloads that have the right arity but known
87
// incompatible arguments.
88
// - There are either no, or more than one, overloads that just have an
89
// arity mismatch.
90
// The best we can do here is unify against the error type and move on.
91
return {std::nullopt, {}, false};
92
}
93
94
OverloadResolver::OverloadResolver(
95
NotNull<BuiltinTypes> builtinTypes,
96
NotNull<TypeArena> arena,
97
NotNull<Normalizer> normalizer,
98
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
99
NotNull<Scope> scope,
100
NotNull<InternalErrorReporter> reporter,
101
NotNull<TypeCheckLimits> limits,
102
Location callLocation
103
)
104
: builtinTypes(builtinTypes)
105
, arena(arena)
106
, normalizer(normalizer)
107
, typeFunctionRuntime(typeFunctionRuntime)
108
, scope(scope)
109
, ice(reporter)
110
, limits(limits)
111
, subtyping({builtinTypes, arena, normalizer, typeFunctionRuntime, ice})
112
, callLoc(callLocation)
113
{
114
}
115
116
static bool reasoningIsReturnTypes(const Path& path)
117
{
118
if (path.empty())
119
return false;
120
121
const auto& firstComponent = path.components[0];
122
123
const auto field = get_if<TypePath::PackField>(&firstComponent);
124
return field != nullptr && *field == TypePath::PackField::Returns;
125
}
126
127
static void ignoreReasoningForReturnType(SubtypingResult& sr)
128
{
129
SubtypingReasonings result{kEmptyReasoning};
130
131
for (const SubtypingReasoning& reasoning : sr.reasoning)
132
{
133
if (reasoningIsReturnTypes(reasoning.subPath) && reasoningIsReturnTypes(reasoning.superPath))
134
continue;
135
136
result.insert(reasoning);
137
}
138
139
std::swap(sr.reasoning, result);
140
141
// If the return type mismatch was the only reason for the subtype failure,
142
// then we actually consider this a successful match.
143
if (sr.reasoning.empty() && sr.genericBoundsMismatches.empty() && sr.errors.empty())
144
sr.isSubtype = true;
145
}
146
147
static bool areUnsatisfiedArgumentsOptional(const SubtypingReasonings& reasonings, TypePackId argPack, TypePackId funcArgPack)
148
{
149
// If the two argument lists are incompatible solely because of the argument
150
// counts, the reasonings will simply point at the argument lists
151
// themselves. If the reasonings point into a pack, it's because that
152
// specific argument has an incompatible type.
153
if (1 != reasonings.size())
154
return false;
155
156
const TypePath::Path justArguments{TypePath::PackField::Arguments};
157
const auto& reason = *reasonings.begin();
158
if (reason.subPath != justArguments || reason.superPath != justArguments)
159
return false;
160
161
const auto [argHead, argTail] = flatten(argPack);
162
const auto [funArgHead, funArgTail] = flatten(funcArgPack);
163
164
if (argHead.size() >= funArgHead.size())
165
return false;
166
167
for (size_t i = argHead.size(); i < funArgHead.size(); ++i)
168
{
169
if (!isOptional(funArgHead[i]))
170
return false;
171
}
172
return true;
173
}
174
175
OverloadResolution OverloadResolver::resolveOverload(
176
TypeId ty,
177
TypePackId argsPack,
178
Location fnLocation,
179
NotNull<DenseHashSet<TypeId>> uniqueTypes,
180
bool useFreeTypeBounds
181
)
182
{
183
OverloadResolution result;
184
185
ty = follow(ty);
186
187
if (auto it = get<IntersectionType>(ty))
188
{
189
for (TypeId component : it)
190
testFunctionOrUnion(result, component, argsPack, fnLocation, uniqueTypes);
191
}
192
else
193
testFunctionOrUnion(result, ty, argsPack, fnLocation, uniqueTypes);
194
195
return result;
196
}
197
198
static bool isPathOnArgumentList(const Path& path)
199
{
200
auto iter = begin(path.components);
201
const auto endIter = end(path.components);
202
203
if (iter == endIter)
204
return false;
205
206
if (auto args = get_if<TypePath::PackField>(&*iter); args && *args != TypePath::PackField::Arguments)
207
return false;
208
209
++iter;
210
211
while (iter != endIter)
212
{
213
if (get_if<TypePath::PackSlice>(&*iter) || get_if<TypePath::GenericPackMapping>(&*iter))
214
++iter;
215
else if (const auto packField = get_if<TypePath::PackField>(&*iter); packField && *packField == TypePath::PackField::Tail)
216
++iter;
217
else
218
return false;
219
}
220
221
return true;
222
}
223
224
// Figuring out which argument a particular path points at can be kind of tricky
225
// due to generic pack substitutions.
226
static std::optional<size_t> getArgumentIndex(const Path& path, TypeId fnTy)
227
{
228
auto iter = begin(path.components);
229
const auto endIter = end(path.components);
230
231
if (iter == endIter)
232
return std::nullopt;
233
234
if (auto args = get_if<TypePath::PackField>(&*iter); args && *args != TypePath::PackField::Arguments)
235
return std::nullopt;
236
237
++iter;
238
239
const FunctionType* ft = get<FunctionType>(fnTy);
240
LUAU_ASSERT(fnTy);
241
242
size_t result = 0;
243
TypeOrPack ty = ft->argTypes;
244
245
while (iter != endIter)
246
{
247
const auto& component = *iter;
248
++iter;
249
250
if (auto index = get_if<TypePath::Index>(&component))
251
return result + index->index;
252
else if (auto subst = get_if<TypePath::GenericPackMapping>(&component))
253
ty = subst->mappedType;
254
else if (auto slice = get_if<TypePath::PackSlice>(&component))
255
result += slice->start_index;
256
else if (auto packField = get_if<TypePath::PackField>(&component); packField && *packField == TypePath::PackField::Tail)
257
{
258
// If the path component points at the tail of the pack, we need to
259
// advance the count by the length of the current pack.
260
TypePackId* tp = get_if<TypePackId>(&ty);
261
LUAU_ASSERT(tp);
262
if (!tp)
263
return std::nullopt;
264
265
// Subtyping flattens out chains of concrete packs when it generates
266
// these TypePaths, so we need to do the same here.
267
auto packIter = begin(*tp);
268
auto packEndIter = end(*tp);
269
while (packIter != packEndIter)
270
{
271
result += 1;
272
++packIter;
273
}
274
275
if (!packIter.tail())
276
return std::nullopt;
277
278
ty = *packIter.tail();
279
280
continue;
281
}
282
else
283
return std::nullopt;
284
}
285
286
return std::nullopt;
287
}
288
289
void OverloadResolver::reportErrors(
290
ErrorVec& errors,
291
TypeId fnTy,
292
Location fnLocation,
293
const ModuleName& moduleName,
294
TypePackId argPack,
295
const std::vector<AstExpr*>& argExprs,
296
const SubtypingReasoning& reason
297
) const
298
{
299
std::optional<size_t> argumentIndex = getArgumentIndex(reason.subPath, fnTy);
300
301
Location argLocation;
302
// If the Nth argument directly corresponds to a term in the AST, use its location.
303
if (argumentIndex && *argumentIndex < argExprs.size())
304
argLocation = argExprs.at(*argumentIndex)->location;
305
// Else if any arguments were passed at all, use the location of the last one.
306
// TODO: I think we can get the location of the close paren of the whole
307
// function call. That would be much better.
308
else if (argExprs.size() != 0)
309
argLocation = argExprs.back()->location;
310
// If no arguments were present, just use the location of the whole function call.
311
else
312
argLocation = fnLocation;
313
314
const TypeId prospectiveFunction = arena->addType(FunctionType{argPack, builtinTypes->anyTypePack});
315
316
std::optional<TypePackId> failedSubPack = traverseForPack(prospectiveFunction, reason.superPath, builtinTypes, arena);
317
std::optional<TypePackId> failedSuperPack = traverseForPack(fnTy, reason.subPath, builtinTypes, arena);
318
319
if (failedSuperPack && get<GenericTypePack>(*failedSuperPack))
320
{
321
maybeEmplaceError(&errors, argLocation, moduleName, &reason, failedSuperPack, failedSubPack.value_or(builtinTypes->emptyTypePack));
322
return;
323
}
324
325
// If the mismatch is on the argument list itself, then the wrong number of parameters were passed.
326
if (isPathOnArgumentList(reason.subPath))
327
{
328
/*
329
* If insufficiently many parameters are passed, we expect an empty
330
* subPath.
331
*
332
* If too many parameters are passed, we expect a slice subPath which
333
* points to the start of the unsatisfied arguments, and a superPath
334
* which points at the tail of the parameter list.
335
*
336
* Sometimes, the superPath includes generic substitutions. We need to
337
* take this into account when computing the expected parameter count.
338
*/
339
340
if (!failedSuperPack)
341
{
342
errors.emplace_back(fnLocation, moduleName, InternalError{"Malformed SubtypingReasoning"});
343
return;
344
}
345
346
const TypePackId requiredMappedArgs = arena->addTypePack(traverseForFlattenedPack(fnTy, reason.subPath, builtinTypes, arena));
347
const auto [paramsHead, paramsTail] = flatten(requiredMappedArgs);
348
const auto [argHead, argTail] = flatten(argPack);
349
350
const size_t argCount = argHead.size();
351
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), requiredMappedArgs);
352
353
switch (shouldSuppressErrors(normalizer, argPack))
354
{
355
case ErrorSuppression::Suppress:
356
return;
357
case ErrorSuppression::DoNotSuppress:
358
break;
359
case ErrorSuppression::NormalizationFailed:
360
errors.emplace_back(fnLocation, moduleName, NormalizationTooComplex{});
361
return;
362
}
363
364
if (failedSuperPack)
365
{
366
switch (shouldSuppressErrors(normalizer, requiredMappedArgs))
367
{
368
case ErrorSuppression::Suppress:
369
return;
370
case ErrorSuppression::DoNotSuppress:
371
break;
372
case ErrorSuppression::NormalizationFailed:
373
errors.emplace_back(fnLocation, moduleName, NormalizationTooComplex{});
374
return;
375
}
376
}
377
378
const bool isVariadic = argTail && Luau::isVariadic(*argTail);
379
380
if (isVariadic)
381
{
382
// Not actually a count mismatch! This can happen if the
383
// required parameters are a generic pack that has not been
384
// satisfied.
385
386
maybeEmplaceError(&errors, argLocation, moduleName, &reason, failedSuperPack, failedSubPack.value_or(builtinTypes->emptyTypePack));
387
}
388
else
389
errors.emplace_back(fnLocation, moduleName, CountMismatch{paramsHead.size(), optMaxParams, argCount, CountMismatch::Arg, isVariadic});
390
391
return;
392
}
393
394
if (argumentIndex)
395
{
396
// If the Nth argument directly corresponds to a term in the AST, use its location.
397
if (*argumentIndex < argExprs.size())
398
argLocation = argExprs.at(*argumentIndex)->location;
399
// Else if any arguments were passed at all, use the location of the last one.
400
else if (argExprs.size() != 0)
401
argLocation = argExprs.back()->location;
402
// If no arguments were present, just use the location of the whole function call.
403
else
404
argLocation = fnLocation;
405
406
// The first path component should always be PackField::Arguments
407
LUAU_ASSERT(reason.subPath.components.size() > 1);
408
Path superPathTail = reason.superPath;
409
superPathTail.components.erase(superPathTail.components.begin());
410
411
std::optional<TypeOrPack> failedSub = traverse(argPack, superPathTail, builtinTypes, arena);
412
std::optional<TypeOrPack> failedSuper = traverse(fnTy, reason.subPath, builtinTypes, arena);
413
414
maybeEmplaceError(&errors, argLocation, moduleName, &reason, failedSuper, failedSub);
415
return;
416
}
417
418
if (failedSubPack && !failedSuperPack && get<GenericTypePack>(*failedSubPack))
419
{
420
errors.emplace_back(argLocation, moduleName, TypePackMismatch{*failedSubPack, builtinTypes->emptyTypePack});
421
}
422
423
if (failedSubPack && failedSuperPack)
424
{
425
// If a bug in type inference occurs, we may have a mismatch in the return packs.
426
// This happens when inference incorrectly leaves the result type of a function free.
427
// If this happens, we don't want to explode, so we'll use the function's location.
428
if (argExprs.empty())
429
argLocation = fnLocation;
430
else
431
argLocation = argExprs.at(argExprs.size() - 1)->location;
432
433
auto errorSuppression = shouldSuppressErrors(normalizer, *failedSubPack).orElse(shouldSuppressErrors(normalizer, *failedSuperPack));
434
if (errorSuppression == ErrorSuppression::Suppress)
435
return;
436
437
switch (reason.variance)
438
{
439
case SubtypingVariance::Covariant:
440
errors.emplace_back(argLocation, moduleName, TypePackMismatch{*failedSubPack, *failedSuperPack});
441
break;
442
case SubtypingVariance::Contravariant:
443
errors.emplace_back(argLocation, moduleName, TypePackMismatch{*failedSuperPack, *failedSubPack});
444
break;
445
case SubtypingVariance::Invariant:
446
errors.emplace_back(argLocation, moduleName, TypePackMismatch{*failedSubPack, *failedSuperPack});
447
break;
448
default:
449
LUAU_ASSERT(0);
450
break;
451
}
452
}
453
}
454
455
// Test a single FunctionType against an argument list. Reduces type functions
456
// and does a proper arity check.
457
void OverloadResolver::testFunction(
458
OverloadResolution& result,
459
TypeId fnTy,
460
TypePackId argsPack,
461
Location fnLocation,
462
NotNull<DenseHashSet<TypeId>> uniqueTypes
463
)
464
{
465
fnTy = follow(fnTy);
466
467
// TODO: This seems like the wrong spot to do this check.
468
if (is<FreeType, BlockedType, PendingExpansionType>(fnTy))
469
{
470
std::vector<ConstraintV> constraints; // TODO. Luckily, these constraints are not yet used.
471
result.potentialOverloads.emplace_back(fnTy, std::move(constraints));
472
return;
473
}
474
475
if (auto tfit = get<TypeFunctionInstanceType>(fnTy); tfit && tfit->state == TypeFunctionInstanceState::Unsolved)
476
{
477
std::vector<ConstraintV> constraints; // TODO. Luckily, these constraints are not yet used.
478
result.potentialOverloads.emplace_back(fnTy, std::move(constraints));
479
return;
480
}
481
482
const FunctionType* ftv = get<FunctionType>(fnTy);
483
if (!ftv)
484
{
485
result.nonFunctions.emplace_back(fnTy);
486
return;
487
}
488
489
if (!isArityCompatible(argsPack, ftv->argTypes, builtinTypes))
490
{
491
result.arityMismatches.emplace_back(fnTy);
492
return;
493
}
494
495
TypeFunctionContext context{arena, builtinTypes, scope, normalizer, typeFunctionRuntime, ice, limits};
496
FunctionGraphReductionResult reduceResult = reduceTypeFunctions(fnTy, callLoc, NotNull{&context}, /*force=*/true);
497
if (!reduceResult.errors.empty())
498
{
499
result.incompatibleOverloads.emplace_back(fnTy, std::move(reduceResult.errors));
500
return;
501
}
502
503
TypeId prospectiveFunction = arena->addType(FunctionType{argsPack, builtinTypes->anyTypePack});
504
505
subtyping.uniqueTypes = uniqueTypes;
506
SubtypingResult r = subtyping.isSubtype(fnTy, prospectiveFunction, scope);
507
508
// Frustratingly, subtyping does not know about error suppression, so this
509
// subtype test will probably fail due to the mismatched return types. Here,
510
// we'll prune any SubtypingReasons that have anything to do with the return
511
// type.
512
//
513
// TODO: I'd like to adjust the subtype test to only run across the argument
514
// types so that the return pack doesn't get in the way, but that causes the
515
// resultant TypePaths to change, so it's not a trivial thing to do.
516
ignoreReasoningForReturnType(r);
517
518
if (r.isSubtype)
519
{
520
if (r.assumedConstraints.empty())
521
result.ok.emplace_back(fnTy);
522
else
523
result.potentialOverloads.emplace_back(fnTy, std::move(r.assumedConstraints));
524
}
525
else
526
{
527
if (!r.genericBoundsMismatches.empty())
528
{
529
ErrorVec errors;
530
for (const auto& gbm : r.genericBoundsMismatches)
531
errors.emplace_back(fnLocation, gbm);
532
result.incompatibleOverloads.emplace_back(fnTy, std::move(errors));
533
}
534
else if (areUnsatisfiedArgumentsOptional(r.reasoning, argsPack, ftv->argTypes))
535
{
536
// Important! Subtyping doesn't know anything about
537
// optional arguments. If the only reason subtyping
538
// failed is because optional arguments were not provided,
539
// then this overload is actually okay.
540
if (r.assumedConstraints.empty())
541
result.ok.emplace_back(fnTy);
542
else
543
result.potentialOverloads.emplace_back(fnTy, std::move(r.assumedConstraints));
544
}
545
else
546
result.incompatibleOverloads.emplace_back(fnTy, std::move(r.reasoning));
547
}
548
}
549
550
void OverloadResolver::testFunctionOrUnion(
551
OverloadResolution& result,
552
TypeId fnTy,
553
TypePackId argsPack,
554
Location fnLocation,
555
NotNull<DenseHashSet<TypeId>> uniqueTypes
556
)
557
{
558
LUAU_ASSERT(fnTy == follow(fnTy));
559
560
if (auto ut = get<UnionType>(fnTy))
561
{
562
// A union of functions is a valid overload iff every type within it is a valid overload.
563
564
OverloadResolution innerResult;
565
size_t count = 0;
566
for (TypeId t : ut)
567
{
568
++count;
569
testFunctionOrCallMetamethod(innerResult, t, argsPack, fnLocation, uniqueTypes);
570
}
571
572
if (count == innerResult.ok.size())
573
{
574
result.ok.emplace_back(fnTy);
575
}
576
else if (count == innerResult.ok.size() + innerResult.potentialOverloads.size())
577
{
578
std::vector<ConstraintV> allConstraints;
579
for (const auto& [_t, constraints] : innerResult.potentialOverloads)
580
allConstraints.insert(allConstraints.end(), constraints.begin(), constraints.end());
581
582
result.potentialOverloads.emplace_back(fnTy, std::move(allConstraints));
583
}
584
else
585
{
586
// FIXME: We should probably report something better here, but it's
587
// important for type checking that we include this.
588
result.incompatibleOverloads.emplace_back(fnTy, ErrorVec{{fnLocation, CannotCallNonFunction{fnTy}}});
589
}
590
}
591
else
592
testFunctionOrCallMetamethod(result, fnTy, argsPack, fnLocation, uniqueTypes);
593
}
594
595
/*
596
* A utility function for ::resolveOverload. If a particular overload is a table
597
* with a __call metamethod, unwrap that and test it.
598
*
599
* Note: The __call metamethod can itself be overloaded, but it cannot be a
600
* table that overloads __call. It must be an actual function.
601
*
602
* TODO: It would be nice to report a good type error in this case.
603
*/
604
void OverloadResolver::testFunctionOrCallMetamethod(
605
OverloadResolution& result,
606
TypeId fnTy,
607
TypePackId argsPack,
608
Location fnLocation,
609
NotNull<DenseHashSet<TypeId>> uniqueTypes
610
)
611
{
612
fnTy = follow(fnTy);
613
614
ErrorVec dummyErrors;
615
if (auto callMetamethod = findMetatableEntry(builtinTypes, dummyErrors, fnTy, "__call", callLoc))
616
{
617
// Calling a metamethod forwards `fnTy` as self.
618
argsPack = arena->addTypePack({fnTy}, argsPack);
619
fnTy = follow(*callMetamethod);
620
621
// Handle an overloaded __call metamethod.
622
if (auto it = get<IntersectionType>(fnTy))
623
{
624
for (TypeId component : it)
625
{
626
component = follow(component);
627
result.metamethods.insert(component);
628
const FunctionType* fn = get<FunctionType>(component);
629
630
if (fn && !isArityCompatible(argsPack, fn->argTypes, builtinTypes))
631
result.arityMismatches.emplace_back(component);
632
else
633
testFunction(result, component, argsPack, fnLocation, uniqueTypes);
634
}
635
return;
636
}
637
638
result.metamethods.insert(fnTy);
639
}
640
641
// Handle non-metamethods and metamethods which aren't overloaded.
642
testFunction(result, fnTy, argsPack, fnLocation, uniqueTypes);
643
}
644
645
void OverloadResolver::maybeEmplaceError(
646
ErrorVec* errors,
647
Location argLocation,
648
const SubtypingReasoning* reason,
649
const std::optional<TypeId> wantedType,
650
const std::optional<TypeId> givenType
651
) const
652
{
653
// This is a temporary compatibility shim for the old API. It's ok to pass
654
// an empty ModuleName here because the caller of
655
// OverloadResolver::resolve() will overwrite the moduleName of any errors
656
// that are reported.
657
return maybeEmplaceError(errors, argLocation, ModuleName{}, reason, wantedType, givenType);
658
}
659
660
void OverloadResolver::maybeEmplaceError(
661
ErrorVec* errors,
662
Location argLocation,
663
const ModuleName& moduleName,
664
const SubtypingReasoning* reason,
665
const std::optional<TypeId> wantedType,
666
const std::optional<TypeId> givenType
667
) const
668
{
669
if (wantedType && givenType)
670
{
671
switch (shouldSuppressErrors(normalizer, *wantedType).orElse(shouldSuppressErrors(normalizer, *givenType)))
672
{
673
case ErrorSuppression::Suppress:
674
break;
675
case ErrorSuppression::NormalizationFailed:
676
errors->emplace_back(argLocation, moduleName, NormalizationTooComplex{});
677
// intentionally fallthrough here since we couldn't prove this was error-suppressing
678
[[fallthrough]];
679
case ErrorSuppression::DoNotSuppress:
680
// TODO extract location from the SubtypingResult path and argExprs
681
switch (reason->variance)
682
{
683
case SubtypingVariance::Covariant:
684
case SubtypingVariance::Contravariant:
685
errors->emplace_back(argLocation, moduleName, TypeMismatch{*wantedType, *givenType, TypeMismatch::CovariantContext});
686
break;
687
case SubtypingVariance::Invariant:
688
errors->emplace_back(argLocation, moduleName, TypeMismatch{*wantedType, *givenType, TypeMismatch::InvariantContext});
689
break;
690
default:
691
LUAU_ASSERT(0);
692
break;
693
}
694
}
695
}
696
}
697
698
void OverloadResolver::maybeEmplaceError(
699
ErrorVec* errors,
700
Location argLocation,
701
const ModuleName& moduleName,
702
const SubtypingReasoning* reason,
703
const std::optional<TypePackId> wantedTp,
704
const std::optional<TypePackId> givenTp
705
) const
706
{
707
if (!wantedTp || !givenTp)
708
return;
709
switch (shouldSuppressErrors(normalizer, *wantedTp).orElse(shouldSuppressErrors(normalizer, *givenTp)))
710
{
711
case ErrorSuppression::Suppress:
712
break;
713
case ErrorSuppression::NormalizationFailed:
714
errors->emplace_back(argLocation, moduleName, NormalizationTooComplex{});
715
break;
716
case ErrorSuppression::DoNotSuppress:
717
errors->emplace_back(argLocation, moduleName, TypePackMismatch{*wantedTp, *givenTp});
718
break;
719
}
720
}
721
722
void OverloadResolver::maybeEmplaceError(
723
ErrorVec* errors,
724
Location argLocation,
725
const ModuleName& moduleName,
726
const SubtypingReasoning* reason,
727
const std::optional<TypeOrPack> wantedType,
728
const std::optional<TypeOrPack> givenType
729
) const
730
{
731
if (!wantedType || !givenType)
732
return;
733
734
const TypeId* wantedTy = get_if<TypeId>(&*wantedType);
735
const TypeId* givenTy = get_if<TypeId>(&*givenType);
736
if (wantedTy && givenTy)
737
return maybeEmplaceError(errors, argLocation, moduleName, reason, std::optional<TypeId>{*wantedTy}, std::optional<TypeId>{*givenTy});
738
739
const TypePackId* wantedTp = get_if<TypePackId>(&*wantedType);
740
const TypePackId* givenTp = get_if<TypePackId>(&*givenType);
741
742
if (wantedTp && givenTp)
743
return maybeEmplaceError(errors, argLocation, moduleName, reason, std::optional<TypePackId>{*wantedTp}, std::optional<TypePackId>{*givenTp});
744
}
745
746
bool OverloadResolver::isArityCompatible(const TypePackId candidate, const TypePackId desired, NotNull<BuiltinTypes> builtinTypes) const
747
{
748
auto [candidateHead, candidateTail] = flatten(candidate);
749
auto [desiredHead, desiredTail] = flatten(desired);
750
751
// Insufficiently many parameters were passed
752
if (candidateHead.size() < desiredHead.size())
753
{
754
if (candidateTail)
755
return true; // A tail can fill in remaining values
756
757
// If the candidate is shorter than desired and has no tail, it can only match if the extra desired args are all optional
758
for (size_t i = candidateHead.size(); i < desiredHead.size(); ++i)
759
{
760
if (const TypeId ty = follow(desiredHead[i]); !isOptionalType(ty, builtinTypes))
761
return false;
762
}
763
}
764
765
// Too many parameters were passed
766
if (candidateHead.size() > desiredHead.size())
767
{
768
// If the function being called accepts a variadic or generic tail, then the arities match.
769
return desiredTail.has_value();
770
}
771
// There aren't any other failure conditions; we don't care if we pass more args than needed
772
773
return true;
774
}
775
776
} // namespace Luau
777
778