luau/Analysis/src/TypeChecker2.cpp

2694 lines
97 KiB
C++
Raw Normal View History

2022-09-08 22:44:50 +01:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2022-06-17 01:54:42 +01:00
#include "Luau/TypeChecker2.h"
#include "Luau/Ast.h"
#include "Luau/AstQuery.h"
#include "Luau/Clone.h"
2023-02-24 18:24:22 +00:00
#include "Luau/Common.h"
2023-02-03 12:34:12 +00:00
#include "Luau/DcrLogger.h"
2023-01-20 12:02:39 +00:00
#include "Luau/Error.h"
2023-06-24 06:33:44 +01:00
#include "Luau/InsertionOrderedMap.h"
2022-07-01 00:29:02 +01:00
#include "Luau/Instantiation.h"
2022-10-21 18:33:43 +01:00
#include "Luau/Metamethods.h"
2022-06-17 01:54:42 +01:00
#include "Luau/Normalize.h"
2022-08-18 22:04:33 +01:00
#include "Luau/ToString.h"
2022-07-01 00:29:02 +01:00
#include "Luau/TxnLog.h"
2023-01-03 17:33:19 +00:00
#include "Luau/Type.h"
2023-05-25 21:46:51 +01:00
#include "Luau/TypePack.h"
2023-02-03 12:34:12 +00:00
#include "Luau/TypeUtils.h"
2022-06-24 02:44:07 +01:00
#include "Luau/Unifier.h"
2023-05-12 13:15:01 +01:00
#include "Luau/TypeFamily.h"
2023-05-25 21:46:51 +01:00
#include "Luau/VisitType.h"
2022-09-08 22:44:50 +01:00
#include <algorithm>
2023-02-03 12:34:12 +00:00
LUAU_FASTFLAG(DebugLuauMagicTypes)
2022-06-17 01:54:42 +01:00
namespace Luau
{
2022-09-29 23:11:54 +01:00
// TypeInfer.h
// TODO move these
2022-10-13 23:59:53 +01:00
using PrintLineProc = void (*)(const std::string&);
2022-09-29 23:11:54 +01:00
extern PrintLineProc luauPrintLine;
2022-08-18 22:04:33 +01:00
/* Push a scope onto the end of a stack for the lifetime of the StackPusher instance.
* TypeChecker2 uses this to maintain knowledge about which scope encloses every
* given AstNode.
*/
struct StackPusher
{
std::vector<NotNull<Scope>>* stack;
NotNull<Scope> scope;
explicit StackPusher(std::vector<NotNull<Scope>>& stack, Scope* scope)
: stack(&stack)
, scope(scope)
{
stack.push_back(NotNull{scope});
}
~StackPusher()
{
if (stack)
{
LUAU_ASSERT(stack->back() == scope);
stack->pop_back();
}
}
StackPusher(const StackPusher&) = delete;
StackPusher&& operator=(const StackPusher&) = delete;
StackPusher(StackPusher&& other)
: stack(std::exchange(other.stack, nullptr))
, scope(other.scope)
{
}
};
2022-10-21 18:33:43 +01:00
static std::optional<std::string> getIdentifierOfBaseVar(AstExpr* node)
{
if (AstExprGlobal* expr = node->as<AstExprGlobal>())
return expr->name.value;
if (AstExprLocal* expr = node->as<AstExprLocal>())
return expr->local->name.value;
if (AstExprIndexExpr* expr = node->as<AstExprIndexExpr>())
return getIdentifierOfBaseVar(expr->expr);
if (AstExprIndexName* expr = node->as<AstExprIndexName>())
return getIdentifierOfBaseVar(expr->expr);
return std::nullopt;
}
2023-05-25 21:46:51 +01:00
template<typename T>
bool areEquivalent(const T& a, const T& b)
{
if (a.family != b.family)
return false;
if (a.typeArguments.size() != b.typeArguments.size() || a.packArguments.size() != b.packArguments.size())
return false;
for (size_t i = 0; i < a.typeArguments.size(); ++i)
{
if (follow(a.typeArguments[i]) != follow(b.typeArguments[i]))
return false;
}
for (size_t i = 0; i < a.packArguments.size(); ++i)
{
if (follow(a.packArguments[i]) != follow(b.packArguments[i]))
return false;
}
return true;
}
struct FamilyFinder : TypeOnceVisitor
{
DenseHashSet<TypeId> mentionedFamilies{nullptr};
DenseHashSet<TypePackId> mentionedFamilyPacks{nullptr};
bool visit(TypeId ty, const TypeFamilyInstanceType&) override
{
mentionedFamilies.insert(ty);
return true;
}
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack&) override
{
mentionedFamilyPacks.insert(tp);
return true;
}
};
struct InternalFamilyFinder : TypeOnceVisitor
{
DenseHashSet<TypeId> internalFamilies{nullptr};
DenseHashSet<TypePackId> internalPackFamilies{nullptr};
DenseHashSet<TypeId> mentionedFamilies{nullptr};
DenseHashSet<TypePackId> mentionedFamilyPacks{nullptr};
InternalFamilyFinder(std::vector<TypeId>& declStack)
{
FamilyFinder f;
for (TypeId fn : declStack)
f.traverse(fn);
mentionedFamilies = std::move(f.mentionedFamilies);
mentionedFamilyPacks = std::move(f.mentionedFamilyPacks);
}
bool visit(TypeId ty, const TypeFamilyInstanceType& tfit) override
{
bool hasGeneric = false;
for (TypeId p : tfit.typeArguments)
{
if (get<GenericType>(follow(p)))
{
hasGeneric = true;
break;
}
}
for (TypePackId p : tfit.packArguments)
{
if (get<GenericTypePack>(follow(p)))
{
hasGeneric = true;
break;
}
}
if (hasGeneric)
{
for (TypeId mentioned : mentionedFamilies)
{
const TypeFamilyInstanceType* mentionedTfit = get<TypeFamilyInstanceType>(mentioned);
LUAU_ASSERT(mentionedTfit);
if (areEquivalent(tfit, *mentionedTfit))
{
return true;
}
}
internalFamilies.insert(ty);
}
return true;
}
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack& tfitp) override
{
bool hasGeneric = false;
for (TypeId p : tfitp.typeArguments)
{
if (get<GenericType>(follow(p)))
{
hasGeneric = true;
break;
}
}
for (TypePackId p : tfitp.packArguments)
{
if (get<GenericTypePack>(follow(p)))
{
hasGeneric = true;
break;
}
}
if (hasGeneric)
{
for (TypePackId mentioned : mentionedFamilyPacks)
{
const TypeFamilyInstanceTypePack* mentionedTfitp = get<TypeFamilyInstanceTypePack>(mentioned);
LUAU_ASSERT(mentionedTfitp);
if (areEquivalent(tfitp, *mentionedTfitp))
{
return true;
}
}
internalPackFamilies.insert(tp);
}
return true;
}
};
2022-08-18 22:04:33 +01:00
struct TypeChecker2
2022-06-17 01:54:42 +01:00
{
2023-01-03 17:33:19 +00:00
NotNull<BuiltinTypes> builtinTypes;
2022-09-08 22:44:50 +01:00
DcrLogger* logger;
2023-04-21 22:41:03 +01:00
NotNull<InternalErrorReporter> ice;
2022-06-17 01:54:42 +01:00
const SourceModule* sourceModule;
Module* module;
2023-01-03 17:33:19 +00:00
TypeArena testArena;
2022-06-17 01:54:42 +01:00
2022-08-18 22:04:33 +01:00
std::vector<NotNull<Scope>> stack;
2023-05-25 21:46:51 +01:00
std::vector<TypeId> functionDeclStack;
DenseHashSet<TypeId> noTypeFamilyErrors{nullptr};
2022-08-18 22:04:33 +01:00
2023-04-21 22:41:03 +01:00
Normalizer normalizer;
2022-12-09 18:07:25 +00:00
2023-05-25 21:46:51 +01:00
TypeChecker2(NotNull<BuiltinTypes> builtinTypes, NotNull<UnifierSharedState> unifierState, DcrLogger* logger, const SourceModule* sourceModule,
Module* module)
2023-01-03 17:33:19 +00:00
: builtinTypes(builtinTypes)
2022-09-08 22:44:50 +01:00
, logger(logger)
2023-04-21 22:41:03 +01:00
, ice(unifierState->iceHandler)
2022-09-08 22:44:50 +01:00
, sourceModule(sourceModule)
2022-06-17 01:54:42 +01:00
, module(module)
2023-05-25 21:46:51 +01:00
, normalizer{&testArena, builtinTypes, unifierState, /* cacheInhabitance */ true}
2022-06-17 01:54:42 +01:00
{
}
2022-08-18 22:04:33 +01:00
std::optional<StackPusher> pushStack(AstNode* node)
{
if (Scope** scope = module->astScopes.find(node))
return StackPusher{stack, *scope};
else
return std::nullopt;
}
2022-06-17 01:54:42 +01:00
2023-05-25 21:46:51 +01:00
void checkForInternalFamily(TypeId ty, Location location)
{
InternalFamilyFinder finder(functionDeclStack);
finder.traverse(ty);
for (TypeId internal : finder.internalFamilies)
reportError(WhereClauseNeeded{internal}, location);
for (TypePackId internal : finder.internalPackFamilies)
reportError(PackWhereClauseNeeded{internal}, location);
}
2023-05-12 13:15:01 +01:00
TypeId checkForFamilyInhabitance(TypeId instance, Location location)
{
2023-05-25 21:46:51 +01:00
if (noTypeFamilyErrors.find(instance))
return instance;
2023-05-12 13:15:01 +01:00
TxnLog fake{};
2023-05-25 21:46:51 +01:00
ErrorVec errors =
reduceFamilies(instance, location, NotNull{&testArena}, builtinTypes, stack.back(), NotNull{&normalizer}, &fake, true).errors;
if (errors.empty())
noTypeFamilyErrors.insert(instance);
2023-07-28 12:37:00 +01:00
if (!isErrorSuppressing(location, instance))
reportErrors(std::move(errors));
2023-05-12 13:15:01 +01:00
return instance;
}
2022-06-17 01:54:42 +01:00
TypePackId lookupPack(AstExpr* expr)
{
2022-07-01 00:29:02 +01:00
// If a type isn't in the type graph, it probably means that a recursion limit was exceeded.
// We'll just return anyType in these cases. Typechecking against any is very fast and this
// allows us not to think about this very much in the actual typechecking logic.
2022-06-17 01:54:42 +01:00
TypePackId* tp = module->astTypePacks.find(expr);
2022-07-01 00:29:02 +01:00
if (tp)
return follow(*tp);
else
2023-01-03 17:33:19 +00:00
return builtinTypes->anyTypePack;
2022-06-17 01:54:42 +01:00
}
TypeId lookupType(AstExpr* expr)
{
2022-07-01 00:29:02 +01:00
// If a type isn't in the type graph, it probably means that a recursion limit was exceeded.
// We'll just return anyType in these cases. Typechecking against any is very fast and this
// allows us not to think about this very much in the actual typechecking logic.
2022-06-17 01:54:42 +01:00
TypeId* ty = module->astTypes.find(expr);
2022-07-01 00:29:02 +01:00
if (ty)
2023-05-12 13:15:01 +01:00
return checkForFamilyInhabitance(follow(*ty), expr->location);
2022-07-01 00:29:02 +01:00
TypePackId* tp = module->astTypePacks.find(expr);
if (tp)
2023-05-12 13:15:01 +01:00
return checkForFamilyInhabitance(flattenPack(*tp), expr->location);
2022-07-01 00:29:02 +01:00
2023-01-03 17:33:19 +00:00
return builtinTypes->anyType;
2022-06-17 01:54:42 +01:00
}
2022-06-24 02:44:07 +01:00
TypeId lookupAnnotation(AstType* annotation)
{
2022-09-29 23:11:54 +01:00
if (FFlag::DebugLuauMagicTypes)
{
if (auto ref = annotation->as<AstTypeReference>(); ref && ref->name == "_luau_print" && ref->parameters.size > 0)
{
if (auto ann = ref->parameters.data[0].type)
{
TypeId argTy = lookupAnnotation(ref->parameters.data[0].type);
2022-10-13 23:59:53 +01:00
luauPrintLine(format(
"_luau_print (%d, %d): %s\n", annotation->location.begin.line, annotation->location.begin.column, toString(argTy).c_str()));
2022-09-29 23:11:54 +01:00
return follow(argTy);
}
}
}
2022-06-24 02:44:07 +01:00
TypeId* ty = module->astResolvedTypes.find(annotation);
LUAU_ASSERT(ty);
2023-05-12 13:15:01 +01:00
return checkForFamilyInhabitance(follow(*ty), annotation->location);
2022-06-24 02:44:07 +01:00
}
2022-08-04 22:27:28 +01:00
TypePackId lookupPackAnnotation(AstTypePack* annotation)
{
TypePackId* tp = module->astResolvedTypePacks.find(annotation);
LUAU_ASSERT(tp);
return follow(*tp);
}
2023-04-28 12:55:55 +01:00
TypeId lookupExpectedType(AstExpr* expr)
{
if (TypeId* ty = module->astExpectedTypes.find(expr))
return follow(*ty);
return builtinTypes->anyType;
}
TypePackId lookupExpectedPack(AstExpr* expr, TypeArena& arena)
{
if (TypeId* ty = module->astExpectedTypes.find(expr))
return arena.addTypePack(TypePack{{follow(*ty)}, std::nullopt});
return builtinTypes->anyTypePack;
}
2022-06-24 02:44:07 +01:00
TypePackId reconstructPack(AstArray<AstExpr*> exprs, TypeArena& arena)
{
2022-07-29 04:41:13 +01:00
if (exprs.size == 0)
return arena.addTypePack(TypePack{{}, std::nullopt});
2022-06-24 02:44:07 +01:00
std::vector<TypeId> head;
for (size_t i = 0; i < exprs.size - 1; ++i)
{
head.push_back(lookupType(exprs.data[i]));
}
TypePackId tail = lookupPack(exprs.data[exprs.size - 1]);
return arena.addTypePack(TypePack{head, tail});
}
2022-07-29 04:41:13 +01:00
Scope* findInnermostScope(Location location)
2022-06-24 02:44:07 +01:00
{
2022-07-29 04:41:13 +01:00
Scope* bestScope = module->getModuleScope().get();
Location bestLocation = module->scopes[0].first;
2022-06-24 02:44:07 +01:00
2022-07-29 04:41:13 +01:00
for (size_t i = 0; i < module->scopes.size(); ++i)
2022-06-24 02:44:07 +01:00
{
2022-07-29 04:41:13 +01:00
auto& [scopeBounds, scope] = module->scopes[i];
2022-06-24 02:44:07 +01:00
if (scopeBounds.encloses(location))
{
if (scopeBounds.begin > bestLocation.begin || scopeBounds.end < bestLocation.end)
{
bestScope = scope.get();
bestLocation = scopeBounds;
}
}
}
return bestScope;
}
2022-08-18 22:04:33 +01:00
void visit(AstStat* stat)
{
auto pusher = pushStack(stat);
2023-02-03 12:34:12 +00:00
if (auto s = stat->as<AstStatBlock>())
2022-08-18 22:04:33 +01:00
return visit(s);
else if (auto s = stat->as<AstStatIf>())
return visit(s);
else if (auto s = stat->as<AstStatWhile>())
return visit(s);
else if (auto s = stat->as<AstStatRepeat>())
return visit(s);
else if (auto s = stat->as<AstStatBreak>())
return visit(s);
else if (auto s = stat->as<AstStatContinue>())
return visit(s);
else if (auto s = stat->as<AstStatReturn>())
return visit(s);
else if (auto s = stat->as<AstStatExpr>())
return visit(s);
else if (auto s = stat->as<AstStatLocal>())
return visit(s);
else if (auto s = stat->as<AstStatFor>())
return visit(s);
else if (auto s = stat->as<AstStatForIn>())
return visit(s);
else if (auto s = stat->as<AstStatAssign>())
return visit(s);
else if (auto s = stat->as<AstStatCompoundAssign>())
return visit(s);
else if (auto s = stat->as<AstStatFunction>())
return visit(s);
else if (auto s = stat->as<AstStatLocalFunction>())
return visit(s);
else if (auto s = stat->as<AstStatTypeAlias>())
return visit(s);
else if (auto s = stat->as<AstStatDeclareFunction>())
return visit(s);
else if (auto s = stat->as<AstStatDeclareGlobal>())
return visit(s);
else if (auto s = stat->as<AstStatDeclareClass>())
return visit(s);
else if (auto s = stat->as<AstStatError>())
return visit(s);
else
LUAU_ASSERT(!"TypeChecker2 encountered an unknown node type");
}
void visit(AstStatBlock* block)
{
auto StackPusher = pushStack(block);
for (AstStat* statement : block->body)
visit(statement);
}
void visit(AstStatIf* ifStatement)
{
2023-04-28 12:55:55 +01:00
visit(ifStatement->condition, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
visit(ifStatement->thenbody);
if (ifStatement->elsebody)
visit(ifStatement->elsebody);
}
void visit(AstStatWhile* whileStatement)
{
2023-04-28 12:55:55 +01:00
visit(whileStatement->condition, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
visit(whileStatement->body);
}
void visit(AstStatRepeat* repeatStatement)
{
visit(repeatStatement->body);
2023-04-28 12:55:55 +01:00
visit(repeatStatement->condition, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
}
2022-09-02 00:00:14 +01:00
void visit(AstStatBreak*) {}
2022-08-18 22:04:33 +01:00
2022-09-02 00:00:14 +01:00
void visit(AstStatContinue*) {}
2022-08-18 22:04:33 +01:00
void visit(AstStatReturn* ret)
{
Scope* scope = findInnermostScope(ret->location);
TypePackId expectedRetType = scope->returnType;
2023-01-03 17:33:19 +00:00
TypeArena* arena = &testArena;
2022-12-02 10:46:05 +00:00
TypePackId actualRetType = reconstructPack(ret->list, *arena);
2022-08-18 22:04:33 +01:00
2023-05-25 21:46:51 +01:00
Unifier u{NotNull{&normalizer}, stack.back(), ret->location, Covariant};
2023-05-12 13:15:01 +01:00
u.hideousFixMeGenericsAreActuallyFree = true;
2022-08-18 22:04:33 +01:00
u.tryUnify(actualRetType, expectedRetType);
2023-07-28 12:37:00 +01:00
const bool ok = (u.errors.empty() && u.log.empty()) || isErrorSuppressing(ret->location, actualRetType, ret->location, expectedRetType);
2022-08-18 22:04:33 +01:00
if (!ok)
{
for (const TypeError& e : u.errors)
reportError(e);
}
for (AstExpr* expr : ret->list)
2023-04-28 12:55:55 +01:00
visit(expr, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
}
void visit(AstStatExpr* expr)
{
2023-04-28 12:55:55 +01:00
visit(expr->expr, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
}
void visit(AstStatLocal* local)
2022-06-24 02:44:07 +01:00
{
2022-09-29 23:11:54 +01:00
size_t count = std::max(local->values.size, local->vars.size);
for (size_t i = 0; i < count; ++i)
2022-06-24 02:44:07 +01:00
{
2022-09-29 23:11:54 +01:00
AstExpr* value = i < local->values.size ? local->values.data[i] : nullptr;
2023-02-24 18:24:22 +00:00
const bool isPack = value && (value->is<AstExprCall>() || value->is<AstExprVarargs>());
2022-08-18 22:04:33 +01:00
2022-09-29 23:11:54 +01:00
if (value)
2023-04-28 12:55:55 +01:00
visit(value, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
2023-02-24 18:24:22 +00:00
if (i != local->values.size - 1 || !isPack)
2022-06-24 02:44:07 +01:00
{
2022-09-29 23:11:54 +01:00
AstLocal* var = i < local->vars.size ? local->vars.data[i] : nullptr;
2022-06-24 02:44:07 +01:00
2022-09-29 23:11:54 +01:00
if (var && var->annotation)
{
2022-11-04 17:02:37 +00:00
TypeId annotationType = lookupAnnotation(var->annotation);
2022-09-29 23:11:54 +01:00
TypeId valueType = value ? lookupType(value) : nullptr;
2022-11-04 17:02:37 +00:00
if (valueType)
{
2023-07-28 12:37:00 +01:00
reportErrors(tryUnify(stack.back(), value->location, valueType, annotationType));
2022-11-04 17:02:37 +00:00
}
2023-01-03 17:33:19 +00:00
visit(var->annotation);
2022-06-24 02:44:07 +01:00
}
}
2023-02-24 18:24:22 +00:00
else if (value)
2022-06-24 02:44:07 +01:00
{
2023-02-24 18:24:22 +00:00
TypePackId valuePack = lookupPack(value);
TypePack valueTypes;
if (i < local->vars.size)
valueTypes = extendTypePack(module->internalTypes, builtinTypes, valuePack, local->vars.size - i);
2022-06-24 02:44:07 +01:00
2023-02-24 18:24:22 +00:00
Location errorLocation;
2022-09-29 23:11:54 +01:00
for (size_t j = i; j < local->vars.size; ++j)
2022-06-24 02:44:07 +01:00
{
2023-02-24 18:24:22 +00:00
if (j - i >= valueTypes.head.size())
2022-06-24 02:44:07 +01:00
{
2023-02-24 18:24:22 +00:00
errorLocation = local->vars.data[j]->location;
2022-09-29 23:11:54 +01:00
break;
}
2023-01-27 21:28:45 +00:00
AstLocal* var = local->vars.data[j];
2022-09-29 23:11:54 +01:00
if (var->annotation)
{
TypeId varType = lookupAnnotation(var->annotation);
2023-07-28 12:37:00 +01:00
reportErrors(tryUnify(stack.back(), value->location, valueTypes.head[j - i], varType));
2023-01-03 17:33:19 +00:00
visit(var->annotation);
2022-06-24 02:44:07 +01:00
}
2023-02-24 18:24:22 +00:00
}
2022-09-29 23:11:54 +01:00
2023-02-24 18:24:22 +00:00
if (valueTypes.head.size() < local->vars.size - i)
{
reportError(
CountMismatch{
// We subtract 1 here because the final AST
// expression is not worth one value. It is worth 0
// or more depending on valueTypes.head
local->values.size - 1 + valueTypes.head.size(),
std::nullopt,
local->vars.size,
local->values.data[local->values.size - 1]->is<AstExprCall>() ? CountMismatch::FunctionResult
: CountMismatch::ExprListResult,
},
errorLocation);
2022-06-24 02:44:07 +01:00
}
}
}
2022-08-18 22:04:33 +01:00
}
void visit(AstStatFor* forStatement)
{
2023-02-03 12:34:12 +00:00
NotNull<Scope> scope = stack.back();
2022-08-18 22:04:33 +01:00
if (forStatement->var->annotation)
2023-02-03 12:34:12 +00:00
{
2022-08-18 22:04:33 +01:00
visit(forStatement->var->annotation);
2023-02-03 12:34:12 +00:00
reportErrors(tryUnify(scope, forStatement->var->location, builtinTypes->numberType, lookupAnnotation(forStatement->var->annotation)));
}
auto checkNumber = [this, scope](AstExpr* expr) {
if (!expr)
return;
2023-04-28 12:55:55 +01:00
visit(expr, ValueContext::RValue);
2023-02-03 12:34:12 +00:00
reportErrors(tryUnify(scope, expr->location, lookupType(expr), builtinTypes->numberType));
};
checkNumber(forStatement->from);
checkNumber(forStatement->to);
checkNumber(forStatement->step);
2022-08-18 22:04:33 +01:00
visit(forStatement->body);
}
void visit(AstStatForIn* forInStatement)
{
for (AstLocal* local : forInStatement->vars)
{
if (local->annotation)
visit(local->annotation);
}
for (AstExpr* expr : forInStatement->values)
2023-04-28 12:55:55 +01:00
visit(expr, ValueContext::RValue);
2022-06-24 02:44:07 +01:00
2022-08-18 22:04:33 +01:00
visit(forInStatement->body);
2022-09-02 00:00:14 +01:00
// Rule out crazy stuff. Maybe possible if the file is not syntactically valid.
if (!forInStatement->vars.size || !forInStatement->values.size)
return;
NotNull<Scope> scope = stack.back();
2023-01-03 17:33:19 +00:00
TypeArena& arena = testArena;
2022-09-02 00:00:14 +01:00
std::vector<TypeId> variableTypes;
for (AstLocal* var : forInStatement->vars)
{
std::optional<TypeId> ty = scope->lookup(var);
LUAU_ASSERT(ty);
variableTypes.emplace_back(*ty);
}
2023-05-25 21:46:51 +01:00
AstExpr* firstValue = forInStatement->values.data[0];
// we need to build up a typepack for the iterators/values portion of the for-in statement.
2022-09-02 00:00:14 +01:00
std::vector<TypeId> valueTypes;
2023-05-25 21:46:51 +01:00
std::optional<TypePackId> iteratorTail;
// since the first value may be the only iterator (e.g. if it is a call), we want to
// look to see if it has a resulting typepack as our iterators.
TypePackId* retPack = module->astTypePacks.find(firstValue);
if (retPack)
{
auto [head, tail] = flatten(*retPack);
valueTypes = head;
iteratorTail = tail;
}
else
{
valueTypes.emplace_back(lookupType(firstValue));
}
// if the initial and expected types from the iterator unified during constraint solving,
// we'll have a resolved type to use here, but we'll only use it if either the iterator is
// directly present in the for-in statement or if we have an iterator state constraining us
2023-06-24 06:33:44 +01:00
TypeId* resolvedTy = module->astForInNextTypes.find(firstValue);
2023-05-25 21:46:51 +01:00
if (resolvedTy && (!retPack || valueTypes.size() > 1))
valueTypes[0] = *resolvedTy;
for (size_t i = 1; i < forInStatement->values.size - 1; ++i)
{
2022-09-02 00:00:14 +01:00
valueTypes.emplace_back(lookupType(forInStatement->values.data[i]));
2023-05-25 21:46:51 +01:00
}
// if we had more than one value, the tail from the first value is no longer appropriate to use.
if (forInStatement->values.size > 1)
{
auto [head, tail] = flatten(lookupPack(forInStatement->values.data[forInStatement->values.size - 1]));
valueTypes.insert(valueTypes.end(), head.begin(), head.end());
iteratorTail = tail;
}
// and now we can put everything together to get the actual typepack of the iterators.
2022-09-15 23:13:58 +01:00
TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail);
2022-09-02 00:00:14 +01:00
// ... and then expand it out to 3 values (if possible)
2023-01-03 17:33:19 +00:00
TypePack iteratorTypes = extendTypePack(arena, builtinTypes, iteratorPack, 3);
2022-12-02 10:46:05 +00:00
if (iteratorTypes.head.empty())
2022-09-02 00:00:14 +01:00
{
reportError(GenericError{"for..in loops require at least one value to iterate over. Got zero"}, getLocation(forInStatement->values));
return;
}
2022-12-02 10:46:05 +00:00
TypeId iteratorTy = follow(iteratorTypes.head[0]);
2022-09-02 00:00:14 +01:00
2022-10-13 23:59:53 +01:00
auto checkFunction = [this, &arena, &scope, &forInStatement, &variableTypes](
2023-01-03 17:33:19 +00:00
const FunctionType* iterFtv, std::vector<TypeId> iterTys, bool isMm) {
2022-09-29 23:11:54 +01:00
if (iterTys.size() < 1 || iterTys.size() > 3)
{
if (isMm)
reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values));
else
reportError(GenericError{"for..in loops must be passed (next[, table[, state]])"}, getLocation(forInStatement->values));
2022-09-02 00:00:14 +01:00
2022-09-29 23:11:54 +01:00
return;
}
2022-10-13 23:59:53 +01:00
2022-09-02 00:00:14 +01:00
// It is okay if there aren't enough iterators, but the iteratee must provide enough.
2023-01-03 17:33:19 +00:00
TypePack expectedVariableTypes = extendTypePack(arena, builtinTypes, iterFtv->retTypes, variableTypes.size());
2022-12-02 10:46:05 +00:00
if (expectedVariableTypes.head.size() < variableTypes.size())
2022-09-29 23:11:54 +01:00
{
if (isMm)
2022-10-13 23:59:53 +01:00
reportError(
GenericError{"__iter metamethod's next() function does not return enough values"}, getLocation(forInStatement->values));
2022-09-29 23:11:54 +01:00
else
reportError(GenericError{"next() does not return enough values"}, forInStatement->values.data[0]->location);
}
2022-09-02 00:00:14 +01:00
2022-12-02 10:46:05 +00:00
for (size_t i = 0; i < std::min(expectedVariableTypes.head.size(), variableTypes.size()); ++i)
reportErrors(tryUnify(scope, forInStatement->vars.data[i]->location, variableTypes[i], expectedVariableTypes.head[i]));
2022-10-13 23:59:53 +01:00
2022-09-02 00:00:14 +01:00
// nextFn is going to be invoked with (arrayTy, startIndexTy)
// It will be passed two arguments on every iteration save the
// first.
// It may be invoked with 0 or 1 argument on the first iteration.
// This depends on the types in iterateePack and therefore
// iteratorTypes.
2023-05-25 21:46:51 +01:00
// If the iteratee is an error type, then we can't really say anything else about iteration over it.
// After all, it _could've_ been a table.
if (get<ErrorType>(follow(flattenPack(iterFtv->argTypes))))
return;
2022-09-02 00:00:14 +01:00
// If iteratorTypes is too short to be a valid call to nextFn, we have to report a count mismatch error.
// If 2 is too short to be a valid call to nextFn, we have to report a count mismatch error.
// If 2 is too long to be a valid call to nextFn, we have to report a count mismatch error.
2022-09-29 23:11:54 +01:00
auto [minCount, maxCount] = getParameterExtents(TxnLog::empty(), iterFtv->argTypes, /*includeHiddenVariadics*/ true);
2022-09-02 00:00:14 +01:00
2023-01-03 17:33:19 +00:00
TypePack flattenedArgTypes = extendTypePack(arena, builtinTypes, iterFtv->argTypes, 2);
2022-09-29 23:11:54 +01:00
size_t firstIterationArgCount = iterTys.empty() ? 0 : iterTys.size() - 1;
2022-12-02 10:46:05 +00:00
size_t actualArgCount = expectedVariableTypes.head.size();
2022-09-02 00:00:14 +01:00
if (firstIterationArgCount < minCount)
2023-05-05 20:57:12 +01:00
{
if (isMm)
reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values));
else
2023-05-25 21:46:51 +01:00
reportError(CountMismatch{2, std::nullopt, firstIterationArgCount, CountMismatch::Arg}, forInStatement->values.data[0]->location);
2023-05-05 20:57:12 +01:00
}
2022-09-02 00:00:14 +01:00
else if (actualArgCount < minCount)
2023-05-05 20:57:12 +01:00
{
if (isMm)
reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values));
else
2023-05-25 21:46:51 +01:00
reportError(CountMismatch{2, std::nullopt, firstIterationArgCount, CountMismatch::Arg}, forInStatement->values.data[0]->location);
2023-05-05 20:57:12 +01:00
}
2022-09-02 00:00:14 +01:00
2022-12-02 10:46:05 +00:00
if (iterTys.size() >= 2 && flattenedArgTypes.head.size() > 0)
2022-09-02 00:00:14 +01:00
{
size_t valueIndex = forInStatement->values.size > 1 ? 1 : 0;
2022-12-02 10:46:05 +00:00
reportErrors(tryUnify(scope, forInStatement->values.data[valueIndex]->location, iterTys[1], flattenedArgTypes.head[0]));
2022-09-02 00:00:14 +01:00
}
2022-12-02 10:46:05 +00:00
if (iterTys.size() == 3 && flattenedArgTypes.head.size() > 1)
2022-09-02 00:00:14 +01:00
{
size_t valueIndex = forInStatement->values.size > 2 ? 2 : 0;
2022-12-02 10:46:05 +00:00
reportErrors(tryUnify(scope, forInStatement->values.data[valueIndex]->location, iterTys[2], flattenedArgTypes.head[1]));
2022-09-02 00:00:14 +01:00
}
2022-09-29 23:11:54 +01:00
};
2023-07-28 12:37:00 +01:00
const NormalizedType* iteratorNorm = normalizer.normalize(iteratorTy);
if (!iteratorNorm)
reportError(NormalizationTooComplex{}, firstValue->location);
2022-09-29 23:11:54 +01:00
/*
* If the first iterator argument is a function
* * There must be 1 to 3 iterator arguments. Name them (nextTy,
* arrayTy, startIndexTy)
* * The return type of nextTy() must correspond to the variables'
* types and counts. HOWEVER the first iterator will never be nil.
* * The first return value of nextTy must be compatible with
* startIndexTy.
* * The first argument to nextTy() must be compatible with arrayTy if
* present. nil if not.
* * The second argument to nextTy() must be compatible with
* startIndexTy if it is present. Else, it must be compatible with
* nil.
* * nextTy() must be callable with only 2 arguments.
*/
2023-01-03 17:33:19 +00:00
if (const FunctionType* nextFn = get<FunctionType>(iteratorTy))
2022-09-29 23:11:54 +01:00
{
2022-12-02 10:46:05 +00:00
checkFunction(nextFn, iteratorTypes.head, false);
2022-09-02 00:00:14 +01:00
}
2023-01-03 17:33:19 +00:00
else if (const TableType* ttv = get<TableType>(iteratorTy))
2022-09-02 00:00:14 +01:00
{
if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer)
{
reportErrors(tryUnify(scope, forInStatement->vars.data[0]->location, variableTypes[0], ttv->indexer->indexType));
if (variableTypes.size() == 2)
reportErrors(tryUnify(scope, forInStatement->vars.data[1]->location, variableTypes[1], ttv->indexer->indexResultType));
}
else
reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location);
}
2023-02-03 12:34:12 +00:00
else if (get<AnyType>(iteratorTy) || get<ErrorType>(iteratorTy) || get<NeverType>(iteratorTy))
2022-09-02 00:00:14 +01:00
{
// nothing
}
2023-07-28 12:37:00 +01:00
else if (isOptional(iteratorTy) && !(iteratorNorm && iteratorNorm->shouldSuppressErrors()))
2023-03-24 17:34:14 +00:00
{
reportError(OptionalValueAccess{iteratorTy}, forInStatement->values.data[0]->location);
}
2022-10-13 23:59:53 +01:00
else if (std::optional<TypeId> iterMmTy =
2023-01-03 17:33:19 +00:00
findMetatableEntry(builtinTypes, module->errors, iteratorTy, "__iter", forInStatement->values.data[0]->location))
2022-09-29 23:11:54 +01:00
{
Instantiation instantiation{TxnLog::empty(), &arena, TypeLevel{}, scope};
if (std::optional<TypeId> instantiatedIterMmTy = instantiation.substitute(*iterMmTy))
{
2023-01-03 17:33:19 +00:00
if (const FunctionType* iterMmFtv = get<FunctionType>(*instantiatedIterMmTy))
2022-09-29 23:11:54 +01:00
{
TypePackId argPack = arena.addTypePack({iteratorTy});
reportErrors(tryUnify(scope, forInStatement->values.data[0]->location, argPack, iterMmFtv->argTypes));
2023-01-03 17:33:19 +00:00
TypePack mmIteratorTypes = extendTypePack(arena, builtinTypes, iterMmFtv->retTypes, 3);
2022-09-29 23:11:54 +01:00
2022-12-02 10:46:05 +00:00
if (mmIteratorTypes.head.size() == 0)
2022-09-29 23:11:54 +01:00
{
reportError(GenericError{"__iter must return at least one value"}, forInStatement->values.data[0]->location);
return;
}
2022-12-02 10:46:05 +00:00
TypeId nextFn = follow(mmIteratorTypes.head[0]);
2022-09-29 23:11:54 +01:00
if (std::optional<TypeId> instantiatedNextFn = instantiation.substitute(nextFn))
{
2022-12-02 10:46:05 +00:00
std::vector<TypeId> instantiatedIteratorTypes = mmIteratorTypes.head;
2022-09-29 23:11:54 +01:00
instantiatedIteratorTypes[0] = *instantiatedNextFn;
2023-01-03 17:33:19 +00:00
if (const FunctionType* nextFtv = get<FunctionType>(*instantiatedNextFn))
2022-09-29 23:11:54 +01:00
{
checkFunction(nextFtv, instantiatedIteratorTypes, true);
}
2023-07-28 12:37:00 +01:00
else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *instantiatedNextFn))
2022-09-29 23:11:54 +01:00
{
reportError(CannotCallNonFunction{*instantiatedNextFn}, forInStatement->values.data[0]->location);
}
}
else
{
reportError(UnificationTooComplex{}, forInStatement->values.data[0]->location);
}
}
2023-07-28 12:37:00 +01:00
else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *iterMmTy))
2022-09-29 23:11:54 +01:00
{
// TODO: This will not tell the user that this is because the
// metamethod isn't callable. This is not ideal, and we should
// improve this error message.
2022-10-13 23:59:53 +01:00
2022-09-29 23:11:54 +01:00
// TODO: This will also not handle intersections of functions or
// callable tables (which are supported by the runtime).
reportError(CannotCallNonFunction{*iterMmTy}, forInStatement->values.data[0]->location);
}
}
else
{
reportError(UnificationTooComplex{}, forInStatement->values.data[0]->location);
}
}
2023-07-28 12:37:00 +01:00
else if (iteratorNorm && iteratorNorm->hasTopTable())
{
// nothing
}
else if (!iteratorNorm || !iteratorNorm->shouldSuppressErrors())
2022-09-02 00:00:14 +01:00
{
reportError(CannotCallNonFunction{iteratorTy}, forInStatement->values.data[0]->location);
}
2022-06-24 02:44:07 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstStatAssign* assign)
2022-06-17 01:54:42 +01:00
{
size_t count = std::min(assign->vars.size, assign->values.size);
for (size_t i = 0; i < count; ++i)
{
AstExpr* lhs = assign->vars.data[i];
2023-04-28 12:55:55 +01:00
visit(lhs, ValueContext::LValue);
2022-07-01 00:29:02 +01:00
TypeId lhsType = lookupType(lhs);
2022-06-17 01:54:42 +01:00
AstExpr* rhs = assign->values.data[i];
2023-04-28 12:55:55 +01:00
visit(rhs, ValueContext::RValue);
2022-07-01 00:29:02 +01:00
TypeId rhsType = lookupType(rhs);
2022-06-17 01:54:42 +01:00
2023-02-03 12:34:12 +00:00
if (get<NeverType>(lhsType))
continue;
2023-07-28 12:37:00 +01:00
if (!isSubtype(rhsType, lhsType, stack.back()) &&
!isErrorSuppressing(assign->vars.data[i]->location, lhsType, assign->values.data[i]->location, rhsType))
2022-06-17 01:54:42 +01:00
{
2022-07-01 00:29:02 +01:00
reportError(TypeMismatch{lhsType, rhsType}, rhs->location);
2022-06-17 01:54:42 +01:00
}
}
2022-08-18 22:04:33 +01:00
}
2022-06-17 01:54:42 +01:00
2022-08-18 22:04:33 +01:00
void visit(AstStatCompoundAssign* stat)
{
2023-01-06 16:07:19 +00:00
AstExprBinary fake{stat->location, stat->op, stat->var, stat->value};
TypeId resultTy = visit(&fake, stat);
TypeId varTy = lookupType(stat->var);
reportErrors(tryUnify(stack.back(), stat->location, resultTy, varTy));
2022-06-17 01:54:42 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstStatFunction* stat)
2022-06-24 02:44:07 +01:00
{
2023-04-28 12:55:55 +01:00
visit(stat->name, ValueContext::LValue);
2022-08-18 22:04:33 +01:00
visit(stat->func);
}
2022-06-24 02:44:07 +01:00
2022-08-18 22:04:33 +01:00
void visit(AstStatLocalFunction* stat)
{
visit(stat->func);
}
2022-06-24 02:44:07 +01:00
2022-08-18 22:04:33 +01:00
void visit(const AstTypeList* typeList)
{
for (AstType* ty : typeList->types)
visit(ty);
2022-06-24 02:44:07 +01:00
2022-08-18 22:04:33 +01:00
if (typeList->tailType)
visit(typeList->tailType);
}
2022-06-24 02:44:07 +01:00
2022-08-18 22:04:33 +01:00
void visit(AstStatTypeAlias* stat)
{
2023-02-17 14:53:37 +00:00
visitGenerics(stat->generics, stat->genericPacks);
2022-08-18 22:04:33 +01:00
visit(stat->type);
}
void visit(AstTypeList types)
{
for (AstType* type : types.types)
visit(type);
if (types.tailType)
visit(types.tailType);
}
void visit(AstStatDeclareFunction* stat)
{
2023-02-17 14:53:37 +00:00
visitGenerics(stat->generics, stat->genericPacks);
2022-08-18 22:04:33 +01:00
visit(stat->params);
visit(stat->retTypes);
}
void visit(AstStatDeclareGlobal* stat)
{
visit(stat->type);
}
void visit(AstStatDeclareClass* stat)
{
for (const AstDeclaredClassProp& prop : stat->props)
visit(prop.ty);
}
void visit(AstStatError* stat)
{
for (AstExpr* expr : stat->expressions)
2023-04-28 12:55:55 +01:00
visit(expr, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
for (AstStat* s : stat->statements)
visit(s);
}
2023-01-20 12:02:39 +00:00
void visit(AstExpr* expr, ValueContext context)
2022-08-18 22:04:33 +01:00
{
auto StackPusher = pushStack(expr);
2023-02-03 12:34:12 +00:00
if (auto e = expr->as<AstExprGroup>())
2023-01-20 12:02:39 +00:00
return visit(e, context);
2022-08-18 22:04:33 +01:00
else if (auto e = expr->as<AstExprConstantNil>())
return visit(e);
else if (auto e = expr->as<AstExprConstantBool>())
return visit(e);
else if (auto e = expr->as<AstExprConstantNumber>())
return visit(e);
else if (auto e = expr->as<AstExprConstantString>())
return visit(e);
else if (auto e = expr->as<AstExprLocal>())
return visit(e);
else if (auto e = expr->as<AstExprGlobal>())
return visit(e);
else if (auto e = expr->as<AstExprVarargs>())
return visit(e);
else if (auto e = expr->as<AstExprCall>())
return visit(e);
else if (auto e = expr->as<AstExprIndexName>())
2023-01-20 12:02:39 +00:00
return visit(e, context);
2022-08-18 22:04:33 +01:00
else if (auto e = expr->as<AstExprIndexExpr>())
2023-01-20 12:02:39 +00:00
return visit(e, context);
2022-08-18 22:04:33 +01:00
else if (auto e = expr->as<AstExprFunction>())
return visit(e);
else if (auto e = expr->as<AstExprTable>())
return visit(e);
else if (auto e = expr->as<AstExprUnary>())
return visit(e);
else if (auto e = expr->as<AstExprBinary>())
2023-01-06 16:07:19 +00:00
{
visit(e);
return;
}
2022-08-18 22:04:33 +01:00
else if (auto e = expr->as<AstExprTypeAssertion>())
return visit(e);
else if (auto e = expr->as<AstExprIfElse>())
return visit(e);
2023-01-27 21:28:45 +00:00
else if (auto e = expr->as<AstExprInterpString>())
return visit(e);
2022-08-18 22:04:33 +01:00
else if (auto e = expr->as<AstExprError>())
return visit(e);
else
LUAU_ASSERT(!"TypeChecker2 encountered an unknown expression type");
}
2023-01-20 12:02:39 +00:00
void visit(AstExprGroup* expr, ValueContext context)
2022-08-18 22:04:33 +01:00
{
2023-01-20 12:02:39 +00:00
visit(expr->expr, context);
2022-08-18 22:04:33 +01:00
}
void visit(AstExprConstantNil* expr)
{
2023-02-03 12:34:12 +00:00
NotNull<Scope> scope = stack.back();
TypeId actualType = lookupType(expr);
TypeId expectedType = builtinTypes->nilType;
LUAU_ASSERT(isSubtype(actualType, expectedType, scope));
2022-08-18 22:04:33 +01:00
}
void visit(AstExprConstantBool* expr)
{
2023-02-03 12:34:12 +00:00
NotNull<Scope> scope = stack.back();
TypeId actualType = lookupType(expr);
TypeId expectedType = builtinTypes->booleanType;
LUAU_ASSERT(isSubtype(actualType, expectedType, scope));
2022-08-18 22:04:33 +01:00
}
2023-02-03 12:34:12 +00:00
void visit(AstExprConstantNumber* expr)
2022-08-18 22:04:33 +01:00
{
2023-02-03 12:34:12 +00:00
NotNull<Scope> scope = stack.back();
TypeId actualType = lookupType(expr);
TypeId expectedType = builtinTypes->numberType;
LUAU_ASSERT(isSubtype(actualType, expectedType, scope));
2022-08-18 22:04:33 +01:00
}
2023-02-03 12:34:12 +00:00
void visit(AstExprConstantString* expr)
2022-08-18 22:04:33 +01:00
{
2023-02-03 12:34:12 +00:00
NotNull<Scope> scope = stack.back();
TypeId actualType = lookupType(expr);
TypeId expectedType = builtinTypes->stringType;
LUAU_ASSERT(isSubtype(actualType, expectedType, scope));
2022-08-18 22:04:33 +01:00
}
void visit(AstExprLocal* expr)
{
// TODO!
}
2022-06-24 02:44:07 +01:00
2022-08-18 22:04:33 +01:00
void visit(AstExprGlobal* expr)
{
// TODO!
}
void visit(AstExprVarargs* expr)
{
// TODO!
2022-06-24 02:44:07 +01:00
}
2023-03-03 13:45:38 +00:00
// Note: this is intentionally separated from `visit(AstExprCall*)` for stack allocation purposes.
void visitCall(AstExprCall* call)
2022-06-17 01:54:42 +01:00
{
2022-10-21 18:33:43 +01:00
TypePack args;
2023-07-28 12:37:00 +01:00
std::vector<AstExpr*> argExprs;
argExprs.reserve(call->args.size + 1);
2022-06-17 01:54:42 +01:00
2023-06-24 06:33:44 +01:00
TypeId* originalCallTy = module->astOriginalCallTypes.find(call);
TypeId* selectedOverloadTy = module->astOverloadResolvedTypes.find(call);
if (!originalCallTy && !selectedOverloadTy)
2023-05-05 20:57:12 +01:00
return;
2023-06-24 06:33:44 +01:00
TypeId fnTy = follow(selectedOverloadTy ? *selectedOverloadTy : *originalCallTy);
if (get<AnyType>(fnTy) || get<ErrorType>(fnTy) || get<NeverType>(fnTy))
2022-09-02 00:00:14 +01:00
return;
2023-06-24 06:33:44 +01:00
else if (isOptional(fnTy))
2022-09-02 00:00:14 +01:00
{
2023-06-24 06:33:44 +01:00
reportError(OptionalValueAccess{fnTy}, call->func->location);
2022-09-02 00:00:14 +01:00
return;
}
2022-11-18 18:45:14 +00:00
if (call->self)
{
AstExprIndexName* indexExpr = call->func->as<AstExprIndexName>();
if (!indexExpr)
2023-04-21 22:41:03 +01:00
ice->ice("method call expression has no 'self'");
2022-11-18 18:45:14 +00:00
2022-12-02 10:46:05 +00:00
args.head.push_back(lookupType(indexExpr->expr));
2023-07-28 12:37:00 +01:00
argExprs.push_back(indexExpr->expr);
2022-12-02 10:46:05 +00:00
}
2023-07-07 18:14:35 +01:00
else if (findMetatableEntry(builtinTypes, module->errors, *originalCallTy, "__call", call->func->location))
{
args.head.insert(args.head.begin(), lookupType(call->func));
2023-07-28 12:37:00 +01:00
argExprs.push_back(call->func);
2023-07-07 18:14:35 +01:00
}
2022-12-02 10:46:05 +00:00
for (size_t i = 0; i < call->args.size; ++i)
{
AstExpr* arg = call->args.data[i];
2023-07-28 12:37:00 +01:00
argExprs.push_back(arg);
2022-12-02 10:46:05 +00:00
TypeId* argTy = module->astTypes.find(arg);
if (argTy)
args.head.push_back(*argTy);
else if (i == call->args.size - 1)
{
2023-06-24 06:33:44 +01:00
if (auto argTail = module->astTypePacks.find(arg))
{
auto [head, tail] = flatten(*argTail);
args.head.insert(args.head.end(), head.begin(), head.end());
args.tail = tail;
}
2022-12-02 10:46:05 +00:00
else
2023-01-03 17:33:19 +00:00
args.tail = builtinTypes->anyTypePack;
2022-12-02 10:46:05 +00:00
}
else
2023-01-03 17:33:19 +00:00
args.head.push_back(builtinTypes->anyType);
2022-11-18 18:45:14 +00:00
}
2023-06-24 06:33:44 +01:00
FunctionCallResolver resolver{
builtinTypes,
NotNull{&testArena},
NotNull{&normalizer},
NotNull{stack.back()},
ice,
call->location,
};
2023-07-28 12:37:00 +01:00
resolver.resolve(fnTy, &args, call->func, &argExprs);
auto norm = normalizer.normalize(fnTy);
if (!norm)
reportError(NormalizationTooComplex{}, call->func->location);
2023-01-20 12:02:39 +00:00
2023-07-28 12:37:00 +01:00
if (norm && norm->shouldSuppressErrors())
return; // error suppressing function type!
else if (!resolver.ok.empty())
2023-06-24 06:33:44 +01:00
return; // We found a call that works, so this is ok.
2023-07-28 12:37:00 +01:00
else if (!norm || !normalizer.isInhabited(norm))
return; // Ok. Calling an uninhabited type is no-op.
2023-06-24 06:33:44 +01:00
else if (!resolver.nonviableOverloads.empty())
{
2023-07-28 12:37:00 +01:00
if (resolver.nonviableOverloads.size() == 1 && !isErrorSuppressing(call->func->location, resolver.nonviableOverloads.front().first))
2023-06-24 06:33:44 +01:00
reportErrors(resolver.nonviableOverloads.front().second);
else
{
std::string s = "None of the overloads for function that accept ";
s += std::to_string(args.head.size());
s += " arguments are compatible.";
reportError(GenericError{std::move(s)}, call->location);
}
}
else if (!resolver.arityMismatches.empty())
{
if (resolver.arityMismatches.size() == 1)
reportErrors(resolver.arityMismatches.front().second);
else
{
std::string s = "No overload for function accepts ";
s += std::to_string(args.head.size());
s += " arguments.";
reportError(GenericError{std::move(s)}, call->location);
}
}
else if (!resolver.nonFunctions.empty())
reportError(CannotCallNonFunction{fnTy}, call->func->location);
else
LUAU_ASSERT(!"Generating the best possible error from this function call resolution was inexhaustive?");
2023-01-20 12:02:39 +00:00
2023-06-24 06:33:44 +01:00
if (resolver.arityMismatches.size() > 1 || resolver.nonviableOverloads.size() > 1)
{
std::string s = "Available overloads: ";
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
std::vector<TypeId> overloads;
if (resolver.nonviableOverloads.empty())
2023-02-24 18:24:22 +00:00
{
2023-06-24 06:33:44 +01:00
for (const auto& [ty, p] : resolver.resolution)
{
if (p.first == FunctionCallResolver::TypeIsNotAFunction)
continue;
overloads.push_back(ty);
}
2023-02-24 18:24:22 +00:00
}
2023-06-24 06:33:44 +01:00
else
2023-05-05 20:57:12 +01:00
{
2023-06-24 06:33:44 +01:00
for (const auto& [ty, _] : resolver.nonviableOverloads)
overloads.push_back(ty);
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
for (size_t i = 0; i < overloads.size(); ++i)
2023-02-24 18:24:22 +00:00
{
2023-06-24 06:33:44 +01:00
if (i > 0)
s += (i == overloads.size() - 1) ? "; and " : "; ";
s += toString(overloads[i]);
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
reportError(ExtraInformation{std::move(s)}, call->func->location);
}
}
2023-05-12 13:15:01 +01:00
2023-06-24 06:33:44 +01:00
struct FunctionCallResolver
{
enum Analysis
{
Ok,
TypeIsNotAFunction,
ArityMismatch,
OverloadIsNonviable, // Arguments were incompatible with the overload's parameters, but were otherwise compatible by arity.
};
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
NotNull<BuiltinTypes> builtinTypes;
NotNull<TypeArena> arena;
NotNull<Normalizer> normalizer;
NotNull<Scope> scope;
NotNull<InternalErrorReporter> ice;
Location callLoc;
std::vector<TypeId> ok;
std::vector<TypeId> nonFunctions;
std::vector<std::pair<TypeId, ErrorVec>> arityMismatches;
std::vector<std::pair<TypeId, ErrorVec>> nonviableOverloads;
InsertionOrderedMap<TypeId, std::pair<Analysis, size_t>> resolution;
private:
2023-07-28 12:37:00 +01:00
std::optional<ErrorVec> tryUnify(const Location& location, TypeId subTy, TypeId superTy, const LiteralProperties* literalProperties = nullptr)
{
Unifier u{normalizer, scope, location, Covariant};
u.ctx = CountMismatch::Arg;
u.hideousFixMeGenericsAreActuallyFree = true;
u.enableNewSolver();
u.tryUnify(subTy, superTy, /*isFunctionCall*/ false, /*isIntersection*/ false, literalProperties);
if (u.errors.empty())
return std::nullopt;
return std::move(u.errors);
}
std::optional<ErrorVec> tryUnify(const Location& location, TypePackId subTy, TypePackId superTy)
2023-06-24 06:33:44 +01:00
{
Unifier u{normalizer, scope, location, Covariant};
u.ctx = CountMismatch::Arg;
u.hideousFixMeGenericsAreActuallyFree = true;
2023-07-28 12:37:00 +01:00
u.enableNewSolver();
2023-06-24 06:33:44 +01:00
u.tryUnify(subTy, superTy);
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
if (u.errors.empty())
return std::nullopt;
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
return std::move(u.errors);
}
2023-05-05 20:57:12 +01:00
2023-07-14 16:57:16 +01:00
std::pair<Analysis, ErrorVec> checkOverload(
2023-07-28 12:37:00 +01:00
TypeId fnTy, const TypePack* args, AstExpr* fnLoc, const std::vector<AstExpr*>* argExprs, bool callMetamethodOk = true)
2023-06-24 06:33:44 +01:00
{
fnTy = follow(fnTy);
ErrorVec discard;
if (get<AnyType>(fnTy) || get<ErrorType>(fnTy) || get<NeverType>(fnTy))
return {Ok, {}};
else if (auto fn = get<FunctionType>(fnTy))
2023-07-28 12:37:00 +01:00
return checkOverload_(fnTy, fn, args, fnLoc, argExprs); // Intentionally split to reduce the stack pressure of this function.
2023-06-24 06:33:44 +01:00
else if (auto callMm = findMetatableEntry(builtinTypes, discard, fnTy, "__call", callLoc); callMm && callMetamethodOk)
{
// Calling a metamethod forwards the `fnTy` as self.
TypePack withSelf = *args;
withSelf.head.insert(withSelf.head.begin(), fnTy);
2023-07-28 12:37:00 +01:00
std::vector<AstExpr*> withSelfExprs = *argExprs;
withSelfExprs.insert(withSelfExprs.begin(), fnLoc);
2023-05-05 20:57:12 +01:00
2023-07-28 12:37:00 +01:00
return checkOverload(*callMm, &withSelf, fnLoc, &withSelfExprs, /*callMetamethodOk=*/false);
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
else
return {TypeIsNotAFunction, {}}; // Intentionally empty. We can just fabricate the type error later on.
}
2023-07-28 12:37:00 +01:00
static bool isLiteral(AstExpr* expr)
{
if (auto group = expr->as<AstExprGroup>())
return isLiteral(group->expr);
else if (auto assertion = expr->as<AstExprTypeAssertion>())
return isLiteral(assertion->expr);
return
expr->is<AstExprConstantNil>() ||
expr->is<AstExprConstantBool>() ||
expr->is<AstExprConstantNumber>() ||
expr->is<AstExprConstantString>() ||
expr->is<AstExprFunction>() ||
expr->is<AstExprTable>();
}
static std::unique_ptr<LiteralProperties> buildLiteralPropertiesSet(AstExpr* expr)
{
const AstExprTable* table = expr->as<AstExprTable>();
if (!table)
return nullptr;
std::unique_ptr<LiteralProperties> result = std::make_unique<LiteralProperties>(Name{});
for (const AstExprTable::Item& item : table->items)
{
if (item.kind != AstExprTable::Item::Record)
continue;
AstExprConstantString* keyExpr = item.key->as<AstExprConstantString>();
LUAU_ASSERT(keyExpr);
if (isLiteral(item.value))
result->insert(Name{keyExpr->value.begin(), keyExpr->value.end()});
}
return result;
}
2023-06-24 06:33:44 +01:00
LUAU_NOINLINE
2023-07-14 16:57:16 +01:00
std::pair<Analysis, ErrorVec> checkOverload_(
2023-07-28 12:37:00 +01:00
TypeId fnTy, const FunctionType* fn, const TypePack* args, AstExpr* fnExpr, const std::vector<AstExpr*>* argExprs)
2023-06-24 06:33:44 +01:00
{
TxnLog fake;
2023-07-14 16:57:16 +01:00
FamilyGraphReductionResult result = reduceFamilies(fnTy, callLoc, arena, builtinTypes, scope, normalizer, &fake, /*force=*/true);
2023-06-24 06:33:44 +01:00
if (!result.errors.empty())
return {OverloadIsNonviable, result.errors};
ErrorVec argumentErrors;
// Reminder: Functions have parameters. You provide arguments.
auto paramIter = begin(fn->argTypes);
size_t argOffset = 0;
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
while (paramIter != end(fn->argTypes))
2023-05-05 20:57:12 +01:00
{
2023-06-24 06:33:44 +01:00
if (argOffset >= args->head.size())
break;
TypeId paramTy = *paramIter;
TypeId argTy = args->head[argOffset];
2023-07-28 12:37:00 +01:00
AstExpr* argLoc = argExprs->at(argOffset >= argExprs->size() ? argExprs->size() - 1 : argOffset);
std::unique_ptr<LiteralProperties> literalProperties{buildLiteralPropertiesSet(argLoc)};
2023-06-24 06:33:44 +01:00
2023-07-28 12:37:00 +01:00
if (auto errors = tryUnify(argLoc->location, argTy, paramTy, literalProperties.get()))
2023-02-24 18:24:22 +00:00
{
2023-06-24 06:33:44 +01:00
// Since we're stopping right here, we need to decide if this is a nonviable overload or if there is an arity mismatch.
// If it's a nonviable overload, then we need to keep going to get all type errors.
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes);
if (args->head.size() < minParams)
return {ArityMismatch, *errors};
else
argumentErrors.insert(argumentErrors.end(), errors->begin(), errors->end());
2023-02-24 18:24:22 +00:00
}
2023-06-24 06:33:44 +01:00
++paramIter;
++argOffset;
2023-02-24 18:24:22 +00:00
}
2023-06-24 06:33:44 +01:00
while (argOffset < args->head.size())
2023-02-24 18:24:22 +00:00
{
2023-06-24 06:33:44 +01:00
// If we can iterate over the head of arguments, then we have exhausted the head of the parameters.
LUAU_ASSERT(paramIter == end(fn->argTypes));
2023-07-28 12:37:00 +01:00
AstExpr* argExpr = argExprs->at(argOffset >= argExprs->size() ? argExprs->size() - 1 : argOffset);
2023-06-24 06:33:44 +01:00
if (!paramIter.tail())
2023-05-05 20:57:12 +01:00
{
2023-06-24 06:33:44 +01:00
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes);
2023-07-28 12:37:00 +01:00
TypeError error{argExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, false}};
2023-06-24 06:33:44 +01:00
return {ArityMismatch, {error}};
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
else if (auto vtp = get<VariadicTypePack>(follow(paramIter.tail())))
2023-02-24 18:24:22 +00:00
{
2023-07-28 12:37:00 +01:00
if (auto errors = tryUnify(argExpr->location, args->head[argOffset], vtp->ty))
2023-06-24 06:33:44 +01:00
argumentErrors.insert(argumentErrors.end(), errors->begin(), errors->end());
2023-02-24 18:24:22 +00:00
}
2023-07-28 12:37:00 +01:00
else if (get<GenericTypePack>(follow(paramIter.tail())))
argumentErrors.push_back(TypeError{argExpr->location, TypePackMismatch{fn->argTypes, arena->addTypePack(*args)}});
2023-06-24 06:33:44 +01:00
++argOffset;
2023-02-24 18:24:22 +00:00
}
2023-01-20 12:02:39 +00:00
2023-06-24 06:33:44 +01:00
while (paramIter != end(fn->argTypes))
2023-05-05 20:57:12 +01:00
{
2023-06-24 06:33:44 +01:00
// If we can iterate over parameters, then we have exhausted the head of the arguments.
LUAU_ASSERT(argOffset == args->head.size());
// It may have a tail, however, so check that.
if (auto vtp = get<VariadicTypePack>(follow(args->tail)))
{
2023-07-28 12:37:00 +01:00
AstExpr* argExpr = argExprs->at(argExprs->size() - 1);
2023-06-24 06:33:44 +01:00
2023-07-28 12:37:00 +01:00
if (auto errors = tryUnify(argExpr->location, vtp->ty, *paramIter))
2023-06-24 06:33:44 +01:00
argumentErrors.insert(argumentErrors.end(), errors->begin(), errors->end());
}
else if (!isOptional(*paramIter))
{
2023-07-28 12:37:00 +01:00
AstExpr* argExpr = argExprs->empty() ? fnExpr : argExprs->at(argExprs->size() - 1);
2023-06-24 06:33:44 +01:00
// It is ok to have excess parameters as long as they are all optional.
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes);
2023-07-28 12:37:00 +01:00
TypeError error{argExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, false}};
2023-06-24 06:33:44 +01:00
return {ArityMismatch, {error}};
}
++paramIter;
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
// We hit the end of the heads for both parameters and arguments, so check their tails.
LUAU_ASSERT(paramIter == end(fn->argTypes));
LUAU_ASSERT(argOffset == args->head.size());
2023-07-28 12:37:00 +01:00
const Location argLoc = argExprs->empty() ? Location{} // TODO
: argExprs->at(argExprs->size() - 1)->location;
2023-06-24 06:33:44 +01:00
if (paramIter.tail() && args->tail)
2023-05-05 20:57:12 +01:00
{
2023-06-24 06:33:44 +01:00
if (auto errors = tryUnify(argLoc, *args->tail, *paramIter.tail()))
argumentErrors.insert(argumentErrors.end(), errors->begin(), errors->end());
2023-05-05 20:57:12 +01:00
}
2023-07-28 12:37:00 +01:00
else if (paramIter.tail())
{
const TypePackId paramTail = follow(*paramIter.tail());
if (get<GenericTypePack>(paramTail))
{
argumentErrors.push_back(TypeError{argLoc, TypePackMismatch{fn->argTypes, arena->addTypePack(*args)}});
}
else if (get<VariadicTypePack>(paramTail))
{
// Nothing. This is ok.
}
}
2023-02-24 18:24:22 +00:00
2023-06-24 06:33:44 +01:00
return {argumentErrors.empty() ? Ok : OverloadIsNonviable, argumentErrors};
}
size_t indexof(Analysis analysis)
{
switch (analysis)
2023-05-05 20:57:12 +01:00
{
2023-06-24 06:33:44 +01:00
case Ok:
return ok.size();
case TypeIsNotAFunction:
return nonFunctions.size();
case ArityMismatch:
return arityMismatches.size();
case OverloadIsNonviable:
return nonviableOverloads.size();
}
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
ice->ice("Inexhaustive switch in FunctionCallResolver::indexof");
}
2023-02-24 18:24:22 +00:00
2023-06-24 06:33:44 +01:00
void add(Analysis analysis, TypeId ty, ErrorVec&& errors)
{
resolution.insert(ty, {analysis, indexof(analysis)});
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
switch (analysis)
{
case Ok:
LUAU_ASSERT(errors.empty());
ok.push_back(ty);
break;
case TypeIsNotAFunction:
LUAU_ASSERT(errors.empty());
nonFunctions.push_back(ty);
break;
case ArityMismatch:
LUAU_ASSERT(!errors.empty());
arityMismatches.emplace_back(ty, std::move(errors));
break;
case OverloadIsNonviable:
LUAU_ASSERT(!errors.empty());
nonviableOverloads.emplace_back(ty, std::move(errors));
break;
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
}
public:
2023-07-28 12:37:00 +01:00
void resolve(TypeId fnTy, const TypePack* args, AstExpr* selfExpr, const std::vector<AstExpr*>* argExprs)
2023-06-24 06:33:44 +01:00
{
fnTy = follow(fnTy);
2023-05-05 20:57:12 +01:00
2023-06-24 06:33:44 +01:00
auto it = get<IntersectionType>(fnTy);
if (!it)
{
2023-07-28 12:37:00 +01:00
auto [analysis, errors] = checkOverload(fnTy, args, selfExpr, argExprs);
2023-06-24 06:33:44 +01:00
add(analysis, fnTy, std::move(errors));
return;
}
for (TypeId ty : it)
{
if (resolution.find(ty) != resolution.end())
continue;
2023-07-28 12:37:00 +01:00
auto [analysis, errors] = checkOverload(ty, args, selfExpr, argExprs);
2023-06-24 06:33:44 +01:00
add(analysis, ty, std::move(errors));
}
2023-05-05 20:57:12 +01:00
}
2023-06-24 06:33:44 +01:00
};
2022-08-18 22:04:33 +01:00
2023-03-03 13:45:38 +00:00
void visit(AstExprCall* call)
{
2023-04-28 12:55:55 +01:00
visit(call->func, ValueContext::RValue);
2023-03-03 13:45:38 +00:00
for (AstExpr* arg : call->args)
2023-04-28 12:55:55 +01:00
visit(arg, ValueContext::RValue);
2023-03-03 13:45:38 +00:00
visitCall(call);
}
2023-03-10 19:20:04 +00:00
std::optional<TypeId> tryStripUnionFromNil(TypeId ty)
{
if (const UnionType* utv = get<UnionType>(ty))
{
if (!std::any_of(begin(utv), end(utv), isNil))
return ty;
std::vector<TypeId> result;
for (TypeId option : utv)
{
if (!isNil(option))
result.push_back(option);
}
if (result.empty())
return std::nullopt;
return result.size() == 1 ? result[0] : module->internalTypes.addType(UnionType{std::move(result)});
}
return std::nullopt;
}
TypeId stripFromNilAndReport(TypeId ty, const Location& location)
{
ty = follow(ty);
if (auto utv = get<UnionType>(ty))
{
if (!std::any_of(begin(utv), end(utv), isNil))
return ty;
}
if (std::optional<TypeId> strippedUnion = tryStripUnionFromNil(ty))
{
reportError(OptionalValueAccess{ty}, location);
return follow(*strippedUnion);
}
return ty;
}
2023-05-19 19:59:59 +01:00
void visitExprName(AstExpr* expr, Location location, const std::string& propName, ValueContext context, TypeId astIndexExprTy)
2022-08-18 22:04:33 +01:00
{
2023-04-28 12:55:55 +01:00
visit(expr, ValueContext::RValue);
2023-03-10 19:20:04 +00:00
TypeId leftType = stripFromNilAndReport(lookupType(expr), location);
2023-05-19 19:59:59 +01:00
checkIndexTypeFromType(leftType, propName, location, context, astIndexExprTy);
2023-02-24 18:24:22 +00:00
}
void visit(AstExprIndexName* indexName, ValueContext context)
{
2023-05-19 19:59:59 +01:00
// If we're indexing like _.foo - foo could either be a prop or a string.
visitExprName(indexName->expr, indexName->location, indexName->index.value, context, builtinTypes->stringType);
2022-08-18 22:04:33 +01:00
}
2022-06-17 01:54:42 +01:00
2023-01-20 12:02:39 +00:00
void visit(AstExprIndexExpr* indexExpr, ValueContext context)
2022-08-18 22:04:33 +01:00
{
2023-02-24 18:24:22 +00:00
if (auto str = indexExpr->index->as<AstExprConstantString>())
{
2023-05-19 19:59:59 +01:00
TypeId astIndexExprType = lookupType(indexExpr->index);
2023-02-24 18:24:22 +00:00
const std::string stringValue(str->value.data, str->value.size);
2023-05-19 19:59:59 +01:00
visitExprName(indexExpr->expr, indexExpr->location, stringValue, context, astIndexExprType);
2023-02-24 18:24:22 +00:00
return;
}
2023-07-28 12:37:00 +01:00
visit(indexExpr->expr, ValueContext::RValue);
2023-04-28 12:55:55 +01:00
visit(indexExpr->index, ValueContext::RValue);
2023-02-24 18:24:22 +00:00
NotNull<Scope> scope = stack.back();
TypeId exprType = lookupType(indexExpr->expr);
TypeId indexType = lookupType(indexExpr->index);
if (auto tt = get<TableType>(exprType))
{
if (tt->indexer)
reportErrors(tryUnify(scope, indexExpr->index->location, indexType, tt->indexer->indexType));
else
reportError(CannotExtendTable{exprType, CannotExtendTable::Indexer, "indexer??"}, indexExpr->location);
}
2023-05-19 19:59:59 +01:00
else if (auto cls = get<ClassType>(exprType); cls && cls->indexer)
reportErrors(tryUnify(scope, indexExpr->index->location, indexType, cls->indexer->indexType));
2023-03-24 17:34:14 +00:00
else if (get<UnionType>(exprType) && isOptional(exprType))
reportError(OptionalValueAccess{exprType}, indexExpr->location);
2022-06-17 01:54:42 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstExprFunction* fn)
2022-06-24 02:44:07 +01:00
{
2022-08-18 22:04:33 +01:00
auto StackPusher = pushStack(fn);
2023-02-17 14:53:37 +00:00
visitGenerics(fn->generics, fn->genericPacks);
2022-06-24 02:44:07 +01:00
TypeId inferredFnTy = lookupType(fn);
2023-05-25 21:46:51 +01:00
functionDeclStack.push_back(inferredFnTy);
2023-02-17 14:53:37 +00:00
2023-05-19 19:59:59 +01:00
const NormalizedType* normalizedFnTy = normalizer.normalize(inferredFnTy);
if (!normalizedFnTy)
{
reportError(CodeTooComplex{}, fn->location);
}
else if (get<ErrorType>(normalizedFnTy->errors))
{
// Nothing
}
2023-06-09 13:20:36 +01:00
else if (!normalizedFnTy->hasFunctions())
2023-05-19 19:59:59 +01:00
{
ice->ice("Internal error: Lambda has non-function type " + toString(inferredFnTy), fn->location);
}
else
2022-06-24 02:44:07 +01:00
{
2023-05-19 19:59:59 +01:00
if (1 != normalizedFnTy->functions.parts.size())
ice->ice("Unexpected: Lambda has unexpected type " + toString(inferredFnTy), fn->location);
2022-06-24 02:44:07 +01:00
2023-05-19 19:59:59 +01:00
const FunctionType* inferredFtv = get<FunctionType>(normalizedFnTy->functions.parts.front());
LUAU_ASSERT(inferredFtv);
// There is no way to write an annotation for the self argument, so we
// cannot do anything to check it.
auto argIt = begin(inferredFtv->argTypes);
if (fn->self)
++argIt;
for (const auto& arg : fn->args)
2022-06-24 02:44:07 +01:00
{
2023-05-19 19:59:59 +01:00
if (argIt == end(inferredFtv->argTypes))
break;
2022-06-24 02:44:07 +01:00
2023-05-19 19:59:59 +01:00
if (arg->annotation)
2022-06-24 02:44:07 +01:00
{
2023-05-19 19:59:59 +01:00
TypeId inferredArgTy = *argIt;
TypeId annotatedArgTy = lookupAnnotation(arg->annotation);
2023-07-28 12:37:00 +01:00
if (!isSubtype(inferredArgTy, annotatedArgTy, stack.back()) &&
!isErrorSuppressing(arg->location, inferredArgTy, arg->annotation->location, annotatedArgTy))
2023-05-19 19:59:59 +01:00
{
reportError(TypeMismatch{inferredArgTy, annotatedArgTy}, arg->location);
}
2022-06-24 02:44:07 +01:00
}
2023-05-19 19:59:59 +01:00
++argIt;
}
2022-06-24 02:44:07 +01:00
}
2022-08-18 22:04:33 +01:00
visit(fn->body);
2023-05-25 21:46:51 +01:00
functionDeclStack.pop_back();
2022-06-24 02:44:07 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstExprTable* expr)
2022-06-17 01:54:42 +01:00
{
2022-08-18 22:04:33 +01:00
// TODO!
for (const AstExprTable::Item& item : expr->items)
2022-06-17 01:54:42 +01:00
{
2022-08-18 22:04:33 +01:00
if (item.key)
2023-04-28 12:55:55 +01:00
visit(item.key, ValueContext::LValue);
visit(item.value, ValueContext::RValue);
2022-06-17 01:54:42 +01:00
}
}
2022-08-18 22:04:33 +01:00
void visit(AstExprUnary* expr)
2022-06-17 01:54:42 +01:00
{
2023-04-28 12:55:55 +01:00
visit(expr->expr, ValueContext::RValue);
2022-10-27 23:22:49 +01:00
NotNull<Scope> scope = stack.back();
TypeId operandType = lookupType(expr->expr);
2023-02-17 14:53:37 +00:00
TypeId resultType = lookupType(expr);
2022-10-27 23:22:49 +01:00
2023-07-28 12:37:00 +01:00
if (isErrorSuppressing(expr->expr->location, operandType))
2022-10-27 23:22:49 +01:00
return;
if (auto it = kUnaryOpMetamethods.find(expr->op); it != kUnaryOpMetamethods.end())
{
2023-01-03 17:33:19 +00:00
std::optional<TypeId> mm = findMetatableEntry(builtinTypes, module->errors, operandType, it->second, expr->location);
2022-10-27 23:22:49 +01:00
if (mm)
{
2023-01-03 17:33:19 +00:00
if (const FunctionType* ftv = get<FunctionType>(follow(*mm)))
2022-10-27 23:22:49 +01:00
{
if (std::optional<TypeId> ret = first(ftv->retTypes))
{
if (expr->op == AstExprUnary::Op::Len)
{
2023-01-03 17:33:19 +00:00
reportErrors(tryUnify(scope, expr->location, follow(*ret), builtinTypes->numberType));
2022-10-27 23:22:49 +01:00
}
}
else
{
reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location);
}
2023-02-17 14:53:37 +00:00
std::optional<TypeId> firstArg = first(ftv->argTypes);
if (!firstArg)
{
reportError(GenericError{"__unm metamethod must accept one argument"}, expr->location);
return;
}
TypePackId expectedArgs = testArena.addTypePack({operandType});
TypePackId expectedRet = testArena.addTypePack({resultType});
TypeId expectedFunction = testArena.addType(FunctionType{expectedArgs, expectedRet});
ErrorVec errors = tryUnify(scope, expr->location, *mm, expectedFunction);
2023-07-28 12:37:00 +01:00
if (!errors.empty() && !isErrorSuppressing(expr->expr->location, *firstArg, expr->expr->location, operandType))
2023-02-17 14:53:37 +00:00
{
reportError(TypeMismatch{*firstArg, operandType}, expr->location);
return;
}
2022-10-27 23:22:49 +01:00
}
return;
}
}
if (expr->op == AstExprUnary::Op::Len)
{
DenseHashSet<TypeId> seen{nullptr};
int recursionCount = 0;
2023-07-28 12:37:00 +01:00
const NormalizedType* nty = normalizer.normalize(operandType);
2022-10-27 23:22:49 +01:00
2023-07-28 12:37:00 +01:00
if (nty && nty->shouldSuppressErrors())
return;
2023-03-24 17:34:14 +00:00
2022-10-27 23:22:49 +01:00
if (!hasLength(operandType, seen, &recursionCount))
{
2023-03-24 17:34:14 +00:00
if (isOptional(operandType))
reportError(OptionalValueAccess{operandType}, expr->location);
else
reportError(NotATable{operandType}, expr->location);
2022-10-27 23:22:49 +01:00
}
}
else if (expr->op == AstExprUnary::Op::Minus)
{
2023-01-03 17:33:19 +00:00
reportErrors(tryUnify(scope, expr->location, operandType, builtinTypes->numberType));
2022-10-27 23:22:49 +01:00
}
else if (expr->op == AstExprUnary::Op::Not)
{
}
else
{
LUAU_ASSERT(!"Unhandled unary operator");
}
2022-06-17 01:54:42 +01:00
}
2023-02-03 12:34:12 +00:00
TypeId visit(AstExprBinary* expr, AstNode* overrideKey = nullptr)
2022-06-17 01:54:42 +01:00
{
2023-04-28 12:55:55 +01:00
visit(expr->left, ValueContext::LValue);
visit(expr->right, ValueContext::LValue);
2022-10-21 18:33:43 +01:00
NotNull<Scope> scope = stack.back();
bool isEquality = expr->op == AstExprBinary::Op::CompareEq || expr->op == AstExprBinary::Op::CompareNe;
bool isComparison = expr->op >= AstExprBinary::Op::CompareEq && expr->op <= AstExprBinary::Op::CompareGe;
bool isLogical = expr->op == AstExprBinary::Op::And || expr->op == AstExprBinary::Op::Or;
TypeId leftType = lookupType(expr->left);
TypeId rightType = lookupType(expr->right);
2023-05-19 19:59:59 +01:00
TypeId expectedResult = lookupType(expr);
if (get<TypeFamilyInstanceType>(expectedResult))
2023-05-25 21:46:51 +01:00
{
checkForInternalFamily(expectedResult, expr->location);
2023-05-19 19:59:59 +01:00
return expectedResult;
2023-05-25 21:46:51 +01:00
}
2022-10-21 18:33:43 +01:00
if (expr->op == AstExprBinary::Op::Or)
{
2023-01-03 17:33:19 +00:00
leftType = stripNil(builtinTypes, testArena, leftType);
2022-10-21 18:33:43 +01:00
}
2023-06-24 06:33:44 +01:00
const NormalizedType* normLeft = normalizer.normalize(leftType);
const NormalizedType* normRight = normalizer.normalize(rightType);
bool isStringOperation =
(normLeft ? normLeft->isSubtypeOfString() : isString(leftType)) && (normRight ? normRight->isSubtypeOfString() : isString(rightType));
2022-10-21 18:33:43 +01:00
2023-05-25 21:46:51 +01:00
if (get<AnyType>(leftType) || get<ErrorType>(leftType) || get<NeverType>(leftType))
2023-01-06 16:07:19 +00:00
return leftType;
2023-05-25 21:46:51 +01:00
else if (get<AnyType>(rightType) || get<ErrorType>(rightType) || get<NeverType>(rightType))
2023-01-06 16:07:19 +00:00
return rightType;
2023-07-28 12:37:00 +01:00
else if ((normLeft && normLeft->shouldSuppressErrors()) || (normRight && normRight->shouldSuppressErrors()))
return builtinTypes->anyType; // we can't say anything better if it's error suppressing but not any or error alone.
2022-10-21 18:33:43 +01:00
2023-05-12 13:15:01 +01:00
if ((get<BlockedType>(leftType) || get<FreeType>(leftType) || get<GenericType>(leftType)) && !isEquality && !isLogical)
2022-10-21 18:33:43 +01:00
{
auto name = getIdentifierOfBaseVar(expr->left);
reportError(CannotInferBinaryOperation{expr->op, name,
isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation},
expr->location);
2023-01-06 16:07:19 +00:00
return leftType;
2022-10-21 18:33:43 +01:00
}
2023-04-28 12:55:55 +01:00
bool typesHaveIntersection = normalizer.isIntersectionInhabited(leftType, rightType);
2022-10-21 18:33:43 +01:00
if (auto it = kBinaryOpMetamethods.find(expr->op); it != kBinaryOpMetamethods.end())
{
2023-01-03 17:33:19 +00:00
std::optional<TypeId> leftMt = getMetatable(leftType, builtinTypes);
std::optional<TypeId> rightMt = getMetatable(rightType, builtinTypes);
2022-10-21 18:33:43 +01:00
bool matches = leftMt == rightMt;
2023-04-28 12:55:55 +01:00
2022-10-21 18:33:43 +01:00
if (isEquality && !matches)
{
2023-01-03 17:33:19 +00:00
auto testUnion = [&matches, builtinTypes = this->builtinTypes](const UnionType* utv, std::optional<TypeId> otherMt) {
2022-10-21 18:33:43 +01:00
for (TypeId option : utv)
{
2023-01-03 17:33:19 +00:00
if (getMetatable(follow(option), builtinTypes) == otherMt)
2022-10-21 18:33:43 +01:00
{
matches = true;
break;
}
}
};
2023-01-03 17:33:19 +00:00
if (const UnionType* utv = get<UnionType>(leftType); utv && rightMt)
2022-10-21 18:33:43 +01:00
{
testUnion(utv, rightMt);
}
2023-01-03 17:33:19 +00:00
if (const UnionType* utv = get<UnionType>(rightType); utv && leftMt && !matches)
2022-10-21 18:33:43 +01:00
{
testUnion(utv, leftMt);
}
2023-06-24 06:33:44 +01:00
}
2023-04-28 12:55:55 +01:00
2023-06-24 06:33:44 +01:00
// If we're working with things that are not tables, the metatable comparisons above are a little excessive
// It's ok for one type to have a meta table and the other to not. In that case, we should fall back on
// checking if the intersection of the types is inhabited.
// TODO: Maybe add more checks here (e.g. for functions, classes, etc)
if (!(get<TableType>(leftType) || get<TableType>(rightType)))
2023-04-28 12:55:55 +01:00
if (!leftMt.has_value() || !rightMt.has_value())
matches = matches || typesHaveIntersection;
2022-10-21 18:33:43 +01:00
if (!matches && isComparison)
{
reportError(GenericError{format("Types %s and %s cannot be compared with %s because they do not have the same metatable",
toString(leftType).c_str(), toString(rightType).c_str(), toString(expr->op).c_str())},
expr->location);
2023-01-06 16:07:19 +00:00
return builtinTypes->errorRecoveryType();
2022-10-21 18:33:43 +01:00
}
std::optional<TypeId> mm;
2023-01-03 17:33:19 +00:00
if (std::optional<TypeId> leftMm = findMetatableEntry(builtinTypes, module->errors, leftType, it->second, expr->left->location))
2022-10-21 18:33:43 +01:00
mm = leftMm;
2023-01-03 17:33:19 +00:00
else if (std::optional<TypeId> rightMm = findMetatableEntry(builtinTypes, module->errors, rightType, it->second, expr->right->location))
2022-12-09 18:07:25 +00:00
{
2022-10-21 18:33:43 +01:00
mm = rightMm;
2022-12-09 18:07:25 +00:00
std::swap(leftType, rightType);
}
2022-10-21 18:33:43 +01:00
if (mm)
{
2023-02-03 12:34:12 +00:00
AstNode* key = expr;
2023-01-06 16:07:19 +00:00
if (overrideKey != nullptr)
key = overrideKey;
2023-06-24 06:33:44 +01:00
TypeId* selectedOverloadTy = module->astOverloadResolvedTypes.find(key);
if (!selectedOverloadTy)
2023-05-19 19:59:59 +01:00
{
// reportError(CodeTooComplex{}, expr->location);
// was handled by a type family
return expectedResult;
}
2022-12-09 18:07:25 +00:00
2023-06-24 06:33:44 +01:00
else if (const FunctionType* ftv = get<FunctionType>(follow(*selectedOverloadTy)))
2022-10-21 18:33:43 +01:00
{
TypePackId expectedArgs;
// For >= and > we invoke __lt and __le respectively with
// swapped argument ordering.
if (expr->op == AstExprBinary::Op::CompareGe || expr->op == AstExprBinary::Op::CompareGt)
{
2023-01-03 17:33:19 +00:00
expectedArgs = testArena.addTypePack({rightType, leftType});
2022-10-21 18:33:43 +01:00
}
else
{
2023-01-03 17:33:19 +00:00
expectedArgs = testArena.addTypePack({leftType, rightType});
2022-10-21 18:33:43 +01:00
}
2023-01-06 16:07:19 +00:00
TypePackId expectedRets;
2022-10-21 18:33:43 +01:00
if (expr->op == AstExprBinary::CompareEq || expr->op == AstExprBinary::CompareNe || expr->op == AstExprBinary::CompareGe ||
expr->op == AstExprBinary::CompareGt || expr->op == AstExprBinary::Op::CompareLe || expr->op == AstExprBinary::Op::CompareLt)
{
2023-01-06 16:07:19 +00:00
expectedRets = testArena.addTypePack({builtinTypes->booleanType});
}
else
{
expectedRets = testArena.addTypePack({testArena.freshType(scope, TypeLevel{})});
}
TypeId expectedTy = testArena.addType(FunctionType(expectedArgs, expectedRets));
reportErrors(tryUnify(scope, expr->location, follow(*mm), expectedTy));
std::optional<TypeId> ret = first(ftv->retTypes);
if (ret)
{
if (isComparison)
{
if (!isBoolean(follow(*ret)))
{
reportError(GenericError{format("Metamethod '%s' must return a boolean", it->second)}, expr->location);
}
return builtinTypes->booleanType;
}
else
2022-10-21 18:33:43 +01:00
{
2023-01-06 16:07:19 +00:00
return follow(*ret);
2022-10-21 18:33:43 +01:00
}
}
2023-01-06 16:07:19 +00:00
else
2022-10-21 18:33:43 +01:00
{
2023-01-06 16:07:19 +00:00
if (isComparison)
{
reportError(GenericError{format("Metamethod '%s' must return a boolean", it->second)}, expr->location);
}
else
{
reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location);
}
return builtinTypes->errorRecoveryType();
2022-10-21 18:33:43 +01:00
}
}
else
{
reportError(CannotCallNonFunction{*mm}, expr->location);
}
2023-01-06 16:07:19 +00:00
return builtinTypes->errorRecoveryType();
2022-10-21 18:33:43 +01:00
}
// If this is a string comparison, or a concatenation of strings, we
// want to fall through to primitive behavior.
else if (!isEquality && !(isStringOperation && (expr->op == AstExprBinary::Op::Concat || isComparison)))
{
2023-01-06 16:07:19 +00:00
if ((leftMt && !isString(leftType)) || (rightMt && !isString(rightType)))
2022-10-21 18:33:43 +01:00
{
if (isComparison)
{
reportError(GenericError{format(
"Types '%s' and '%s' cannot be compared with %s because neither type's metatable has a '%s' metamethod",
toString(leftType).c_str(), toString(rightType).c_str(), toString(expr->op).c_str(), it->second)},
expr->location);
}
else
{
reportError(GenericError{format(
"Operator %s is not applicable for '%s' and '%s' because neither type's metatable has a '%s' metamethod",
toString(expr->op).c_str(), toString(leftType).c_str(), toString(rightType).c_str(), it->second)},
expr->location);
}
2023-01-06 16:07:19 +00:00
return builtinTypes->errorRecoveryType();
2022-10-21 18:33:43 +01:00
}
2023-01-03 17:33:19 +00:00
else if (!leftMt && !rightMt && (get<TableType>(leftType) || get<TableType>(rightType)))
2022-10-21 18:33:43 +01:00
{
if (isComparison)
{
reportError(GenericError{format("Types '%s' and '%s' cannot be compared with %s because neither type has a metatable",
toString(leftType).c_str(), toString(rightType).c_str(), toString(expr->op).c_str())},
expr->location);
}
else
{
reportError(GenericError{format("Operator %s is not applicable for '%s' and '%s' because neither type has a metatable",
toString(expr->op).c_str(), toString(leftType).c_str(), toString(rightType).c_str())},
expr->location);
}
2023-01-06 16:07:19 +00:00
return builtinTypes->errorRecoveryType();
2022-10-21 18:33:43 +01:00
}
}
}
switch (expr->op)
{
case AstExprBinary::Op::Add:
case AstExprBinary::Op::Sub:
case AstExprBinary::Op::Mul:
case AstExprBinary::Op::Div:
case AstExprBinary::Op::Pow:
case AstExprBinary::Op::Mod:
2023-01-03 17:33:19 +00:00
reportErrors(tryUnify(scope, expr->left->location, leftType, builtinTypes->numberType));
reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->numberType));
2022-10-21 18:33:43 +01:00
2023-01-06 16:07:19 +00:00
return builtinTypes->numberType;
2022-10-21 18:33:43 +01:00
case AstExprBinary::Op::Concat:
2023-01-03 17:33:19 +00:00
reportErrors(tryUnify(scope, expr->left->location, leftType, builtinTypes->stringType));
reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->stringType));
2022-10-21 18:33:43 +01:00
2023-01-06 16:07:19 +00:00
return builtinTypes->stringType;
2022-10-21 18:33:43 +01:00
case AstExprBinary::Op::CompareGe:
case AstExprBinary::Op::CompareGt:
case AstExprBinary::Op::CompareLe:
case AstExprBinary::Op::CompareLt:
2023-06-09 13:20:36 +01:00
{
2023-07-28 12:37:00 +01:00
if (normLeft && normLeft->shouldSuppressErrors())
return builtinTypes->numberType;
2023-06-24 06:33:44 +01:00
if (normLeft && normLeft->isExactlyNumber())
2023-01-06 16:07:19 +00:00
{
2023-01-03 17:33:19 +00:00
reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->numberType));
2023-01-06 16:07:19 +00:00
return builtinTypes->numberType;
}
2023-06-24 06:33:44 +01:00
else if (normLeft && normLeft->isSubtypeOfString())
2023-01-06 16:07:19 +00:00
{
2023-01-03 17:33:19 +00:00
reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->stringType));
2023-01-06 16:07:19 +00:00
return builtinTypes->stringType;
}
2022-10-21 18:33:43 +01:00
else
2023-01-06 16:07:19 +00:00
{
2022-10-21 18:33:43 +01:00
reportError(GenericError{format("Types '%s' and '%s' cannot be compared with relational operator %s", toString(leftType).c_str(),
toString(rightType).c_str(), toString(expr->op).c_str())},
expr->location);
2023-01-06 16:07:19 +00:00
return builtinTypes->errorRecoveryType();
}
2023-06-09 13:20:36 +01:00
}
2022-10-21 18:33:43 +01:00
case AstExprBinary::Op::And:
case AstExprBinary::Op::Or:
case AstExprBinary::Op::CompareEq:
case AstExprBinary::Op::CompareNe:
2023-01-06 16:07:19 +00:00
// Ugly case: we don't care about this possibility, because a
// compound assignment will never exist with one of these operators.
return builtinTypes->anyType;
2022-10-21 18:33:43 +01:00
default:
// Unhandled AstExprBinary::Op possibility.
LUAU_ASSERT(false);
2023-01-06 16:07:19 +00:00
return builtinTypes->errorRecoveryType();
2022-10-21 18:33:43 +01:00
}
2022-06-17 01:54:42 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstExprTypeAssertion* expr)
2022-08-11 21:42:54 +01:00
{
2023-04-28 12:55:55 +01:00
visit(expr->expr, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
visit(expr->annotation);
2022-08-11 21:42:54 +01:00
TypeId annotationType = lookupAnnotation(expr->annotation);
TypeId computedType = lookupType(expr->expr);
// Note: As an optimization, we try 'number <: number | string' first, as that is the more likely case.
2023-05-12 13:15:01 +01:00
if (isSubtype(annotationType, computedType, stack.back(), true))
2022-08-18 22:04:33 +01:00
return;
2022-08-11 21:42:54 +01:00
2023-05-12 13:15:01 +01:00
if (isSubtype(computedType, annotationType, stack.back(), true))
2022-08-18 22:04:33 +01:00
return;
2022-08-11 21:42:54 +01:00
reportError(TypesAreUnrelated{computedType, annotationType}, expr->location);
2022-08-18 22:04:33 +01:00
}
void visit(AstExprIfElse* expr)
{
// TODO!
2023-04-28 12:55:55 +01:00
visit(expr->condition, ValueContext::RValue);
visit(expr->trueExpr, ValueContext::RValue);
visit(expr->falseExpr, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
}
2023-01-27 21:28:45 +00:00
void visit(AstExprInterpString* interpString)
{
for (AstExpr* expr : interpString->expressions)
2023-04-28 12:55:55 +01:00
visit(expr, ValueContext::RValue);
2023-01-27 21:28:45 +00:00
}
2022-08-18 22:04:33 +01:00
void visit(AstExprError* expr)
{
// TODO!
for (AstExpr* e : expr->expressions)
2023-04-28 12:55:55 +01:00
visit(e, ValueContext::RValue);
2022-08-11 21:42:54 +01:00
}
2022-07-01 00:29:02 +01:00
/** Extract a TypeId for the first type of the provided pack.
*
* Note that this may require modifying some types. I hope this doesn't cause problems!
*/
TypeId flattenPack(TypePackId pack)
{
pack = follow(pack);
2023-02-03 12:34:12 +00:00
if (auto fst = first(pack, /*ignoreHiddenVariadics*/ false))
return *fst;
2022-07-01 00:29:02 +01:00
else if (auto ftp = get<FreeTypePack>(pack))
{
2023-01-03 17:33:19 +00:00
TypeId result = testArena.addType(FreeType{ftp->scope});
TypePackId freeTail = testArena.addTypePack(FreeTypePack{ftp->scope});
2022-07-01 00:29:02 +01:00
TypePack& resultPack = asMutable(pack)->ty.emplace<TypePack>();
resultPack.head.assign(1, result);
resultPack.tail = freeTail;
return result;
}
else if (get<Unifiable::Error>(pack))
2023-01-03 17:33:19 +00:00
return builtinTypes->errorRecoveryType();
2023-02-03 12:34:12 +00:00
else if (finite(pack) && size(pack) == 0)
return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil`
2022-07-01 00:29:02 +01:00
else
2023-04-21 22:41:03 +01:00
ice->ice("flattenPack got a weird pack!");
2022-07-01 00:29:02 +01:00
}
2023-02-17 14:53:37 +00:00
void visitGenerics(AstArray<AstGenericType> generics, AstArray<AstGenericTypePack> genericPacks)
{
DenseHashSet<AstName> seen{AstName{}};
for (const auto& g : generics)
{
if (seen.contains(g.name))
reportError(DuplicateGenericParameter{g.name.value}, g.location);
else
seen.insert(g.name);
if (g.defaultValue)
visit(g.defaultValue);
}
for (const auto& g : genericPacks)
{
if (seen.contains(g.name))
reportError(DuplicateGenericParameter{g.name.value}, g.location);
else
seen.insert(g.name);
if (g.defaultValue)
visit(g.defaultValue);
}
}
2022-08-18 22:04:33 +01:00
void visit(AstType* ty)
2022-06-24 02:44:07 +01:00
{
2023-05-12 13:15:01 +01:00
TypeId* resolvedTy = module->astResolvedTypes.find(ty);
if (resolvedTy)
checkForFamilyInhabitance(follow(*resolvedTy), ty->location);
2022-08-18 22:04:33 +01:00
if (auto t = ty->as<AstTypeReference>())
return visit(t);
else if (auto t = ty->as<AstTypeTable>())
return visit(t);
else if (auto t = ty->as<AstTypeFunction>())
return visit(t);
else if (auto t = ty->as<AstTypeTypeof>())
return visit(t);
else if (auto t = ty->as<AstTypeUnion>())
return visit(t);
else if (auto t = ty->as<AstTypeIntersection>())
return visit(t);
2022-06-24 02:44:07 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstTypeReference* ty)
2022-06-24 02:44:07 +01:00
{
2023-01-03 17:33:19 +00:00
// No further validation is necessary in this case. The main logic for
// _luau_print is contained in lookupAnnotation.
2023-05-19 19:59:59 +01:00
if (FFlag::DebugLuauMagicTypes && ty->name == "_luau_print")
2023-01-03 17:33:19 +00:00
return;
2022-08-18 22:04:33 +01:00
for (const AstTypeOrPack& param : ty->parameters)
{
if (param.type)
visit(param.type);
else
visit(param.typePack);
}
2022-07-29 04:41:13 +01:00
Scope* scope = findInnermostScope(ty->location);
2022-08-04 22:27:28 +01:00
LUAU_ASSERT(scope);
2022-06-24 02:44:07 +01:00
2022-10-27 23:22:49 +01:00
std::optional<TypeFun> alias =
(ty->prefix) ? scope->lookupImportedType(ty->prefix->value, ty->name.value) : scope->lookupType(ty->name.value);
2022-08-04 22:27:28 +01:00
if (alias.has_value())
{
size_t typesRequired = alias->typeParams.size();
size_t packsRequired = alias->typePackParams.size();
bool hasDefaultTypes = std::any_of(alias->typeParams.begin(), alias->typeParams.end(), [](auto&& el) {
return el.defaultValue.has_value();
});
bool hasDefaultPacks = std::any_of(alias->typePackParams.begin(), alias->typePackParams.end(), [](auto&& el) {
return el.defaultValue.has_value();
});
if (!ty->hasParameterList)
{
if ((!alias->typeParams.empty() && !hasDefaultTypes) || (!alias->typePackParams.empty() && !hasDefaultPacks))
{
reportError(GenericError{"Type parameter list is required"}, ty->location);
}
}
size_t typesProvided = 0;
size_t extraTypes = 0;
size_t packsProvided = 0;
for (const AstTypeOrPack& p : ty->parameters)
{
if (p.type)
{
if (packsProvided != 0)
{
reportError(GenericError{"Type parameters must come before type pack parameters"}, ty->location);
2023-05-19 19:59:59 +01:00
continue;
2022-08-04 22:27:28 +01:00
}
if (typesProvided < typesRequired)
{
typesProvided += 1;
}
else
{
extraTypes += 1;
}
}
else if (p.typePack)
{
TypePackId tp = lookupPackAnnotation(p.typePack);
if (typesProvided < typesRequired && size(tp) == 1 && finite(tp) && first(tp))
{
typesProvided += 1;
}
else
{
packsProvided += 1;
}
}
}
if (extraTypes != 0 && packsProvided == 0)
{
2023-05-19 19:59:59 +01:00
// Extra types are only collected into a pack if a pack is expected
if (packsRequired != 0)
packsProvided += 1;
else
typesProvided += extraTypes;
2022-08-04 22:27:28 +01:00
}
for (size_t i = typesProvided; i < typesRequired; ++i)
{
if (alias->typeParams[i].defaultValue)
{
typesProvided += 1;
}
}
2023-03-03 13:45:38 +00:00
for (size_t i = packsProvided; i < packsRequired; ++i)
2022-08-04 22:27:28 +01:00
{
if (alias->typePackParams[i].defaultValue)
{
packsProvided += 1;
}
}
if (extraTypes == 0 && packsProvided + 1 == packsRequired)
{
packsProvided += 1;
}
if (typesProvided != typesRequired || packsProvided != packsRequired)
{
reportError(IncorrectGenericParameterCount{
/* name */ ty->name.value,
/* typeFun */ *alias,
/* actualParameters */ typesProvided,
/* actualPackParameters */ packsProvided,
},
ty->location);
}
}
else
{
2022-08-11 21:42:54 +01:00
if (scope->lookupPack(ty->name.value))
2022-08-04 22:27:28 +01:00
{
reportError(
SwappedGenericTypeParameter{
ty->name.value,
SwappedGenericTypeParameter::Kind::Type,
},
ty->location);
}
else
{
2023-03-10 19:20:04 +00:00
std::string symbol = "";
if (ty->prefix)
{
symbol += (*(ty->prefix)).value;
symbol += ".";
}
symbol += ty->name.value;
reportError(UnknownSymbol{symbol, UnknownSymbol::Context::Type}, ty->location);
2022-08-04 22:27:28 +01:00
}
}
2022-08-18 22:04:33 +01:00
}
void visit(AstTypeTable* table)
{
// TODO!
for (const AstTableProp& prop : table->props)
visit(prop.type);
if (table->indexer)
{
visit(table->indexer->indexType);
visit(table->indexer->resultType);
}
}
void visit(AstTypeFunction* ty)
{
2023-02-17 14:53:37 +00:00
visitGenerics(ty->generics, ty->genericPacks);
2022-08-18 22:04:33 +01:00
visit(ty->argTypes);
visit(ty->returnTypes);
}
void visit(AstTypeTypeof* ty)
{
2023-04-28 12:55:55 +01:00
visit(ty->expr, ValueContext::RValue);
2022-08-18 22:04:33 +01:00
}
void visit(AstTypeUnion* ty)
{
// TODO!
for (AstType* type : ty->types)
visit(type);
}
void visit(AstTypeIntersection* ty)
{
// TODO!
for (AstType* type : ty->types)
visit(type);
}
void visit(AstTypePack* pack)
{
if (auto p = pack->as<AstTypePackExplicit>())
return visit(p);
else if (auto p = pack->as<AstTypePackVariadic>())
return visit(p);
else if (auto p = pack->as<AstTypePackGeneric>())
return visit(p);
}
void visit(AstTypePackExplicit* tp)
{
// TODO!
for (AstType* type : tp->typeList.types)
visit(type);
2022-08-04 22:27:28 +01:00
2022-08-18 22:04:33 +01:00
if (tp->typeList.tailType)
visit(tp->typeList.tailType);
2022-08-04 22:27:28 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstTypePackVariadic* tp)
2022-08-04 22:27:28 +01:00
{
2022-08-18 22:04:33 +01:00
// TODO!
visit(tp->variadicType);
2022-08-04 22:27:28 +01:00
}
2022-08-18 22:04:33 +01:00
void visit(AstTypePackGeneric* tp)
2022-08-04 22:27:28 +01:00
{
Scope* scope = findInnermostScope(tp->location);
LUAU_ASSERT(scope);
2022-08-11 21:42:54 +01:00
std::optional<TypePackId> alias = scope->lookupPack(tp->genericName.value);
2022-08-04 22:27:28 +01:00
if (!alias.has_value())
2022-06-24 02:44:07 +01:00
{
2022-08-11 21:42:54 +01:00
if (scope->lookupType(tp->genericName.value))
2022-08-04 22:27:28 +01:00
{
reportError(
SwappedGenericTypeParameter{
tp->genericName.value,
SwappedGenericTypeParameter::Kind::Pack,
},
tp->location);
}
else
{
reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location);
}
2022-06-24 02:44:07 +01:00
}
}
2022-11-10 22:04:44 +00:00
template<typename TID>
2023-05-12 13:15:01 +01:00
bool isSubtype(TID subTy, TID superTy, NotNull<Scope> scope, bool genericsOkay = false)
2022-11-10 22:04:44 +00:00
{
TypeArena arena;
2023-05-25 21:46:51 +01:00
Unifier u{NotNull{&normalizer}, scope, Location{}, Covariant};
2023-05-12 13:15:01 +01:00
u.hideousFixMeGenericsAreActuallyFree = genericsOkay;
2023-07-28 12:37:00 +01:00
u.enableNewSolver();
2022-11-10 22:04:44 +00:00
u.tryUnify(subTy, superTy);
const bool ok = u.errors.empty() && u.log.empty();
return ok;
}
2022-09-02 00:00:14 +01:00
template<typename TID>
2023-05-12 13:15:01 +01:00
ErrorVec tryUnify(NotNull<Scope> scope, const Location& location, TID subTy, TID superTy, CountMismatch::Context context = CountMismatch::Arg,
bool genericsOkay = false)
2022-09-02 00:00:14 +01:00
{
2023-05-25 21:46:51 +01:00
Unifier u{NotNull{&normalizer}, scope, location, Covariant};
2023-01-20 12:02:39 +00:00
u.ctx = context;
2023-05-12 13:15:01 +01:00
u.hideousFixMeGenericsAreActuallyFree = genericsOkay;
2023-07-28 12:37:00 +01:00
u.enableNewSolver();
2022-09-02 00:00:14 +01:00
u.tryUnify(subTy, superTy);
2023-07-28 12:37:00 +01:00
if (isErrorSuppressing(location, subTy, location, superTy))
return {};
2022-09-02 00:00:14 +01:00
return std::move(u.errors);
}
void reportError(TypeErrorData data, const Location& location)
2022-06-17 01:54:42 +01:00
{
2023-05-19 19:59:59 +01:00
if (auto utk = get_if<UnknownProperty>(&data))
diagnoseMissingTableKey(utk, data);
2023-04-21 22:41:03 +01:00
module->errors.emplace_back(location, module->name, std::move(data));
2022-09-08 22:44:50 +01:00
2023-03-03 13:45:38 +00:00
if (logger)
2022-09-08 22:44:50 +01:00
logger->captureTypeCheckError(module->errors.back());
2022-06-17 01:54:42 +01:00
}
2022-07-01 00:29:02 +01:00
void reportError(TypeError e)
{
2022-09-02 00:00:14 +01:00
reportError(std::move(e.data), e.location);
}
void reportErrors(ErrorVec errors)
{
for (TypeError e : errors)
reportError(std::move(e));
2022-07-01 00:29:02 +01:00
}
2022-08-11 21:42:54 +01:00
2023-04-14 13:05:27 +01:00
// If the provided type does not have the named property, report an error.
2023-05-19 19:59:59 +01:00
void checkIndexTypeFromType(TypeId tableTy, const std::string& prop, const Location& location, ValueContext context, TypeId astIndexExprType)
2022-08-11 21:42:54 +01:00
{
2023-04-14 13:05:27 +01:00
const NormalizedType* norm = normalizer.normalize(tableTy);
if (!norm)
{
reportError(NormalizationTooComplex{}, location);
return;
}
2023-07-28 12:37:00 +01:00
// if the type is error suppressing, we don't actually have any work left to do.
2023-07-14 16:57:16 +01:00
if (norm->shouldSuppressErrors())
return;
2022-12-09 18:07:25 +00:00
bool foundOneProp = false;
std::vector<TypeId> typesMissingTheProp;
auto fetch = [&](TypeId ty) {
if (!normalizer.isInhabited(ty))
return;
2023-04-14 13:05:27 +01:00
std::unordered_set<TypeId> seen;
2023-05-19 19:59:59 +01:00
bool found = hasIndexTypeFromType(ty, prop, location, seen, astIndexExprType);
2022-12-09 18:07:25 +00:00
foundOneProp |= found;
if (!found)
typesMissingTheProp.push_back(ty);
};
2023-04-14 13:05:27 +01:00
fetch(norm->tops);
fetch(norm->booleans);
2023-01-03 17:33:19 +00:00
2023-05-05 20:57:12 +01:00
for (const auto& [ty, _negations] : norm->classes.classes)
2023-01-03 17:33:19 +00:00
{
2023-05-05 20:57:12 +01:00
fetch(ty);
2023-01-03 17:33:19 +00:00
}
2023-04-14 13:05:27 +01:00
fetch(norm->errors);
fetch(norm->nils);
fetch(norm->numbers);
if (!norm->strings.isNever())
2023-01-03 17:33:19 +00:00
fetch(builtinTypes->stringType);
2023-04-14 13:05:27 +01:00
fetch(norm->threads);
for (TypeId ty : norm->tables)
2022-12-09 18:07:25 +00:00
fetch(ty);
2023-04-14 13:05:27 +01:00
if (norm->functions.isTop)
2023-01-03 17:33:19 +00:00
fetch(builtinTypes->functionType);
2023-04-14 13:05:27 +01:00
else if (!norm->functions.isNever())
2022-12-09 18:07:25 +00:00
{
2023-04-14 13:05:27 +01:00
if (norm->functions.parts.size() == 1)
fetch(norm->functions.parts.front());
2022-12-09 18:07:25 +00:00
else
{
std::vector<TypeId> parts;
2023-04-14 13:05:27 +01:00
parts.insert(parts.end(), norm->functions.parts.begin(), norm->functions.parts.end());
2023-01-03 17:33:19 +00:00
fetch(testArena.addType(IntersectionType{std::move(parts)}));
2022-12-09 18:07:25 +00:00
}
}
2023-04-14 13:05:27 +01:00
for (const auto& [tyvar, intersect] : norm->tyvars)
2022-12-09 18:07:25 +00:00
{
2023-01-03 17:33:19 +00:00
if (get<NeverType>(intersect->tops))
2022-12-09 18:07:25 +00:00
{
TypeId ty = normalizer.typeFromNormal(*intersect);
2023-01-03 17:33:19 +00:00
fetch(testArena.addType(IntersectionType{{tyvar, ty}}));
2022-12-09 18:07:25 +00:00
}
else
fetch(tyvar);
}
if (!typesMissingTheProp.empty())
{
if (foundOneProp)
2023-01-20 12:02:39 +00:00
reportError(MissingUnionProperty{tableTy, typesMissingTheProp, prop}, location);
2023-03-10 19:20:04 +00:00
// For class LValues, we don't want to report an extension error,
// because classes come into being with full knowledge of their
// shape. We instead want to report the unknown property error of
// the `else` branch.
2023-04-28 12:55:55 +01:00
else if (context == ValueContext::LValue && !get<ClassType>(tableTy))
2023-01-20 12:02:39 +00:00
reportError(CannotExtendTable{tableTy, CannotExtendTable::Property, prop}, location);
2022-12-09 18:07:25 +00:00
else
2023-01-20 12:02:39 +00:00
reportError(UnknownProperty{tableTy, prop}, location);
2022-12-09 18:07:25 +00:00
}
}
2023-05-19 19:59:59 +01:00
bool hasIndexTypeFromType(TypeId ty, const std::string& prop, const Location& location, std::unordered_set<TypeId>& seen, TypeId astIndexExprType)
2022-12-09 18:07:25 +00:00
{
2023-04-14 13:05:27 +01:00
// If we have already encountered this type, we must assume that some
// other codepath will do the right thing and signal false if the
// property is not present.
const bool isUnseen = seen.insert(ty).second;
if (!isUnseen)
return true;
2023-01-03 17:33:19 +00:00
if (get<ErrorType>(ty) || get<AnyType>(ty) || get<NeverType>(ty))
2022-12-09 18:07:25 +00:00
return true;
if (isString(ty))
{
2023-01-03 17:33:19 +00:00
std::optional<TypeId> mtIndex = Luau::findMetatableEntry(builtinTypes, module->errors, builtinTypes->stringType, "__index", location);
2022-12-09 18:07:25 +00:00
LUAU_ASSERT(mtIndex);
ty = *mtIndex;
}
2023-02-24 18:24:22 +00:00
if (auto tt = getTableType(ty))
{
if (findTablePropertyRespectingMeta(builtinTypes, module->errors, ty, prop, location))
return true;
2023-05-19 19:59:59 +01:00
if (tt->indexer)
{
TypeId indexType = follow(tt->indexer->indexType);
if (isPrim(indexType, PrimitiveType::String))
return true;
// If the indexer looks like { [any] : _} - the prop lookup should be allowed!
else if (get<AnyType>(indexType) || get<UnknownType>(indexType))
return true;
}
2023-02-24 18:24:22 +00:00
2023-05-19 19:59:59 +01:00
return false;
2023-02-24 18:24:22 +00:00
}
2023-01-03 17:33:19 +00:00
else if (const ClassType* cls = get<ClassType>(ty))
2023-05-19 19:59:59 +01:00
{
// If the property doesn't exist on the class, we consult the indexer
// We need to check if the type of the index expression foo (x[foo])
// is compatible with the indexer's indexType
// Construct the intersection and test inhabitedness!
if (auto property = lookupClassProp(cls, prop))
return true;
if (cls->indexer)
{
TypeId inhabitatedTestType = testArena.addType(IntersectionType{{cls->indexer->indexType, astIndexExprType}});
return normalizer.isInhabited(inhabitatedTestType);
}
return false;
}
2023-01-03 17:33:19 +00:00
else if (const UnionType* utv = get<UnionType>(ty))
2023-04-14 13:05:27 +01:00
return std::all_of(begin(utv), end(utv), [&](TypeId part) {
2023-05-19 19:59:59 +01:00
return hasIndexTypeFromType(part, prop, location, seen, astIndexExprType);
2023-04-14 13:05:27 +01:00
});
2023-01-03 17:33:19 +00:00
else if (const IntersectionType* itv = get<IntersectionType>(ty))
2022-12-09 18:07:25 +00:00
return std::any_of(begin(itv), end(itv), [&](TypeId part) {
2023-05-19 19:59:59 +01:00
return hasIndexTypeFromType(part, prop, location, seen, astIndexExprType);
2022-12-09 18:07:25 +00:00
});
else
return false;
2022-08-11 21:42:54 +01:00
}
2023-05-19 19:59:59 +01:00
void diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& data) const
{
std::string_view sv(utk->key);
std::set<Name> candidates;
auto accumulate = [&](const TableType::Props& props) {
for (const auto& [name, ty] : props)
{
if (sv != name && equalsLower(sv, name))
candidates.insert(name);
}
};
if (auto ttv = getTableType(utk->table))
accumulate(ttv->props);
else if (auto ctv = get<ClassType>(follow(utk->table)))
{
while (ctv)
{
accumulate(ctv->props);
if (!ctv->parent)
break;
ctv = get<ClassType>(*ctv->parent);
LUAU_ASSERT(ctv);
}
}
if (!candidates.empty())
data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, candidates});
}
2023-07-28 12:37:00 +01:00
bool isErrorSuppressing(Location loc, TypeId ty)
{
switch (shouldSuppressErrors(NotNull{&normalizer}, ty))
{
case ErrorSuppression::DoNotSuppress:
return false;
case ErrorSuppression::Suppress:
return true;
case ErrorSuppression::NormalizationFailed:
reportError(NormalizationTooComplex{}, loc);
return false;
};
LUAU_ASSERT(false);
return false; // UNREACHABLE
}
bool isErrorSuppressing(Location loc1, TypeId ty1, Location loc2, TypeId ty2)
{
return isErrorSuppressing(loc1, ty1) || isErrorSuppressing(loc2, ty2);
}
bool isErrorSuppressing(Location loc, TypePackId tp)
{
switch (shouldSuppressErrors(NotNull{&normalizer}, tp))
{
case ErrorSuppression::DoNotSuppress:
return false;
case ErrorSuppression::Suppress:
return true;
case ErrorSuppression::NormalizationFailed:
reportError(NormalizationTooComplex{}, loc);
return false;
};
LUAU_ASSERT(false);
return false; // UNREACHABLE
}
bool isErrorSuppressing(Location loc1, TypePackId tp1, Location loc2, TypePackId tp2)
{
return isErrorSuppressing(loc1, tp1) || isErrorSuppressing(loc2, tp2);
}
2022-06-17 01:54:42 +01:00
};
2023-07-14 16:57:16 +01:00
void check(
NotNull<BuiltinTypes> builtinTypes, NotNull<UnifierSharedState> unifierState, DcrLogger* logger, const SourceModule& sourceModule, Module* module)
2022-06-17 01:54:42 +01:00
{
2023-04-21 22:41:03 +01:00
TypeChecker2 typeChecker{builtinTypes, unifierState, logger, &sourceModule, module};
2023-05-19 19:59:59 +01:00
2022-08-18 22:04:33 +01:00
typeChecker.visit(sourceModule.root);
2023-01-03 17:33:19 +00:00
unfreeze(module->interfaceTypes);
copyErrors(module->errors, module->interfaceTypes);
freeze(module->interfaceTypes);
2022-06-17 01:54:42 +01:00
}
} // namespace Luau