mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 06:15:44 +08:00
Sync to upstream/release/538 (#616)
This commit is contained in:
parent
cb16555608
commit
d3b566c258
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};
|
||||
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))
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -2845,7 +2845,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
|
||||
@ -2883,9 +2883,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 = {}
|
||||
@ -2901,7 +2917,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
|
||||
@ -2916,7 +2932,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 = {}
|
||||
@ -2931,9 +2947,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"
|
||||
@ -2952,7 +2985,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"
|
||||
@ -2969,7 +3002,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
|
||||
@ -3000,7 +3033,7 @@ table.@1
|
||||
|
||||
TEST_CASE_FIXTURE(ACBuiltinsFixture, "library_self_calls_are_invalid")
|
||||
{
|
||||
ScopedFastFlag selfCallAutocompleteFix2{"LuauSelfCallAutocompleteFix2", true};
|
||||
ScopedFastFlag selfCallAutocompleteFix3{"LuauSelfCallAutocompleteFix3", true};
|
||||
|
||||
check(R"(
|
||||
string:@1
|
||||
@ -3012,8 +3045,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…
Reference in New Issue
Block a user