2021-10-29 16:25:12 -04:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "Luau/Predicate.h"
|
|
|
|
#include "Luau/Error.h"
|
|
|
|
#include "Luau/Module.h"
|
|
|
|
#include "Luau/Symbol.h"
|
|
|
|
#include "Luau/Substitution.h"
|
|
|
|
#include "Luau/TxnLog.h"
|
|
|
|
#include "Luau/TypePack.h"
|
|
|
|
#include "Luau/TypeVar.h"
|
|
|
|
#include "Luau/Unifier.h"
|
2021-11-04 22:42:00 -04:00
|
|
|
#include "Luau/UnifierSharedState.h"
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
struct Scope;
|
|
|
|
struct TypeChecker;
|
|
|
|
struct ModuleResolver;
|
|
|
|
|
|
|
|
using Name = std::string;
|
|
|
|
using ScopePtr = std::shared_ptr<Scope>;
|
|
|
|
using OverloadErrorEntry = std::tuple<std::vector<TypeError>, std::vector<TypeId>, const FunctionTypeVar*>;
|
|
|
|
|
|
|
|
bool doesCallError(const AstExprCall* call);
|
|
|
|
bool hasBreak(AstStat* node);
|
|
|
|
const AstStat* getFallthrough(const AstStat* node);
|
|
|
|
|
2022-02-24 18:15:41 -05:00
|
|
|
struct UnifierOptions;
|
2021-10-29 16:25:12 -04:00
|
|
|
struct Unifier;
|
|
|
|
|
|
|
|
// A substitution which replaces free types by any
|
|
|
|
struct Anyification : Substitution
|
|
|
|
{
|
2022-04-14 17:57:15 -04:00
|
|
|
Anyification(TypeArena* arena, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack)
|
2022-02-17 19:41:20 -05:00
|
|
|
: Substitution(TxnLog::empty(), arena)
|
2022-04-14 17:57:15 -04:00
|
|
|
, iceHandler(iceHandler)
|
2022-02-17 19:41:20 -05:00
|
|
|
, anyType(anyType)
|
|
|
|
, anyTypePack(anyTypePack)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-04-14 17:57:15 -04:00
|
|
|
InternalErrorReporter* iceHandler;
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
TypeId anyType;
|
|
|
|
TypePackId anyTypePack;
|
2022-04-14 17:57:15 -04:00
|
|
|
bool normalizationTooComplex = false;
|
2021-10-29 16:25:12 -04:00
|
|
|
bool isDirty(TypeId ty) override;
|
|
|
|
bool isDirty(TypePackId tp) override;
|
|
|
|
TypeId clean(TypeId ty) override;
|
|
|
|
TypePackId clean(TypePackId tp) override;
|
2022-04-14 17:57:15 -04:00
|
|
|
|
|
|
|
bool ignoreChildren(TypeId ty) override
|
|
|
|
{
|
|
|
|
return ty->persistent;
|
|
|
|
}
|
|
|
|
bool ignoreChildren(TypePackId ty) override
|
|
|
|
{
|
|
|
|
return ty->persistent;
|
|
|
|
}
|
2021-10-29 16:25:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// A substitution which replaces the type parameters of a type function by arguments
|
|
|
|
struct ApplyTypeFunction : Substitution
|
|
|
|
{
|
2022-02-17 19:41:20 -05:00
|
|
|
ApplyTypeFunction(TypeArena* arena, TypeLevel level)
|
|
|
|
: Substitution(TxnLog::empty(), arena)
|
|
|
|
, level(level)
|
|
|
|
, encounteredForwardedType(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
TypeLevel level;
|
|
|
|
bool encounteredForwardedType;
|
2021-11-04 22:07:18 -04:00
|
|
|
std::unordered_map<TypeId, TypeId> typeArguments;
|
|
|
|
std::unordered_map<TypePackId, TypePackId> typePackArguments;
|
|
|
|
bool ignoreChildren(TypeId ty) override;
|
|
|
|
bool ignoreChildren(TypePackId tp) override;
|
2021-10-29 16:25:12 -04:00
|
|
|
bool isDirty(TypeId ty) override;
|
|
|
|
bool isDirty(TypePackId tp) override;
|
|
|
|
TypeId clean(TypeId ty) override;
|
|
|
|
TypePackId clean(TypePackId tp) override;
|
|
|
|
};
|
|
|
|
|
2022-01-14 11:06:31 -05:00
|
|
|
struct GenericTypeDefinitions
|
|
|
|
{
|
|
|
|
std::vector<GenericTypeDefinition> genericTypes;
|
|
|
|
std::vector<GenericTypePackDefinition> genericPacks;
|
|
|
|
};
|
|
|
|
|
2022-02-11 13:43:14 -05:00
|
|
|
struct HashBoolNamePair
|
|
|
|
{
|
|
|
|
size_t operator()(const std::pair<bool, Name>& pair) const;
|
|
|
|
};
|
|
|
|
|
2022-04-07 16:53:47 -04:00
|
|
|
class TimeLimitError : public std::exception
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual const char* what() const throw();
|
|
|
|
};
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
// All TypeVars are retained via Environment::typeVars. All TypeIds
|
|
|
|
// within a program are borrowed pointers into this set.
|
|
|
|
struct TypeChecker
|
|
|
|
{
|
|
|
|
explicit TypeChecker(ModuleResolver* resolver, InternalErrorReporter* iceHandler);
|
|
|
|
TypeChecker(const TypeChecker&) = delete;
|
|
|
|
TypeChecker& operator=(const TypeChecker&) = delete;
|
|
|
|
|
|
|
|
ModulePtr check(const SourceModule& module, Mode mode, std::optional<ScopePtr> environmentScope = std::nullopt);
|
2022-04-14 17:57:15 -04:00
|
|
|
ModulePtr checkWithoutRecursionCheck(const SourceModule& module, Mode mode, std::optional<ScopePtr> environmentScope = std::nullopt);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
std::vector<std::pair<Location, ScopePtr>> getScopes() const;
|
|
|
|
|
|
|
|
void check(const ScopePtr& scope, const AstStat& statement);
|
|
|
|
void check(const ScopePtr& scope, const AstStatBlock& statement);
|
|
|
|
void check(const ScopePtr& scope, const AstStatIf& statement);
|
|
|
|
void check(const ScopePtr& scope, const AstStatWhile& statement);
|
|
|
|
void check(const ScopePtr& scope, const AstStatRepeat& statement);
|
|
|
|
void check(const ScopePtr& scope, const AstStatReturn& return_);
|
|
|
|
void check(const ScopePtr& scope, const AstStatAssign& assign);
|
|
|
|
void check(const ScopePtr& scope, const AstStatCompoundAssign& assign);
|
|
|
|
void check(const ScopePtr& scope, const AstStatLocal& local);
|
|
|
|
void check(const ScopePtr& scope, const AstStatFor& local);
|
|
|
|
void check(const ScopePtr& scope, const AstStatForIn& forin);
|
|
|
|
void check(const ScopePtr& scope, TypeId ty, const ScopePtr& funScope, const AstStatFunction& function);
|
|
|
|
void check(const ScopePtr& scope, TypeId ty, const ScopePtr& funScope, const AstStatLocalFunction& function);
|
2021-11-04 22:42:00 -04:00
|
|
|
void check(const ScopePtr& scope, const AstStatTypeAlias& typealias, int subLevel = 0, bool forwardDeclare = false);
|
2021-10-29 16:25:12 -04:00
|
|
|
void check(const ScopePtr& scope, const AstStatDeclareClass& declaredClass);
|
|
|
|
void check(const ScopePtr& scope, const AstStatDeclareFunction& declaredFunction);
|
|
|
|
|
|
|
|
void checkBlock(const ScopePtr& scope, const AstStatBlock& statement);
|
2022-04-14 17:57:15 -04:00
|
|
|
void checkBlockWithoutRecursionCheck(const ScopePtr& scope, const AstStatBlock& statement);
|
2021-10-29 16:25:12 -04:00
|
|
|
void checkBlockTypeAliases(const ScopePtr& scope, std::vector<AstStat*>& sorted);
|
|
|
|
|
2022-06-16 20:54:42 -04:00
|
|
|
WithPredicate<TypeId> checkExpr(
|
2022-01-27 16:29:34 -05:00
|
|
|
const ScopePtr& scope, const AstExpr& expr, std::optional<TypeId> expectedType = std::nullopt, bool forceSingleton = false);
|
2022-06-16 20:54:42 -04:00
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprLocal& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprGlobal& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprVarargs& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprCall& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprIndexName& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprIndexExpr& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprFunction& expr, std::optional<TypeId> expectedType = std::nullopt);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprTable& expr, std::optional<TypeId> expectedType = std::nullopt);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprUnary& expr);
|
2021-10-29 16:25:12 -04:00
|
|
|
TypeId checkRelationalOperation(
|
|
|
|
const ScopePtr& scope, const AstExprBinary& expr, TypeId lhsType, TypeId rhsType, const PredicateVec& predicates = {});
|
|
|
|
TypeId checkBinaryOperation(
|
|
|
|
const ScopePtr& scope, const AstExprBinary& expr, TypeId lhsType, TypeId rhsType, const PredicateVec& predicates = {});
|
2022-07-07 21:05:31 -04:00
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType = std::nullopt);
|
2022-06-16 20:54:42 -04:00
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprTypeAssertion& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprError& expr);
|
|
|
|
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprIfElse& expr, std::optional<TypeId> expectedType = std::nullopt);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
TypeId checkExprTable(const ScopePtr& scope, const AstExprTable& expr, const std::vector<std::pair<TypeId, TypeId>>& fieldTypes,
|
|
|
|
std::optional<TypeId> expectedType);
|
|
|
|
|
|
|
|
// Returns the type of the lvalue.
|
|
|
|
TypeId checkLValue(const ScopePtr& scope, const AstExpr& expr);
|
|
|
|
|
2022-01-27 16:29:34 -05:00
|
|
|
// Returns the type of the lvalue.
|
|
|
|
TypeId checkLValueBinding(const ScopePtr& scope, const AstExpr& expr);
|
|
|
|
TypeId checkLValueBinding(const ScopePtr& scope, const AstExprLocal& expr);
|
|
|
|
TypeId checkLValueBinding(const ScopePtr& scope, const AstExprGlobal& expr);
|
|
|
|
TypeId checkLValueBinding(const ScopePtr& scope, const AstExprIndexName& expr);
|
|
|
|
TypeId checkLValueBinding(const ScopePtr& scope, const AstExprIndexExpr& expr);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2021-12-10 16:17:10 -05:00
|
|
|
TypeId checkFunctionName(const ScopePtr& scope, AstExpr& funName, TypeLevel level);
|
2021-10-29 16:25:12 -04:00
|
|
|
std::pair<TypeId, ScopePtr> checkFunctionSignature(const ScopePtr& scope, int subLevel, const AstExprFunction& expr,
|
2022-06-30 19:29:02 -04:00
|
|
|
std::optional<Location> originalNameLoc, std::optional<TypeId> selfType, std::optional<TypeId> expectedType);
|
2021-10-29 16:25:12 -04:00
|
|
|
void checkFunctionBody(const ScopePtr& scope, TypeId type, const AstExprFunction& function);
|
|
|
|
|
|
|
|
void checkArgumentList(
|
|
|
|
const ScopePtr& scope, Unifier& state, TypePackId paramPack, TypePackId argPack, const std::vector<Location>& argLocations);
|
|
|
|
|
2022-06-16 20:54:42 -04:00
|
|
|
WithPredicate<TypePackId> checkExprPack(const ScopePtr& scope, const AstExpr& expr);
|
2022-07-07 21:05:31 -04:00
|
|
|
|
|
|
|
WithPredicate<TypePackId> checkExprPackHelper(const ScopePtr& scope, const AstExpr& expr);
|
|
|
|
WithPredicate<TypePackId> checkExprPackHelper(const ScopePtr& scope, const AstExprCall& expr);
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
std::vector<std::optional<TypeId>> getExpectedTypesForCall(const std::vector<TypeId>& overloads, size_t argumentCount, bool selfCall);
|
2022-07-07 21:05:31 -04:00
|
|
|
|
2022-06-16 20:54:42 -04:00
|
|
|
std::optional<WithPredicate<TypePackId>> checkCallOverload(const ScopePtr& scope, const AstExprCall& expr, TypeId fn, TypePackId retPack,
|
|
|
|
TypePackId argPack, TypePack* args, const std::vector<Location>* argLocations, const WithPredicate<TypePackId>& argListResult,
|
2021-11-18 17:21:07 -05:00
|
|
|
std::vector<TypeId>& overloadsThatMatchArgCount, std::vector<TypeId>& overloadsThatDont, std::vector<OverloadErrorEntry>& errors);
|
2021-10-29 16:25:12 -04:00
|
|
|
bool handleSelfCallMismatch(const ScopePtr& scope, const AstExprCall& expr, TypePack* args, const std::vector<Location>& argLocations,
|
|
|
|
const std::vector<OverloadErrorEntry>& errors);
|
2021-11-18 17:21:07 -05:00
|
|
|
void reportOverloadResolutionError(const ScopePtr& scope, const AstExprCall& expr, TypePackId retPack, TypePackId argPack,
|
2021-10-29 16:25:12 -04:00
|
|
|
const std::vector<Location>& argLocations, const std::vector<TypeId>& overloads, const std::vector<TypeId>& overloadsThatMatchArgCount,
|
|
|
|
const std::vector<OverloadErrorEntry>& errors);
|
|
|
|
|
2022-06-16 20:54:42 -04:00
|
|
|
WithPredicate<TypePackId> checkExprList(const ScopePtr& scope, const Location& location, const AstArray<AstExpr*>& exprs,
|
2021-10-29 16:25:12 -04:00
|
|
|
bool substituteFreeForNil = false, const std::vector<bool>& lhsAnnotations = {},
|
|
|
|
const std::vector<std::optional<TypeId>>& expectedTypes = {});
|
|
|
|
|
|
|
|
static std::optional<AstExpr*> matchRequire(const AstExprCall& call);
|
|
|
|
TypeId checkRequire(const ScopePtr& scope, const ModuleInfo& moduleInfo, const Location& location);
|
|
|
|
|
|
|
|
// Try to infer that the provided type is a table of some sort.
|
|
|
|
// Reports an error if the type is already some kind of non-table.
|
|
|
|
void tablify(TypeId type);
|
|
|
|
|
|
|
|
/** In nonstrict mode, many typevars need to be replaced by any.
|
|
|
|
*/
|
|
|
|
TypeId anyIfNonstrict(TypeId ty) const;
|
|
|
|
|
2022-01-06 17:10:07 -05:00
|
|
|
/** Attempt to unify the types.
|
|
|
|
* Treat any failures as type errors in the final typecheck report.
|
2021-10-29 16:25:12 -04:00
|
|
|
*/
|
2022-01-06 17:10:07 -05:00
|
|
|
bool unify(TypeId subTy, TypeId superTy, const Location& location);
|
2022-02-24 18:15:41 -05:00
|
|
|
bool unify(TypeId subTy, TypeId superTy, const Location& location, const UnifierOptions& options);
|
2022-01-06 17:10:07 -05:00
|
|
|
bool unify(TypePackId subTy, TypePackId superTy, const Location& location, CountMismatch::Context ctx = CountMismatch::Context::Arg);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2022-01-06 17:10:07 -05:00
|
|
|
/** Attempt to unify the types.
|
|
|
|
* If this fails, and the subTy type can be instantiated, do so and try unification again.
|
2021-10-29 16:25:12 -04:00
|
|
|
*/
|
2022-01-06 17:10:07 -05:00
|
|
|
bool unifyWithInstantiationIfNeeded(const ScopePtr& scope, TypeId subTy, TypeId superTy, const Location& location);
|
|
|
|
void unifyWithInstantiationIfNeeded(const ScopePtr& scope, TypeId subTy, TypeId superTy, Unifier& state);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2022-01-06 17:10:07 -05:00
|
|
|
/** Attempt to unify.
|
2021-10-29 16:25:12 -04:00
|
|
|
* If there are errors, undo everything and return the errors.
|
|
|
|
* If there are no errors, commit and return an empty error vector.
|
|
|
|
*/
|
2022-01-06 17:10:07 -05:00
|
|
|
template<typename Id>
|
|
|
|
ErrorVec tryUnify_(Id subTy, Id superTy, const Location& location);
|
|
|
|
ErrorVec tryUnify(TypeId subTy, TypeId superTy, const Location& location);
|
|
|
|
ErrorVec tryUnify(TypePackId subTy, TypePackId superTy, const Location& location);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
// Test whether the two type vars unify. Never commits the result.
|
2022-01-06 17:10:07 -05:00
|
|
|
template<typename Id>
|
|
|
|
ErrorVec canUnify_(Id subTy, Id superTy, const Location& location);
|
|
|
|
ErrorVec canUnify(TypeId subTy, TypeId superTy, const Location& location);
|
|
|
|
ErrorVec canUnify(TypePackId subTy, TypePackId superTy, const Location& location);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2022-06-16 20:54:42 -04:00
|
|
|
void unifyLowerBound(TypePackId subTy, TypePackId superTy, TypeLevel demotedLevel, const Location& location);
|
2022-04-14 17:57:15 -04:00
|
|
|
|
2022-07-07 21:05:31 -04:00
|
|
|
std::optional<TypeId> findMetatableEntry(TypeId type, std::string entry, const Location& location, bool addErrors);
|
|
|
|
std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location, bool addErrors);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors);
|
2022-07-07 21:05:31 -04:00
|
|
|
std::optional<TypeId> getIndexTypeFromTypeImpl(const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
// Reduces the union to its simplest possible shape.
|
|
|
|
// (A | B) | B | C yields A | B | C
|
|
|
|
std::vector<TypeId> reduceUnion(const std::vector<TypeId>& types);
|
|
|
|
|
|
|
|
std::optional<TypeId> tryStripUnionFromNil(TypeId ty);
|
|
|
|
TypeId stripFromNilAndReport(TypeId ty, const Location& location);
|
|
|
|
|
|
|
|
public:
|
|
|
|
/*
|
|
|
|
* Convert monotype into a a polytype, by replacing any metavariables in descendant scopes
|
|
|
|
* by bound generic type variables. This is used to infer that a function is generic.
|
|
|
|
*/
|
|
|
|
TypeId quantify(const ScopePtr& scope, TypeId ty, Location location);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert a polytype into a monotype, by replacing any bound generic types by type metavariables.
|
|
|
|
* This is used to typecheck particular calls to generic functions, and when generic functions
|
|
|
|
* are passed as arguments.
|
|
|
|
*
|
|
|
|
* The "changed" boolean is used to permit us to return the same TypeId in the case that the instantiated type is unchanged.
|
|
|
|
* This is important in certain cases, such as methods on objects, where a table contains a function whose first argument is the table.
|
|
|
|
* Without this property, we can wind up in a situation where a new TypeId is allocated for the outer table. This can cause us to produce
|
|
|
|
* unfortunate types like
|
|
|
|
*
|
|
|
|
* {method: ({method: (<CYCLE>) -> a}) -> a}
|
|
|
|
*
|
|
|
|
*/
|
2022-02-03 18:09:37 -05:00
|
|
|
TypeId instantiate(const ScopePtr& scope, TypeId ty, Location location, const TxnLog* log = TxnLog::empty());
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
// Replace any free types or type packs by `any`.
|
|
|
|
// This is used when exporting types from modules, to make sure free types don't leak.
|
|
|
|
TypeId anyify(const ScopePtr& scope, TypeId ty, Location location);
|
|
|
|
TypePackId anyify(const ScopePtr& scope, TypePackId ty, Location location);
|
|
|
|
|
|
|
|
void reportError(const TypeError& error);
|
|
|
|
void reportError(const Location& location, TypeErrorData error);
|
|
|
|
void reportErrors(const ErrorVec& errors);
|
|
|
|
|
|
|
|
[[noreturn]] void ice(const std::string& message, const Location& location);
|
|
|
|
[[noreturn]] void ice(const std::string& message);
|
|
|
|
|
|
|
|
ScopePtr childFunctionScope(const ScopePtr& parent, const Location& location, int subLevel = 0);
|
2021-12-10 16:17:10 -05:00
|
|
|
ScopePtr childScope(const ScopePtr& parent, const Location& location);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
// Wrapper for merge(l, r, toUnion) but without the lambda junk.
|
|
|
|
void merge(RefinementMap& l, const RefinementMap& r);
|
|
|
|
|
2021-11-18 17:21:07 -05:00
|
|
|
// Produce an "emergency backup type" for recovery from type errors.
|
|
|
|
// This comes in two flavours, depening on whether or not we can make a good guess
|
|
|
|
// for an error recovery type.
|
|
|
|
TypeId errorRecoveryType(TypeId guess);
|
|
|
|
TypePackId errorRecoveryTypePack(TypePackId guess);
|
|
|
|
TypeId errorRecoveryType(const ScopePtr& scope);
|
|
|
|
TypePackId errorRecoveryTypePack(const ScopePtr& scope);
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
private:
|
|
|
|
void prepareErrorsForDisplay(ErrorVec& errVec);
|
|
|
|
void diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& data);
|
|
|
|
void reportErrorCodeTooComplex(const Location& location);
|
|
|
|
|
|
|
|
private:
|
|
|
|
Unifier mkUnifier(const Location& location);
|
|
|
|
|
|
|
|
// These functions are only safe to call when we are in the process of typechecking a module.
|
|
|
|
|
|
|
|
// Produce a new free type var.
|
|
|
|
TypeId freshType(const ScopePtr& scope);
|
|
|
|
TypeId freshType(TypeLevel level);
|
|
|
|
|
2021-11-18 17:21:07 -05:00
|
|
|
// Produce a new singleton type var.
|
|
|
|
TypeId singletonType(bool value);
|
|
|
|
TypeId singletonType(std::string value);
|
|
|
|
|
2022-02-03 18:09:37 -05:00
|
|
|
TypeIdPredicate mkTruthyPredicate(bool sense);
|
|
|
|
|
2022-07-07 21:05:31 -04:00
|
|
|
// TODO: Return TypeId only.
|
|
|
|
std::optional<TypeId> filterMapImpl(TypeId type, TypeIdPredicate predicate);
|
|
|
|
std::pair<std::optional<TypeId>, bool> filterMap(TypeId type, TypeIdPredicate predicate);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2022-02-03 18:09:37 -05:00
|
|
|
public:
|
2022-07-07 21:05:31 -04:00
|
|
|
std::pair<std::optional<TypeId>, bool> pickTypesFromSense(TypeId type, bool sense);
|
2022-02-03 18:09:37 -05:00
|
|
|
|
|
|
|
private:
|
2021-10-29 16:25:12 -04:00
|
|
|
TypeId unionOfTypes(TypeId a, TypeId b, const Location& location, bool unifyFreeTypes = true);
|
|
|
|
|
|
|
|
// ex
|
|
|
|
// TypeId id = addType(FreeTypeVar());
|
|
|
|
template<typename T>
|
|
|
|
TypeId addType(const T& tv)
|
|
|
|
{
|
|
|
|
return addTV(TypeVar(tv));
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId addTV(TypeVar&& tv);
|
|
|
|
|
|
|
|
TypePackId addTypePack(TypePackVar&& tp);
|
|
|
|
TypePackId addTypePack(TypePack&& tp);
|
|
|
|
|
|
|
|
TypePackId addTypePack(const std::vector<TypeId>& ty);
|
|
|
|
TypePackId addTypePack(const std::vector<TypeId>& ty, std::optional<TypePackId> tail);
|
|
|
|
TypePackId addTypePack(std::initializer_list<TypeId>&& ty);
|
|
|
|
TypePackId freshTypePack(const ScopePtr& scope);
|
|
|
|
TypePackId freshTypePack(TypeLevel level);
|
|
|
|
|
2021-11-11 21:12:39 -05:00
|
|
|
TypeId resolveType(const ScopePtr& scope, const AstType& annotation);
|
2022-07-07 21:05:31 -04:00
|
|
|
TypeId resolveTypeWorker(const ScopePtr& scope, const AstType& annotation);
|
2021-10-29 16:25:12 -04:00
|
|
|
TypePackId resolveTypePack(const ScopePtr& scope, const AstTypeList& types);
|
|
|
|
TypePackId resolveTypePack(const ScopePtr& scope, const AstTypePack& annotation);
|
2021-11-04 22:07:18 -04:00
|
|
|
TypeId instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf, const std::vector<TypeId>& typeParams,
|
|
|
|
const std::vector<TypePackId>& typePackParams, const Location& location);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
// Note: `scope` must be a fresh scope.
|
2022-01-14 11:06:31 -05:00
|
|
|
GenericTypeDefinitions createGenericTypes(const ScopePtr& scope, std::optional<TypeLevel> levelOpt, const AstNode& node,
|
2022-02-17 19:41:20 -05:00
|
|
|
const AstArray<AstGenericType>& genericNames, const AstArray<AstGenericTypePack>& genericPackNames, bool useCache = false);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
public:
|
2022-05-19 19:46:52 -04:00
|
|
|
void resolve(const PredicateVec& predicates, const ScopePtr& scope, bool sense);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
private:
|
2022-01-27 16:29:34 -05:00
|
|
|
void refineLValue(const LValue& lvalue, RefinementMap& refis, const ScopePtr& scope, TypeIdPredicate predicate);
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
std::optional<TypeId> resolveLValue(const ScopePtr& scope, const LValue& lvalue);
|
|
|
|
std::optional<TypeId> resolveLValue(const RefinementMap& refis, const ScopePtr& scope, const LValue& lvalue);
|
|
|
|
|
2022-05-19 19:46:52 -04:00
|
|
|
void resolve(const PredicateVec& predicates, RefinementMap& refis, const ScopePtr& scope, bool sense, bool fromOr = false);
|
|
|
|
void resolve(const Predicate& predicate, RefinementMap& refis, const ScopePtr& scope, bool sense, bool fromOr);
|
|
|
|
void resolve(const TruthyPredicate& truthyP, RefinementMap& refis, const ScopePtr& scope, bool sense, bool fromOr);
|
|
|
|
void resolve(const AndPredicate& andP, RefinementMap& refis, const ScopePtr& scope, bool sense);
|
|
|
|
void resolve(const OrPredicate& orP, RefinementMap& refis, const ScopePtr& scope, bool sense);
|
|
|
|
void resolve(const IsAPredicate& isaP, RefinementMap& refis, const ScopePtr& scope, bool sense);
|
|
|
|
void resolve(const TypeGuardPredicate& typeguardP, RefinementMap& refis, const ScopePtr& scope, bool sense);
|
|
|
|
void resolve(const EqPredicate& eqP, RefinementMap& refis, const ScopePtr& scope, bool sense);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
bool isNonstrictMode() const;
|
2022-04-14 17:57:15 -04:00
|
|
|
bool useConstrainedIntersections() const;
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
public:
|
|
|
|
/** Extract the types in a type pack, given the assumption that the pack must have some exact length.
|
|
|
|
* TypePacks can have free tails, which means that inference has not yet determined the length of the pack.
|
|
|
|
* Calling this function means submitting evidence that the pack must have the length provided.
|
|
|
|
* If the pack is known not to have the correct length, an error will be reported.
|
|
|
|
* The return vector is always of the exact requested length. In the event that the pack's length does
|
|
|
|
* not match up, excess TypeIds will be ErrorTypeVars.
|
|
|
|
*/
|
|
|
|
std::vector<TypeId> unTypePack(const ScopePtr& scope, TypePackId pack, size_t expectedLength, const Location& location);
|
|
|
|
|
|
|
|
TypeArena globalTypes;
|
|
|
|
|
|
|
|
ModuleResolver* resolver;
|
|
|
|
SourceModule globalNames; // names for symbols entered into globalScope
|
|
|
|
ScopePtr globalScope; // shared by all modules
|
|
|
|
ModulePtr currentModule;
|
|
|
|
ModuleName currentModuleName;
|
|
|
|
|
|
|
|
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope;
|
|
|
|
InternalErrorReporter* iceHandler;
|
|
|
|
|
2021-11-04 22:42:00 -04:00
|
|
|
UnifierSharedState unifierState;
|
|
|
|
|
2022-04-07 16:53:47 -04:00
|
|
|
std::vector<RequireCycle> requireCycles;
|
|
|
|
|
2022-04-14 17:57:15 -04:00
|
|
|
// Type inference limits
|
2022-04-07 16:53:47 -04:00
|
|
|
std::optional<double> finishTime;
|
2022-04-14 17:57:15 -04:00
|
|
|
std::optional<int> instantiationChildLimit;
|
|
|
|
std::optional<int> unifierIterationLimit;
|
2022-04-07 16:53:47 -04:00
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
public:
|
|
|
|
const TypeId nilType;
|
|
|
|
const TypeId numberType;
|
|
|
|
const TypeId stringType;
|
|
|
|
const TypeId booleanType;
|
|
|
|
const TypeId threadType;
|
|
|
|
const TypeId anyType;
|
2022-07-07 21:05:31 -04:00
|
|
|
const TypeId unknownType;
|
|
|
|
const TypeId neverType;
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
const TypePackId anyTypePack;
|
2022-07-07 21:05:31 -04:00
|
|
|
const TypePackId neverTypePack;
|
|
|
|
const TypePackId uninhabitableTypePack;
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
private:
|
|
|
|
int checkRecursionCount = 0;
|
|
|
|
int recursionCount = 0;
|
2022-02-11 13:43:14 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* We use this to avoid doing second-pass analysis of type aliases that are duplicates. We record a pair
|
|
|
|
* (exported, name) to properly deal with the case where the two duplicates do not have the same export status.
|
|
|
|
*/
|
|
|
|
DenseHashSet<std::pair<bool, Name>, HashBoolNamePair> duplicateTypeAliases;
|
2022-06-30 19:29:02 -04:00
|
|
|
|
|
|
|
std::vector<std::pair<TypeId, ScopePtr>> deferredQuantification;
|
2021-10-29 16:25:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Unit test hook
|
|
|
|
void setPrintLine(void (*pl)(const std::string& s));
|
|
|
|
void resetPrintLine();
|
|
|
|
|
|
|
|
} // namespace Luau
|