mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Merge branch 'master' of https://github.com/Roblox/luau into autocomplete-context
This commit is contained in:
commit
33c3843c78
68 changed files with 1598 additions and 757 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -8,3 +8,4 @@
|
|||
/default.prof*
|
||||
/fuzz-*
|
||||
/luau
|
||||
__pycache__
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct Scope2;
|
||||
struct Scope;
|
||||
|
||||
struct TypeVar;
|
||||
using TypeId = const TypeVar*;
|
||||
|
||||
|
@ -38,7 +39,7 @@ struct GeneralizationConstraint
|
|||
{
|
||||
TypeId generalizedType;
|
||||
TypeId sourceType;
|
||||
Scope2* scope;
|
||||
Scope* scope;
|
||||
};
|
||||
|
||||
// subType ~ inst superType
|
||||
|
|
|
@ -17,21 +17,22 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct Scope2;
|
||||
struct Scope;
|
||||
using ScopePtr = std::shared_ptr<Scope>;
|
||||
|
||||
struct ConstraintGraphBuilder
|
||||
{
|
||||
// A list of all the scopes in the module. This vector holds ownership of the
|
||||
// scope pointers; the scopes themselves borrow pointers to other scopes to
|
||||
// define the scope hierarchy.
|
||||
std::vector<std::pair<Location, std::unique_ptr<Scope2>>> scopes;
|
||||
std::vector<std::pair<Location, ScopePtr>> scopes;
|
||||
|
||||
ModuleName moduleName;
|
||||
SingletonTypes& singletonTypes;
|
||||
const NotNull<TypeArena> arena;
|
||||
// The root scope of the module we're generating constraints for.
|
||||
// This is null when the CGB is initially constructed.
|
||||
Scope2* rootScope;
|
||||
Scope* rootScope;
|
||||
// A mapping of AST node to TypeId.
|
||||
DenseHashMap<const AstExpr*, TypeId> astTypes{nullptr};
|
||||
// A mapping of AST node to TypePackId.
|
||||
|
@ -50,42 +51,42 @@ struct ConstraintGraphBuilder
|
|||
// Occasionally constraint generation needs to produce an ICE.
|
||||
const NotNull<InternalErrorReporter> ice;
|
||||
|
||||
NotNull<Scope2> globalScope;
|
||||
NotNull<Scope> globalScope;
|
||||
|
||||
ConstraintGraphBuilder(const ModuleName& moduleName, TypeArena* arena, NotNull<InternalErrorReporter> ice, NotNull<Scope2> globalScope);
|
||||
ConstraintGraphBuilder(const ModuleName& moduleName, TypeArena* arena, NotNull<InternalErrorReporter> ice, NotNull<Scope> globalScope);
|
||||
|
||||
/**
|
||||
* Fabricates a new free type belonging to a given scope.
|
||||
* @param scope the scope the free type belongs to.
|
||||
*/
|
||||
TypeId freshType(NotNull<Scope2> scope);
|
||||
TypeId freshType(const ScopePtr& scope);
|
||||
|
||||
/**
|
||||
* Fabricates a new free type pack belonging to a given scope.
|
||||
* @param scope the scope the free type pack belongs to.
|
||||
*/
|
||||
TypePackId freshTypePack(NotNull<Scope2> scope);
|
||||
TypePackId freshTypePack(const ScopePtr& scope);
|
||||
|
||||
/**
|
||||
* Fabricates a scope that is a child of another scope.
|
||||
* @param location the lexical extent of the scope in the source code.
|
||||
* @param parent the parent scope of the new scope. Must not be null.
|
||||
*/
|
||||
NotNull<Scope2> childScope(Location location, NotNull<Scope2> parent);
|
||||
ScopePtr childScope(Location location, const ScopePtr& parent);
|
||||
|
||||
/**
|
||||
* Adds a new constraint with no dependencies to a given scope.
|
||||
* @param scope the scope to add the constraint to.
|
||||
* @param cv the constraint variant to add.
|
||||
*/
|
||||
void addConstraint(NotNull<Scope2> scope, ConstraintV cv);
|
||||
void addConstraint(const ScopePtr& scope, ConstraintV cv);
|
||||
|
||||
/**
|
||||
* Adds a constraint to a given scope.
|
||||
* @param scope the scope to add the constraint to. Must not be null.
|
||||
* @param c the constraint to add.
|
||||
*/
|
||||
void addConstraint(NotNull<Scope2> scope, std::unique_ptr<Constraint> c);
|
||||
void addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c);
|
||||
|
||||
/**
|
||||
* The entry point to the ConstraintGraphBuilder. This will construct a set
|
||||
|
@ -94,23 +95,23 @@ struct ConstraintGraphBuilder
|
|||
*/
|
||||
void visit(AstStatBlock* block);
|
||||
|
||||
void visitBlockWithoutChildScope(NotNull<Scope2> scope, AstStatBlock* block);
|
||||
void visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block);
|
||||
|
||||
void visit(NotNull<Scope2> scope, AstStat* stat);
|
||||
void visit(NotNull<Scope2> scope, AstStatBlock* block);
|
||||
void visit(NotNull<Scope2> scope, AstStatLocal* local);
|
||||
void visit(NotNull<Scope2> scope, AstStatFor* for_);
|
||||
void visit(NotNull<Scope2> scope, AstStatLocalFunction* function);
|
||||
void visit(NotNull<Scope2> scope, AstStatFunction* function);
|
||||
void visit(NotNull<Scope2> scope, AstStatReturn* ret);
|
||||
void visit(NotNull<Scope2> scope, AstStatAssign* assign);
|
||||
void visit(NotNull<Scope2> scope, AstStatIf* ifStatement);
|
||||
void visit(NotNull<Scope2> scope, AstStatTypeAlias* alias);
|
||||
void visit(const ScopePtr& scope, AstStat* stat);
|
||||
void visit(const ScopePtr& scope, AstStatBlock* block);
|
||||
void visit(const ScopePtr& scope, AstStatLocal* local);
|
||||
void visit(const ScopePtr& scope, AstStatFor* for_);
|
||||
void visit(const ScopePtr& scope, AstStatLocalFunction* function);
|
||||
void visit(const ScopePtr& scope, AstStatFunction* function);
|
||||
void visit(const ScopePtr& scope, AstStatReturn* ret);
|
||||
void visit(const ScopePtr& scope, AstStatAssign* assign);
|
||||
void visit(const ScopePtr& scope, AstStatIf* ifStatement);
|
||||
void visit(const ScopePtr& scope, AstStatTypeAlias* alias);
|
||||
|
||||
TypePackId checkExprList(NotNull<Scope2> scope, const AstArray<AstExpr*>& exprs);
|
||||
TypePackId checkExprList(const ScopePtr& scope, const AstArray<AstExpr*>& exprs);
|
||||
|
||||
TypePackId checkPack(NotNull<Scope2> scope, AstArray<AstExpr*> exprs);
|
||||
TypePackId checkPack(NotNull<Scope2> scope, AstExpr* expr);
|
||||
TypePackId checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs);
|
||||
TypePackId checkPack(const ScopePtr& scope, AstExpr* expr);
|
||||
|
||||
/**
|
||||
* Checks an expression that is expected to evaluate to one type.
|
||||
|
@ -118,13 +119,13 @@ struct ConstraintGraphBuilder
|
|||
* @param expr the expression to check.
|
||||
* @return the type of the expression.
|
||||
*/
|
||||
TypeId check(NotNull<Scope2> scope, AstExpr* expr);
|
||||
TypeId check(const ScopePtr& scope, AstExpr* expr);
|
||||
|
||||
TypeId checkExprTable(NotNull<Scope2> scope, AstExprTable* expr);
|
||||
TypeId check(NotNull<Scope2> scope, AstExprIndexName* indexName);
|
||||
TypeId check(NotNull<Scope2> scope, AstExprIndexExpr* indexExpr);
|
||||
TypeId check(NotNull<Scope2> scope, AstExprUnary* unary);
|
||||
TypeId check(NotNull<Scope2> scope, AstExprBinary* binary);
|
||||
TypeId checkExprTable(const ScopePtr& scope, AstExprTable* expr);
|
||||
TypeId check(const ScopePtr& scope, AstExprIndexName* indexName);
|
||||
TypeId check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
|
||||
TypeId check(const ScopePtr& scope, AstExprUnary* unary);
|
||||
TypeId check(const ScopePtr& scope, AstExprBinary* binary);
|
||||
|
||||
struct FunctionSignature
|
||||
{
|
||||
|
@ -133,20 +134,20 @@ struct ConstraintGraphBuilder
|
|||
// The scope that encompasses the function's signature. May be nullptr
|
||||
// if there was no need for a signature scope (the function has no
|
||||
// generics).
|
||||
Scope2* signatureScope;
|
||||
ScopePtr signatureScope;
|
||||
// The scope that encompasses the function's body. Is a child scope of
|
||||
// signatureScope, if present.
|
||||
NotNull<Scope2> bodyScope;
|
||||
ScopePtr bodyScope;
|
||||
};
|
||||
|
||||
FunctionSignature checkFunctionSignature(NotNull<Scope2> parent, AstExprFunction* fn);
|
||||
FunctionSignature checkFunctionSignature(const ScopePtr& parent, AstExprFunction* fn);
|
||||
|
||||
/**
|
||||
* Checks the body of a function expression.
|
||||
* @param scope the interior scope of the body of the function.
|
||||
* @param fn the function expression to check.
|
||||
*/
|
||||
void checkFunctionBody(NotNull<Scope2> scope, AstExprFunction* fn);
|
||||
void checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn);
|
||||
|
||||
/**
|
||||
* Resolves a type from its AST annotation.
|
||||
|
@ -154,7 +155,7 @@ struct ConstraintGraphBuilder
|
|||
* @param ty the AST annotation to resolve.
|
||||
* @return the type of the AST annotation.
|
||||
**/
|
||||
TypeId resolveType(NotNull<Scope2> scope, AstType* ty);
|
||||
TypeId resolveType(const ScopePtr& scope, AstType* ty);
|
||||
|
||||
/**
|
||||
* Resolves a type pack from its AST annotation.
|
||||
|
@ -162,14 +163,14 @@ struct ConstraintGraphBuilder
|
|||
* @param tp the AST annotation to resolve.
|
||||
* @return the type pack of the AST annotation.
|
||||
**/
|
||||
TypePackId resolveTypePack(NotNull<Scope2> scope, AstTypePack* tp);
|
||||
TypePackId resolveTypePack(const ScopePtr& scope, AstTypePack* tp);
|
||||
|
||||
TypePackId resolveTypePack(NotNull<Scope2> scope, const AstTypeList& list);
|
||||
TypePackId resolveTypePack(const ScopePtr& scope, const AstTypeList& list);
|
||||
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> createGenerics(NotNull<Scope2> scope, AstArray<AstGenericType> generics);
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> createGenericPacks(NotNull<Scope2> scope, AstArray<AstGenericTypePack> packs);
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> createGenerics(const ScopePtr& scope, AstArray<AstGenericType> generics);
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> createGenericPacks(const ScopePtr& scope, AstArray<AstGenericTypePack> packs);
|
||||
|
||||
TypeId flattenPack(NotNull<Scope2> scope, Location location, TypePackId tp);
|
||||
TypeId flattenPack(const ScopePtr& scope, Location location, TypePackId tp);
|
||||
|
||||
void reportError(Location location, TypeErrorData err);
|
||||
void reportCodeTooComplex(Location location);
|
||||
|
@ -180,7 +181,7 @@ struct ConstraintGraphBuilder
|
|||
* real" in a general way is going to be pretty hard, so we are choosing not to tackle that yet. For now, we do an
|
||||
* initial scan of the AST and note what globals are defined.
|
||||
*/
|
||||
void prepopulateGlobalScope(NotNull<Scope2> globalScope, AstStatBlock* program);
|
||||
void prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -193,6 +194,6 @@ struct ConstraintGraphBuilder
|
|||
* @return a list of pointers to constraints contained within the scope graph.
|
||||
* None of these pointers should be null.
|
||||
*/
|
||||
std::vector<NotNull<Constraint>> collectConstraints(NotNull<Scope2> rootScope);
|
||||
std::vector<NotNull<Constraint>> collectConstraints(NotNull<Scope> rootScope);
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -25,7 +25,7 @@ struct ConstraintSolver
|
|||
// is important to not add elements to this vector, lest the underlying
|
||||
// storage that we retain pointers to be mutated underneath us.
|
||||
const std::vector<NotNull<Constraint>> constraints;
|
||||
NotNull<Scope2> rootScope;
|
||||
NotNull<Scope> rootScope;
|
||||
|
||||
// This includes every constraint that has not been fully solved.
|
||||
// A constraint can be both blocked and unsolved, for instance.
|
||||
|
@ -40,7 +40,7 @@ struct ConstraintSolver
|
|||
|
||||
ConstraintSolverLogger logger;
|
||||
|
||||
explicit ConstraintSolver(TypeArena* arena, NotNull<Scope2> rootScope);
|
||||
explicit ConstraintSolver(TypeArena* arena, NotNull<Scope> rootScope);
|
||||
|
||||
/**
|
||||
* Attempts to dispatch all pending constraints and reach a type solution
|
||||
|
@ -121,6 +121,6 @@ private:
|
|||
void unblock_(BlockedConstraintId progressed);
|
||||
};
|
||||
|
||||
void dump(NotNull<Scope2> rootScope, struct ToStringOptions& opts);
|
||||
void dump(NotNull<Scope> rootScope, struct ToStringOptions& opts);
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Luau
|
|||
struct ConstraintSolverLogger
|
||||
{
|
||||
std::string compileOutput();
|
||||
void captureBoundarySnapshot(const Scope2* rootScope, std::vector<NotNull<const Constraint>>& unsolvedConstraints);
|
||||
void prepareStepSnapshot(const Scope2* rootScope, NotNull<const Constraint> current, std::vector<NotNull<const Constraint>>& unsolvedConstraints);
|
||||
void captureBoundarySnapshot(const Scope* rootScope, std::vector<NotNull<const Constraint>>& unsolvedConstraints);
|
||||
void prepareStepSnapshot(const Scope* rootScope, NotNull<const Constraint> current, std::vector<NotNull<const Constraint>>& unsolvedConstraints);
|
||||
void commitPreparedStepSnapshot();
|
||||
|
||||
private:
|
||||
|
|
|
@ -152,7 +152,7 @@ struct Frontend
|
|||
void registerBuiltinDefinition(const std::string& name, std::function<void(TypeChecker&, ScopePtr)>);
|
||||
void applyBuiltinDefinitionToEnvironment(const std::string& environmentName, const std::string& definitionName);
|
||||
|
||||
NotNull<Scope2> getGlobalScope2();
|
||||
NotNull<Scope> getGlobalScope();
|
||||
|
||||
private:
|
||||
ModulePtr check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope);
|
||||
|
@ -169,7 +169,7 @@ private:
|
|||
std::unordered_map<std::string, ScopePtr> environments;
|
||||
std::unordered_map<std::string, std::function<void(TypeChecker&, ScopePtr)>> builtinDefinitions;
|
||||
|
||||
std::unique_ptr<Scope2> globalScope2;
|
||||
std::unique_ptr<Scope> globalScope;
|
||||
|
||||
public:
|
||||
FileResolver* fileResolver;
|
||||
|
|
|
@ -69,7 +69,6 @@ struct Module
|
|||
std::shared_ptr<AstNameTable> names;
|
||||
|
||||
std::vector<std::pair<Location, ScopePtr>> scopes; // never empty
|
||||
std::vector<std::pair<Location, std::unique_ptr<Scope2>>> scope2s; // never empty
|
||||
|
||||
DenseHashMap<const AstExpr*, TypeId> astTypes{nullptr};
|
||||
DenseHashMap<const AstExpr*, TypePackId> astTypePacks{nullptr};
|
||||
|
@ -86,7 +85,6 @@ struct Module
|
|||
bool timeout = false;
|
||||
|
||||
ScopePtr getModuleScope() const;
|
||||
Scope2* getModuleScope2() const;
|
||||
|
||||
// Once a module has been typechecked, we clone its public interface into a separate arena.
|
||||
// This helps us to force TypeVar ownership into a DAG rather than a DCG.
|
||||
|
|
|
@ -7,9 +7,9 @@ namespace Luau
|
|||
{
|
||||
|
||||
struct TypeArena;
|
||||
struct Scope2;
|
||||
struct Scope;
|
||||
|
||||
void quantify(TypeId ty, TypeLevel level);
|
||||
TypeId quantify(TypeArena* arena, TypeId ty, Scope2* scope);
|
||||
TypeId quantify(TypeArena* arena, TypeId ty, Scope* scope);
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -32,10 +32,16 @@ struct Scope
|
|||
explicit Scope(const ScopePtr& parent, int subLevel = 0); // child scope. Parent must not be nullptr.
|
||||
|
||||
const ScopePtr parent; // null for the root
|
||||
|
||||
// All the children of this scope.
|
||||
std::vector<NotNull<Scope>> children;
|
||||
std::unordered_map<Symbol, Binding> bindings;
|
||||
std::unordered_map<Name, TypeId> typeBindings;
|
||||
std::unordered_map<Name, TypePackId> typePackBindings;
|
||||
TypePackId returnType;
|
||||
bool breakOk = false;
|
||||
std::optional<TypePackId> varargPack;
|
||||
// All constraints belonging to this scope.
|
||||
std::vector<ConstraintPtr> constraints;
|
||||
|
||||
TypeLevel level;
|
||||
|
||||
|
@ -45,7 +51,9 @@ struct Scope
|
|||
|
||||
std::unordered_map<Name, std::unordered_map<Name, TypeFun>> importedTypeBindings;
|
||||
|
||||
std::optional<TypeId> lookup(const Symbol& name);
|
||||
std::optional<TypeId> lookup(Symbol sym);
|
||||
std::optional<TypeId> lookupTypeBinding(const Name& name);
|
||||
std::optional<TypePackId> lookupTypePackBinding(const Name& name);
|
||||
|
||||
std::optional<TypeFun> lookupType(const Name& name);
|
||||
std::optional<TypeFun> lookupImportedType(const Name& moduleAlias, const Name& name);
|
||||
|
@ -66,24 +74,4 @@ struct Scope
|
|||
std::unordered_map<Name, TypePackId> typeAliasTypePackParameters;
|
||||
};
|
||||
|
||||
struct Scope2
|
||||
{
|
||||
// The parent scope of this scope. Null if there is no parent (i.e. this
|
||||
// is the module-level scope).
|
||||
Scope2* parent = nullptr;
|
||||
// All the children of this scope.
|
||||
std::vector<NotNull<Scope2>> children;
|
||||
std::unordered_map<Symbol, TypeId> bindings; // TODO: I think this can be a DenseHashMap
|
||||
std::unordered_map<Name, TypeId> typeBindings;
|
||||
std::unordered_map<Name, TypePackId> typePackBindings;
|
||||
TypePackId returnType;
|
||||
std::optional<TypePackId> varargPack;
|
||||
// All constraints belonging to this scope.
|
||||
std::vector<ConstraintPtr> constraints;
|
||||
|
||||
std::optional<TypeId> lookup(Symbol sym);
|
||||
std::optional<TypeId> lookupTypeBinding(const Name& name);
|
||||
std::optional<TypePackId> lookupTypePackBinding(const Name& name);
|
||||
};
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Luau
|
|||
{
|
||||
|
||||
struct TypeArena;
|
||||
struct Scope2;
|
||||
struct Scope;
|
||||
|
||||
/**
|
||||
* There are three kinds of type variables:
|
||||
|
@ -143,7 +143,7 @@ struct ConstrainedTypeVar
|
|||
|
||||
std::vector<TypeId> parts;
|
||||
TypeLevel level;
|
||||
Scope2* scope = nullptr;
|
||||
Scope* scope = nullptr;
|
||||
};
|
||||
|
||||
// Singleton types https://github.com/Roblox/luau/blob/master/rfcs/syntax-singleton-types.md
|
||||
|
@ -275,7 +275,7 @@ struct FunctionTypeVar
|
|||
std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
|
||||
|
||||
TypeLevel level;
|
||||
Scope2* scope = nullptr;
|
||||
Scope* scope = nullptr;
|
||||
/// These should all be generic
|
||||
std::vector<TypeId> generics;
|
||||
std::vector<TypePackId> genericPacks;
|
||||
|
@ -344,7 +344,7 @@ struct TableTypeVar
|
|||
|
||||
TableState state = TableState::Unsealed;
|
||||
TypeLevel level;
|
||||
Scope2* scope = nullptr;
|
||||
Scope* scope = nullptr;
|
||||
std::optional<std::string> name;
|
||||
|
||||
// Sometimes we throw a type on a name to make for nicer error messages, but without creating any entry in the type namespace
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct Scope2;
|
||||
struct Scope;
|
||||
|
||||
/**
|
||||
* The 'level' of a TypeVar is an indirect way to talk about the scope that it 'belongs' too.
|
||||
|
@ -84,11 +84,11 @@ using Name = std::string;
|
|||
struct Free
|
||||
{
|
||||
explicit Free(TypeLevel level);
|
||||
explicit Free(Scope2* scope);
|
||||
explicit Free(Scope* scope);
|
||||
|
||||
int index;
|
||||
TypeLevel level;
|
||||
Scope2* scope = nullptr;
|
||||
Scope* scope = nullptr;
|
||||
// True if this free type variable is part of a mutually
|
||||
// recursive type alias whose definitions haven't been
|
||||
// resolved yet.
|
||||
|
@ -115,13 +115,13 @@ struct Generic
|
|||
Generic();
|
||||
explicit Generic(TypeLevel level);
|
||||
explicit Generic(const Name& name);
|
||||
explicit Generic(Scope2* scope);
|
||||
explicit Generic(Scope* scope);
|
||||
Generic(TypeLevel level, const Name& name);
|
||||
Generic(Scope2* scope, const Name& name);
|
||||
Generic(Scope* scope, const Name& name);
|
||||
|
||||
int index;
|
||||
TypeLevel level;
|
||||
Scope2* scope = nullptr;
|
||||
Scope* scope = nullptr;
|
||||
Name name;
|
||||
bool explicitName = false;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
LUAU_FASTFLAG(LuauSelfCallAutocompleteFix2)
|
||||
LUAU_FASTFLAG(LuauSelfCallAutocompleteFix3)
|
||||
|
||||
static const std::unordered_set<std::string> kStatementStartingKeywords = {
|
||||
"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
|
||||
|
@ -149,7 +149,7 @@ static TypeCorrectKind checkTypeCorrectKind(const Module& module, TypeArena* typ
|
|||
ty = follow(ty);
|
||||
|
||||
auto canUnify = [&typeArena](TypeId subTy, TypeId superTy) {
|
||||
LUAU_ASSERT(!FFlag::LuauSelfCallAutocompleteFix2);
|
||||
LUAU_ASSERT(!FFlag::LuauSelfCallAutocompleteFix3);
|
||||
|
||||
InternalErrorReporter iceReporter;
|
||||
UnifierSharedState unifierState(&iceReporter);
|
||||
|
@ -168,7 +168,7 @@ static TypeCorrectKind checkTypeCorrectKind(const Module& module, TypeArena* typ
|
|||
TypeId expectedType = follow(*typeAtPosition);
|
||||
|
||||
auto checkFunctionType = [typeArena, &canUnify, &expectedType](const FunctionTypeVar* ftv) {
|
||||
if (FFlag::LuauSelfCallAutocompleteFix2)
|
||||
if (FFlag::LuauSelfCallAutocompleteFix3)
|
||||
{
|
||||
if (std::optional<TypeId> firstRetTy = first(ftv->retTypes))
|
||||
return checkTypeMatch(typeArena, *firstRetTy, expectedType);
|
||||
|
@ -209,7 +209,7 @@ static TypeCorrectKind checkTypeCorrectKind(const Module& module, TypeArena* typ
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauSelfCallAutocompleteFix2)
|
||||
if (FFlag::LuauSelfCallAutocompleteFix3)
|
||||
return checkTypeMatch(typeArena, ty, expectedType) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
|
||||
else
|
||||
return canUnify(ty, expectedType) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
|
||||
|
@ -226,7 +226,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
const std::vector<AstNode*>& nodes, AutocompleteEntryMap& result, std::unordered_set<TypeId>& seen,
|
||||
std::optional<const ClassTypeVar*> containingClass = std::nullopt)
|
||||
{
|
||||
if (FFlag::LuauSelfCallAutocompleteFix2)
|
||||
if (FFlag::LuauSelfCallAutocompleteFix3)
|
||||
rootTy = follow(rootTy);
|
||||
|
||||
ty = follow(ty);
|
||||
|
@ -236,7 +236,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
seen.insert(ty);
|
||||
|
||||
auto isWrongIndexer_DEPRECATED = [indexType, useStrictFunctionIndexers = !!get<ClassTypeVar>(ty)](Luau::TypeId type) {
|
||||
LUAU_ASSERT(!FFlag::LuauSelfCallAutocompleteFix2);
|
||||
LUAU_ASSERT(!FFlag::LuauSelfCallAutocompleteFix3);
|
||||
|
||||
if (indexType == PropIndexType::Key)
|
||||
return false;
|
||||
|
@ -269,7 +269,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
}
|
||||
};
|
||||
auto isWrongIndexer = [typeArena, rootTy, indexType](Luau::TypeId type) {
|
||||
LUAU_ASSERT(FFlag::LuauSelfCallAutocompleteFix2);
|
||||
LUAU_ASSERT(FFlag::LuauSelfCallAutocompleteFix3);
|
||||
|
||||
if (indexType == PropIndexType::Key)
|
||||
return false;
|
||||
|
@ -277,21 +277,20 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
bool calledWithSelf = indexType == PropIndexType::Colon;
|
||||
|
||||
auto isCompatibleCall = [typeArena, rootTy, calledWithSelf](const FunctionTypeVar* ftv) {
|
||||
if (get<ClassTypeVar>(rootTy))
|
||||
{
|
||||
// Calls on classes require strict match between how function is declared and how it's called
|
||||
return calledWithSelf == ftv->hasSelf;
|
||||
}
|
||||
// Strong match with definition is a success
|
||||
if (calledWithSelf == ftv->hasSelf)
|
||||
return true;
|
||||
|
||||
// If a call is made with ':', it is invalid if a function has incompatible first argument or no arguments at all
|
||||
// If a call is made with '.', but it was declared with 'self', it is considered invalid if first argument is compatible
|
||||
if (calledWithSelf || ftv->hasSelf)
|
||||
// Calls on classes require strict match between how function is declared and how it's called
|
||||
if (get<ClassTypeVar>(rootTy))
|
||||
return false;
|
||||
|
||||
// When called with ':', but declared without 'self', it is invalid if a function has incompatible first argument or no arguments at all
|
||||
// When called with '.', but declared with 'self', it is considered invalid if first argument is compatible
|
||||
if (std::optional<TypeId> firstArgTy = first(ftv->argTypes))
|
||||
{
|
||||
if (std::optional<TypeId> firstArgTy = first(ftv->argTypes))
|
||||
{
|
||||
if (checkTypeMatch(typeArena, rootTy, *firstArgTy))
|
||||
return calledWithSelf;
|
||||
}
|
||||
if (checkTypeMatch(typeArena, rootTy, *firstArgTy))
|
||||
return calledWithSelf;
|
||||
}
|
||||
|
||||
return !calledWithSelf;
|
||||
|
@ -333,7 +332,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
AutocompleteEntryKind::Property,
|
||||
type,
|
||||
prop.deprecated,
|
||||
FFlag::LuauSelfCallAutocompleteFix2 ? isWrongIndexer(type) : isWrongIndexer_DEPRECATED(type),
|
||||
FFlag::LuauSelfCallAutocompleteFix3 ? isWrongIndexer(type) : isWrongIndexer_DEPRECATED(type),
|
||||
typeCorrect,
|
||||
containingClass,
|
||||
&prop,
|
||||
|
@ -376,7 +375,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
{
|
||||
autocompleteProps(module, typeArena, rootTy, mt->table, indexType, nodes, result, seen);
|
||||
|
||||
if (FFlag::LuauSelfCallAutocompleteFix2)
|
||||
if (FFlag::LuauSelfCallAutocompleteFix3)
|
||||
{
|
||||
if (auto mtable = get<TableTypeVar>(mt->metatable))
|
||||
fillMetatableProps(mtable);
|
||||
|
@ -442,7 +441,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
AutocompleteEntryMap inner;
|
||||
std::unordered_set<TypeId> innerSeen;
|
||||
|
||||
if (!FFlag::LuauSelfCallAutocompleteFix2)
|
||||
if (!FFlag::LuauSelfCallAutocompleteFix3)
|
||||
innerSeen = seen;
|
||||
|
||||
if (isNil(*iter))
|
||||
|
@ -468,7 +467,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
++iter;
|
||||
}
|
||||
}
|
||||
else if (auto pt = get<PrimitiveTypeVar>(ty); pt && FFlag::LuauSelfCallAutocompleteFix2)
|
||||
else if (auto pt = get<PrimitiveTypeVar>(ty); pt && FFlag::LuauSelfCallAutocompleteFix3)
|
||||
{
|
||||
if (pt->metatable)
|
||||
{
|
||||
|
@ -476,7 +475,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
|
|||
fillMetatableProps(mtable);
|
||||
}
|
||||
}
|
||||
else if (FFlag::LuauSelfCallAutocompleteFix2 && get<StringSingleton>(get<SingletonTypeVar>(ty)))
|
||||
else if (FFlag::LuauSelfCallAutocompleteFix3 && get<StringSingleton>(get<SingletonTypeVar>(ty)))
|
||||
{
|
||||
autocompleteProps(module, typeArena, rootTy, getSingletonTypes().stringType, indexType, nodes, result, seen);
|
||||
}
|
||||
|
@ -1405,7 +1404,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
|
|||
TypeId ty = follow(*it);
|
||||
PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point;
|
||||
|
||||
if (!FFlag::LuauSelfCallAutocompleteFix2 && isString(ty))
|
||||
if (!FFlag::LuauSelfCallAutocompleteFix3 && isString(ty))
|
||||
return {
|
||||
autocompleteProps(*module, typeArena, typeChecker.globalScope->bindings[AstName{"string"}].typeId, indexType, ancestry), ancestry, AutocompleteContext::Property};
|
||||
else
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Luau
|
|||
const AstStat* getFallthrough(const AstStat* node); // TypeInfer.cpp
|
||||
|
||||
ConstraintGraphBuilder::ConstraintGraphBuilder(
|
||||
const ModuleName& moduleName, TypeArena* arena, NotNull<InternalErrorReporter> ice, NotNull<Scope2> globalScope)
|
||||
const ModuleName& moduleName, TypeArena* arena, NotNull<InternalErrorReporter> ice, NotNull<Scope> globalScope)
|
||||
: moduleName(moduleName)
|
||||
, singletonTypes(getSingletonTypes())
|
||||
, arena(arena)
|
||||
|
@ -25,36 +25,34 @@ ConstraintGraphBuilder::ConstraintGraphBuilder(
|
|||
LUAU_ASSERT(arena);
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::freshType(NotNull<Scope2> scope)
|
||||
TypeId ConstraintGraphBuilder::freshType(const ScopePtr& scope)
|
||||
{
|
||||
return arena->addType(FreeTypeVar{scope});
|
||||
return arena->addType(FreeTypeVar{scope.get()});
|
||||
}
|
||||
|
||||
TypePackId ConstraintGraphBuilder::freshTypePack(NotNull<Scope2> scope)
|
||||
TypePackId ConstraintGraphBuilder::freshTypePack(const ScopePtr& scope)
|
||||
{
|
||||
FreeTypePack f{scope};
|
||||
FreeTypePack f{scope.get()};
|
||||
return arena->addTypePack(TypePackVar{std::move(f)});
|
||||
}
|
||||
|
||||
NotNull<Scope2> ConstraintGraphBuilder::childScope(Location location, NotNull<Scope2> parent)
|
||||
ScopePtr ConstraintGraphBuilder::childScope(Location location, const ScopePtr& parent)
|
||||
{
|
||||
auto scope = std::make_unique<Scope2>();
|
||||
NotNull<Scope2> borrow = NotNull(scope.get());
|
||||
scopes.emplace_back(location, std::move(scope));
|
||||
auto scope = std::make_shared<Scope>(parent);
|
||||
scopes.emplace_back(location, scope);
|
||||
|
||||
borrow->parent = parent;
|
||||
borrow->returnType = parent->returnType;
|
||||
parent->children.push_back(borrow);
|
||||
scope->returnType = parent->returnType;
|
||||
parent->children.push_back(NotNull(scope.get()));
|
||||
|
||||
return borrow;
|
||||
return scope;
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::addConstraint(NotNull<Scope2> scope, ConstraintV cv)
|
||||
void ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, ConstraintV cv)
|
||||
{
|
||||
scope->constraints.emplace_back(new Constraint{std::move(cv)});
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::addConstraint(NotNull<Scope2> scope, std::unique_ptr<Constraint> c)
|
||||
void ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c)
|
||||
{
|
||||
scope->constraints.emplace_back(std::move(c));
|
||||
}
|
||||
|
@ -63,13 +61,13 @@ void ConstraintGraphBuilder::visit(AstStatBlock* block)
|
|||
{
|
||||
LUAU_ASSERT(scopes.empty());
|
||||
LUAU_ASSERT(rootScope == nullptr);
|
||||
scopes.emplace_back(block->location, std::make_unique<Scope2>());
|
||||
rootScope = scopes.back().second.get();
|
||||
NotNull<Scope2> borrow = NotNull(rootScope);
|
||||
ScopePtr scope = std::make_shared<Scope>(singletonTypes.anyTypePack);
|
||||
rootScope = scope.get();
|
||||
scopes.emplace_back(block->location, scope);
|
||||
|
||||
rootScope->returnType = freshTypePack(borrow);
|
||||
rootScope->returnType = freshTypePack(scope);
|
||||
|
||||
prepopulateGlobalScope(borrow, block);
|
||||
prepopulateGlobalScope(scope, block);
|
||||
|
||||
// TODO: We should share the global scope.
|
||||
rootScope->typeBindings["nil"] = singletonTypes.nilType;
|
||||
|
@ -78,10 +76,10 @@ void ConstraintGraphBuilder::visit(AstStatBlock* block)
|
|||
rootScope->typeBindings["boolean"] = singletonTypes.booleanType;
|
||||
rootScope->typeBindings["thread"] = singletonTypes.threadType;
|
||||
|
||||
visitBlockWithoutChildScope(borrow, block);
|
||||
visitBlockWithoutChildScope(scope, block);
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visitBlockWithoutChildScope(NotNull<Scope2> scope, AstStatBlock* block)
|
||||
void ConstraintGraphBuilder::visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block)
|
||||
{
|
||||
RecursionCounter counter{&recursionCount};
|
||||
|
||||
|
@ -95,7 +93,7 @@ void ConstraintGraphBuilder::visitBlockWithoutChildScope(NotNull<Scope2> scope,
|
|||
visit(scope, stat);
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStat* stat)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStat* stat)
|
||||
{
|
||||
RecursionLimiter limiter{&recursionCount, FInt::LuauCheckRecursionLimit};
|
||||
|
||||
|
@ -123,22 +121,24 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStat* stat)
|
|||
LUAU_ASSERT(0);
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatLocal* local)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
|
||||
{
|
||||
std::vector<TypeId> varTypes;
|
||||
|
||||
for (AstLocal* local : local->vars)
|
||||
{
|
||||
TypeId ty = freshType(scope);
|
||||
Location location = local->location;
|
||||
|
||||
if (local->annotation)
|
||||
{
|
||||
location = local->annotation->location;
|
||||
TypeId annotation = resolveType(scope, local->annotation);
|
||||
addConstraint(scope, SubtypeConstraint{ty, annotation});
|
||||
}
|
||||
|
||||
varTypes.push_back(ty);
|
||||
scope->bindings[local] = ty;
|
||||
scope->bindings[local] = Binding{ty, location};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < local->values.size; ++i)
|
||||
|
@ -169,7 +169,7 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatLocal* local)
|
|||
}
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatFor* for_)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
|
||||
{
|
||||
auto checkNumber = [&](AstExpr* expr)
|
||||
{
|
||||
|
@ -184,24 +184,24 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatFor* for_)
|
|||
checkNumber(for_->to);
|
||||
checkNumber(for_->step);
|
||||
|
||||
NotNull<Scope2> forScope = childScope(for_->location, scope);
|
||||
forScope->bindings[for_->var] = singletonTypes.numberType;
|
||||
ScopePtr forScope = childScope(for_->location, scope);
|
||||
forScope->bindings[for_->var] = Binding{singletonTypes.numberType, for_->var->location};
|
||||
|
||||
visit(forScope, for_->body);
|
||||
}
|
||||
|
||||
void addConstraints(Constraint* constraint, NotNull<Scope2> scope)
|
||||
void addConstraints(Constraint* constraint, NotNull<Scope> scope)
|
||||
{
|
||||
scope->constraints.reserve(scope->constraints.size() + scope->constraints.size());
|
||||
|
||||
for (const auto& c : scope->constraints)
|
||||
constraint->dependencies.push_back(NotNull{c.get()});
|
||||
|
||||
for (NotNull<Scope2> childScope : scope->children)
|
||||
for (NotNull<Scope> childScope : scope->children)
|
||||
addConstraints(constraint, childScope);
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatLocalFunction* function)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFunction* function)
|
||||
{
|
||||
// Local
|
||||
// Global
|
||||
|
@ -213,21 +213,21 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatLocalFunction*
|
|||
LUAU_ASSERT(!ty.has_value()); // The parser ensures that every local function has a distinct Symbol for its name.
|
||||
|
||||
functionType = arena->addType(BlockedTypeVar{});
|
||||
scope->bindings[function->name] = functionType;
|
||||
scope->bindings[function->name] = Binding{functionType, function->name->location};
|
||||
|
||||
FunctionSignature sig = checkFunctionSignature(scope, function->func);
|
||||
sig.bodyScope->bindings[function->name] = sig.signature;
|
||||
sig.bodyScope->bindings[function->name] = Binding{sig.signature, function->func->location};
|
||||
|
||||
checkFunctionBody(sig.bodyScope, function->func);
|
||||
|
||||
std::unique_ptr<Constraint> c{
|
||||
new Constraint{GeneralizationConstraint{functionType, sig.signature, sig.signatureScope ? sig.signatureScope : sig.bodyScope}}};
|
||||
addConstraints(c.get(), sig.bodyScope);
|
||||
new Constraint{GeneralizationConstraint{functionType, sig.signature, sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()}}};
|
||||
addConstraints(c.get(), NotNull(sig.bodyScope.get()));
|
||||
|
||||
addConstraint(scope, std::move(c));
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatFunction* function)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* function)
|
||||
{
|
||||
// Name could be AstStatLocal, AstStatGlobal, AstStatIndexName.
|
||||
// With or without self
|
||||
|
@ -247,9 +247,9 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatFunction* funct
|
|||
else
|
||||
{
|
||||
functionType = arena->addType(BlockedTypeVar{});
|
||||
scope->bindings[localName->local] = functionType;
|
||||
scope->bindings[localName->local] = Binding{functionType, localName->location};
|
||||
}
|
||||
sig.bodyScope->bindings[localName->local] = sig.signature;
|
||||
sig.bodyScope->bindings[localName->local] = Binding{sig.signature, localName->location};
|
||||
}
|
||||
else if (AstExprGlobal* globalName = function->name->as<AstExprGlobal>())
|
||||
{
|
||||
|
@ -262,9 +262,9 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatFunction* funct
|
|||
else
|
||||
{
|
||||
functionType = arena->addType(BlockedTypeVar{});
|
||||
rootScope->bindings[globalName->name] = functionType;
|
||||
rootScope->bindings[globalName->name] = Binding{functionType, globalName->location};
|
||||
}
|
||||
sig.bodyScope->bindings[globalName->name] = sig.signature;
|
||||
sig.bodyScope->bindings[globalName->name] = Binding{sig.signature, globalName->location};
|
||||
}
|
||||
else if (AstExprIndexName* indexName = function->name->as<AstExprIndexName>())
|
||||
{
|
||||
|
@ -291,21 +291,21 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatFunction* funct
|
|||
checkFunctionBody(sig.bodyScope, function->func);
|
||||
|
||||
std::unique_ptr<Constraint> c{
|
||||
new Constraint{GeneralizationConstraint{functionType, sig.signature, sig.signatureScope ? sig.signatureScope : sig.bodyScope}}};
|
||||
addConstraints(c.get(), sig.bodyScope);
|
||||
new Constraint{GeneralizationConstraint{functionType, sig.signature, sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()}}};
|
||||
addConstraints(c.get(), NotNull(sig.bodyScope.get()));
|
||||
|
||||
addConstraint(scope, std::move(c));
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatReturn* ret)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatReturn* ret)
|
||||
{
|
||||
TypePackId exprTypes = checkPack(scope, ret->list);
|
||||
addConstraint(scope, PackSubtypeConstraint{exprTypes, scope->returnType});
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatBlock* block)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatBlock* block)
|
||||
{
|
||||
NotNull<Scope2> innerScope = childScope(block->location, scope);
|
||||
ScopePtr innerScope = childScope(block->location, scope);
|
||||
|
||||
// In order to enable mutually-recursive type aliases, we need to
|
||||
// populate the type bindings before we actually check any of the
|
||||
|
@ -323,7 +323,7 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatBlock* block)
|
|||
visitBlockWithoutChildScope(innerScope, block);
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatAssign* assign)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign* assign)
|
||||
{
|
||||
TypePackId varPackId = checkExprList(scope, assign->vars);
|
||||
TypePackId valuePack = checkPack(scope, assign->values);
|
||||
|
@ -331,21 +331,21 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatAssign* assign)
|
|||
addConstraint(scope, PackSubtypeConstraint{valuePack, varPackId});
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatIf* ifStatement)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatIf* ifStatement)
|
||||
{
|
||||
check(scope, ifStatement->condition);
|
||||
|
||||
NotNull<Scope2> thenScope = childScope(ifStatement->thenbody->location, scope);
|
||||
ScopePtr thenScope = childScope(ifStatement->thenbody->location, scope);
|
||||
visit(thenScope, ifStatement->thenbody);
|
||||
|
||||
if (ifStatement->elsebody)
|
||||
{
|
||||
NotNull<Scope2> elseScope = childScope(ifStatement->elsebody->location, scope);
|
||||
ScopePtr elseScope = childScope(ifStatement->elsebody->location, scope);
|
||||
visit(elseScope, ifStatement->elsebody);
|
||||
}
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatTypeAlias* alias)
|
||||
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alias)
|
||||
{
|
||||
// TODO: Exported type aliases
|
||||
// TODO: Generic type aliases
|
||||
|
@ -371,7 +371,7 @@ void ConstraintGraphBuilder::visit(NotNull<Scope2> scope, AstStatTypeAlias* alia
|
|||
addConstraint(scope, NameConstraint{ty, alias->name.value});
|
||||
}
|
||||
|
||||
TypePackId ConstraintGraphBuilder::checkPack(NotNull<Scope2> scope, AstArray<AstExpr*> exprs)
|
||||
TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs)
|
||||
{
|
||||
if (exprs.size == 0)
|
||||
return arena->addTypePack({});
|
||||
|
@ -392,7 +392,7 @@ TypePackId ConstraintGraphBuilder::checkPack(NotNull<Scope2> scope, AstArray<Ast
|
|||
return arena->addTypePack(TypePack{std::move(types), last});
|
||||
}
|
||||
|
||||
TypePackId ConstraintGraphBuilder::checkExprList(NotNull<Scope2> scope, const AstArray<AstExpr*>& exprs)
|
||||
TypePackId ConstraintGraphBuilder::checkExprList(const ScopePtr& scope, const AstArray<AstExpr*>& exprs)
|
||||
{
|
||||
TypePackId result = arena->addTypePack({});
|
||||
TypePack* resultPack = getMutable<TypePack>(result);
|
||||
|
@ -413,7 +413,7 @@ TypePackId ConstraintGraphBuilder::checkExprList(NotNull<Scope2> scope, const As
|
|||
return result;
|
||||
}
|
||||
|
||||
TypePackId ConstraintGraphBuilder::checkPack(NotNull<Scope2> scope, AstExpr* expr)
|
||||
TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* expr)
|
||||
{
|
||||
RecursionCounter counter{&recursionCount};
|
||||
|
||||
|
@ -468,7 +468,7 @@ TypePackId ConstraintGraphBuilder::checkPack(NotNull<Scope2> scope, AstExpr* exp
|
|||
return result;
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExpr* expr)
|
||||
TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr)
|
||||
{
|
||||
RecursionCounter counter{&recursionCount};
|
||||
|
||||
|
@ -548,7 +548,7 @@ TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExpr* expr)
|
|||
return result;
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprIndexName* indexName)
|
||||
TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName* indexName)
|
||||
{
|
||||
TypeId obj = check(scope, indexName->expr);
|
||||
TypeId result = freshType(scope);
|
||||
|
@ -564,7 +564,7 @@ TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprIndexName* in
|
|||
return result;
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprIndexExpr* indexExpr)
|
||||
TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
|
||||
{
|
||||
TypeId obj = check(scope, indexExpr->expr);
|
||||
TypeId indexType = check(scope, indexExpr->index);
|
||||
|
@ -579,7 +579,7 @@ TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprIndexExpr* in
|
|||
return result;
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprUnary* unary)
|
||||
TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* unary)
|
||||
{
|
||||
TypeId operandType = check(scope, unary->expr);
|
||||
|
||||
|
@ -599,7 +599,7 @@ TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprUnary* unary)
|
|||
return singletonTypes.errorRecoveryType();
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprBinary* binary)
|
||||
TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprBinary* binary)
|
||||
{
|
||||
TypeId leftType = check(scope, binary->left);
|
||||
TypeId rightType = check(scope, binary->right);
|
||||
|
@ -624,7 +624,7 @@ TypeId ConstraintGraphBuilder::check(NotNull<Scope2> scope, AstExprBinary* binar
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::checkExprTable(NotNull<Scope2> scope, AstExprTable* expr)
|
||||
TypeId ConstraintGraphBuilder::checkExprTable(const ScopePtr& scope, AstExprTable* expr)
|
||||
{
|
||||
TypeId ty = arena->addType(TableTypeVar{});
|
||||
TableTypeVar* ttv = getMutable<TableTypeVar>(ty);
|
||||
|
@ -674,10 +674,10 @@ TypeId ConstraintGraphBuilder::checkExprTable(NotNull<Scope2> scope, AstExprTabl
|
|||
return ty;
|
||||
}
|
||||
|
||||
ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionSignature(NotNull<Scope2> parent, AstExprFunction* fn)
|
||||
ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionSignature(const ScopePtr& parent, AstExprFunction* fn)
|
||||
{
|
||||
Scope2* signatureScope = nullptr;
|
||||
Scope2* bodyScope = nullptr;
|
||||
ScopePtr signatureScope = nullptr;
|
||||
ScopePtr bodyScope = nullptr;
|
||||
TypePackId returnType = nullptr;
|
||||
|
||||
std::vector<TypeId> genericTypes;
|
||||
|
@ -690,18 +690,17 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
|
|||
// generics properly.
|
||||
if (hasGenerics)
|
||||
{
|
||||
NotNull signatureBorrow = childScope(fn->location, parent);
|
||||
signatureScope = signatureBorrow.get();
|
||||
signatureScope = childScope(fn->location, parent);
|
||||
|
||||
// We need to assign returnType before creating bodyScope so that the
|
||||
// return type gets propogated to bodyScope.
|
||||
returnType = freshTypePack(signatureBorrow);
|
||||
returnType = freshTypePack(signatureScope);
|
||||
signatureScope->returnType = returnType;
|
||||
|
||||
bodyScope = childScope(fn->body->location, signatureBorrow).get();
|
||||
bodyScope = childScope(fn->body->location, signatureScope);
|
||||
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureBorrow, fn->generics);
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureBorrow, fn->genericPacks);
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureScope, fn->generics);
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureScope, fn->genericPacks);
|
||||
|
||||
// We do not support default values on function generics, so we only
|
||||
// care about the types involved.
|
||||
|
@ -719,11 +718,10 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
|
|||
}
|
||||
else
|
||||
{
|
||||
NotNull bodyBorrow = childScope(fn->body->location, parent);
|
||||
bodyScope = bodyBorrow.get();
|
||||
bodyScope = childScope(fn->body->location, parent);
|
||||
|
||||
returnType = freshTypePack(bodyBorrow);
|
||||
bodyBorrow->returnType = returnType;
|
||||
returnType = freshTypePack(bodyScope);
|
||||
bodyScope->returnType = returnType;
|
||||
|
||||
// To eliminate the need to branch on hasGenerics below, we say that the
|
||||
// signature scope is the body scope when there is no real signature
|
||||
|
@ -731,27 +729,24 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
|
|||
signatureScope = bodyScope;
|
||||
}
|
||||
|
||||
NotNull bodyBorrow = NotNull(bodyScope);
|
||||
NotNull signatureBorrow = NotNull(signatureScope);
|
||||
|
||||
if (fn->returnAnnotation)
|
||||
{
|
||||
TypePackId annotatedRetType = resolveTypePack(signatureBorrow, *fn->returnAnnotation);
|
||||
addConstraint(signatureBorrow, PackSubtypeConstraint{returnType, annotatedRetType});
|
||||
TypePackId annotatedRetType = resolveTypePack(signatureScope, *fn->returnAnnotation);
|
||||
addConstraint(signatureScope, PackSubtypeConstraint{returnType, annotatedRetType});
|
||||
}
|
||||
|
||||
std::vector<TypeId> argTypes;
|
||||
|
||||
for (AstLocal* local : fn->args)
|
||||
{
|
||||
TypeId t = freshType(signatureBorrow);
|
||||
TypeId t = freshType(signatureScope);
|
||||
argTypes.push_back(t);
|
||||
signatureScope->bindings[local] = t;
|
||||
signatureScope->bindings[local] = Binding{t, local->location};
|
||||
|
||||
if (local->annotation)
|
||||
{
|
||||
TypeId argAnnotation = resolveType(signatureBorrow, local->annotation);
|
||||
addConstraint(signatureBorrow, SubtypeConstraint{t, argAnnotation});
|
||||
TypeId argAnnotation = resolveType(signatureScope, local->annotation);
|
||||
addConstraint(signatureScope, SubtypeConstraint{t, argAnnotation});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,11 +767,11 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
|
|||
// Undo the workaround we made above: if there's no signature scope,
|
||||
// don't report it.
|
||||
/* signatureScope */ hasGenerics ? signatureScope : nullptr,
|
||||
/* bodyScope */ bodyBorrow,
|
||||
/* bodyScope */ bodyScope,
|
||||
};
|
||||
}
|
||||
|
||||
void ConstraintGraphBuilder::checkFunctionBody(NotNull<Scope2> scope, AstExprFunction* fn)
|
||||
void ConstraintGraphBuilder::checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn)
|
||||
{
|
||||
visitBlockWithoutChildScope(scope, fn->body);
|
||||
|
||||
|
@ -789,7 +784,7 @@ void ConstraintGraphBuilder::checkFunctionBody(NotNull<Scope2> scope, AstExprFun
|
|||
}
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::resolveType(NotNull<Scope2> scope, AstType* ty)
|
||||
TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty)
|
||||
{
|
||||
TypeId result = nullptr;
|
||||
|
||||
|
@ -834,7 +829,7 @@ TypeId ConstraintGraphBuilder::resolveType(NotNull<Scope2> scope, AstType* ty)
|
|||
{
|
||||
// TODO: Recursion limit.
|
||||
bool hasGenerics = fn->generics.size > 0 || fn->genericPacks.size > 0;
|
||||
Scope2* signatureScope = nullptr;
|
||||
ScopePtr signatureScope = nullptr;
|
||||
|
||||
std::vector<TypeId> genericTypes;
|
||||
std::vector<TypePackId> genericTypePacks;
|
||||
|
@ -843,22 +838,21 @@ TypeId ConstraintGraphBuilder::resolveType(NotNull<Scope2> scope, AstType* ty)
|
|||
// for the generic bindings to live on.
|
||||
if (hasGenerics)
|
||||
{
|
||||
NotNull<Scope2> signatureBorrow = childScope(fn->location, scope);
|
||||
signatureScope = signatureBorrow.get();
|
||||
signatureScope = childScope(fn->location, scope);
|
||||
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureBorrow, fn->generics);
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureBorrow, fn->genericPacks);
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureScope, fn->generics);
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureScope, fn->genericPacks);
|
||||
|
||||
for (const auto& [name, g] : genericDefinitions)
|
||||
{
|
||||
genericTypes.push_back(g.ty);
|
||||
signatureBorrow->typeBindings[name] = g.ty;
|
||||
signatureScope->typeBindings[name] = g.ty;
|
||||
}
|
||||
|
||||
for (const auto& [name, g] : genericPackDefinitions)
|
||||
{
|
||||
genericTypePacks.push_back(g.tp);
|
||||
signatureBorrow->typePackBindings[name] = g.tp;
|
||||
signatureScope->typePackBindings[name] = g.tp;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -866,13 +860,11 @@ TypeId ConstraintGraphBuilder::resolveType(NotNull<Scope2> scope, AstType* ty)
|
|||
// To eliminate the need to branch on hasGenerics below, we say that
|
||||
// the signature scope is the parent scope if we don't have
|
||||
// generics.
|
||||
signatureScope = scope.get();
|
||||
signatureScope = scope;
|
||||
}
|
||||
|
||||
NotNull<Scope2> signatureBorrow(signatureScope);
|
||||
|
||||
TypePackId argTypes = resolveTypePack(signatureBorrow, fn->argTypes);
|
||||
TypePackId returnTypes = resolveTypePack(signatureBorrow, fn->returnTypes);
|
||||
TypePackId argTypes = resolveTypePack(signatureScope, fn->argTypes);
|
||||
TypePackId returnTypes = resolveTypePack(signatureScope, fn->returnTypes);
|
||||
|
||||
// TODO: FunctionTypeVar needs a pointer to the scope so that we know
|
||||
// how to quantify/instantiate it.
|
||||
|
@ -950,7 +942,7 @@ TypeId ConstraintGraphBuilder::resolveType(NotNull<Scope2> scope, AstType* ty)
|
|||
return result;
|
||||
}
|
||||
|
||||
TypePackId ConstraintGraphBuilder::resolveTypePack(NotNull<Scope2> scope, AstTypePack* tp)
|
||||
TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, AstTypePack* tp)
|
||||
{
|
||||
TypePackId result;
|
||||
if (auto expl = tp->as<AstTypePackExplicit>())
|
||||
|
@ -964,7 +956,7 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(NotNull<Scope2> scope, AstTyp
|
|||
}
|
||||
else if (auto gen = tp->as<AstTypePackGeneric>())
|
||||
{
|
||||
result = arena->addTypePack(TypePackVar{GenericTypePack{scope, gen->genericName.value}});
|
||||
result = arena->addTypePack(TypePackVar{GenericTypePack{scope.get(), gen->genericName.value}});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -976,7 +968,7 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(NotNull<Scope2> scope, AstTyp
|
|||
return result;
|
||||
}
|
||||
|
||||
TypePackId ConstraintGraphBuilder::resolveTypePack(NotNull<Scope2> scope, const AstTypeList& list)
|
||||
TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, const AstTypeList& list)
|
||||
{
|
||||
std::vector<TypeId> head;
|
||||
|
||||
|
@ -994,12 +986,12 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(NotNull<Scope2> scope, const
|
|||
return arena->addTypePack(TypePack{head, tail});
|
||||
}
|
||||
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::createGenerics(NotNull<Scope2> scope, AstArray<AstGenericType> generics)
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::createGenerics(const ScopePtr& scope, AstArray<AstGenericType> generics)
|
||||
{
|
||||
std::vector<std::pair<Name, GenericTypeDefinition>> result;
|
||||
for (const auto& generic : generics)
|
||||
{
|
||||
TypeId genericTy = arena->addType(GenericTypeVar{scope, generic.name.value});
|
||||
TypeId genericTy = arena->addType(GenericTypeVar{scope.get(), generic.name.value});
|
||||
std::optional<TypeId> defaultTy = std::nullopt;
|
||||
|
||||
if (generic.defaultValue)
|
||||
|
@ -1015,12 +1007,12 @@ std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::crea
|
|||
}
|
||||
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGraphBuilder::createGenericPacks(
|
||||
NotNull<Scope2> scope, AstArray<AstGenericTypePack> generics)
|
||||
const ScopePtr& scope, AstArray<AstGenericTypePack> generics)
|
||||
{
|
||||
std::vector<std::pair<Name, GenericTypePackDefinition>> result;
|
||||
for (const auto& generic : generics)
|
||||
{
|
||||
TypePackId genericTy = arena->addTypePack(TypePackVar{GenericTypePack{scope, generic.name.value}});
|
||||
TypePackId genericTy = arena->addTypePack(TypePackVar{GenericTypePack{scope.get(), generic.name.value}});
|
||||
std::optional<TypePackId> defaultTy = std::nullopt;
|
||||
|
||||
if (generic.defaultValue)
|
||||
|
@ -1035,7 +1027,7 @@ std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGraphBuilder::
|
|||
return result;
|
||||
}
|
||||
|
||||
TypeId ConstraintGraphBuilder::flattenPack(NotNull<Scope2> scope, Location location, TypePackId tp)
|
||||
TypeId ConstraintGraphBuilder::flattenPack(const ScopePtr& scope, Location location, TypePackId tp)
|
||||
{
|
||||
if (auto f = first(tp))
|
||||
return *f;
|
||||
|
@ -1061,10 +1053,10 @@ void ConstraintGraphBuilder::reportCodeTooComplex(Location location)
|
|||
|
||||
struct GlobalPrepopulator : AstVisitor
|
||||
{
|
||||
const NotNull<Scope2> globalScope;
|
||||
const NotNull<Scope> globalScope;
|
||||
const NotNull<TypeArena> arena;
|
||||
|
||||
GlobalPrepopulator(NotNull<Scope2> globalScope, NotNull<TypeArena> arena)
|
||||
GlobalPrepopulator(NotNull<Scope> globalScope, NotNull<TypeArena> arena)
|
||||
: globalScope(globalScope)
|
||||
, arena(arena)
|
||||
{
|
||||
|
@ -1073,29 +1065,29 @@ struct GlobalPrepopulator : AstVisitor
|
|||
bool visit(AstStatFunction* function) override
|
||||
{
|
||||
if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
|
||||
globalScope->bindings[g->name] = arena->addType(BlockedTypeVar{});
|
||||
globalScope->bindings[g->name] = Binding{arena->addType(BlockedTypeVar{})};
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void ConstraintGraphBuilder::prepopulateGlobalScope(NotNull<Scope2> globalScope, AstStatBlock* program)
|
||||
void ConstraintGraphBuilder::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)
|
||||
{
|
||||
GlobalPrepopulator gp{NotNull{globalScope}, arena};
|
||||
GlobalPrepopulator gp{NotNull{globalScope.get()}, arena};
|
||||
|
||||
program->visit(&gp);
|
||||
}
|
||||
|
||||
void collectConstraints(std::vector<NotNull<Constraint>>& result, NotNull<Scope2> scope)
|
||||
void collectConstraints(std::vector<NotNull<Constraint>>& result, NotNull<Scope> scope)
|
||||
{
|
||||
for (const auto& c : scope->constraints)
|
||||
result.push_back(NotNull{c.get()});
|
||||
|
||||
for (NotNull<Scope2> child : scope->children)
|
||||
for (NotNull<Scope> child : scope->children)
|
||||
collectConstraints(result, child);
|
||||
}
|
||||
|
||||
std::vector<NotNull<Constraint>> collectConstraints(NotNull<Scope2> rootScope)
|
||||
std::vector<NotNull<Constraint>> collectConstraints(NotNull<Scope> rootScope)
|
||||
{
|
||||
std::vector<NotNull<Constraint>> result;
|
||||
collectConstraints(result, rootScope);
|
||||
|
|
|
@ -13,31 +13,31 @@ LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false);
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
[[maybe_unused]] static void dumpBindings(NotNull<Scope2> scope, ToStringOptions& opts)
|
||||
[[maybe_unused]] static void dumpBindings(NotNull<Scope> scope, ToStringOptions& opts)
|
||||
{
|
||||
for (const auto& [k, v] : scope->bindings)
|
||||
{
|
||||
auto d = toStringDetailed(v, opts);
|
||||
auto d = toStringDetailed(v.typeId, opts);
|
||||
opts.nameMap = d.nameMap;
|
||||
printf("\t%s : %s\n", k.c_str(), d.name.c_str());
|
||||
}
|
||||
|
||||
for (NotNull<Scope2> child : scope->children)
|
||||
for (NotNull<Scope> child : scope->children)
|
||||
dumpBindings(child, opts);
|
||||
}
|
||||
|
||||
static void dumpConstraints(NotNull<Scope2> scope, ToStringOptions& opts)
|
||||
static void dumpConstraints(NotNull<Scope> scope, ToStringOptions& opts)
|
||||
{
|
||||
for (const ConstraintPtr& c : scope->constraints)
|
||||
{
|
||||
printf("\t%s\n", toString(*c, opts).c_str());
|
||||
}
|
||||
|
||||
for (NotNull<Scope2> child : scope->children)
|
||||
for (NotNull<Scope> child : scope->children)
|
||||
dumpConstraints(child, opts);
|
||||
}
|
||||
|
||||
void dump(NotNull<Scope2> rootScope, ToStringOptions& opts)
|
||||
void dump(NotNull<Scope> rootScope, ToStringOptions& opts)
|
||||
{
|
||||
printf("constraints:\n");
|
||||
dumpConstraints(rootScope, opts);
|
||||
|
@ -55,7 +55,7 @@ void dump(ConstraintSolver* cs, ToStringOptions& opts)
|
|||
}
|
||||
}
|
||||
|
||||
ConstraintSolver::ConstraintSolver(TypeArena* arena, NotNull<Scope2> rootScope)
|
||||
ConstraintSolver::ConstraintSolver(TypeArena* arena, NotNull<Scope> rootScope)
|
||||
: arena(arena)
|
||||
, constraints(collectConstraints(rootScope))
|
||||
, rootScope(rootScope)
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
static std::string dumpScopeAndChildren(const Scope2* scope, ToStringOptions& opts)
|
||||
static std::string dumpScopeAndChildren(const Scope* scope, ToStringOptions& opts)
|
||||
{
|
||||
std::string output = "{\"bindings\":{";
|
||||
|
||||
bool comma = false;
|
||||
for (const auto& [name, type] : scope->bindings)
|
||||
for (const auto& [name, binding] : scope->bindings)
|
||||
{
|
||||
if (comma)
|
||||
output += ",";
|
||||
|
@ -19,7 +19,7 @@ static std::string dumpScopeAndChildren(const Scope2* scope, ToStringOptions& op
|
|||
output += name.c_str();
|
||||
output += "\": \"";
|
||||
|
||||
ToStringResult result = toStringDetailed(type, opts);
|
||||
ToStringResult result = toStringDetailed(binding.typeId, opts);
|
||||
opts.nameMap = std::move(result.nameMap);
|
||||
output += result.name;
|
||||
output += "\"";
|
||||
|
@ -30,7 +30,7 @@ static std::string dumpScopeAndChildren(const Scope2* scope, ToStringOptions& op
|
|||
output += "},\"children\":[";
|
||||
comma = false;
|
||||
|
||||
for (const Scope2* child : scope->children)
|
||||
for (const Scope* child : scope->children)
|
||||
{
|
||||
if (comma)
|
||||
output += ",";
|
||||
|
@ -96,7 +96,7 @@ std::string ConstraintSolverLogger::compileOutput()
|
|||
return output;
|
||||
}
|
||||
|
||||
void ConstraintSolverLogger::captureBoundarySnapshot(const Scope2* rootScope, std::vector<NotNull<const Constraint>>& unsolvedConstraints)
|
||||
void ConstraintSolverLogger::captureBoundarySnapshot(const Scope* rootScope, std::vector<NotNull<const Constraint>>& unsolvedConstraints)
|
||||
{
|
||||
std::string snapshot = "{\"type\":\"boundary\",\"rootScope\":";
|
||||
|
||||
|
@ -109,7 +109,7 @@ void ConstraintSolverLogger::captureBoundarySnapshot(const Scope2* rootScope, st
|
|||
}
|
||||
|
||||
void ConstraintSolverLogger::prepareStepSnapshot(
|
||||
const Scope2* rootScope, NotNull<const Constraint> current, std::vector<NotNull<const Constraint>>& unsolvedConstraints)
|
||||
const Scope* rootScope, NotNull<const Constraint> current, std::vector<NotNull<const Constraint>>& unsolvedConstraints)
|
||||
{
|
||||
// LUAU_ASSERT(!preparedSnapshot);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "Luau/BuiltinDefinitions.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauUnknownAndNeverType)
|
||||
LUAU_FASTFLAG(LuauCheckLenMT)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -123,6 +122,7 @@ declare function tonumber<T>(value: T, radix: number?): number?
|
|||
declare function rawequal<T1, T2>(a: T1, b: T2): boolean
|
||||
declare function rawget<K, V>(tab: {[K]: V}, k: K): V
|
||||
declare function rawset<K, V>(tab: {[K]: V}, k: K, v: V): {[K]: V}
|
||||
declare function rawlen<K, V>(obj: {[K]: V} | string): number
|
||||
|
||||
declare function setfenv<T..., R...>(target: number | (T...) -> R..., env: {[string]: any}): ((T...) -> R...)?
|
||||
|
||||
|
@ -206,10 +206,6 @@ std::string getBuiltinDefinitionSource()
|
|||
|
||||
std::string result = kBuiltinDefinitionLuaSrc;
|
||||
|
||||
// TODO: move this into kBuiltinDefinitionLuaSrc
|
||||
if (FFlag::LuauCheckLenMT)
|
||||
result += "declare function rawlen<K, V>(obj: {[K]: V} | string): number\n";
|
||||
|
||||
if (FFlag::LuauUnknownAndNeverType)
|
||||
result += "declare function error<T>(message: T, level: number?): never\n";
|
||||
else
|
||||
|
|
|
@ -766,35 +766,35 @@ const SourceModule* Frontend::getSourceModule(const ModuleName& moduleName) cons
|
|||
return const_cast<Frontend*>(this)->getSourceModule(moduleName);
|
||||
}
|
||||
|
||||
NotNull<Scope2> Frontend::getGlobalScope2()
|
||||
NotNull<Scope> Frontend::getGlobalScope()
|
||||
{
|
||||
if (!globalScope2)
|
||||
if (!globalScope)
|
||||
{
|
||||
const SingletonTypes& singletonTypes = getSingletonTypes();
|
||||
|
||||
globalScope2 = std::make_unique<Scope2>();
|
||||
globalScope2->typeBindings["nil"] = singletonTypes.nilType;
|
||||
globalScope2->typeBindings["number"] = singletonTypes.numberType;
|
||||
globalScope2->typeBindings["string"] = singletonTypes.stringType;
|
||||
globalScope2->typeBindings["boolean"] = singletonTypes.booleanType;
|
||||
globalScope2->typeBindings["thread"] = singletonTypes.threadType;
|
||||
globalScope = std::make_unique<Scope>(singletonTypes.anyTypePack);
|
||||
globalScope->typeBindings["nil"] = singletonTypes.nilType;
|
||||
globalScope->typeBindings["number"] = singletonTypes.numberType;
|
||||
globalScope->typeBindings["string"] = singletonTypes.stringType;
|
||||
globalScope->typeBindings["boolean"] = singletonTypes.booleanType;
|
||||
globalScope->typeBindings["thread"] = singletonTypes.threadType;
|
||||
}
|
||||
|
||||
return NotNull(globalScope2.get());
|
||||
return NotNull(globalScope.get());
|
||||
}
|
||||
|
||||
ModulePtr Frontend::check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope)
|
||||
{
|
||||
ModulePtr result = std::make_shared<Module>();
|
||||
|
||||
ConstraintGraphBuilder cgb{sourceModule.name, &result->internalTypes, NotNull(&iceHandler), getGlobalScope2()};
|
||||
ConstraintGraphBuilder cgb{sourceModule.name, &result->internalTypes, NotNull(&iceHandler), getGlobalScope()};
|
||||
cgb.visit(sourceModule.root);
|
||||
result->errors = std::move(cgb.errors);
|
||||
|
||||
ConstraintSolver cs{&result->internalTypes, NotNull(cgb.rootScope)};
|
||||
cs.run();
|
||||
|
||||
result->scope2s = std::move(cgb.scopes);
|
||||
result->scopes = std::move(cgb.scopes);
|
||||
result->astTypes = std::move(cgb.astTypes);
|
||||
result->astTypePacks = std::move(cgb.astTypePacks);
|
||||
result->astOriginalCallTypes = std::move(cgb.astOriginalCallTypes);
|
||||
|
|
|
@ -103,8 +103,8 @@ struct AstJsonEncoder : public AstVisitor
|
|||
|
||||
void write(double d)
|
||||
{
|
||||
char b[256];
|
||||
sprintf(b, "%.17g", d);
|
||||
char b[32];
|
||||
snprintf(b, sizeof(b), "%.17g", d);
|
||||
writeRaw(b);
|
||||
}
|
||||
|
||||
|
|
|
@ -100,29 +100,20 @@ void Module::clonePublicInterface(InternalErrorReporter& ice)
|
|||
|
||||
CloneState cloneState;
|
||||
|
||||
ScopePtr moduleScope = FFlag::DebugLuauDeferredConstraintResolution ? nullptr : getModuleScope();
|
||||
Scope2* moduleScope2 = FFlag::DebugLuauDeferredConstraintResolution ? getModuleScope2() : nullptr;
|
||||
ScopePtr moduleScope = getModuleScope();
|
||||
|
||||
TypePackId returnType = FFlag::DebugLuauDeferredConstraintResolution ? moduleScope2->returnType : moduleScope->returnType;
|
||||
TypePackId returnType = moduleScope->returnType;
|
||||
std::optional<TypePackId> varargPack = FFlag::DebugLuauDeferredConstraintResolution ? std::nullopt : moduleScope->varargPack;
|
||||
std::unordered_map<Name, TypeFun>* exportedTypeBindings =
|
||||
FFlag::DebugLuauDeferredConstraintResolution ? nullptr : &moduleScope->exportedTypeBindings;
|
||||
|
||||
returnType = clone(returnType, interfaceTypes, cloneState);
|
||||
|
||||
if (moduleScope)
|
||||
moduleScope->returnType = returnType;
|
||||
if (varargPack)
|
||||
{
|
||||
moduleScope->returnType = returnType;
|
||||
if (varargPack)
|
||||
{
|
||||
varargPack = clone(*varargPack, interfaceTypes, cloneState);
|
||||
moduleScope->varargPack = varargPack;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(moduleScope2);
|
||||
moduleScope2->returnType = returnType; // TODO varargPack
|
||||
varargPack = clone(*varargPack, interfaceTypes, cloneState);
|
||||
moduleScope->varargPack = varargPack;
|
||||
}
|
||||
|
||||
ForceNormal forceNormal{&interfaceTypes};
|
||||
|
@ -201,10 +192,4 @@ ScopePtr Module::getModuleScope() const
|
|||
return scopes.front().second;
|
||||
}
|
||||
|
||||
Scope2* Module::getModuleScope2() const
|
||||
{
|
||||
LUAU_ASSERT(!scope2s.empty());
|
||||
return scope2s.front().second.get();
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -16,13 +16,13 @@ namespace Luau
|
|||
{
|
||||
|
||||
/// @return true if outer encloses inner
|
||||
static bool subsumes(Scope2* outer, Scope2* inner)
|
||||
static bool subsumes(Scope* outer, Scope* inner)
|
||||
{
|
||||
while (inner)
|
||||
{
|
||||
if (inner == outer)
|
||||
return true;
|
||||
inner = inner->parent;
|
||||
inner = inner->parent.get();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -33,7 +33,7 @@ struct Quantifier final : TypeVarOnceVisitor
|
|||
TypeLevel level;
|
||||
std::vector<TypeId> generics;
|
||||
std::vector<TypePackId> genericPacks;
|
||||
Scope2* scope = nullptr;
|
||||
Scope* scope = nullptr;
|
||||
bool seenGenericType = false;
|
||||
bool seenMutableType = false;
|
||||
|
||||
|
@ -43,20 +43,20 @@ struct Quantifier final : TypeVarOnceVisitor
|
|||
LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution);
|
||||
}
|
||||
|
||||
explicit Quantifier(Scope2* scope)
|
||||
explicit Quantifier(Scope* scope)
|
||||
: scope(scope)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution);
|
||||
}
|
||||
|
||||
/// @return true if outer encloses inner
|
||||
bool subsumes(Scope2* outer, Scope2* inner)
|
||||
bool subsumes(Scope* outer, Scope* inner)
|
||||
{
|
||||
while (inner)
|
||||
{
|
||||
if (inner == outer)
|
||||
return true;
|
||||
inner = inner->parent;
|
||||
inner = inner->parent.get();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -216,7 +216,7 @@ void quantify(TypeId ty, TypeLevel level)
|
|||
}
|
||||
}
|
||||
|
||||
void quantify(TypeId ty, Scope2* scope)
|
||||
void quantify(TypeId ty, Scope* scope)
|
||||
{
|
||||
Quantifier q{scope};
|
||||
q.traverse(ty);
|
||||
|
@ -240,11 +240,11 @@ void quantify(TypeId ty, Scope2* scope)
|
|||
|
||||
struct PureQuantifier : Substitution
|
||||
{
|
||||
Scope2* scope;
|
||||
Scope* scope;
|
||||
std::vector<TypeId> insertedGenerics;
|
||||
std::vector<TypePackId> insertedGenericPacks;
|
||||
|
||||
PureQuantifier(TypeArena* arena, Scope2* scope)
|
||||
PureQuantifier(TypeArena* arena, Scope* scope)
|
||||
: Substitution(TxnLog::empty(), arena)
|
||||
, scope(scope)
|
||||
{
|
||||
|
@ -322,7 +322,7 @@ struct PureQuantifier : Substitution
|
|||
}
|
||||
};
|
||||
|
||||
TypeId quantify(TypeArena* arena, TypeId ty, Scope2* scope)
|
||||
TypeId quantify(TypeArena* arena, TypeId ty, Scope* scope)
|
||||
{
|
||||
PureQuantifier quantifier{arena, scope};
|
||||
std::optional<TypeId> result = quantifier.substitute(ty);
|
||||
|
|
|
@ -21,22 +21,6 @@ Scope::Scope(const ScopePtr& parent, int subLevel)
|
|||
level.subLevel = subLevel;
|
||||
}
|
||||
|
||||
std::optional<TypeId> Scope::lookup(const Symbol& name)
|
||||
{
|
||||
Scope* scope = this;
|
||||
|
||||
while (scope)
|
||||
{
|
||||
auto it = scope->bindings.find(name);
|
||||
if (it != scope->bindings.end())
|
||||
return it->second.typeId;
|
||||
|
||||
scope = scope->parent.get();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeFun> Scope::lookupType(const Name& name)
|
||||
{
|
||||
const Scope* scope = this;
|
||||
|
@ -121,48 +105,48 @@ std::optional<Binding> Scope::linearSearchForBinding(const std::string& name, bo
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeId> Scope2::lookup(Symbol sym)
|
||||
std::optional<TypeId> Scope::lookup(Symbol sym)
|
||||
{
|
||||
Scope2* s = this;
|
||||
Scope* s = this;
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto it = s->bindings.find(sym);
|
||||
if (it != s->bindings.end())
|
||||
return it->second;
|
||||
return it->second.typeId;
|
||||
|
||||
if (s->parent)
|
||||
s = s->parent;
|
||||
s = s->parent.get();
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeId> Scope2::lookupTypeBinding(const Name& name)
|
||||
std::optional<TypeId> Scope::lookupTypeBinding(const Name& name)
|
||||
{
|
||||
Scope2* s = this;
|
||||
Scope* s = this;
|
||||
while (s)
|
||||
{
|
||||
auto it = s->typeBindings.find(name);
|
||||
if (it != s->typeBindings.end())
|
||||
return it->second;
|
||||
|
||||
s = s->parent;
|
||||
s = s->parent.get();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypePackId> Scope2::lookupTypePackBinding(const Name& name)
|
||||
std::optional<TypePackId> Scope::lookupTypePackBinding(const Name& name)
|
||||
{
|
||||
Scope2* s = this;
|
||||
Scope* s = this;
|
||||
while (s)
|
||||
{
|
||||
auto it = s->typePackBindings.find(name);
|
||||
if (it != s->typePackBindings.end())
|
||||
return it->second;
|
||||
|
||||
s = s->parent;
|
||||
s = s->parent.get();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
|
||||
LUAU_FASTFLAG(LuauUnknownAndNeverType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSpecialTypesAsterisked, false)
|
||||
|
||||
/*
|
||||
* Prefix generic typenames with gen-
|
||||
|
@ -277,7 +278,10 @@ struct TypeVarStringifier
|
|||
if (tv->ty.valueless_by_exception())
|
||||
{
|
||||
state.result.error = true;
|
||||
state.emit("< VALUELESS BY EXCEPTION >");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("* VALUELESS BY EXCEPTION *");
|
||||
else
|
||||
state.emit("< VALUELESS BY EXCEPTION >");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -453,7 +457,10 @@ struct TypeVarStringifier
|
|||
if (state.hasSeen(&ftv))
|
||||
{
|
||||
state.result.cycle = true;
|
||||
state.emit("<CYCLE>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("*CYCLE*");
|
||||
else
|
||||
state.emit("<CYCLE>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -561,7 +568,10 @@ struct TypeVarStringifier
|
|||
if (state.hasSeen(&ttv))
|
||||
{
|
||||
state.result.cycle = true;
|
||||
state.emit("<CYCLE>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("*CYCLE*");
|
||||
else
|
||||
state.emit("<CYCLE>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -691,7 +701,10 @@ struct TypeVarStringifier
|
|||
if (state.hasSeen(&uv))
|
||||
{
|
||||
state.result.cycle = true;
|
||||
state.emit("<CYCLE>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("*CYCLE*");
|
||||
else
|
||||
state.emit("<CYCLE>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -758,7 +771,10 @@ struct TypeVarStringifier
|
|||
if (state.hasSeen(&uv))
|
||||
{
|
||||
state.result.cycle = true;
|
||||
state.emit("<CYCLE>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("*CYCLE*");
|
||||
else
|
||||
state.emit("<CYCLE>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -803,7 +819,10 @@ struct TypeVarStringifier
|
|||
void operator()(TypeId, const ErrorTypeVar& tv)
|
||||
{
|
||||
state.result.error = true;
|
||||
state.emit(FFlag::LuauUnknownAndNeverType ? "<error-type>" : "*unknown*");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit(FFlag::LuauUnknownAndNeverType ? "*error-type*" : "*unknown*");
|
||||
else
|
||||
state.emit(FFlag::LuauUnknownAndNeverType ? "<error-type>" : "*unknown*");
|
||||
}
|
||||
|
||||
void operator()(TypeId, const LazyTypeVar& ltv)
|
||||
|
@ -857,7 +876,10 @@ struct TypePackStringifier
|
|||
if (tp->ty.valueless_by_exception())
|
||||
{
|
||||
state.result.error = true;
|
||||
state.emit("< VALUELESS TP BY EXCEPTION >");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("* VALUELESS TP BY EXCEPTION *");
|
||||
else
|
||||
state.emit("< VALUELESS TP BY EXCEPTION >");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -881,7 +903,10 @@ struct TypePackStringifier
|
|||
if (state.hasSeen(&tp))
|
||||
{
|
||||
state.result.cycle = true;
|
||||
state.emit("<CYCLETP>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("*CYCLETP*");
|
||||
else
|
||||
state.emit("<CYCLETP>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -926,14 +951,22 @@ struct TypePackStringifier
|
|||
void operator()(TypePackId, const Unifiable::Error& error)
|
||||
{
|
||||
state.result.error = true;
|
||||
state.emit(FFlag::LuauUnknownAndNeverType ? "<error-type>" : "*unknown*");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit(FFlag::LuauUnknownAndNeverType ? "*error-type*" : "*unknown*");
|
||||
else
|
||||
state.emit(FFlag::LuauUnknownAndNeverType ? "<error-type>" : "*unknown*");
|
||||
}
|
||||
|
||||
void operator()(TypePackId, const VariadicTypePack& pack)
|
||||
{
|
||||
state.emit("...");
|
||||
if (FFlag::DebugLuauVerboseTypeNames && pack.hidden)
|
||||
state.emit("<hidden>");
|
||||
{
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
state.emit("*hidden*");
|
||||
else
|
||||
state.emit("<hidden>");
|
||||
}
|
||||
stringify(pack.ty);
|
||||
}
|
||||
|
||||
|
@ -1128,7 +1161,11 @@ ToStringResult toStringDetailed(TypeId ty, const ToStringOptions& opts)
|
|||
if (opts.maxTypeLength > 0 && result.name.length() > opts.maxTypeLength)
|
||||
{
|
||||
result.truncated = true;
|
||||
result.name += "... <TRUNCATED>";
|
||||
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
result.name += "... *TRUNCATED*";
|
||||
else
|
||||
result.name += "... <TRUNCATED>";
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1199,7 +1236,12 @@ ToStringResult toStringDetailed(TypePackId tp, const ToStringOptions& opts)
|
|||
}
|
||||
|
||||
if (opts.maxTypeLength > 0 && result.name.length() > opts.maxTypeLength)
|
||||
result.name += "... <TRUNCATED>";
|
||||
{
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
result.name += "... *TRUNCATED*";
|
||||
else
|
||||
result.name += "... <TRUNCATED>";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -69,6 +69,9 @@ struct TypeChecker2 : public AstVisitor
|
|||
|
||||
TypePackId reconstructPack(AstArray<AstExpr*> exprs, TypeArena& arena)
|
||||
{
|
||||
if (exprs.size == 0)
|
||||
return arena.addTypePack(TypePack{{}, std::nullopt});
|
||||
|
||||
std::vector<TypeId> head;
|
||||
|
||||
for (size_t i = 0; i < exprs.size - 1; ++i)
|
||||
|
@ -80,14 +83,14 @@ struct TypeChecker2 : public AstVisitor
|
|||
return arena.addTypePack(TypePack{head, tail});
|
||||
}
|
||||
|
||||
Scope2* findInnermostScope(Location location)
|
||||
Scope* findInnermostScope(Location location)
|
||||
{
|
||||
Scope2* bestScope = module->getModuleScope2();
|
||||
Location bestLocation = module->scope2s[0].first;
|
||||
Scope* bestScope = module->getModuleScope().get();
|
||||
Location bestLocation = module->scopes[0].first;
|
||||
|
||||
for (size_t i = 0; i < module->scope2s.size(); ++i)
|
||||
for (size_t i = 0; i < module->scopes.size(); ++i)
|
||||
{
|
||||
auto& [scopeBounds, scope] = module->scope2s[i];
|
||||
auto& [scopeBounds, scope] = module->scopes[i];
|
||||
if (scopeBounds.encloses(location))
|
||||
{
|
||||
if (scopeBounds.begin > bestLocation.begin || scopeBounds.end < bestLocation.end)
|
||||
|
@ -181,7 +184,7 @@ struct TypeChecker2 : public AstVisitor
|
|||
|
||||
bool visit(AstStatReturn* ret) override
|
||||
{
|
||||
Scope2* scope = findInnermostScope(ret->location);
|
||||
Scope* scope = findInnermostScope(ret->location);
|
||||
TypePackId expectedRetType = scope->returnType;
|
||||
|
||||
TypeArena arena;
|
||||
|
@ -359,7 +362,7 @@ struct TypeChecker2 : public AstVisitor
|
|||
|
||||
bool visit(AstTypeReference* ty) override
|
||||
{
|
||||
Scope2* scope = findInnermostScope(ty->location);
|
||||
Scope* scope = findInnermostScope(ty->location);
|
||||
|
||||
// TODO: Imported types
|
||||
// TODO: Generic types
|
||||
|
|
|
@ -35,7 +35,7 @@ LUAU_FASTFLAGVARIABLE(LuauExpectedTableUnionIndexerType, false)
|
|||
LUAU_FASTFLAGVARIABLE(LuauIndexSilenceErrors, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauLowerBoundsCalculation, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSelfCallAutocompleteFix2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSelfCallAutocompleteFix3, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReduceUnionRecursion, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReturnAnyInsteadOfICE, false) // Eventually removed as false.
|
||||
LUAU_FASTFLAG(LuauNormalizeFlagIsConservative)
|
||||
|
@ -45,7 +45,6 @@ LUAU_FASTFLAGVARIABLE(LuauReportErrorsOnIndexerKeyMismatch, false)
|
|||
LUAU_FASTFLAGVARIABLE(LuauUnknownAndNeverType, false)
|
||||
LUAU_FASTFLAG(LuauQuantifyConstrained)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFalsyPredicateReturnsNilInstead, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCheckLenMT, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCheckGenericHOFTypes, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBinaryNeedsExpectedTypesToo, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNeverTypesAndOperatorsInference, false)
|
||||
|
@ -1667,7 +1666,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar
|
|||
ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}});
|
||||
ftv->argTypes = addTypePack(TypePack{{classTy}, ftv->argTypes});
|
||||
|
||||
if (FFlag::LuauSelfCallAutocompleteFix2)
|
||||
if (FFlag::LuauSelfCallAutocompleteFix3)
|
||||
ftv->hasSelf = true;
|
||||
}
|
||||
}
|
||||
|
@ -2465,7 +2464,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
|
|||
|
||||
DenseHashSet<TypeId> seen{nullptr};
|
||||
|
||||
if (FFlag::LuauCheckLenMT && typeCouldHaveMetatable(operandType))
|
||||
if (typeCouldHaveMetatable(operandType))
|
||||
{
|
||||
if (auto fnt = findMetatableEntry(operandType, "__len", expr.location, /* addErrors= */ true))
|
||||
{
|
||||
|
@ -3640,6 +3639,9 @@ void TypeChecker::checkFunctionBody(const ScopePtr& scope, TypeId ty, const AstE
|
|||
reportError(getEndLocation(function), FunctionExitsWithoutReturning{funTy->retTypes});
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentModule->astTypes.find(&function))
|
||||
currentModule->astTypes[&function] = ty;
|
||||
}
|
||||
else
|
||||
ice("Checking non functional type");
|
||||
|
|
|
@ -12,7 +12,7 @@ Free::Free(TypeLevel level)
|
|||
{
|
||||
}
|
||||
|
||||
Free::Free(Scope2* scope)
|
||||
Free::Free(Scope* scope)
|
||||
: scope(scope)
|
||||
{
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ Generic::Generic(const Name& name)
|
|||
{
|
||||
}
|
||||
|
||||
Generic::Generic(Scope2* scope)
|
||||
Generic::Generic(Scope* scope)
|
||||
: index(++nextIndex)
|
||||
, scope(scope)
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ Generic::Generic(TypeLevel level, const Name& name)
|
|||
{
|
||||
}
|
||||
|
||||
Generic::Generic(Scope2* scope, const Name& name)
|
||||
Generic::Generic(Scope* scope, const Name& name)
|
||||
: index(++nextIndex)
|
||||
, scope(scope)
|
||||
, name(name)
|
||||
|
|
|
@ -24,8 +24,6 @@ bool lua_telemetry_parsed_named_non_function_type = false;
|
|||
LUAU_FASTFLAGVARIABLE(LuauErrorParseIntegerIssues, false)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauAlwaysCaptureHotComments, false)
|
||||
|
||||
bool lua_telemetry_parsed_out_of_range_bin_integer = false;
|
||||
bool lua_telemetry_parsed_out_of_range_hex_integer = false;
|
||||
bool lua_telemetry_parsed_double_prefix_hex_integer = false;
|
||||
|
@ -2920,39 +2918,34 @@ AstTypeError* Parser::reportTypeAnnotationError(const Location& location, const
|
|||
|
||||
void Parser::nextLexeme()
|
||||
{
|
||||
if (options.captureComments || FFlag::LuauAlwaysCaptureHotComments)
|
||||
Lexeme::Type type = lexer.next(/* skipComments= */ false, true).type;
|
||||
|
||||
while (type == Lexeme::BrokenComment || type == Lexeme::Comment || type == Lexeme::BlockComment)
|
||||
{
|
||||
Lexeme::Type type = lexer.next(/* skipComments= */ false, true).type;
|
||||
const Lexeme& lexeme = lexer.current();
|
||||
|
||||
while (type == Lexeme::BrokenComment || type == Lexeme::Comment || type == Lexeme::BlockComment)
|
||||
if (options.captureComments)
|
||||
commentLocations.push_back(Comment{lexeme.type, lexeme.location});
|
||||
|
||||
// Subtlety: Broken comments are weird because we record them as comments AND pass them to the parser as a lexeme.
|
||||
// The parser will turn this into a proper syntax error.
|
||||
if (lexeme.type == Lexeme::BrokenComment)
|
||||
return;
|
||||
|
||||
// Comments starting with ! are called "hot comments" and contain directives for type checking / linting / compiling
|
||||
if (lexeme.type == Lexeme::Comment && lexeme.length && lexeme.data[0] == '!')
|
||||
{
|
||||
const Lexeme& lexeme = lexer.current();
|
||||
const char* text = lexeme.data;
|
||||
|
||||
if (options.captureComments)
|
||||
commentLocations.push_back(Comment{lexeme.type, lexeme.location});
|
||||
unsigned int end = lexeme.length;
|
||||
while (end > 0 && isSpace(text[end - 1]))
|
||||
--end;
|
||||
|
||||
// Subtlety: Broken comments are weird because we record them as comments AND pass them to the parser as a lexeme.
|
||||
// The parser will turn this into a proper syntax error.
|
||||
if (lexeme.type == Lexeme::BrokenComment)
|
||||
return;
|
||||
|
||||
// Comments starting with ! are called "hot comments" and contain directives for type checking / linting / compiling
|
||||
if (lexeme.type == Lexeme::Comment && lexeme.length && lexeme.data[0] == '!')
|
||||
{
|
||||
const char* text = lexeme.data;
|
||||
|
||||
unsigned int end = lexeme.length;
|
||||
while (end > 0 && isSpace(text[end - 1]))
|
||||
--end;
|
||||
|
||||
hotcomments.push_back({hotcommentHeader, lexeme.location, std::string(text + 1, text + end)});
|
||||
}
|
||||
|
||||
type = lexer.next(/* skipComments= */ false, /* updatePrevLocation= */ false).type;
|
||||
hotcomments.push_back({hotcommentHeader, lexeme.location, std::string(text + 1, text + end)});
|
||||
}
|
||||
|
||||
type = lexer.next(/* skipComments= */ false, /* updatePrevLocation= */ false).type;
|
||||
}
|
||||
else
|
||||
lexer.next();
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Repl.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
return replMain(argc, argv);
|
||||
|
|
|
@ -25,8 +25,6 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
|||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileNoIpairs, false)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileFoldBuiltins, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileBetterMultret, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileFreeReassign, false)
|
||||
|
||||
namespace Luau
|
||||
|
@ -276,9 +274,6 @@ struct Compiler
|
|||
// returns true if node can return multiple values; may conservatively return true even if expr is known to return just a single value
|
||||
bool isExprMultRet(AstExpr* node)
|
||||
{
|
||||
if (!FFlag::LuauCompileBetterMultret)
|
||||
return node->is<AstExprCall>() || node->is<AstExprVarargs>();
|
||||
|
||||
AstExprCall* expr = node->as<AstExprCall>();
|
||||
if (!expr)
|
||||
return node->is<AstExprVarargs>();
|
||||
|
@ -310,27 +305,10 @@ struct Compiler
|
|||
if (AstExprCall* expr = node->as<AstExprCall>())
|
||||
{
|
||||
// Optimization: convert multret calls that always return one value to fixedret calls; this facilitates inlining/constant folding
|
||||
if (options.optimizationLevel >= 2)
|
||||
if (options.optimizationLevel >= 2 && !isExprMultRet(node))
|
||||
{
|
||||
if (FFlag::LuauCompileBetterMultret)
|
||||
{
|
||||
if (!isExprMultRet(node))
|
||||
{
|
||||
compileExprTemp(node, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AstExprFunction* func = getFunctionExpr(expr->func);
|
||||
Function* fi = func ? functions.find(func) : nullptr;
|
||||
|
||||
if (fi && fi->returnsOne)
|
||||
{
|
||||
compileExprTemp(node, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
compileExprTemp(node, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We temporarily swap out regTop to have targetTop work correctly...
|
||||
|
@ -3437,30 +3415,7 @@ struct Compiler
|
|||
|
||||
bool visit(AstStatReturn* stat) override
|
||||
{
|
||||
if (FFlag::LuauCompileBetterMultret)
|
||||
{
|
||||
returnsOne &= stat->list.size == 1 && !self->isExprMultRet(stat->list.data[0]);
|
||||
}
|
||||
else if (stat->list.size == 1)
|
||||
{
|
||||
AstExpr* value = stat->list.data[0];
|
||||
|
||||
if (AstExprCall* expr = value->as<AstExprCall>())
|
||||
{
|
||||
AstExprFunction* func = self->getFunctionExpr(expr->func);
|
||||
Function* fi = func ? self->functions.find(func) : nullptr;
|
||||
|
||||
returnsOne &= fi && fi->returnsOne;
|
||||
}
|
||||
else if (value->is<AstExprVarargs>())
|
||||
{
|
||||
returnsOne = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
returnsOne = false;
|
||||
}
|
||||
returnsOne &= stat->list.size == 1 && !self->isExprMultRet(stat->list.data[0]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -3601,7 +3556,7 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c
|
|||
trackValues(compiler.globals, compiler.variables, root);
|
||||
|
||||
// builtin folding is enabled on optimization level 2 since we can't deoptimize folding at runtime
|
||||
if (options.optimizationLevel >= 2 && FFlag::LuauCompileFoldBuiltins)
|
||||
if (options.optimizationLevel >= 2)
|
||||
compiler.builtinsFold = &compiler.builtins;
|
||||
|
||||
if (options.optimizationLevel >= 1)
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileModelBuiltins, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace Compile
|
||||
|
@ -155,7 +153,7 @@ struct CostVisitor : AstVisitor
|
|||
{
|
||||
// builtin cost modeling is different from regular calls because we use FASTCALL to compile these
|
||||
// thus we use a cheaper baseline, don't account for function, and assume constant/local copy is free
|
||||
bool builtin = FFlag::LuauCompileModelBuiltins && builtins.find(expr) != nullptr;
|
||||
bool builtin = builtins.find(expr) != nullptr;
|
||||
bool builtinShort = builtin && expr->args.size <= 2; // FASTCALL1/2
|
||||
|
||||
Cost cost = builtin ? 2 : 3;
|
||||
|
|
|
@ -267,6 +267,7 @@ if(TARGET Luau.UnitTest)
|
|||
tests/Error.test.cpp
|
||||
tests/Frontend.test.cpp
|
||||
tests/JsonEncoder.test.cpp
|
||||
tests/Lexer.test.cpp
|
||||
tests/Linter.test.cpp
|
||||
tests/LValue.test.cpp
|
||||
tests/Module.test.cpp
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
* therefore call luaC_checkGC before luaC_checkthreadsleep to guarantee the object is pushed to an awake thread.
|
||||
*/
|
||||
|
||||
LUAU_FASTFLAG(LuauLazyAtoms)
|
||||
|
||||
const char* lua_ident = "$Lua: Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio $\n"
|
||||
"$Authors: R. Ierusalimschy, L. H. de Figueiredo & W. Celes $\n"
|
||||
"$URL: www.lua.org $\n";
|
||||
|
@ -54,7 +52,6 @@ const char* luau_ident = "$Luau: Copyright (C) 2019-2022 Roblox Corporation $\n"
|
|||
}
|
||||
|
||||
#define updateatom(L, ts) \
|
||||
if (FFlag::LuauLazyAtoms) \
|
||||
{ \
|
||||
if (ts->atom == ATOM_UNDEF) \
|
||||
ts->atom = L->global->cb.useratom ? L->global->cb.useratom(ts->data, ts->len) : -1; \
|
||||
|
|
|
@ -130,15 +130,14 @@ static int db_traceback(lua_State* L)
|
|||
|
||||
if (ar.currentline > 0)
|
||||
{
|
||||
char line[32];
|
||||
#ifdef _MSC_VER
|
||||
_itoa(ar.currentline, line, 10); // 5x faster than sprintf
|
||||
#else
|
||||
sprintf(line, "%d", ar.currentline);
|
||||
#endif
|
||||
char line[32]; // manual conversion for performance
|
||||
char* lineend = line + sizeof(line);
|
||||
char* lineptr = lineend;
|
||||
for (unsigned int r = ar.currentline; r > 0; r /= 10)
|
||||
*--lineptr = '0' + (r % 10);
|
||||
|
||||
luaL_addchar(&buf, ':');
|
||||
luaL_addstring(&buf, line);
|
||||
luaL_addlstring(&buf, lineptr, lineend - lineptr);
|
||||
}
|
||||
|
||||
if (ar.name)
|
||||
|
|
|
@ -529,7 +529,7 @@ const char* lua_debugtrace(lua_State* L)
|
|||
if (ar.currentline > 0)
|
||||
{
|
||||
char line[32];
|
||||
sprintf(line, ":%d", ar.currentline);
|
||||
snprintf(line, sizeof(line), ":%d", ar.currentline);
|
||||
|
||||
offset = append(buf, sizeof(buf), offset, line);
|
||||
}
|
||||
|
@ -545,7 +545,7 @@ const char* lua_debugtrace(lua_State* L)
|
|||
if (depth > limit1 + limit2 && level == limit1 - 1)
|
||||
{
|
||||
char skip[32];
|
||||
sprintf(skip, "... (+%d frames)\n", int(depth - limit1 - limit2));
|
||||
snprintf(skip, sizeof(skip), "... (+%d frames)\n", int(depth - limit1 - limit2));
|
||||
|
||||
offset = append(buf, sizeof(buf), offset, skip);
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauLazyAtoms, false)
|
||||
|
||||
unsigned int luaS_hash(const char* str, size_t len)
|
||||
{
|
||||
// Note that this hashing algorithm is replicated in BytecodeBuilder.cpp, BytecodeBuilder::getStringHash
|
||||
|
@ -84,7 +82,7 @@ static TString* newlstr(lua_State* L, const char* str, size_t l, unsigned int h)
|
|||
ts->memcat = L->activememcat;
|
||||
memcpy(ts->data, str, l);
|
||||
ts->data[l] = '\0'; /* ending 0 */
|
||||
ts->atom = FFlag::LuauLazyAtoms ? ATOM_UNDEF : L->global->cb.useratom ? L->global->cb.useratom(ts->data, l) : -1;
|
||||
ts->atom = ATOM_UNDEF;
|
||||
tb = &L->global->strt;
|
||||
h = lmod(h, tb->size);
|
||||
ts->next = tb->hash[h]; /* chain new entry */
|
||||
|
@ -165,9 +163,7 @@ TString* luaS_buffinish(lua_State* L, TString* ts)
|
|||
|
||||
ts->hash = h;
|
||||
ts->data[ts->len] = '\0'; // ending 0
|
||||
|
||||
// Complete string object
|
||||
ts->atom = FFlag::LuauLazyAtoms ? ATOM_UNDEF : L->global->cb.useratom ? L->global->cb.useratom(ts->data, ts->len) : -1;
|
||||
ts->atom = ATOM_UNDEF;
|
||||
ts->next = tb->hash[bucket]; // chain new entry
|
||||
tb->hash[bucket] = ts;
|
||||
|
||||
|
|
|
@ -979,14 +979,14 @@ static int str_format(lua_State* L)
|
|||
{
|
||||
case 'c':
|
||||
{
|
||||
sprintf(buff, form, (int)luaL_checknumber(L, arg));
|
||||
snprintf(buff, sizeof(buff), form, (int)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i':
|
||||
{
|
||||
addInt64Format(form, formatIndicator, formatItemSize);
|
||||
sprintf(buff, form, (long long)luaL_checknumber(L, arg));
|
||||
snprintf(buff, sizeof(buff), form, (long long)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
|
@ -997,7 +997,7 @@ static int str_format(lua_State* L)
|
|||
double argValue = luaL_checknumber(L, arg);
|
||||
addInt64Format(form, formatIndicator, formatItemSize);
|
||||
unsigned long long v = (argValue < 0) ? (unsigned long long)(long long)argValue : (unsigned long long)argValue;
|
||||
sprintf(buff, form, v);
|
||||
snprintf(buff, sizeof(buff), form, v);
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
|
@ -1006,7 +1006,7 @@ static int str_format(lua_State* L)
|
|||
case 'g':
|
||||
case 'G':
|
||||
{
|
||||
sprintf(buff, form, (double)luaL_checknumber(L, arg));
|
||||
snprintf(buff, sizeof(buff), form, (double)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'q':
|
||||
|
@ -1028,7 +1028,7 @@ static int str_format(lua_State* L)
|
|||
}
|
||||
else
|
||||
{
|
||||
sprintf(buff, form, s);
|
||||
snprintf(buff, sizeof(buff), form, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,9 +44,6 @@ static_assert(TKey{{NULL}, {0}, LUA_TDEADKEY, 0}.tt == LUA_TDEADKEY, "not enough
|
|||
static_assert(TKey{{NULL}, {0}, LUA_TNIL, MAXSIZE - 1}.next == MAXSIZE - 1, "not enough bits for next");
|
||||
static_assert(TKey{{NULL}, {0}, LUA_TNIL, -(MAXSIZE - 1)}.next == -(MAXSIZE - 1), "not enough bits for next");
|
||||
|
||||
// reset cache of absent metamethods, cache is updated in luaT_gettm
|
||||
#define invalidateTMcache(t) t->tmcache = 0
|
||||
|
||||
// empty hash data points to dummynode so that we can always dereference it
|
||||
const LuaNode luaH_dummynode = {
|
||||
{{NULL}, {0}, LUA_TNIL}, /* value */
|
||||
|
@ -667,15 +664,18 @@ TValue* luaH_set(lua_State* L, Table* t, const TValue* key)
|
|||
if (p != luaO_nilobject)
|
||||
return cast_to(TValue*, p);
|
||||
else
|
||||
{
|
||||
if (ttisnil(key))
|
||||
luaG_runerror(L, "table index is nil");
|
||||
else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
|
||||
luaG_runerror(L, "table index is NaN");
|
||||
else if (ttisvector(key) && luai_vecisnan(vvalue(key)))
|
||||
luaG_runerror(L, "table index contains NaN");
|
||||
return newkey(L, t, key);
|
||||
}
|
||||
return luaH_newkey(L, t, key);
|
||||
}
|
||||
|
||||
TValue* luaH_newkey(lua_State* L, Table* t, const TValue* key)
|
||||
{
|
||||
if (ttisnil(key))
|
||||
luaG_runerror(L, "table index is nil");
|
||||
else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
|
||||
luaG_runerror(L, "table index is NaN");
|
||||
else if (ttisvector(key) && luai_vecisnan(vvalue(key)))
|
||||
luaG_runerror(L, "table index contains NaN");
|
||||
return newkey(L, t, key);
|
||||
}
|
||||
|
||||
TValue* luaH_setnum(lua_State* L, Table* t, int key)
|
||||
|
|
|
@ -11,12 +11,16 @@
|
|||
|
||||
#define gval2slot(t, v) int(cast_to(LuaNode*, static_cast<const TValue*>(v)) - t->node)
|
||||
|
||||
// reset cache of absent metamethods, cache is updated in luaT_gettm
|
||||
#define invalidateTMcache(t) t->tmcache = 0
|
||||
|
||||
LUAI_FUNC const TValue* luaH_getnum(Table* t, int key);
|
||||
LUAI_FUNC TValue* luaH_setnum(lua_State* L, Table* t, int key);
|
||||
LUAI_FUNC const TValue* luaH_getstr(Table* t, TString* key);
|
||||
LUAI_FUNC TValue* luaH_setstr(lua_State* L, Table* t, TString* key);
|
||||
LUAI_FUNC const TValue* luaH_get(Table* t, const TValue* key);
|
||||
LUAI_FUNC TValue* luaH_set(lua_State* L, Table* t, const TValue* key);
|
||||
LUAI_FUNC TValue* luaH_newkey(lua_State* L, Table* t, const TValue* key);
|
||||
LUAI_FUNC Table* luaH_new(lua_State* L, int narray, int lnhash);
|
||||
LUAI_FUNC void luaH_resizearray(lua_State* L, Table* t, int nasize);
|
||||
LUAI_FUNC void luaH_resizehash(lua_State* L, Table* t, int nhsize);
|
||||
|
@ -26,4 +30,6 @@ LUAI_FUNC int luaH_getn(Table* t);
|
|||
LUAI_FUNC Table* luaH_clone(lua_State* L, Table* tt);
|
||||
LUAI_FUNC void luaH_clear(Table* tt);
|
||||
|
||||
#define luaH_setslot(L, t, slot, key) (invalidateTMcache(t), (slot == luaO_nilobject ? luaH_newkey(L, t, key) : cast_to(TValue*, slot)))
|
||||
|
||||
extern const LuaNode luaH_dummynode;
|
||||
|
|
|
@ -33,7 +33,7 @@ LUAU_FASTFLAGVARIABLE(LuauLenTM, false)
|
|||
// 3. VM_PROTECT macro saves savedpc and restores base for you; most external calls need to be wrapped into that. However, it does NOT restore
|
||||
// ra/rb/rc!
|
||||
// 4. When copying an object to any existing object as a field, generally speaking you need to call luaC_barrier! Be careful with all setobj calls
|
||||
// 5. To make 4 easier to follow, please use setobj2s for copies to stack and setobj for other copies.
|
||||
// 5. To make 4 easier to follow, please use setobj2s for copies to stack, setobj2t for writes to tables, and setobj for other copies.
|
||||
// 6. You can define HARDSTACKTESTS in llimits.h which will aggressively realloc stack; with address sanitizer this should be effective at finding
|
||||
// stack corruption bugs
|
||||
// 7. Many external Lua functions can call GC! GC will *not* traverse pointers to new objects that aren't reachable from Lua root. Be careful when
|
||||
|
@ -458,7 +458,7 @@ static void luau_execute(lua_State* L)
|
|||
|
||||
if (LUAU_LIKELY(ttisstring(gkey(n)) && tsvalue(gkey(n)) == tsvalue(kv) && !ttisnil(gval(n)) && !h->readonly))
|
||||
{
|
||||
setobj(L, gval(n), ra);
|
||||
setobj2t(L, gval(n), ra);
|
||||
luaC_barriert(L, h, ra);
|
||||
VM_NEXT();
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ static void luau_execute(lua_State* L)
|
|||
// fast-path: value is in expected slot
|
||||
if (LUAU_LIKELY(ttisstring(gkey(n)) && tsvalue(gkey(n)) == tsvalue(kv) && !ttisnil(gval(n)) && !h->readonly))
|
||||
{
|
||||
setobj(L, gval(n), ra);
|
||||
setobj2t(L, gval(n), ra);
|
||||
luaC_barriert(L, h, ra);
|
||||
VM_NEXT();
|
||||
}
|
||||
|
@ -684,7 +684,7 @@ static void luau_execute(lua_State* L)
|
|||
int cachedslot = gval2slot(h, res);
|
||||
// save cachedslot to accelerate future lookups; patches currently executing instruction since pc-2 rolls back two pc++
|
||||
VM_PATCH_C(pc - 2, cachedslot);
|
||||
setobj(L, res, ra);
|
||||
setobj2t(L, res, ra);
|
||||
luaC_barriert(L, h, ra);
|
||||
VM_NEXT();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauLenTM)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterNewindex, false)
|
||||
|
||||
/* limit for table tag-method chains (to avoid loops) */
|
||||
#define MAXTAGLOOP 100
|
||||
|
||||
|
@ -142,24 +144,50 @@ void luaV_settable(lua_State* L, const TValue* t, TValue* key, StkId val)
|
|||
{ /* `t' is a table? */
|
||||
Table* h = hvalue(t);
|
||||
|
||||
if (h->readonly)
|
||||
luaG_readonlyerror(L);
|
||||
if (FFlag::LuauBetterNewindex)
|
||||
{
|
||||
const TValue* oldval = luaH_get(h, key);
|
||||
|
||||
TValue* oldval = luaH_set(L, h, key); /* do a primitive set */
|
||||
/* should we assign the key? (if key is valid or __newindex is not set) */
|
||||
if (!ttisnil(oldval) || (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL)
|
||||
{
|
||||
if (h->readonly)
|
||||
luaG_readonlyerror(L);
|
||||
|
||||
L->cachedslot = gval2slot(h, oldval); /* remember slot to accelerate future lookups */
|
||||
/* luaH_set would work but would repeat the lookup so we use luaH_setslot that can reuse oldval if it's safe */
|
||||
TValue* newval = luaH_setslot(L, h, oldval, key);
|
||||
|
||||
if (!ttisnil(oldval) || /* result is no nil? */
|
||||
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL)
|
||||
{ /* or no TM? */
|
||||
setobj2t(L, oldval, val);
|
||||
luaC_barriert(L, h, val);
|
||||
return;
|
||||
L->cachedslot = gval2slot(h, newval); /* remember slot to accelerate future lookups */
|
||||
|
||||
setobj2t(L, newval, val);
|
||||
luaC_barriert(L, h, val);
|
||||
return;
|
||||
}
|
||||
|
||||
/* fallthrough to metamethod */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (h->readonly)
|
||||
luaG_readonlyerror(L);
|
||||
|
||||
TValue* oldval = luaH_set(L, h, key); /* do a primitive set */
|
||||
|
||||
L->cachedslot = gval2slot(h, oldval); /* remember slot to accelerate future lookups */
|
||||
|
||||
if (!ttisnil(oldval) || /* result is no nil? */
|
||||
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL)
|
||||
{ /* or no TM? */
|
||||
setobj2t(L, oldval, val);
|
||||
luaC_barriert(L, h, val);
|
||||
return;
|
||||
}
|
||||
/* else will try the tag method */
|
||||
}
|
||||
/* else will try the tag method */
|
||||
}
|
||||
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
|
||||
luaG_indexerror(L, t, key);
|
||||
|
||||
if (ttisfunction(tm))
|
||||
{
|
||||
callTM(L, tm, t, key, val);
|
||||
|
|
129
rfcs/disallow-proposals-leading-to-ambiguity-in-grammar.md
Normal file
129
rfcs/disallow-proposals-leading-to-ambiguity-in-grammar.md
Normal file
|
@ -0,0 +1,129 @@
|
|||
# Disallow `name T` and `name(T)` in future syntactic extensions for type annotations
|
||||
|
||||
## Summary
|
||||
|
||||
We propose to disallow the syntax ``<name> `('`` as well as `<name> <type>` in future syntax extensions for type annotations to ensure that all existing programs continue to parse correctly. This still keeps the door open for future syntax extensions of different forms such as ``<name> `<' <type> `>'``.
|
||||
|
||||
## Motivation
|
||||
|
||||
Lua and by extension Luau's syntax is very free form, which means that when the parser finishes parsing a node, it doesn't try to look for a semi-colon or any termination token e.g. a `{` to start a block, or `;` to end a statement, or a newline, etc. It just immediately invokes the next parser to figure out how to parse the next node based on the remainder's starting token.
|
||||
|
||||
That feature is sometimes quite troublesome when we want to add new syntax.
|
||||
|
||||
We have had cases where we talked about using syntax like `setmetatable(T, MT)` and `keyof T`. They all look innocent, but when you look beyond that, and try to apply it onto Luau's grammar, things break down really fast.
|
||||
|
||||
### `F(T)`?
|
||||
|
||||
An example that _will_ cause a change in semantics:
|
||||
|
||||
```
|
||||
local t: F
|
||||
(u):m()
|
||||
```
|
||||
|
||||
where today, `local t: F` is one statement, and `(u):m()` is another. If we had the syntax for `F(T)` here, it becomes invalid input because it gets parsed as
|
||||
|
||||
```
|
||||
local t: F(u)
|
||||
:m()
|
||||
```
|
||||
|
||||
This is important because of the `setmetatable(T, MT)` case:
|
||||
|
||||
```
|
||||
type Foo = setmetatable({ x: number }, { ... })
|
||||
```
|
||||
|
||||
For `setmetatable`, the parser isn't sure whether `{}` is actually a type or an expression, because _today_ `setmetatable` is parsed as a type reference, and `({}, {})` is the remainder that we'll attempt to parse as a statement. This means `{ x: number }` is invalid table _literal_. Recovery by backtracking is technically possible here, but this means performance loss on invalid input + may introduce false positives wrt how things are parsed. We'd much rather take a very strict stance about how things get parsed.
|
||||
|
||||
### `F T`?
|
||||
|
||||
An example that _will_ cause a change in semantics:
|
||||
|
||||
```
|
||||
local function f(t): F T
|
||||
(t or u):m()
|
||||
end
|
||||
```
|
||||
|
||||
where today, the return type annotation `F T` is simply parsed as just `F`, followed by a ambiguous parse error from the statement `T(t or u)` because its `(` is on the next line. If at some point in the future we were to allow `T` followed by `(` on the next line, then there's yet another semantic change. `F T` could be parsed as a type annotation and the first statement is `(t or u):m()` instead of `F` followed by `T(t or u):m()`.
|
||||
|
||||
For `keyof`, here's a practical example of the above issue:
|
||||
|
||||
```
|
||||
type Vec2 = {x: number, y: number}
|
||||
|
||||
local function f(t, u): keyof Vec2
|
||||
(t or u):m()
|
||||
end
|
||||
```
|
||||
|
||||
There's three possible outcomes:
|
||||
1. Return type of `f` is `keyof`, statement throws a parse error because `(` is on the next line after `Vec2`,
|
||||
2. Return type of `f` is `keyof Vec2` and next statement is `(t or u):m()`, or
|
||||
3. Return type of `f` is `keyof` and next statement is `Vec2(t or u):m()` (if we allow `(` on the next line to be part of previous line).
|
||||
|
||||
This particular case is even worse when we keep going:
|
||||
|
||||
```
|
||||
local function f(t): F
|
||||
T(t or u):m()
|
||||
end
|
||||
```
|
||||
|
||||
```
|
||||
local function f(t): F T
|
||||
{1, 2, 3}
|
||||
end
|
||||
```
|
||||
|
||||
where today, `F` is the return type annotation of `f`, and `T(t or u):m()`/`T{1, 2, 3}` is the first statement, respectively.
|
||||
|
||||
Adding some syntax for `F T` **will** cause the parser to change the semantics of the above three examples.
|
||||
|
||||
### But what about `typeof(...)`?
|
||||
|
||||
This syntax is grandfathered in because the parser supported `typeof(...)` before we stabilized our syntax, and especially before type annotations were released to the public, so we didn't need to worry about compatibility here. We are very glad that we used parentheses in this case, because it's natural for expressions to belong within parentheses `()`, and types to belong within angles `<>`.
|
||||
|
||||
## The One Exception with a caveat
|
||||
|
||||
This is a strict requirement!
|
||||
|
||||
`function() -> ()` has been talked about in the past, and this one is different despite falling under the same category as ``<name> `('``. The token `function` is in actual fact a "hard keyword," meaning that it cannot be parsed as a type annotation because it is not an identifier, just a keyword.
|
||||
|
||||
Likewise, we also have talked about adding standalone `function` as a type annotation (semantics of it is irrelevant for this RFC)
|
||||
|
||||
It's possible that we may end up adding both, but the requirements are as such:
|
||||
1. `function() -> ()` must be added first before standalone `function`, OR
|
||||
2. `function` can be added first, but with a future-proofing parse error if `<` or `(` follows after it
|
||||
|
||||
If #1 is what ends up happening, there's not much to worry about because the type annotation parser will parse greedily already, so any new valid input will remain valid and have same semantics, except it also allows omitting of `(` and `<`.
|
||||
|
||||
If #2 is what ends up happening, there could be a problem if we didn't future-proof against `<` and `(` to follow `function`:
|
||||
|
||||
```
|
||||
return f :: function(T) -> U
|
||||
```
|
||||
|
||||
which would be a parse error because at the point of `(` we expect one of `until`, `end`, or `EOF`, and
|
||||
|
||||
```
|
||||
return f :: function<a>(a) -> a
|
||||
```
|
||||
|
||||
which would also be a parse error by the time we reach `->`, that is the production of the above is semantically equivalent to `(f < a) > (a)` which would compare whether the value of `f` is less than the value of `a`, then whether the result of that value is greater than `a`.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Only allow these syntax when used inside parentheses e.g. `(F T)` or `(F(T))`. This makes it inconsistent with the existing `typeof(...)` type annotation, and changing that over is also breaking change.
|
||||
|
||||
Support backtracking in the parser, so if `: MyType(t or u):m()` is invalid syntax, revert and parse `MyType` as a type, and `(t or u):m()` as an expression statement. Even so, this option is terrible for:
|
||||
1. parsing performance (backtracking means losing progress on invalid input),
|
||||
2. user experience (why was this annotation parsed as `X(...)` instead of `X` followed by a statement `(...)`),
|
||||
3. has false positives (`foo(bar)(baz)` may be parsed as `foo(bar)` as the type annotation and `(baz)` is the remainder to parse)
|
||||
|
||||
## Drawbacks
|
||||
|
||||
To be able to expose some kind of type-level operations using `F<T>` syntax, means one of the following must be chosen:
|
||||
1. introduce the concept of "magic type functions" into type inference, or
|
||||
2. introduce them into the prelude as `export type F<T> = ...` (where `...` is to be read as "we haven't decided")
|
|
@ -31,9 +31,9 @@ Because we care about backward compatibility, we need some new syntax in order t
|
|||
|
||||
1. A string chunk (`` `...{ ``, `}...{`, and `` }...` ``) where `...` is a range of 0 to many characters.
|
||||
* `\` escapes `` ` ``, `{`, and itself `\`.
|
||||
* Restriction: the string interpolation literal must have at least one value to interpolate. We do not need 3 ways to express a single line string literal.
|
||||
* The pairs must be on the same line (unless a `\` escapes the newline) but expressions needn't be on the same line.
|
||||
2. An expression between the braces. This is the value that will be interpolated into the string.
|
||||
* Restriction: we explicitly reject `{{` as it is considered an attempt to escape and get a single `{` character at runtime.
|
||||
3. Formatting specification may follow after the expression, delimited by an unambiguous character.
|
||||
* Restriction: the formatting specification must be constant at parse time.
|
||||
* In the absence of an explicit formatting specification, the `%*` token will be used.
|
||||
|
@ -61,7 +61,6 @@ local set2 = Set.new({0, 5, 4})
|
|||
print(`{set1} ∪ {set2} = {Set.union(set1, set2)}`)
|
||||
--> {0, 1, 3} ∪ {0, 5, 4} = {0, 1, 3, 4, 5}
|
||||
|
||||
-- For illustrative purposes. These are illegal specifically because they don't interpolate anything.
|
||||
print(`Some example escaping the braces \{like so}`)
|
||||
print(`backslash \ that escapes the space is not a part of the string...`)
|
||||
print(`backslash \\ will escape the second backslash...`)
|
||||
|
@ -88,13 +87,25 @@ print(`Welcome to \
|
|||
-- Luau!
|
||||
```
|
||||
|
||||
This expression will not be allowed to come after a `prefixexp`. I believe this is fully additive, so a future RFC may allow this. So for now, we explicitly reject the following:
|
||||
This expression can also come after a `prefixexp`:
|
||||
|
||||
```
|
||||
local name = "world"
|
||||
print`Hello {name}`
|
||||
```
|
||||
|
||||
The restriction on `{{` exists solely for the people coming from languages e.g. C#, Rust, or Python which uses `{{` to escape and get the character `{` at runtime. We're also rejecting this at parse time too, since the proper way to escape it is `\{`, so:
|
||||
|
||||
```lua
|
||||
print(`{{1, 2, 3}} = {myCoolSet}`) -- parse error
|
||||
```
|
||||
|
||||
If we did not apply this as a parse error, then the above would wind up printing as the following, which is obviously a gotcha we can and should avoid.
|
||||
|
||||
```
|
||||
--> table: 0xSOMEADDRESS = {1, 2, 3}
|
||||
```
|
||||
|
||||
Since the string interpolation expression is going to be lowered into a `string.format` call, we'll also need to extend `string.format`. The bare minimum to support the lowering is to add a new token whose definition is to perform a `tostring` call. `%*` is currently an invalid token, so this is a backward compatible extension. This RFC shall define `%*` to have the same behavior as if `tostring` was called.
|
||||
|
||||
```lua
|
||||
|
@ -121,6 +132,13 @@ print(string.format("%* %* %*", return_two_nils()))
|
|||
--> error: value #3 is missing, got 2
|
||||
```
|
||||
|
||||
It must be said that we are not allowing this style of string literals in type annotations at this time, regardless of zero or many interpolating expressions, so the following two type annotations below are illegal syntax:
|
||||
|
||||
```lua
|
||||
local foo: `foo`
|
||||
local bar: `bar{baz}`
|
||||
```
|
||||
|
||||
## Drawbacks
|
||||
|
||||
If we want to use backticks for other purposes, it may introduce some potential ambiguity. One option to solve that is to only ever produce string interpolation tokens from the context of an expression. This is messy but doable because the parser and the lexer are already implemented to work in tandem. The other option is to pick a different delimiter syntax to keep backticks available for use in the future.
|
||||
|
|
|
@ -2946,7 +2946,7 @@ local abc = b@1
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls_on_class")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
loadDefinition(R"(
|
||||
declare class Foo
|
||||
|
@ -2984,9 +2984,25 @@ t.@1
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "do_compatible_self_calls")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
local t = {}
|
||||
function t:m() end
|
||||
t:@1
|
||||
)");
|
||||
|
||||
auto ac = autocomplete('1');
|
||||
|
||||
REQUIRE(ac.entryMap.count("m"));
|
||||
CHECK(!ac.entryMap["m"].wrongIndexType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
local t = {}
|
||||
|
@ -3002,7 +3018,7 @@ t:@1
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls_2")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
local f: (() -> number) & ((number) -> number) = function(x: number?) return 2 end
|
||||
|
@ -3017,7 +3033,7 @@ t:@1
|
|||
CHECK(ac.entryMap["f"].wrongIndexType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls_provisional")
|
||||
TEST_CASE_FIXTURE(ACFixture, "do_wrong_compatible_self_calls")
|
||||
{
|
||||
check(R"(
|
||||
local t = {}
|
||||
|
@ -3032,9 +3048,26 @@ t:@1
|
|||
CHECK(!ac.entryMap["m"].wrongIndexType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "no_wrong_compatible_self_calls_with_generics")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
local t = {}
|
||||
function t.m<T>(a: T) end
|
||||
t:@1
|
||||
)");
|
||||
|
||||
auto ac = autocomplete('1');
|
||||
|
||||
REQUIRE(ac.entryMap.count("m"));
|
||||
// While this call is compatible with the type, this requires instantiation of a generic type which we don't perform
|
||||
CHECK(ac.entryMap["m"].wrongIndexType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "string_prim_self_calls_are_fine")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
local s = "hello"
|
||||
|
@ -3053,7 +3086,7 @@ s:@1
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "string_prim_non_self_calls_are_avoided")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
local s = "hello"
|
||||
|
@ -3070,7 +3103,7 @@ s.@1
|
|||
|
||||
TEST_CASE_FIXTURE(ACBuiltinsFixture, "library_non_self_calls_are_fine")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
string.@1
|
||||
|
@ -3101,7 +3134,7 @@ table.@1
|
|||
|
||||
TEST_CASE_FIXTURE(ACBuiltinsFixture, "library_self_calls_are_invalid")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
string:@1
|
||||
|
@ -3113,8 +3146,11 @@ string:@1
|
|||
CHECK(ac.entryMap["byte"].wrongIndexType == true);
|
||||
REQUIRE(ac.entryMap.count("char"));
|
||||
CHECK(ac.entryMap["char"].wrongIndexType == true);
|
||||
|
||||
// We want the next test to evaluate to 'true', but we have to allow function defined with 'self' to be callable with ':'
|
||||
// We may change the definition of the string metatable to not use 'self' types in the future (like byte/char/pack/unpack)
|
||||
REQUIRE(ac.entryMap.count("sub"));
|
||||
CHECK(ac.entryMap["sub"].wrongIndexType == true);
|
||||
CHECK(ac.entryMap["sub"].wrongIndexType == false);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "source_module_preservation_and_invalidation")
|
||||
|
|
|
@ -4352,8 +4352,6 @@ TEST_CASE("LoopUnrollControlFlow")
|
|||
{"LuauCompileLoopUnrollThresholdMaxBoost", 300},
|
||||
};
|
||||
|
||||
ScopedFastFlag sff("LuauCompileFoldBuiltins", true);
|
||||
|
||||
// break jumps to the end
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
for i=1,3 do
|
||||
|
@ -4669,8 +4667,6 @@ TEST_CASE("LoopUnrollCostBuiltins")
|
|||
{"LuauCompileLoopUnrollThresholdMaxBoost", 300},
|
||||
};
|
||||
|
||||
ScopedFastFlag sff("LuauCompileModelBuiltins", true);
|
||||
|
||||
// this loop uses builtins and is close to the cost budget so it's important that we model builtins as cheaper than regular calls
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
function cipher(block, nonce)
|
||||
|
@ -5893,8 +5889,6 @@ RETURN R0 2
|
|||
|
||||
TEST_CASE("OptimizationLevel")
|
||||
{
|
||||
ScopedFastFlag sff("LuauAlwaysCaptureHotComments", true);
|
||||
|
||||
// at optimization level 1, no inlining is performed
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
local function foo(a)
|
||||
|
@ -5964,8 +5958,6 @@ RETURN R1 -1
|
|||
|
||||
TEST_CASE("BuiltinFolding")
|
||||
{
|
||||
ScopedFastFlag sff("LuauCompileFoldBuiltins", true);
|
||||
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
return
|
||||
math.abs(-42),
|
||||
|
@ -6073,8 +6065,6 @@ RETURN R0 48
|
|||
|
||||
TEST_CASE("BuiltinFoldingProhibited")
|
||||
{
|
||||
ScopedFastFlag sff("LuauCompileFoldBuiltins", true);
|
||||
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
return
|
||||
math.abs(),
|
||||
|
@ -6108,9 +6098,6 @@ L3: RETURN R0 -1
|
|||
|
||||
TEST_CASE("BuiltinFoldingMultret")
|
||||
{
|
||||
ScopedFastFlag sff1("LuauCompileFoldBuiltins", true);
|
||||
ScopedFastFlag sff2("LuauCompileBetterMultret", true);
|
||||
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
local NoLanes: Lanes = --[[ ]] 0b0000000000000000000000000000000
|
||||
local OffscreenLane: Lane = --[[ ]] 0b1000000000000000000000000000000
|
||||
|
|
|
@ -316,7 +316,8 @@ TEST_CASE("Errors")
|
|||
|
||||
TEST_CASE("Events")
|
||||
{
|
||||
ScopedFastFlag sff("LuauLenTM", true);
|
||||
ScopedFastFlag sff1("LuauLenTM", true);
|
||||
ScopedFastFlag sff2("LuauBetterNewindex", true);
|
||||
|
||||
runConformance("events.lua");
|
||||
}
|
||||
|
@ -490,8 +491,6 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
|
|||
|
||||
TEST_CASE("Types")
|
||||
{
|
||||
ScopedFastFlag sff("LuauCheckLenMT", true);
|
||||
|
||||
runConformance("types.lua", [](lua_State* L) {
|
||||
Luau::NullModuleResolver moduleResolver;
|
||||
Luau::InternalErrorReporter iceHandler;
|
||||
|
@ -862,8 +861,6 @@ TEST_CASE("ApiCalls")
|
|||
|
||||
TEST_CASE("ApiAtoms")
|
||||
{
|
||||
ScopedFastFlag sff("LuauLazyAtoms", true);
|
||||
|
||||
StateRef globalState(luaL_newstate(), lua_close);
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
static TypeId requireBinding(NotNull<Scope2> scope, const char* name)
|
||||
static TypeId requireBinding(NotNull<Scope> scope, const char* name)
|
||||
{
|
||||
auto b = linearSearchForBinding(scope, name);
|
||||
LUAU_ASSERT(b.has_value());
|
||||
|
@ -26,7 +26,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
|
|||
)");
|
||||
|
||||
cgb.visit(block);
|
||||
NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
|
||||
NotNull<Scope> rootScope = NotNull(cgb.rootScope);
|
||||
|
||||
ConstraintSolver cs{&arena, rootScope};
|
||||
|
||||
|
@ -46,7 +46,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
|
|||
)");
|
||||
|
||||
cgb.visit(block);
|
||||
NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
|
||||
NotNull<Scope> rootScope = NotNull(cgb.rootScope);
|
||||
|
||||
ConstraintSolver cs{&arena, rootScope};
|
||||
|
||||
|
@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
|
|||
)");
|
||||
|
||||
cgb.visit(block);
|
||||
NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
|
||||
NotNull<Scope> rootScope = NotNull(cgb.rootScope);
|
||||
|
||||
ToStringOptions opts;
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ std::optional<TypeId> Fixture::getType(const std::string& name)
|
|||
REQUIRE(module);
|
||||
|
||||
if (FFlag::DebugLuauDeferredConstraintResolution)
|
||||
return linearSearchForBinding(module->getModuleScope2(), name.c_str());
|
||||
return linearSearchForBinding(module->getModuleScope().get(), name.c_str());
|
||||
else
|
||||
return lookupName(module->getModuleScope(), name);
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ BuiltinsFixture::BuiltinsFixture(bool freeze, bool prepareAutocomplete)
|
|||
|
||||
ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
|
||||
: Fixture()
|
||||
, cgb(mainModuleName, &arena, NotNull(&ice), frontend.getGlobalScope2())
|
||||
, cgb(mainModuleName, &arena, NotNull(&ice), frontend.getGlobalScope())
|
||||
, forceTheFlag{"DebugLuauDeferredConstraintResolution", true}
|
||||
{
|
||||
BlockedTypeVar::nextIndex = 0;
|
||||
|
@ -479,17 +479,17 @@ std::optional<TypeId> lookupName(ScopePtr scope, const std::string& name)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeId> linearSearchForBinding(Scope2* scope, const char* name)
|
||||
std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name)
|
||||
{
|
||||
while (scope)
|
||||
{
|
||||
for (const auto& [n, ty] : scope->bindings)
|
||||
{
|
||||
if (n.astName() == name)
|
||||
return ty;
|
||||
return ty.typeId;
|
||||
}
|
||||
|
||||
scope = scope->parent;
|
||||
scope = scope->parent.get();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
|
|
@ -192,7 +192,7 @@ void dump(const std::vector<Constraint>& constraints);
|
|||
|
||||
std::optional<TypeId> lookupName(ScopePtr scope, const std::string& name); // Warning: This function runs in O(n**2)
|
||||
|
||||
std::optional<TypeId> linearSearchForBinding(Scope2* scope, const char* name);
|
||||
std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
|
||||
|
||||
} // namespace Luau
|
||||
|
||||
|
|
141
tests/Lexer.test.cpp
Normal file
141
tests/Lexer.test.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/Lexer.h"
|
||||
|
||||
#include "Fixture.h"
|
||||
#include "ScopedFlags.h"
|
||||
|
||||
#include "doctest.h"
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
TEST_SUITE_BEGIN("LexerTests");
|
||||
|
||||
TEST_CASE("broken_string_works")
|
||||
{
|
||||
const std::string testInput = "[[";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme lexeme = lexer.next();
|
||||
CHECK_EQ(lexeme.type, Lexeme::Type::BrokenString);
|
||||
CHECK_EQ(lexeme.location, Luau::Location(Luau::Position(0, 0), Luau::Position(0, 2)));
|
||||
}
|
||||
|
||||
TEST_CASE("broken_comment")
|
||||
{
|
||||
const std::string testInput = "--[[ ";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme lexeme = lexer.next();
|
||||
CHECK_EQ(lexeme.type, Lexeme::Type::BrokenComment);
|
||||
CHECK_EQ(lexeme.location, Luau::Location(Luau::Position(0, 0), Luau::Position(0, 6)));
|
||||
}
|
||||
|
||||
TEST_CASE("broken_comment_kept")
|
||||
{
|
||||
const std::string testInput = "--[[ ";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
lexer.setSkipComments(true);
|
||||
CHECK_EQ(lexer.next().type, Lexeme::Type::BrokenComment);
|
||||
}
|
||||
|
||||
TEST_CASE("comment_skipped")
|
||||
{
|
||||
const std::string testInput = "-- ";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
lexer.setSkipComments(true);
|
||||
CHECK_EQ(lexer.next().type, Lexeme::Type::Eof);
|
||||
}
|
||||
|
||||
TEST_CASE("multilineCommentWithLexemeInAndAfter")
|
||||
{
|
||||
const std::string testInput = "--[[ function \n"
|
||||
"]] end";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme comment = lexer.next();
|
||||
Lexeme end = lexer.next();
|
||||
|
||||
CHECK_EQ(comment.type, Lexeme::Type::BlockComment);
|
||||
CHECK_EQ(comment.location, Luau::Location(Luau::Position(0, 0), Luau::Position(1, 2)));
|
||||
CHECK_EQ(end.type, Lexeme::Type::ReservedEnd);
|
||||
CHECK_EQ(end.location, Luau::Location(Luau::Position(1, 3), Luau::Position(1, 6)));
|
||||
}
|
||||
|
||||
TEST_CASE("testBrokenEscapeTolerant")
|
||||
{
|
||||
const std::string testInput = "'\\3729472897292378'";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme item = lexer.next();
|
||||
|
||||
CHECK_EQ(item.type, Lexeme::QuotedString);
|
||||
CHECK_EQ(item.location, Luau::Location(Luau::Position(0, 0), Luau::Position(0, int(testInput.size()))));
|
||||
}
|
||||
|
||||
TEST_CASE("testBigDelimiters")
|
||||
{
|
||||
const std::string testInput = "--[===[\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"]===]";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme item = lexer.next();
|
||||
|
||||
CHECK_EQ(item.type, Lexeme::Type::BlockComment);
|
||||
CHECK_EQ(item.location, Luau::Location(Luau::Position(0, 0), Luau::Position(4, 5)));
|
||||
}
|
||||
|
||||
TEST_CASE("lookahead")
|
||||
{
|
||||
const std::string testInput = "foo --[[ comment ]] bar : nil end";
|
||||
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
lexer.setSkipComments(true);
|
||||
lexer.next(); // must call next() before reading data from lexer at least once
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::Name);
|
||||
CHECK_EQ(lexer.current().name, std::string("foo"));
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::Name);
|
||||
CHECK_EQ(lexer.lookahead().name, std::string("bar"));
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::Name);
|
||||
CHECK_EQ(lexer.current().name, std::string("bar"));
|
||||
CHECK_EQ(lexer.lookahead().type, ':');
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, ':');
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::ReservedNil);
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::ReservedNil);
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::ReservedEnd);
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::ReservedEnd);
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::Eof);
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::Eof);
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::Eof);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -97,138 +97,6 @@ TEST_CASE("initial_double_is_aligned")
|
|||
|
||||
TEST_SUITE_END();
|
||||
|
||||
TEST_SUITE_BEGIN("LexerTests");
|
||||
|
||||
TEST_CASE("broken_string_works")
|
||||
{
|
||||
const std::string testInput = "[[";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme lexeme = lexer.next();
|
||||
CHECK_EQ(lexeme.type, Lexeme::Type::BrokenString);
|
||||
CHECK_EQ(lexeme.location, Luau::Location(Luau::Position(0, 0), Luau::Position(0, 2)));
|
||||
}
|
||||
|
||||
TEST_CASE("broken_comment")
|
||||
{
|
||||
const std::string testInput = "--[[ ";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme lexeme = lexer.next();
|
||||
CHECK_EQ(lexeme.type, Lexeme::Type::BrokenComment);
|
||||
CHECK_EQ(lexeme.location, Luau::Location(Luau::Position(0, 0), Luau::Position(0, 6)));
|
||||
}
|
||||
|
||||
TEST_CASE("broken_comment_kept")
|
||||
{
|
||||
const std::string testInput = "--[[ ";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
lexer.setSkipComments(true);
|
||||
CHECK_EQ(lexer.next().type, Lexeme::Type::BrokenComment);
|
||||
}
|
||||
|
||||
TEST_CASE("comment_skipped")
|
||||
{
|
||||
const std::string testInput = "-- ";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
lexer.setSkipComments(true);
|
||||
CHECK_EQ(lexer.next().type, Lexeme::Type::Eof);
|
||||
}
|
||||
|
||||
TEST_CASE("multilineCommentWithLexemeInAndAfter")
|
||||
{
|
||||
const std::string testInput = "--[[ function \n"
|
||||
"]] end";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme comment = lexer.next();
|
||||
Lexeme end = lexer.next();
|
||||
|
||||
CHECK_EQ(comment.type, Lexeme::Type::BlockComment);
|
||||
CHECK_EQ(comment.location, Luau::Location(Luau::Position(0, 0), Luau::Position(1, 2)));
|
||||
CHECK_EQ(end.type, Lexeme::Type::ReservedEnd);
|
||||
CHECK_EQ(end.location, Luau::Location(Luau::Position(1, 3), Luau::Position(1, 6)));
|
||||
}
|
||||
|
||||
TEST_CASE("testBrokenEscapeTolerant")
|
||||
{
|
||||
const std::string testInput = "'\\3729472897292378'";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme item = lexer.next();
|
||||
|
||||
CHECK_EQ(item.type, Lexeme::QuotedString);
|
||||
CHECK_EQ(item.location, Luau::Location(Luau::Position(0, 0), Luau::Position(0, int(testInput.size()))));
|
||||
}
|
||||
|
||||
TEST_CASE("testBigDelimiters")
|
||||
{
|
||||
const std::string testInput = "--[===[\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"]===]";
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
Lexeme item = lexer.next();
|
||||
|
||||
CHECK_EQ(item.type, Lexeme::Type::BlockComment);
|
||||
CHECK_EQ(item.location, Luau::Location(Luau::Position(0, 0), Luau::Position(4, 5)));
|
||||
}
|
||||
|
||||
TEST_CASE("lookahead")
|
||||
{
|
||||
const std::string testInput = "foo --[[ comment ]] bar : nil end";
|
||||
|
||||
Luau::Allocator alloc;
|
||||
AstNameTable table(alloc);
|
||||
Lexer lexer(testInput.c_str(), testInput.size(), table);
|
||||
lexer.setSkipComments(true);
|
||||
lexer.next(); // must call next() before reading data from lexer at least once
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::Name);
|
||||
CHECK_EQ(lexer.current().name, std::string("foo"));
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::Name);
|
||||
CHECK_EQ(lexer.lookahead().name, std::string("bar"));
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::Name);
|
||||
CHECK_EQ(lexer.current().name, std::string("bar"));
|
||||
CHECK_EQ(lexer.lookahead().type, ':');
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, ':');
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::ReservedNil);
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::ReservedNil);
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::ReservedEnd);
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::ReservedEnd);
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::Eof);
|
||||
|
||||
lexer.next();
|
||||
|
||||
CHECK_EQ(lexer.current().type, Lexeme::Eof);
|
||||
CHECK_EQ(lexer.lookahead().type, Lexeme::Eof);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
||||
TEST_SUITE_BEGIN("ParserTests");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "basic_parse")
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction);
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
|
||||
|
||||
TEST_SUITE_BEGIN("ToString");
|
||||
|
||||
|
@ -267,8 +268,16 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_type_when_length_is_exceeded")
|
|||
o.maxTypeLength = 40;
|
||||
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
|
||||
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()");
|
||||
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
{
|
||||
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
|
||||
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive")
|
||||
|
@ -286,8 +295,17 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive")
|
|||
o.maxTypeLength = 40;
|
||||
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
|
||||
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()");
|
||||
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
{
|
||||
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
|
||||
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table_state_braces")
|
||||
|
@ -497,7 +515,10 @@ local function target(callback: nil) return callback(4, "hello") end
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
CHECK_EQ("(nil) -> (<error-type>)", toString(requireType("target")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("(nil) -> (*error-type*)", toString(requireType("target")));
|
||||
else
|
||||
CHECK_EQ("(nil) -> (<error-type>)", toString(requireType("target")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferAnyError");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any")
|
||||
|
@ -94,7 +96,10 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error")
|
|||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("a")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2")
|
||||
|
@ -110,7 +115,10 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2")
|
|||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("a")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "length_of_error_type_does_not_produce_an_error")
|
||||
|
@ -225,7 +233,10 @@ TEST_CASE_FIXTURE(Fixture, "calling_error_type_yields_error")
|
|||
|
||||
CHECK_EQ("unknown", err->name);
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("a")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
|
||||
|
@ -234,7 +245,10 @@ TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
|
|||
local a = Utility.Create "Foo" {}
|
||||
)");
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("a")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("a")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_complex_function_with_any")
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
|
||||
|
||||
TEST_SUITE_BEGIN("BuiltinTests");
|
||||
|
||||
|
@ -952,7 +953,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
|
|||
CHECK_EQ("number", toString(requireType("a")));
|
||||
CHECK_EQ("string", toString(requireType("b")));
|
||||
CHECK_EQ("boolean", toString(requireType("c")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("d")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("d")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("d")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments")
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferFunctions");
|
||||
|
||||
|
@ -907,13 +908,19 @@ TEST_CASE_FIXTURE(Fixture, "function_cast_error_uses_correct_language")
|
|||
REQUIRE(tm1);
|
||||
|
||||
CHECK_EQ("(string) -> number", toString(tm1->wantedType));
|
||||
CHECK_EQ("(string, <error-type>) -> number", toString(tm1->givenType));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("(string, *error-type*) -> number", toString(tm1->givenType));
|
||||
else
|
||||
CHECK_EQ("(string, <error-type>) -> number", toString(tm1->givenType));
|
||||
|
||||
auto tm2 = get<TypeMismatch>(result.errors[1]);
|
||||
REQUIRE(tm2);
|
||||
|
||||
CHECK_EQ("(number, number) -> (number, number)", toString(tm2->wantedType));
|
||||
CHECK_EQ("(string, <error-type>) -> number", toString(tm2->givenType));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("(string, *error-type*) -> number", toString(tm2->givenType));
|
||||
else
|
||||
CHECK_EQ("(string, <error-type>) -> number", toString(tm2->givenType));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type")
|
||||
|
@ -1526,10 +1533,21 @@ function t:b() return 2 end -- not OK
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ(R"(Type '(<error-type>) -> number' could not be converted into '() -> number'
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
{
|
||||
CHECK_EQ(R"(Type '(*error-type*) -> number' could not be converted into '() -> number'
|
||||
caused by:
|
||||
Argument count mismatch. Function expects 1 argument, but none are specified)",
|
||||
toString(result.errors[0]));
|
||||
toString(result.errors[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EQ(R"(Type '(<error-type>) -> number' could not be converted into '() -> number'
|
||||
caused by:
|
||||
Argument count mismatch. Function expects 1 argument, but none are specified)",
|
||||
toString(result.errors[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic")
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauCheckGenericHOFTypes)
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1003,7 +1004,10 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying")
|
|||
|
||||
std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType("t0");
|
||||
REQUIRE(t0);
|
||||
CHECK_EQ("<error-type>", toString(t0->type));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(t0->type));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(t0->type));
|
||||
|
||||
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
|
||||
return get<OccursCheckFailed>(err);
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferLoops");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_loop")
|
||||
|
@ -142,7 +144,10 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
|
|||
CHECK_EQ(2, result.errors.size());
|
||||
|
||||
TypeId p = requireType("p");
|
||||
CHECK_EQ("<error-type>", toString(p));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(p));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(p));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferModules");
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "require")
|
||||
|
@ -143,7 +145,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_module_that_does_not_export")
|
|||
|
||||
auto hootyType = requireType(bModule, "Hooty");
|
||||
|
||||
CHECK_EQ("<error-type>", toString(hootyType));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(hootyType));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(hootyType));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "warn_if_you_try_to_require_a_non_modulescript")
|
||||
|
@ -244,7 +249,11 @@ local ModuleA = require(game.A)
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
std::optional<TypeId> oty = requireType("ModuleA");
|
||||
CHECK_EQ("<error-type>", toString(*oty));
|
||||
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(*oty));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(*oty));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types")
|
||||
|
|
|
@ -490,8 +490,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error")
|
||||
{
|
||||
ScopedFastFlag sff("LuauCheckLenMT", true);
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local foo = {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauDeduceFindMatchReturnTypes)
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -49,7 +50,10 @@ TEST_CASE_FIXTURE(Fixture, "string_index")
|
|||
REQUIRE(nat);
|
||||
CHECK_EQ("string", toString(nat->ty));
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireType("t")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("t")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("t")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "string_method")
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -526,7 +527,10 @@ TEST_CASE_FIXTURE(Fixture, "type_narrow_to_vector")
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireTypeAtPosition({3, 28})));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireTypeAtPosition({3, 28})));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireTypeAtPosition({3, 28})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true")
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
|
||||
LUAU_FASTFLAG(LuauFixLocationSpanTableIndexExpr);
|
||||
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -237,10 +238,21 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types")
|
|||
// TODO: Should we assert anything about these tests when DCR is being used?
|
||||
if (!FFlag::DebugLuauDeferredConstraintResolution)
|
||||
{
|
||||
CHECK_EQ("<error-type>", toString(requireType("c")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("d")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("e")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("f")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
{
|
||||
CHECK_EQ("*error-type*", toString(requireType("c")));
|
||||
CHECK_EQ("*error-type*", toString(requireType("d")));
|
||||
CHECK_EQ("*error-type*", toString(requireType("e")));
|
||||
CHECK_EQ("*error-type*", toString(requireType("f")));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EQ("<error-type>", toString(requireType("c")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("d")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("e")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("f")));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,7 +662,11 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_isoptional")
|
|||
|
||||
std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType("t0");
|
||||
REQUIRE(t0);
|
||||
CHECK_EQ("<error-type>", toString(t0->type));
|
||||
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(t0->type));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(t0->type));
|
||||
|
||||
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
|
||||
return get<OccursCheckFailed>(err);
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
struct TryUnifyFixture : Fixture
|
||||
{
|
||||
TypeArena arena;
|
||||
|
@ -121,7 +123,10 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_u
|
|||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK_EQ("a", toString(requireType("a")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("b")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("b")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("b")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_constrained")
|
||||
|
@ -136,7 +141,10 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_con
|
|||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK_EQ("a", toString(requireType("a")));
|
||||
CHECK_EQ("<error-type>", toString(requireType("b")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("b")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("b")));
|
||||
CHECK_EQ("number", toString(requireType("c")));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
|
||||
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -199,7 +200,10 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_missing_property")
|
|||
CHECK_EQ(mup->missing[0], *bTy);
|
||||
CHECK_EQ(mup->key, "x");
|
||||
|
||||
CHECK_EQ("<error-type>", toString(requireType("r")));
|
||||
if (FFlag::LuauSpecialTypesAsterisked)
|
||||
CHECK_EQ("*error-type*", toString(requireType("r")));
|
||||
else
|
||||
CHECK_EQ("<error-type>", toString(requireType("r")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_one_property_of_type_any")
|
||||
|
|
|
@ -25,7 +25,7 @@ struct TypePackFixture
|
|||
|
||||
TypePackId freshTypePack()
|
||||
{
|
||||
typePacks.emplace_back(new TypePackVar{Unifiable::Free{{}}});
|
||||
typePacks.emplace_back(new TypePackVar{Unifiable::Free{TypeLevel{}}});
|
||||
return typePacks.back().get();
|
||||
}
|
||||
|
||||
|
|
|
@ -380,7 +380,8 @@ assert(ecall(function() return "a" + "b" end) == "attempt to perform arithmetic
|
|||
assert(ecall(function() return 1 > nil end) == "attempt to compare nil < number") -- note reversed order (by design)
|
||||
assert(ecall(function() return "a" <= 5 end) == "attempt to compare string <= number")
|
||||
|
||||
assert(ecall(function() local t = {} setmetatable(t, { __newindex = function(t,i,v) end }) t[nil] = 2 end) == "table index is nil")
|
||||
assert(ecall(function() local t = {} t[nil] = 2 end) == "table index is nil")
|
||||
assert(ecall(function() local t = {} t[0/0] = 2 end) == "table index is NaN")
|
||||
|
||||
-- for loop type errors
|
||||
assert(ecall(function() for i='a',2 do end end) == "invalid 'for' initial value (number expected, got string)")
|
||||
|
|
|
@ -424,4 +424,57 @@ do
|
|||
assert(not ok and err:match("table or string expected"))
|
||||
end
|
||||
|
||||
-- verify that NaN/nil keys are passed to __newindex even though table assignment with them anywhere in the chain fails
|
||||
do
|
||||
assert(pcall(function() local t = {} t[nil] = 5 end) == false)
|
||||
assert(pcall(function() local t = {} setmetatable(t, { __newindex = {} }) t[nil] = 5 end) == false)
|
||||
assert(pcall(function() local t = {} setmetatable(t, { __newindex = function() end }) t[nil] = 5 end) == true)
|
||||
|
||||
assert(pcall(function() local t = {} t[0/0] = 5 end) == false)
|
||||
assert(pcall(function() local t = {} setmetatable(t, { __newindex = {} }) t[0/0] = 5 end) == false)
|
||||
assert(pcall(function() local t = {} setmetatable(t, { __newindex = function() end }) t[0/0] = 5 end) == true)
|
||||
end
|
||||
|
||||
-- verify that __newindex gets called for frozen tables but only if the assignment is to a key absent from the table
|
||||
do
|
||||
local ni = {}
|
||||
local t = table.create(2)
|
||||
|
||||
t[1] = 42
|
||||
-- t[2] is semantically absent with storage allocated for it
|
||||
|
||||
t.a = 1
|
||||
t.b = 2
|
||||
t.b = nil -- this sets 'b' value to nil but leaves key as is to exercise more internal paths -- no observable behavior change expected between b and other absent keys
|
||||
|
||||
setmetatable(t, { __newindex = function(_, k, v)
|
||||
assert(v == 42)
|
||||
table.insert(ni, k)
|
||||
end })
|
||||
table.freeze(t)
|
||||
|
||||
-- "redundant" combinations are there to test all three of SETTABLEN/SETTABLEKS/SETTABLE
|
||||
assert(pcall(function() t.a = 42 end) == false)
|
||||
assert(pcall(function() t[1] = 42 end) == false)
|
||||
assert(pcall(function() local key key = "a" t[key] = 42 end) == false)
|
||||
assert(pcall(function() local key key = 1 t[key] = 42 end) == false)
|
||||
|
||||
-- now repeat the same for keys absent from the table: b (semantically absent), c (physically absent), 2 (semantically absent), 3 (physically absent)
|
||||
assert(pcall(function() t.b = 42 end) == true)
|
||||
assert(pcall(function() t.c = 42 end) == true)
|
||||
assert(pcall(function() local key key = "b" t[key] = 42 end) == true)
|
||||
assert(pcall(function() local key key = "c" t[key] = 42 end) == true)
|
||||
assert(pcall(function() t[2] = 42 end) == true)
|
||||
assert(pcall(function() t[3] = 42 end) == true)
|
||||
assert(pcall(function() local key key = 2 t[key] = 42 end) == true)
|
||||
assert(pcall(function() local key key = 3 t[key] = 42 end) == true)
|
||||
|
||||
-- validate the assignment sequence
|
||||
local ei = { "b", "c", "b", "c", 2, 3, 2, 3 }
|
||||
assert(#ni == #ei)
|
||||
for k,v in ni do
|
||||
assert(ei[k] == v)
|
||||
end
|
||||
end
|
||||
|
||||
return 'OK'
|
||||
|
|
|
@ -61,7 +61,7 @@ static bool debuggerPresent()
|
|||
static int testAssertionHandler(const char* expr, const char* file, int line, const char* function)
|
||||
{
|
||||
if (debuggerPresent())
|
||||
LUAU_DEBUGBREAK();
|
||||
LUAU_DEBUGBREAK();
|
||||
|
||||
ADD_FAIL_AT(file, line, "Assertion failed: ", std::string(expr));
|
||||
return 1;
|
||||
|
@ -298,5 +298,3 @@ int main(int argc, char** argv)
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ AutocompleteTest.as_types
|
|||
AutocompleteTest.autocomplete_boolean_singleton
|
||||
AutocompleteTest.autocomplete_default_type_pack_parameters
|
||||
AutocompleteTest.autocomplete_default_type_parameters
|
||||
AutocompleteTest.autocomplete_documentation_symbols
|
||||
AutocompleteTest.autocomplete_end_with_fn_exprs
|
||||
AutocompleteTest.autocomplete_end_with_lambda
|
||||
AutocompleteTest.autocomplete_explicit_type_pack
|
||||
|
@ -65,47 +64,34 @@ AutocompleteTest.autocomplete_until_in_repeat
|
|||
AutocompleteTest.autocomplete_while_middle_keywords
|
||||
AutocompleteTest.autocompleteProp_index_function_metamethod_is_variadic
|
||||
AutocompleteTest.bias_toward_inner_scope
|
||||
AutocompleteTest.comments
|
||||
AutocompleteTest.cyclic_table
|
||||
AutocompleteTest.do_compatible_self_calls
|
||||
AutocompleteTest.do_not_overwrite_context_sensitive_kws
|
||||
AutocompleteTest.do_not_suggest_internal_module_type
|
||||
AutocompleteTest.do_not_suggest_synthetic_table_name
|
||||
AutocompleteTest.dont_offer_any_suggestions_from_the_end_of_a_comment
|
||||
AutocompleteTest.do_wrong_compatible_self_calls
|
||||
AutocompleteTest.dont_offer_any_suggestions_from_within_a_broken_comment
|
||||
AutocompleteTest.dont_offer_any_suggestions_from_within_a_broken_comment_at_the_very_end_of_the_file
|
||||
AutocompleteTest.dont_offer_any_suggestions_from_within_a_comment
|
||||
AutocompleteTest.dont_suggest_local_before_its_definition
|
||||
AutocompleteTest.empty_program
|
||||
AutocompleteTest.function_expr_params
|
||||
AutocompleteTest.function_in_assignment_has_parentheses
|
||||
AutocompleteTest.function_in_assignment_has_parentheses_2
|
||||
AutocompleteTest.function_parameters
|
||||
AutocompleteTest.function_result_passed_to_function_has_parentheses
|
||||
AutocompleteTest.function_type_types
|
||||
AutocompleteTest.generic_types
|
||||
AutocompleteTest.get_member_completions
|
||||
AutocompleteTest.get_string_completions
|
||||
AutocompleteTest.get_suggestions_for_new_statement
|
||||
AutocompleteTest.get_suggestions_for_the_very_start_of_the_script
|
||||
AutocompleteTest.global_function_params
|
||||
AutocompleteTest.global_functions_are_not_scoped_lexically
|
||||
AutocompleteTest.if_then_else_elseif_completions
|
||||
AutocompleteTest.if_then_else_full_keywords
|
||||
AutocompleteTest.keyword_members
|
||||
AutocompleteTest.keyword_methods
|
||||
AutocompleteTest.keyword_types
|
||||
AutocompleteTest.leave_numbers_alone
|
||||
AutocompleteTest.library_non_self_calls_are_fine
|
||||
AutocompleteTest.library_self_calls_are_invalid
|
||||
AutocompleteTest.local_function
|
||||
AutocompleteTest.local_function_params
|
||||
AutocompleteTest.local_functions_fall_out_of_scope
|
||||
AutocompleteTest.local_initializer
|
||||
AutocompleteTest.local_initializer_2
|
||||
AutocompleteTest.local_names
|
||||
AutocompleteTest.local_types_builtin
|
||||
AutocompleteTest.method_call_inside_function_body
|
||||
AutocompleteTest.method_call_inside_if_conditional
|
||||
AutocompleteTest.module_type_members
|
||||
AutocompleteTest.modules_with_types
|
||||
AutocompleteTest.nested_member_completions
|
||||
|
@ -114,16 +100,13 @@ AutocompleteTest.no_function_name_suggestions
|
|||
AutocompleteTest.no_incompatible_self_calls
|
||||
AutocompleteTest.no_incompatible_self_calls_2
|
||||
AutocompleteTest.no_incompatible_self_calls_on_class
|
||||
AutocompleteTest.no_incompatible_self_calls_provisional
|
||||
AutocompleteTest.not_the_var_we_are_defining
|
||||
AutocompleteTest.no_wrong_compatible_self_calls_with_generics
|
||||
AutocompleteTest.optional_members
|
||||
AutocompleteTest.private_types
|
||||
AutocompleteTest.recommend_statement_starting_keywords
|
||||
AutocompleteTest.recursive_function
|
||||
AutocompleteTest.recursive_function_global
|
||||
AutocompleteTest.recursive_function_local
|
||||
AutocompleteTest.return_types
|
||||
AutocompleteTest.skip_current_local
|
||||
AutocompleteTest.sometimes_the_metatable_is_an_error
|
||||
AutocompleteTest.source_module_preservation_and_invalidation
|
||||
AutocompleteTest.statement_between_two_statements
|
||||
|
@ -154,9 +137,7 @@ AutocompleteTest.type_correct_suggestion_in_table
|
|||
AutocompleteTest.type_scoping_easy
|
||||
AutocompleteTest.unsealed_table
|
||||
AutocompleteTest.unsealed_table_2
|
||||
AutocompleteTest.user_defined_globals
|
||||
AutocompleteTest.user_defined_local_functions_in_own_definition
|
||||
BuiltinDefinitionsTest.lib_documentation_symbols
|
||||
BuiltinTests.aliased_string_format
|
||||
BuiltinTests.assert_removes_falsy_types
|
||||
BuiltinTests.assert_removes_falsy_types2
|
||||
|
@ -231,16 +212,10 @@ BuiltinTests.tonumber_returns_optional_number_type
|
|||
BuiltinTests.tonumber_returns_optional_number_type2
|
||||
BuiltinTests.xpcall
|
||||
DefinitionTests.class_definition_function_prop
|
||||
DefinitionTests.class_definitions_cannot_extend_non_class
|
||||
DefinitionTests.class_definitions_cannot_overload_non_function
|
||||
DefinitionTests.declaring_generic_functions
|
||||
DefinitionTests.definition_file_class_function_args
|
||||
DefinitionTests.definition_file_classes
|
||||
DefinitionTests.definition_file_loading
|
||||
DefinitionTests.definitions_documentation_symbols
|
||||
DefinitionTests.documentation_symbols_dont_attach_to_persistent_types
|
||||
DefinitionTests.load_definition_file_errors_do_not_pollute_global_scope
|
||||
DefinitionTests.no_cyclic_defined_classes
|
||||
DefinitionTests.single_class_type_identity_in_global_types
|
||||
FrontendTest.accumulate_cached_errors
|
||||
FrontendTest.accumulate_cached_errors_in_consistent_order
|
||||
|
@ -256,12 +231,9 @@ FrontendTest.cycle_error_paths
|
|||
FrontendTest.cycle_errors_can_be_fixed
|
||||
FrontendTest.cycle_incremental_type_surface
|
||||
FrontendTest.cycle_incremental_type_surface_longer
|
||||
FrontendTest.discard_type_graphs
|
||||
FrontendTest.dont_recheck_script_that_hasnt_been_marked_dirty
|
||||
FrontendTest.dont_reparse_clean_file_when_linting
|
||||
FrontendTest.environments
|
||||
FrontendTest.find_a_require
|
||||
FrontendTest.find_a_require_inside_a_function
|
||||
FrontendTest.ignore_require_to_nonexistent_file
|
||||
FrontendTest.imported_table_modification_2
|
||||
FrontendTest.it_should_be_safe_to_stringify_errors_when_full_type_graph_is_discarded
|
||||
|
@ -269,29 +241,97 @@ FrontendTest.no_use_after_free_with_type_fun_instantiation
|
|||
FrontendTest.nocheck_cycle_used_by_checked
|
||||
FrontendTest.nocheck_modules_are_typed
|
||||
FrontendTest.produce_errors_for_unchanged_file_with_a_syntax_error
|
||||
FrontendTest.produce_errors_for_unchanged_file_with_errors
|
||||
FrontendTest.re_report_type_error_in_required_file
|
||||
FrontendTest.real_source
|
||||
FrontendTest.recheck_if_dependent_script_is_dirty
|
||||
FrontendTest.reexport_cyclic_type
|
||||
FrontendTest.reexport_type_alias
|
||||
FrontendTest.report_require_to_nonexistent_file
|
||||
FrontendTest.report_syntax_error_in_required_file
|
||||
FrontendTest.reports_errors_from_multiple_sources
|
||||
FrontendTest.stats_are_not_reset_between_checks
|
||||
FrontendTest.test_lint_uses_correct_config
|
||||
FrontendTest.test_pruneParentSegments
|
||||
FrontendTest.trace_requires_in_nonstrict_mode
|
||||
FrontendTest.typecheck_twice_for_ast_types
|
||||
GenericsTests.apply_type_function_nested_generics1
|
||||
GenericsTests.apply_type_function_nested_generics2
|
||||
GenericsTests.better_mismatch_error_messages
|
||||
GenericsTests.bound_tables_do_not_clone_original_fields
|
||||
GenericsTests.check_generic_typepack_function
|
||||
GenericsTests.check_mutual_generic_functions
|
||||
GenericsTests.correctly_instantiate_polymorphic_member_functions
|
||||
GenericsTests.do_not_always_instantiate_generic_intersection_types
|
||||
GenericsTests.do_not_infer_generic_functions
|
||||
GenericsTests.dont_substitute_bound_types
|
||||
GenericsTests.dont_unify_bound_types
|
||||
GenericsTests.duplicate_generic_type_packs
|
||||
GenericsTests.duplicate_generic_types
|
||||
GenericsTests.error_detailed_function_mismatch_generic_pack
|
||||
GenericsTests.error_detailed_function_mismatch_generic_types
|
||||
GenericsTests.factories_of_generics
|
||||
GenericsTests.function_arguments_can_be_polytypes
|
||||
GenericsTests.function_results_can_be_polytypes
|
||||
GenericsTests.generic_argument_count_too_few
|
||||
GenericsTests.generic_argument_count_too_many
|
||||
GenericsTests.generic_factories
|
||||
GenericsTests.generic_functions_dont_cache_type_parameters
|
||||
GenericsTests.generic_functions_in_types
|
||||
GenericsTests.generic_functions_should_be_memory_safe
|
||||
GenericsTests.generic_table_method
|
||||
GenericsTests.generic_type_pack_syntax
|
||||
GenericsTests.generic_type_pack_unification1
|
||||
GenericsTests.generic_type_pack_unification2
|
||||
GenericsTests.generic_type_pack_unification3
|
||||
GenericsTests.infer_generic_function_function_argument
|
||||
GenericsTests.infer_generic_function_function_argument_overloaded
|
||||
GenericsTests.infer_generic_lib_function_function_argument
|
||||
GenericsTests.infer_generic_property
|
||||
GenericsTests.inferred_local_vars_can_be_polytypes
|
||||
GenericsTests.instantiate_cyclic_generic_function
|
||||
GenericsTests.instantiate_generic_function_in_assignments
|
||||
GenericsTests.instantiate_generic_function_in_assignments2
|
||||
GenericsTests.instantiated_function_argument_names
|
||||
GenericsTests.instantiation_sharing_types
|
||||
GenericsTests.local_vars_can_be_instantiated_polytypes
|
||||
GenericsTests.mutable_state_polymorphism
|
||||
GenericsTests.no_stack_overflow_from_quantifying
|
||||
GenericsTests.properties_can_be_instantiated_polytypes
|
||||
GenericsTests.properties_can_be_polytypes
|
||||
GenericsTests.rank_N_types_via_typeof
|
||||
GenericsTests.reject_clashing_generic_and_pack_names
|
||||
GenericsTests.self_recursive_instantiated_param
|
||||
GenericsTests.substitution_with_bound_table
|
||||
GenericsTests.typefuns_sharing_types
|
||||
GenericsTests.variadic_generics
|
||||
IntersectionTypes.argument_is_intersection
|
||||
IntersectionTypes.error_detailed_intersection_all
|
||||
IntersectionTypes.error_detailed_intersection_part
|
||||
IntersectionTypes.fx_intersection_as_argument
|
||||
IntersectionTypes.fx_union_as_argument_fails
|
||||
IntersectionTypes.index_on_an_intersection_type_with_all_parts_missing_the_property
|
||||
IntersectionTypes.index_on_an_intersection_type_with_mixed_types
|
||||
IntersectionTypes.index_on_an_intersection_type_with_one_part_missing_the_property
|
||||
IntersectionTypes.index_on_an_intersection_type_with_one_property_of_type_any
|
||||
IntersectionTypes.index_on_an_intersection_type_with_property_guaranteed_to_exist
|
||||
IntersectionTypes.index_on_an_intersection_type_works_at_arbitrary_depth
|
||||
IntersectionTypes.no_stack_overflow_from_flattenintersection
|
||||
IntersectionTypes.overload_is_not_a_function
|
||||
IntersectionTypes.propagates_name
|
||||
IntersectionTypes.select_correct_union_fn
|
||||
IntersectionTypes.should_still_pick_an_overload_whose_arguments_are_unions
|
||||
IntersectionTypes.table_combines
|
||||
IntersectionTypes.table_combines_missing
|
||||
IntersectionTypes.table_extra_ok
|
||||
IntersectionTypes.table_intersection_setmetatable
|
||||
IntersectionTypes.table_intersection_write
|
||||
IntersectionTypes.table_intersection_write_sealed
|
||||
IntersectionTypes.table_intersection_write_sealed_indirect
|
||||
IntersectionTypes.table_write_sealed_indirect
|
||||
isSubtype.functions_and_any
|
||||
isSubtype.intersection_of_functions_of_different_arities
|
||||
isSubtype.intersection_of_tables
|
||||
isSubtype.table_with_any_prop
|
||||
isSubtype.table_with_table_prop
|
||||
isSubtype.tables
|
||||
Linter.BuiltinGlobalWrite
|
||||
Linter.DeprecatedApi
|
||||
Linter.LocalShadowGlobal
|
||||
Linter.TableOperations
|
||||
Linter.use_all_parent_scopes_for_globals
|
||||
ModuleTests.any_persistance_does_not_leak
|
||||
ModuleTests.builtin_types_point_into_globalTypes_arena
|
||||
ModuleTests.clone_self_property
|
||||
|
@ -342,45 +382,237 @@ Normalize.skip_force_normal_on_external_types
|
|||
Normalize.union_of_distinct_free_types
|
||||
Normalize.variadic_tail_is_marked_normal
|
||||
Normalize.visiting_a_type_twice_is_not_considered_normal
|
||||
ParseErrorRecovery.empty_function_type_error_recovery
|
||||
ParseErrorRecovery.extra_table_indexer_recovery
|
||||
ParseErrorRecovery.extra_token_in_consume
|
||||
ParseErrorRecovery.extra_token_in_consume_match
|
||||
ParseErrorRecovery.extra_token_in_consume_match_end
|
||||
ParseErrorRecovery.generic_type_list_recovery
|
||||
ParseErrorRecovery.multiple_parse_errors
|
||||
ParseErrorRecovery.recovery_of_parenthesized_expressions
|
||||
ParseErrorRecovery.statement_error_recovery_expected
|
||||
ParseErrorRecovery.statement_error_recovery_unexpected
|
||||
ParserTests.break_return_not_last_error
|
||||
ParserTests.continue_not_last_error
|
||||
ParserTests.error_on_confusable
|
||||
ParserTests.error_on_non_utf8_sequence
|
||||
ParserTests.error_on_unicode
|
||||
ParserTests.export_is_an_identifier_only_when_followed_by_type
|
||||
ParserTests.functions_cannot_have_return_annotations_if_extensions_are_disabled
|
||||
ParserTests.illegal_type_alias_if_extensions_are_disabled
|
||||
ParserTests.incomplete_statement_error
|
||||
ParserTests.local_cannot_have_annotation_with_extensions_disabled
|
||||
ParserTests.parse_compound_assignment_error_call
|
||||
ParserTests.parse_compound_assignment_error_multiple
|
||||
ParserTests.parse_compound_assignment_error_not_lvalue
|
||||
ParserTests.parse_error_function_call
|
||||
ParserTests.parse_error_function_call_newline
|
||||
ParserTests.parse_error_messages
|
||||
ParserTests.parse_error_table_literal
|
||||
ParserTests.parse_error_type_name
|
||||
ParserTests.parse_nesting_based_end_detection
|
||||
ParserTests.parse_nesting_based_end_detection_failsafe_earlier
|
||||
ParserTests.parse_nesting_based_end_detection_local_function
|
||||
ParserTests.parse_nesting_based_end_detection_local_repeat
|
||||
ParserTests.parse_nesting_based_end_detection_nested
|
||||
ParserTests.parse_nesting_based_end_detection_single_line
|
||||
ParserTests.parse_numbers_error
|
||||
ParserTests.parse_numbers_range_error
|
||||
ParserTests.stop_if_line_ends_with_hyphen
|
||||
ParserTests.type_alias_error_messages
|
||||
ProvisionalTests.bail_early_if_unification_is_too_complicated
|
||||
ProvisionalTests.choose_the_right_overload_for_pcall
|
||||
ProvisionalTests.constrained_is_level_dependent
|
||||
ProvisionalTests.discriminate_from_x_not_equal_to_nil
|
||||
ProvisionalTests.do_not_ice_when_trying_to_pick_first_of_generic_type_pack
|
||||
ProvisionalTests.error_on_eq_metamethod_returning_a_type_other_than_boolean
|
||||
ProvisionalTests.free_is_not_bound_to_any
|
||||
ProvisionalTests.function_returns_many_things_but_first_of_it_is_forgotten
|
||||
ProvisionalTests.greedy_inference_with_shared_self_triggers_function_with_no_returns
|
||||
ProvisionalTests.invariant_table_properties_means_instantiating_tables_in_call_is_unsound
|
||||
ProvisionalTests.it_should_be_agnostic_of_actual_size
|
||||
ProvisionalTests.lower_bounds_calculation_is_too_permissive_with_overloaded_higher_order_functions
|
||||
ProvisionalTests.lvalue_equals_another_lvalue_with_no_overlap
|
||||
ProvisionalTests.normalization_fails_on_certain_kinds_of_cyclic_tables
|
||||
ProvisionalTests.operator_eq_completely_incompatible
|
||||
ProvisionalTests.pcall_returns_at_least_two_value_but_function_returns_nothing
|
||||
ProvisionalTests.setmetatable_constrains_free_type_into_free_table
|
||||
ProvisionalTests.typeguard_inference_incomplete
|
||||
ProvisionalTests.weird_fail_to_unify_type_pack
|
||||
ProvisionalTests.weirditer_should_not_loop_forever
|
||||
ProvisionalTests.while_body_are_also_refined
|
||||
ProvisionalTests.xpcall_returns_what_f_returns
|
||||
RefinementTest.and_constraint
|
||||
RefinementTest.and_or_peephole_refinement
|
||||
RefinementTest.apply_refinements_on_astexprindexexpr_whose_subscript_expr_is_constant_string
|
||||
RefinementTest.assert_a_to_be_truthy_then_assert_a_to_be_number
|
||||
RefinementTest.assert_non_binary_expressions_actually_resolve_constraints
|
||||
RefinementTest.assign_table_with_refined_property_with_a_similar_type_is_illegal
|
||||
RefinementTest.call_a_more_specific_function_using_typeguard
|
||||
RefinementTest.correctly_lookup_a_shadowed_local_that_which_was_previously_refined
|
||||
RefinementTest.correctly_lookup_property_whose_base_was_previously_refined
|
||||
RefinementTest.correctly_lookup_property_whose_base_was_previously_refined2
|
||||
RefinementTest.discriminate_from_isa_of_x
|
||||
RefinementTest.discriminate_from_truthiness_of_x
|
||||
RefinementTest.discriminate_on_properties_of_disjoint_tables_where_that_property_is_true_or_false
|
||||
RefinementTest.discriminate_tag
|
||||
RefinementTest.either_number_or_string
|
||||
RefinementTest.eliminate_subclasses_of_instance
|
||||
RefinementTest.falsiness_of_TruthyPredicate_narrows_into_nil
|
||||
RefinementTest.free_type_is_equal_to_an_lvalue
|
||||
RefinementTest.impossible_type_narrow_is_not_an_error
|
||||
RefinementTest.index_on_a_refined_property
|
||||
RefinementTest.invert_is_truthy_constraint
|
||||
RefinementTest.invert_is_truthy_constraint_ifelse_expression
|
||||
RefinementTest.is_truthy_constraint
|
||||
RefinementTest.is_truthy_constraint_ifelse_expression
|
||||
RefinementTest.lvalue_is_equal_to_a_term
|
||||
RefinementTest.lvalue_is_equal_to_another_lvalue
|
||||
RefinementTest.lvalue_is_not_nil
|
||||
RefinementTest.merge_should_be_fully_agnostic_of_hashmap_ordering
|
||||
RefinementTest.narrow_property_of_a_bounded_variable
|
||||
RefinementTest.narrow_this_large_union
|
||||
RefinementTest.nonoptional_type_can_narrow_to_nil_if_sense_is_true
|
||||
RefinementTest.not_a_and_not_b
|
||||
RefinementTest.not_a_and_not_b2
|
||||
RefinementTest.not_a_or_not_b
|
||||
RefinementTest.not_a_or_not_b2
|
||||
RefinementTest.not_and_constraint
|
||||
RefinementTest.not_t_or_some_prop_of_t
|
||||
RefinementTest.or_predicate_with_truthy_predicates
|
||||
RefinementTest.parenthesized_expressions_are_followed_through
|
||||
RefinementTest.refine_a_property_not_to_be_nil_through_an_intersection_table
|
||||
RefinementTest.refine_the_correct_types_opposite_of_when_a_is_not_number_or_string
|
||||
RefinementTest.refine_unknowns
|
||||
RefinementTest.string_not_equal_to_string_or_nil
|
||||
RefinementTest.term_is_equal_to_an_lvalue
|
||||
RefinementTest.truthy_constraint_on_properties
|
||||
RefinementTest.type_assertion_expr_carry_its_constraints
|
||||
RefinementTest.type_comparison_ifelse_expression
|
||||
RefinementTest.type_guard_can_filter_for_intersection_of_tables
|
||||
RefinementTest.type_guard_can_filter_for_overloaded_function
|
||||
RefinementTest.type_guard_narrowed_into_nothingness
|
||||
RefinementTest.type_narrow_for_all_the_userdata
|
||||
RefinementTest.type_narrow_to_vector
|
||||
RefinementTest.typeguard_cast_free_table_to_vector
|
||||
RefinementTest.typeguard_cast_instance_or_vector3_to_vector
|
||||
RefinementTest.typeguard_doesnt_leak_to_elseif
|
||||
RefinementTest.typeguard_in_assert_position
|
||||
RefinementTest.typeguard_in_if_condition_position
|
||||
RefinementTest.typeguard_narrows_for_functions
|
||||
RefinementTest.typeguard_narrows_for_table
|
||||
RefinementTest.typeguard_not_to_be_string
|
||||
RefinementTest.typeguard_only_look_up_types_from_global_scope
|
||||
RefinementTest.unknown_lvalue_is_not_synonymous_with_other_on_not_equal
|
||||
RefinementTest.what_nonsensical_condition
|
||||
RefinementTest.x_as_any_if_x_is_instance_elseif_x_is_table
|
||||
RefinementTest.x_is_not_instance_or_else_not_part
|
||||
RuntimeLimits.typescript_port_of_Result_type
|
||||
TableTests.a_free_shape_can_turn_into_a_scalar_if_it_is_compatible
|
||||
TableTests.a_free_shape_cannot_turn_into_a_scalar_if_it_is_not_compatible
|
||||
TableTests.access_index_metamethod_that_returns_variadic
|
||||
TableTests.accidentally_checked_prop_in_opposite_branch
|
||||
TableTests.assigning_to_an_unsealed_table_with_string_literal_should_infer_new_properties_over_indexer
|
||||
TableTests.augment_nested_table
|
||||
TableTests.augment_table
|
||||
TableTests.builtin_table_names
|
||||
TableTests.call_method
|
||||
TableTests.call_method_with_explicit_self_argument
|
||||
TableTests.cannot_augment_sealed_table
|
||||
TableTests.cannot_call_tables
|
||||
TableTests.cannot_change_type_of_unsealed_table_prop
|
||||
TableTests.casting_sealed_tables_with_props_into_table_with_indexer
|
||||
TableTests.casting_tables_with_props_into_table_with_indexer3
|
||||
TableTests.casting_tables_with_props_into_table_with_indexer4
|
||||
TableTests.casting_unsealed_tables_with_props_into_table_with_indexer
|
||||
TableTests.checked_prop_too_early
|
||||
TableTests.common_table_element_general
|
||||
TableTests.common_table_element_inner_index
|
||||
TableTests.common_table_element_inner_prop
|
||||
TableTests.common_table_element_list
|
||||
TableTests.common_table_element_union_assignment
|
||||
TableTests.common_table_element_union_in_call
|
||||
TableTests.common_table_element_union_in_call_tail
|
||||
TableTests.common_table_element_union_in_prop
|
||||
TableTests.confusing_indexing
|
||||
TableTests.defining_a_method_for_a_builtin_sealed_table_must_fail
|
||||
TableTests.defining_a_method_for_a_local_sealed_table_must_fail
|
||||
TableTests.defining_a_method_for_a_local_unsealed_table_is_ok
|
||||
TableTests.defining_a_self_method_for_a_builtin_sealed_table_must_fail
|
||||
TableTests.defining_a_self_method_for_a_local_sealed_table_must_fail
|
||||
TableTests.defining_a_self_method_for_a_local_unsealed_table_is_ok
|
||||
TableTests.dont_crash_when_setmetatable_does_not_produce_a_metatabletypevar
|
||||
TableTests.dont_hang_when_trying_to_look_up_in_cyclic_metatable_index
|
||||
TableTests.dont_invalidate_the_properties_iterator_of_free_table_when_rolled_back
|
||||
TableTests.dont_leak_free_table_props
|
||||
TableTests.dont_quantify_table_that_belongs_to_outer_scope
|
||||
TableTests.dont_seal_an_unsealed_table_by_passing_it_to_a_function_that_takes_a_sealed_table
|
||||
TableTests.dont_suggest_exact_match_keys
|
||||
TableTests.error_detailed_indexer_key
|
||||
TableTests.error_detailed_indexer_value
|
||||
TableTests.error_detailed_metatable_prop
|
||||
TableTests.error_detailed_prop
|
||||
TableTests.error_detailed_prop_nested
|
||||
TableTests.expected_indexer_from_table_union
|
||||
TableTests.expected_indexer_value_type_extra
|
||||
TableTests.expected_indexer_value_type_extra_2
|
||||
TableTests.explicitly_typed_table
|
||||
TableTests.explicitly_typed_table_error
|
||||
TableTests.explicitly_typed_table_with_indexer
|
||||
TableTests.found_like_key_in_table_function_call
|
||||
TableTests.found_like_key_in_table_property_access
|
||||
TableTests.found_multiple_like_keys
|
||||
TableTests.function_calls_produces_sealed_table_given_unsealed_table
|
||||
TableTests.generalize_table_argument
|
||||
TableTests.getmetatable_returns_pointer_to_metatable
|
||||
TableTests.give_up_after_one_metatable_index_look_up
|
||||
TableTests.hide_table_error_properties
|
||||
TableTests.indexer_fn
|
||||
TableTests.indexer_on_sealed_table_must_unify_with_free_table
|
||||
TableTests.indexer_table
|
||||
TableTests.indexing_from_a_table_should_prefer_properties_when_possible
|
||||
TableTests.inequality_operators_imply_exactly_matching_types
|
||||
TableTests.infer_array_2
|
||||
TableTests.infer_indexer_from_value_property_in_literal
|
||||
TableTests.inferred_return_type_of_free_table
|
||||
TableTests.inferring_crazy_table_should_also_be_quick
|
||||
TableTests.instantiate_table_cloning
|
||||
TableTests.instantiate_table_cloning_2
|
||||
TableTests.instantiate_table_cloning_3
|
||||
TableTests.instantiate_tables_at_scope_level
|
||||
TableTests.invariant_table_properties_means_instantiating_tables_in_assignment_is_unsound
|
||||
TableTests.leaking_bad_metatable_errors
|
||||
TableTests.length_operator_intersection
|
||||
TableTests.length_operator_non_table_union
|
||||
TableTests.length_operator_union
|
||||
TableTests.length_operator_union_errors
|
||||
TableTests.less_exponential_blowup_please
|
||||
TableTests.meta_add
|
||||
TableTests.meta_add_both_ways
|
||||
TableTests.meta_add_inferred
|
||||
TableTests.metatable_mismatch_should_fail
|
||||
TableTests.missing_metatable_for_sealed_tables_do_not_get_inferred
|
||||
TableTests.mixed_tables_with_implicit_numbered_keys
|
||||
TableTests.MixedPropertiesAndIndexers
|
||||
TableTests.nil_assign_doesnt_hit_indexer
|
||||
TableTests.okay_to_add_property_to_unsealed_tables_by_function_call
|
||||
TableTests.only_ascribe_synthetic_names_at_module_scope
|
||||
TableTests.oop_indexer_works
|
||||
TableTests.oop_polymorphic
|
||||
TableTests.open_table_unification_2
|
||||
TableTests.pass_a_union_of_tables_to_a_function_that_requires_a_table
|
||||
TableTests.pass_a_union_of_tables_to_a_function_that_requires_a_table_2
|
||||
TableTests.pass_incompatible_union_to_a_generic_table_without_crashing
|
||||
TableTests.passing_compatible_unions_to_a_generic_table_without_crashing
|
||||
TableTests.persistent_sealed_table_is_immutable
|
||||
TableTests.property_lookup_through_tabletypevar_metatable
|
||||
TableTests.quantify_even_that_table_was_never_exported_at_all
|
||||
TableTests.quantify_metatables_of_metatables_of_table
|
||||
TableTests.quantifying_a_bound_var_works
|
||||
TableTests.reasonable_error_when_adding_a_nonexistent_property_to_an_array_like_table
|
||||
TableTests.recursive_metatable_type_call
|
||||
TableTests.result_is_always_any_if_lhs_is_any
|
||||
TableTests.result_is_bool_for_equality_operators_if_lhs_is_any
|
||||
TableTests.right_table_missing_key
|
||||
TableTests.right_table_missing_key2
|
||||
TableTests.scalar_is_a_subtype_of_a_compatible_polymorphic_shape_type
|
||||
TableTests.scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type
|
||||
TableTests.setmetatable_cant_be_used_to_mutate_global_types
|
||||
TableTests.shared_selfs
|
||||
TableTests.shared_selfs_from_free_param
|
||||
TableTests.shared_selfs_through_metatables
|
||||
TableTests.table_function_check_use_after_free
|
||||
TableTests.table_indexing_error_location
|
||||
TableTests.table_insert_should_cope_with_optional_properties_in_nonstrict
|
||||
TableTests.table_insert_should_cope_with_optional_properties_in_strict
|
||||
TableTests.table_length
|
||||
TableTests.table_param_row_polymorphism_2
|
||||
TableTests.table_param_row_polymorphism_3
|
||||
TableTests.table_simple_call
|
||||
TableTests.table_subtyping_with_extra_props_dont_report_multiple_errors
|
||||
TableTests.table_subtyping_with_missing_props_dont_report_multiple_errors
|
||||
TableTests.table_subtyping_with_missing_props_dont_report_multiple_errors2
|
||||
TableTests.table_unifies_into_map
|
||||
TableTests.tables_get_names_from_their_locals
|
||||
TableTests.tc_member_function
|
||||
TableTests.tc_member_function_2
|
||||
TableTests.top_table_type
|
||||
TableTests.type_mismatch_on_massive_table_is_cut_short
|
||||
TableTests.unification_of_unions_in_a_self_referential_type
|
||||
TableTests.unifying_tables_shouldnt_uaf1
|
||||
TableTests.unifying_tables_shouldnt_uaf2
|
||||
TableTests.used_colon_correctly
|
||||
TableTests.used_colon_instead_of_dot
|
||||
TableTests.used_dot_instead_of_colon
|
||||
TableTests.used_dot_instead_of_colon_but_correctly
|
||||
TableTests.user_defined_table_types_are_named
|
||||
TableTests.width_subtyping
|
||||
ToDot.bound_table
|
||||
ToDot.class
|
||||
ToDot.function
|
||||
|
@ -401,9 +633,13 @@ ToString.toStringNamedFunction_id
|
|||
ToString.toStringNamedFunction_map
|
||||
ToString.toStringNamedFunction_overrides_param_names
|
||||
ToString.toStringNamedFunction_variadics
|
||||
TranspilerTests.attach_types
|
||||
TranspilerTests.type_lists_should_be_emitted_correctly
|
||||
TranspilerTests.types_should_not_be_considered_cyclic_if_they_are_not_recursive
|
||||
TryUnifyTests.cli_41095_concat_log_in_sealed_table_unification
|
||||
TryUnifyTests.members_of_failed_typepack_unification_are_unified_with_errorType
|
||||
TryUnifyTests.result_of_failed_typepack_unification_is_constrained
|
||||
TryUnifyTests.typepack_unification_should_trim_free_tails
|
||||
TryUnifyTests.variadics_should_use_reversed_properly
|
||||
TypeAliases.basic_alias
|
||||
TypeAliases.cannot_steal_hoisted_type_alias
|
||||
TypeAliases.cli_38393_recursive_intersection_oom
|
||||
|
@ -446,6 +682,37 @@ TypeAliases.type_alias_local_synthetic_mutation
|
|||
TypeAliases.type_alias_of_an_imported_recursive_generic_type
|
||||
TypeAliases.type_alias_of_an_imported_recursive_type
|
||||
TypeAliases.use_table_name_and_generic_params_in_errors
|
||||
TypeInfer.check_expr_recursion_limit
|
||||
TypeInfer.checking_should_not_ice
|
||||
TypeInfer.cli_50041_committing_txnlog_in_apollo_client_error
|
||||
TypeInfer.cyclic_follow
|
||||
TypeInfer.do_not_bind_a_free_table_to_a_union_containing_that_table
|
||||
TypeInfer.dont_report_type_errors_within_an_AstStatError
|
||||
TypeInfer.follow_on_new_types_in_substitution
|
||||
TypeInfer.free_typevars_introduced_within_control_flow_constructs_do_not_get_an_elevated_TypeLevel
|
||||
TypeInfer.globals
|
||||
TypeInfer.globals2
|
||||
TypeInfer.index_expr_should_be_checked
|
||||
TypeInfer.infer_assignment_value_types
|
||||
TypeInfer.infer_assignment_value_types_mutable_lval
|
||||
TypeInfer.infer_through_group_expr
|
||||
TypeInfer.infer_type_assertion_value_type
|
||||
TypeInfer.no_heap_use_after_free_error
|
||||
TypeInfer.no_infinite_loop_when_trying_to_unify_uh_this
|
||||
TypeInfer.no_stack_overflow_from_isoptional
|
||||
TypeInfer.no_stack_overflow_from_isoptional2
|
||||
TypeInfer.recursive_metatable_crash
|
||||
TypeInfer.tc_after_error_recovery_no_replacement_name_in_error
|
||||
TypeInfer.tc_if_else_expressions1
|
||||
TypeInfer.tc_if_else_expressions2
|
||||
TypeInfer.tc_if_else_expressions_expected_type_1
|
||||
TypeInfer.tc_if_else_expressions_expected_type_2
|
||||
TypeInfer.tc_if_else_expressions_expected_type_3
|
||||
TypeInfer.tc_if_else_expressions_type_union
|
||||
TypeInfer.type_infer_recursion_limit_no_ice
|
||||
TypeInfer.types stored in astResolvedTypes
|
||||
TypeInfer.warn_on_lowercase_parent_property
|
||||
TypeInfer.weird_case
|
||||
TypeInferAnyError.any_type_propagates
|
||||
TypeInferAnyError.assign_prop_to_table_by_calling_any_yields_any
|
||||
TypeInferAnyError.call_to_any_yields_any
|
||||
|
@ -496,26 +763,289 @@ TypeInferClasses.we_can_infer_that_a_parameter_must_be_a_particular_class
|
|||
TypeInferClasses.we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class
|
||||
TypeInferFunctions.another_indirect_function_case_where_it_is_ok_to_provide_too_many_arguments
|
||||
TypeInferFunctions.another_recursive_local_function
|
||||
TypeInferFunctions.calling_function_with_anytypepack_doesnt_leak_free_types
|
||||
TypeInferFunctions.calling_function_with_incorrect_argument_type_yields_errors_spanning_argument
|
||||
TypeInferFunctions.cannot_hoist_interior_defns_into_signature
|
||||
TypeInferFunctions.check_function_before_lambda_that_uses_it
|
||||
TypeInferFunctions.complicated_return_types_require_an_explicit_annotation
|
||||
TypeInferFunctions.cyclic_function_type_in_args
|
||||
TypeInferFunctions.dont_give_other_overloads_message_if_only_one_argument_matching_overload_exists
|
||||
TypeInferFunctions.dont_infer_parameter_types_for_functions_from_their_call_site
|
||||
TypeInferFunctions.dont_mutate_the_underlying_head_of_typepack_when_calling_with_self
|
||||
TypeInferFunctions.duplicate_functions_with_different_signatures_not_allowed_in_nonstrict
|
||||
TypeInferFunctions.error_detailed_function_mismatch_arg
|
||||
TypeInferFunctions.error_detailed_function_mismatch_arg_count
|
||||
TypeInferFunctions.error_detailed_function_mismatch_ret
|
||||
TypeInferFunctions.error_detailed_function_mismatch_ret_count
|
||||
TypeInferFunctions.error_detailed_function_mismatch_ret_mult
|
||||
TypeInferFunctions.first_argument_can_be_optional
|
||||
TypeInferFunctions.free_is_not_bound_to_unknown
|
||||
TypeInferFunctions.func_expr_doesnt_leak_free
|
||||
TypeInferFunctions.function_cast_error_uses_correct_language
|
||||
TypeInferFunctions.function_decl_non_self_sealed_overwrite
|
||||
TypeInferFunctions.function_decl_non_self_sealed_overwrite_2
|
||||
TypeInferFunctions.function_decl_non_self_unsealed_overwrite
|
||||
TypeInferFunctions.function_decl_quantify_right_type
|
||||
TypeInferFunctions.function_does_not_return_enough_values
|
||||
TypeInferFunctions.function_statement_sealed_table_assignment_through_indexer
|
||||
TypeInferFunctions.higher_order_function_2
|
||||
TypeInferFunctions.higher_order_function_4
|
||||
TypeInferFunctions.ignored_return_values
|
||||
TypeInferFunctions.inconsistent_higher_order_function
|
||||
TypeInferFunctions.inconsistent_return_types
|
||||
TypeInferFunctions.infer_anonymous_function_arguments
|
||||
TypeInferFunctions.infer_anonymous_function_arguments_outside_call
|
||||
TypeInferFunctions.infer_return_type_from_selected_overload
|
||||
TypeInferFunctions.infer_that_function_does_not_return_a_table
|
||||
TypeInferFunctions.inferred_higher_order_functions_are_quantified_at_the_right_time
|
||||
TypeInferFunctions.inferred_higher_order_functions_are_quantified_at_the_right_time2
|
||||
TypeInferFunctions.it_is_ok_not_to_supply_enough_retvals
|
||||
TypeInferFunctions.it_is_ok_to_oversaturate_a_higher_order_function_argument
|
||||
TypeInferFunctions.list_all_overloads_if_no_overload_takes_given_argument_count
|
||||
TypeInferFunctions.list_only_alternative_overloads_that_match_argument_count
|
||||
TypeInferFunctions.mutual_recursion
|
||||
TypeInferFunctions.no_lossy_function_type
|
||||
TypeInferFunctions.occurs_check_failure_in_function_return_type
|
||||
TypeInferFunctions.quantify_constrained_types
|
||||
TypeInferFunctions.record_matching_overload
|
||||
TypeInferFunctions.recursive_function
|
||||
TypeInferFunctions.recursive_local_function
|
||||
TypeInferFunctions.report_exiting_without_return_nonstrict
|
||||
TypeInferFunctions.report_exiting_without_return_strict
|
||||
TypeInferFunctions.return_type_by_overload
|
||||
TypeInferFunctions.strict_mode_ok_with_missing_arguments
|
||||
TypeInferFunctions.too_few_arguments_variadic
|
||||
TypeInferFunctions.too_few_arguments_variadic_generic
|
||||
TypeInferFunctions.too_few_arguments_variadic_generic2
|
||||
TypeInferFunctions.too_many_arguments
|
||||
TypeInferFunctions.too_many_return_values
|
||||
TypeInferFunctions.toposort_doesnt_break_mutual_recursion
|
||||
TypeInferFunctions.vararg_function_is_quantified
|
||||
TypeInferFunctions.vararg_functions_should_allow_calls_of_any_types_and_size
|
||||
TypeInferLoops.correctly_scope_locals_while
|
||||
TypeInferLoops.for_in_loop
|
||||
TypeInferLoops.for_in_loop_error_on_factory_not_returning_the_right_amount_of_values
|
||||
TypeInferLoops.for_in_loop_error_on_iterator_requiring_args_but_none_given
|
||||
TypeInferLoops.for_in_loop_on_error
|
||||
TypeInferLoops.for_in_loop_on_non_function
|
||||
TypeInferLoops.for_in_loop_should_fail_with_non_function_iterator
|
||||
TypeInferLoops.for_in_loop_where_iteratee_is_free
|
||||
TypeInferLoops.for_in_loop_with_custom_iterator
|
||||
TypeInferLoops.for_in_loop_with_next
|
||||
TypeInferLoops.for_in_with_a_custom_iterator_should_type_check
|
||||
TypeInferLoops.for_in_with_an_iterator_of_type_any
|
||||
TypeInferLoops.for_in_with_just_one_iterator_is_ok
|
||||
TypeInferLoops.fuzz_fail_missing_instantitation_follow
|
||||
TypeInferLoops.ipairs_produces_integral_indices
|
||||
TypeInferLoops.loop_iter_basic
|
||||
TypeInferLoops.loop_iter_iter_metamethod
|
||||
TypeInferLoops.loop_iter_no_indexer_nonstrict
|
||||
TypeInferLoops.loop_iter_no_indexer_strict
|
||||
TypeInferLoops.loop_iter_trailing_nil
|
||||
TypeInferLoops.loop_typecheck_crash_on_empty_optional
|
||||
TypeInferLoops.properly_infer_iteratee_is_a_free_table
|
||||
TypeInferLoops.repeat_loop
|
||||
TypeInferLoops.repeat_loop_condition_binds_to_its_block
|
||||
TypeInferLoops.symbols_in_repeat_block_should_not_be_visible_beyond_until_condition
|
||||
TypeInferLoops.unreachable_code_after_infinite_loop
|
||||
TypeInferLoops.varlist_declared_by_for_in_loop_should_be_free
|
||||
TypeInferLoops.while_loop
|
||||
TypeInferModules.bound_free_table_export_is_ok
|
||||
TypeInferModules.constrained_anyification_clone_immutable_types
|
||||
TypeInferModules.custom_require_global
|
||||
TypeInferModules.do_not_modify_imported_types
|
||||
TypeInferModules.do_not_modify_imported_types_2
|
||||
TypeInferModules.do_not_modify_imported_types_3
|
||||
TypeInferModules.do_not_modify_imported_types_4
|
||||
TypeInferModules.general_require_call_expression
|
||||
TypeInferModules.general_require_type_mismatch
|
||||
TypeInferModules.module_type_conflict
|
||||
TypeInferModules.module_type_conflict_instantiated
|
||||
TypeInferModules.require
|
||||
TypeInferModules.require_a_variadic_function
|
||||
TypeInferModules.require_failed_module
|
||||
TypeInferModules.require_module_that_does_not_export
|
||||
TypeInferModules.require_types
|
||||
TypeInferModules.type_error_of_unknown_qualified_type
|
||||
TypeInferModules.warn_if_you_try_to_require_a_non_modulescript
|
||||
TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_another_overload_works
|
||||
TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2
|
||||
TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_not_defined_with_colon
|
||||
TypeInferOOP.inferred_methods_of_free_tables_have_the_same_level_as_the_enclosing_table
|
||||
TypeInferOOP.inferring_hundreds_of_self_calls_should_not_suffocate_memory
|
||||
TypeInferOOP.method_depends_on_table
|
||||
TypeInferOOP.methods_are_topologically_sorted
|
||||
TypeInferOOP.nonstrict_self_mismatch_tail
|
||||
TypeInferOOP.object_constructor_can_refer_to_method_of_self
|
||||
TypeInferOOP.table_oop
|
||||
TypeInferOperators.and_adds_boolean
|
||||
TypeInferOperators.and_adds_boolean_no_superfluous_union
|
||||
TypeInferOperators.and_binexps_dont_unify
|
||||
TypeInferOperators.and_or_ternary
|
||||
TypeInferOperators.CallAndOrOfFunctions
|
||||
TypeInferOperators.cannot_compare_tables_that_do_not_have_the_same_metatable
|
||||
TypeInferOperators.cannot_indirectly_compare_types_that_do_not_have_a_metatable
|
||||
TypeInferOperators.cannot_indirectly_compare_types_that_do_not_offer_overloaded_ordering_operators
|
||||
TypeInferOperators.cli_38355_recursive_union
|
||||
TypeInferOperators.compare_numbers
|
||||
TypeInferOperators.compare_strings
|
||||
TypeInferOperators.compound_assign_basic
|
||||
TypeInferOperators.compound_assign_metatable
|
||||
TypeInferOperators.compound_assign_mismatch_metatable
|
||||
TypeInferOperators.compound_assign_mismatch_op
|
||||
TypeInferOperators.compound_assign_mismatch_result
|
||||
TypeInferOperators.concat_op_on_free_lhs_and_string_rhs
|
||||
TypeInferOperators.concat_op_on_string_lhs_and_free_rhs
|
||||
TypeInferOperators.disallow_string_and_types_without_metatables_from_arithmetic_binary_ops
|
||||
TypeInferOperators.dont_strip_nil_from_rhs_or_operator
|
||||
TypeInferOperators.equality_operations_succeed_if_any_union_branch_succeeds
|
||||
TypeInferOperators.error_on_invalid_operand_types_to_relational_operators
|
||||
TypeInferOperators.error_on_invalid_operand_types_to_relational_operators2
|
||||
TypeInferOperators.expected_types_through_binary_and
|
||||
TypeInferOperators.expected_types_through_binary_or
|
||||
TypeInferOperators.in_nonstrict_mode_strip_nil_from_intersections_when_considering_relational_operators
|
||||
TypeInferOperators.infer_any_in_all_modes_when_lhs_is_unknown
|
||||
TypeInferOperators.operator_eq_operands_are_not_subtypes_of_each_other_but_has_overlap
|
||||
TypeInferOperators.operator_eq_verifies_types_do_intersect
|
||||
TypeInferOperators.or_joins_types
|
||||
TypeInferOperators.or_joins_types_with_no_extras
|
||||
TypeInferOperators.primitive_arith_no_metatable
|
||||
TypeInferOperators.primitive_arith_no_metatable_with_follows
|
||||
TypeInferOperators.primitive_arith_possible_metatable
|
||||
TypeInferOperators.produce_the_correct_error_message_when_comparing_a_table_with_a_metatable_with_one_that_does_not
|
||||
TypeInferOperators.refine_and_or
|
||||
TypeInferOperators.some_primitive_binary_ops
|
||||
TypeInferOperators.strict_binary_op_where_lhs_unknown
|
||||
TypeInferOperators.strip_nil_from_lhs_or_operator
|
||||
TypeInferOperators.strip_nil_from_lhs_or_operator2
|
||||
TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection
|
||||
TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection_on_rhs
|
||||
TypeInferOperators.typecheck_unary_len_error
|
||||
TypeInferOperators.typecheck_unary_minus
|
||||
TypeInferOperators.typecheck_unary_minus_error
|
||||
TypeInferOperators.unary_not_is_boolean
|
||||
TypeInferOperators.unknown_type_in_comparison
|
||||
TypeInferOperators.UnknownGlobalCompoundAssign
|
||||
TypeInferPrimitives.cannot_call_primitives
|
||||
TypeInferPrimitives.CheckMethodsOfNumber
|
||||
TypeInferPrimitives.string_function_other
|
||||
TypeInferPrimitives.string_index
|
||||
TypeInferPrimitives.string_length
|
||||
TypeInferPrimitives.string_method
|
||||
TypeInferUnknownNever.array_like_table_of_never_is_inhabitable
|
||||
TypeInferUnknownNever.assign_to_global_which_is_never
|
||||
TypeInferUnknownNever.assign_to_local_which_is_never
|
||||
TypeInferUnknownNever.assign_to_prop_which_is_never
|
||||
TypeInferUnknownNever.assign_to_subscript_which_is_never
|
||||
TypeInferUnknownNever.call_never
|
||||
TypeInferUnknownNever.dont_unify_operands_if_one_of_the_operand_is_never_in_any_ordering_operators
|
||||
TypeInferUnknownNever.index_on_never
|
||||
TypeInferUnknownNever.index_on_union_of_tables_for_properties_that_is_never
|
||||
TypeInferUnknownNever.index_on_union_of_tables_for_properties_that_is_sorta_never
|
||||
TypeInferUnknownNever.length_of_never
|
||||
TypeInferUnknownNever.math_operators_and_never
|
||||
TypeInferUnknownNever.never_is_reflexive
|
||||
TypeInferUnknownNever.never_subtype_and_string_supertype
|
||||
TypeInferUnknownNever.string_subtype_and_unknown_supertype
|
||||
TypeInferUnknownNever.table_with_prop_of_type_never_is_also_reflexive
|
||||
TypeInferUnknownNever.table_with_prop_of_type_never_is_uninhabitable
|
||||
TypeInferUnknownNever.type_packs_containing_never_is_itself_uninhabitable
|
||||
TypeInferUnknownNever.type_packs_containing_never_is_itself_uninhabitable2
|
||||
TypeInferUnknownNever.unary_minus_of_never
|
||||
TypeInferUnknownNever.unknown_is_reflexive
|
||||
TypePackTests.cyclic_type_packs
|
||||
TypePackTests.higher_order_function
|
||||
TypePackTests.multiple_varargs_inference_are_not_confused
|
||||
TypePackTests.no_return_size_should_be_zero
|
||||
TypePackTests.pack_tail_unification_check
|
||||
TypePackTests.parenthesized_varargs_returns_any
|
||||
TypePackTests.self_and_varargs_should_work
|
||||
TypePackTests.type_alias_backwards_compatible
|
||||
TypePackTests.type_alias_default_export
|
||||
TypePackTests.type_alias_default_mixed_self
|
||||
TypePackTests.type_alias_default_type_chained
|
||||
TypePackTests.type_alias_default_type_errors
|
||||
TypePackTests.type_alias_default_type_explicit
|
||||
TypePackTests.type_alias_default_type_pack_explicit
|
||||
TypePackTests.type_alias_default_type_pack_self_chained_tp
|
||||
TypePackTests.type_alias_default_type_pack_self_tp
|
||||
TypePackTests.type_alias_default_type_pack_self_ty
|
||||
TypePackTests.type_alias_default_type_self
|
||||
TypePackTests.type_alias_default_type_skip_brackets
|
||||
TypePackTests.type_alias_defaults_confusing_types
|
||||
TypePackTests.type_alias_defaults_recursive_type
|
||||
TypePackTests.type_alias_type_pack_explicit
|
||||
TypePackTests.type_alias_type_pack_explicit_multi
|
||||
TypePackTests.type_alias_type_pack_explicit_multi_tostring
|
||||
TypePackTests.type_alias_type_pack_multi
|
||||
TypePackTests.type_alias_type_pack_variadic
|
||||
TypePackTests.type_alias_type_packs
|
||||
TypePackTests.type_alias_type_packs_errors
|
||||
TypePackTests.type_alias_type_packs_import
|
||||
TypePackTests.type_alias_type_packs_nested
|
||||
TypePackTests.type_pack_hidden_free_tail_infinite_growth
|
||||
TypePackTests.type_pack_type_parameters
|
||||
TypePackTests.varargs_inference_through_multiple_scopes
|
||||
TypePackTests.variadic_argument_tail
|
||||
TypePackTests.variadic_pack_syntax
|
||||
TypePackTests.variadic_packs
|
||||
TypeSingletons.bool_singleton_subtype
|
||||
TypeSingletons.bool_singletons
|
||||
TypeSingletons.bool_singletons_mismatch
|
||||
TypeSingletons.enums_using_singletons
|
||||
TypeSingletons.enums_using_singletons_mismatch
|
||||
TypeSingletons.enums_using_singletons_subtyping
|
||||
TypeSingletons.error_detailed_tagged_union_mismatch_bool
|
||||
TypeSingletons.error_detailed_tagged_union_mismatch_string
|
||||
TypeSingletons.function_call_with_singletons_mismatch
|
||||
TypeSingletons.if_then_else_expression_singleton_options
|
||||
TypeSingletons.indexing_on_string_singletons
|
||||
TypeSingletons.indexing_on_union_of_string_singletons
|
||||
TypeSingletons.no_widening_from_callsites
|
||||
TypeSingletons.overloaded_function_call_with_singletons
|
||||
TypeSingletons.overloaded_function_call_with_singletons_mismatch
|
||||
TypeSingletons.return_type_of_f_is_not_widened
|
||||
TypeSingletons.string_singleton_subtype
|
||||
TypeSingletons.string_singletons
|
||||
TypeSingletons.string_singletons_escape_chars
|
||||
TypeSingletons.string_singletons_mismatch
|
||||
TypeSingletons.table_insert_with_a_singleton_argument
|
||||
TypeSingletons.table_properties_alias_or_parens_is_indexer
|
||||
TypeSingletons.table_properties_singleton_strings
|
||||
TypeSingletons.table_properties_singleton_strings_mismatch
|
||||
TypeSingletons.table_properties_type_error_escapes
|
||||
TypeSingletons.tagged_unions_immutable_tag
|
||||
TypeSingletons.tagged_unions_using_singletons
|
||||
TypeSingletons.tagged_unions_using_singletons_mismatch
|
||||
TypeSingletons.taking_the_length_of_string_singleton
|
||||
TypeSingletons.taking_the_length_of_union_of_string_singleton
|
||||
TypeSingletons.widen_the_supertype_if_it_is_free_and_subtype_has_singleton
|
||||
TypeSingletons.widening_happens_almost_everywhere
|
||||
TypeSingletons.widening_happens_almost_everywhere_except_for_tables
|
||||
TypeVarTests.visit_once
|
||||
UnionTypes.error_detailed_optional
|
||||
UnionTypes.error_detailed_union_all
|
||||
UnionTypes.error_detailed_union_part
|
||||
UnionTypes.error_takes_optional_arguments
|
||||
UnionTypes.index_on_a_union_type_with_missing_property
|
||||
UnionTypes.index_on_a_union_type_with_mixed_types
|
||||
UnionTypes.index_on_a_union_type_with_one_optional_property
|
||||
UnionTypes.index_on_a_union_type_with_one_property_of_type_any
|
||||
UnionTypes.index_on_a_union_type_with_property_guaranteed_to_exist
|
||||
UnionTypes.index_on_a_union_type_works_at_arbitrary_depth
|
||||
UnionTypes.optional_arguments
|
||||
UnionTypes.optional_assignment_errors
|
||||
UnionTypes.optional_call_error
|
||||
UnionTypes.optional_field_access_error
|
||||
UnionTypes.optional_index_error
|
||||
UnionTypes.optional_length_error
|
||||
UnionTypes.optional_missing_key_error_details
|
||||
UnionTypes.optional_union_follow
|
||||
UnionTypes.optional_union_functions
|
||||
UnionTypes.optional_union_members
|
||||
UnionTypes.optional_union_methods
|
||||
UnionTypes.return_types_can_be_disjoint
|
||||
UnionTypes.table_union_write_indirect
|
||||
UnionTypes.unify_sealed_table_union_check
|
||||
UnionTypes.unify_unsealed_table_union_check
|
||||
UnionTypes.union_equality_comparisons
|
||||
|
|
|
@ -14,6 +14,11 @@ def loadFailList():
|
|||
with open(FAIL_LIST_PATH) as f:
|
||||
return set(map(str.strip, f.readlines()))
|
||||
|
||||
def safeParseInt(i, default=0):
|
||||
try:
|
||||
return int(i)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
class Handler(x.ContentHandler):
|
||||
def __init__(self, failList):
|
||||
|
@ -22,6 +27,8 @@ class Handler(x.ContentHandler):
|
|||
|
||||
self.results = {} # {DottedName: TrueIfTheTestPassed}
|
||||
|
||||
self.numSkippedTests = 0
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "TestSuite":
|
||||
self.currentTest.append(attrs["name"])
|
||||
|
@ -30,10 +37,7 @@ class Handler(x.ContentHandler):
|
|||
|
||||
elif name == "OverallResultsAsserts":
|
||||
if self.currentTest:
|
||||
try:
|
||||
failed = 0 != int(attrs["failures"])
|
||||
except ValueError:
|
||||
failed = False
|
||||
failed = 0 != safeParseInt(attrs["failures"])
|
||||
|
||||
dottedName = ".".join(self.currentTest)
|
||||
shouldFail = dottedName in self.failList
|
||||
|
@ -45,6 +49,9 @@ class Handler(x.ContentHandler):
|
|||
|
||||
self.results[dottedName] = not failed
|
||||
|
||||
elif name == 'OverallResultsTestCases':
|
||||
self.numSkippedTests = safeParseInt(attrs.get("skipped", 0))
|
||||
|
||||
def endElement(self, name):
|
||||
if name == "TestCase":
|
||||
self.currentTest.pop()
|
||||
|
@ -111,6 +118,10 @@ def main():
|
|||
print(name, file=f)
|
||||
print("Updated faillist.txt")
|
||||
|
||||
if handler.numSkippedTests > 0:
|
||||
print('{} test(s) were skipped! That probably means that a test segfaulted!'.format(handler.numSkippedTests), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(
|
||||
0
|
||||
if all(
|
||||
|
|
Loading…
Add table
Reference in a new issue