-
Notifications
You must be signed in to change notification settings - Fork 346
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Run clang-format * Contains a preliminary implementation of deferred constraint resolution * Reduce stack usage by some recursive functions * Fix a bug when smartCloning a BoundTypeVar * Remove some GC related flags from VM
- Loading branch information
1 parent
edd071f
commit 55a0268
Showing
43 changed files
with
1,875 additions
and
295 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details | ||
|
||
#pragma once | ||
|
||
#include <memory> | ||
#include <vector> | ||
|
||
#include "Luau/Ast.h" | ||
#include "Luau/Module.h" | ||
#include "Luau/Symbol.h" | ||
#include "Luau/TypeVar.h" | ||
#include "Luau/Variant.h" | ||
|
||
namespace Luau | ||
{ | ||
|
||
struct Scope2; | ||
|
||
// subType <: superType | ||
struct SubtypeConstraint | ||
{ | ||
TypeId subType; | ||
TypeId superType; | ||
}; | ||
|
||
// subPack <: superPack | ||
struct PackSubtypeConstraint | ||
{ | ||
TypePackId subPack; | ||
TypePackId superPack; | ||
}; | ||
|
||
// subType ~ gen superType | ||
struct GeneralizationConstraint | ||
{ | ||
TypeId subType; | ||
TypeId superType; | ||
Scope2* scope; | ||
}; | ||
|
||
// subType ~ inst superType | ||
struct InstantiationConstraint | ||
{ | ||
TypeId subType; | ||
TypeId superType; | ||
}; | ||
|
||
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint>; | ||
using ConstraintPtr = std::unique_ptr<struct Constraint>; | ||
|
||
struct Constraint | ||
{ | ||
Constraint(ConstraintV&& c); | ||
Constraint(ConstraintV&& c, std::vector<Constraint*> dependencies); | ||
|
||
Constraint(const Constraint&) = delete; | ||
Constraint& operator=(const Constraint&) = delete; | ||
|
||
ConstraintV c; | ||
std::vector<Constraint*> dependencies; | ||
}; | ||
|
||
inline Constraint& asMutable(const Constraint& c) | ||
{ | ||
return const_cast<Constraint&>(c); | ||
} | ||
|
||
template<typename T> | ||
T* getMutable(Constraint& c) | ||
{ | ||
return ::Luau::get_if<T>(&c.c); | ||
} | ||
|
||
template<typename T> | ||
const T* get(const Constraint& c) | ||
{ | ||
return getMutable<T>(asMutable(c)); | ||
} | ||
|
||
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<Scope2*> children; | ||
std::unordered_map<Symbol, TypeId> bindings; // TODO: I think this can be a DenseHashMap | ||
TypePackId returnType; | ||
// All constraints belonging to this scope. | ||
std::vector<ConstraintPtr> constraints; | ||
|
||
std::optional<TypeId> lookup(Symbol sym); | ||
}; | ||
|
||
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; | ||
SingletonTypes& singletonTypes; | ||
TypeArena* const arena; | ||
// The root scope of the module we're generating constraints for. | ||
Scope2* rootScope; | ||
|
||
explicit ConstraintGraphBuilder(TypeArena* arena); | ||
|
||
/** | ||
* Fabricates a new free type belonging to a given scope. | ||
* @param scope the scope the free type belongs to. Must not be null. | ||
*/ | ||
TypeId freshType(Scope2* scope); | ||
|
||
/** | ||
* Fabricates a new free type pack belonging to a given scope. | ||
* @param scope the scope the free type pack belongs to. Must not be null. | ||
*/ | ||
TypePackId freshTypePack(Scope2* 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. | ||
*/ | ||
Scope2* childScope(Location location, Scope2* parent); | ||
|
||
/** | ||
* Adds a new constraint with no dependencies to a given scope. | ||
* @param scope the scope to add the constraint to. Must not be null. | ||
* @param cv the constraint variant to add. | ||
*/ | ||
void addConstraint(Scope2* 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(Scope2* scope, std::unique_ptr<Constraint> c); | ||
|
||
/** | ||
* The entry point to the ConstraintGraphBuilder. This will construct a set | ||
* of scopes, constraints, and free types that can be solved later. | ||
* @param block the root block to generate constraints for. | ||
*/ | ||
void visit(AstStatBlock* block); | ||
|
||
void visit(Scope2* scope, AstStat* stat); | ||
void visit(Scope2* scope, AstStatBlock* block); | ||
void visit(Scope2* scope, AstStatLocal* local); | ||
void visit(Scope2* scope, AstStatLocalFunction* local); | ||
void visit(Scope2* scope, AstStatReturn* local); | ||
|
||
TypePackId checkPack(Scope2* scope, AstArray<AstExpr*> exprs); | ||
TypePackId checkPack(Scope2* scope, AstExpr* expr); | ||
|
||
TypeId check(Scope2* scope, AstExpr* expr); | ||
}; | ||
|
||
std::vector<const Constraint*> collectConstraints(Scope2* rootScope); | ||
|
||
} // namespace Luau |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details | ||
|
||
#pragma once | ||
|
||
#include "Luau/Error.h" | ||
#include "Luau/Variant.h" | ||
#include "Luau/ConstraintGraphBuilder.h" | ||
#include "Luau/TypeVar.h" | ||
|
||
#include <vector> | ||
|
||
namespace Luau | ||
{ | ||
|
||
// TypeId, TypePackId, or Constraint*. It is impossible to know which, but we | ||
// never dereference this pointer. | ||
using BlockedConstraintId = const void*; | ||
|
||
struct ConstraintSolver | ||
{ | ||
TypeArena* arena; | ||
InternalErrorReporter iceReporter; | ||
// The entire set of constraints that the solver is trying to resolve. | ||
std::vector<const Constraint*> constraints; | ||
Scope2* rootScope; | ||
std::vector<TypeError> errors; | ||
|
||
// This includes every constraint that has not been fully solved. | ||
// A constraint can be both blocked and unsolved, for instance. | ||
std::unordered_set<const Constraint*> unsolvedConstraints; | ||
|
||
// A mapping of constraint pointer to how many things the constraint is | ||
// blocked on. Can be empty or 0 for constraints that are not blocked on | ||
// anything. | ||
std::unordered_map<const Constraint*, size_t> blockedConstraints; | ||
// A mapping of type/pack pointers to the constraints they block. | ||
std::unordered_map<BlockedConstraintId, std::vector<const Constraint*>> blocked; | ||
|
||
explicit ConstraintSolver(TypeArena* arena, Scope2* rootScope); | ||
|
||
/** | ||
* Attempts to dispatch all pending constraints and reach a type solution | ||
* that satisfies all of the constraints, recording any errors that are | ||
* encountered. | ||
**/ | ||
void run(); | ||
|
||
bool done(); | ||
|
||
bool tryDispatch(const Constraint* c); | ||
bool tryDispatch(const SubtypeConstraint& c); | ||
bool tryDispatch(const PackSubtypeConstraint& c); | ||
bool tryDispatch(const GeneralizationConstraint& c); | ||
bool tryDispatch(const InstantiationConstraint& c, const Constraint* constraint); | ||
|
||
/** | ||
* Marks a constraint as being blocked on a type or type pack. The constraint | ||
* solver will not attempt to dispatch blocked constraints until their | ||
* dependencies have made progress. | ||
* @param target the type or type pack pointer that the constraint is blocked on. | ||
* @param constraint the constraint to block. | ||
**/ | ||
void block_(BlockedConstraintId target, const Constraint* constraint); | ||
void block(const Constraint* target, const Constraint* constraint); | ||
void block(TypeId target, const Constraint* constraint); | ||
void block(TypePackId target, const Constraint* constraint); | ||
|
||
/** | ||
* Informs the solver that progress has been made on a type or type pack. The | ||
* solver will wake up all constraints that are blocked on the type or type pack, | ||
* and will resume attempting to dispatch them. | ||
* @param progressed the type or type pack pointer that has progressed. | ||
**/ | ||
void unblock_(BlockedConstraintId progressed); | ||
void unblock(const Constraint* progressed); | ||
void unblock(TypeId progressed); | ||
void unblock(TypePackId progressed); | ||
|
||
/** | ||
* Returns whether the constraint is blocked on anything. | ||
* @param constraint the constraint to check. | ||
*/ | ||
bool isBlocked(const Constraint* constraint); | ||
|
||
void reportErrors(const std::vector<TypeError>& errors); | ||
|
||
/** | ||
* Creates a new Unifier and performs a single unification operation. Commits | ||
* the result and reports errors if necessary. | ||
* @param subType the sub-type to unify. | ||
* @param superType the super-type to unify. | ||
*/ | ||
void unify(TypeId subType, TypeId superType); | ||
|
||
/** | ||
* Creates a new Unifier and performs a single unification operation. Commits | ||
* the result and reports errors if necessary. | ||
* @param subPack the sub-type pack to unify. | ||
* @param superPack the super-type pack to unify. | ||
*/ | ||
void unify(TypePackId subPack, TypePackId superPack); | ||
}; | ||
|
||
void dump(Scope2* rootScope, struct ToStringOptions& opts); | ||
|
||
} // namespace Luau |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details | ||
#pragma once | ||
|
||
#include "Luau/Common.h" | ||
|
||
#include <functional> | ||
|
||
namespace Luau | ||
{ | ||
|
||
/** A non-owning, non-null pointer to a T. | ||
* | ||
* A NotNull<T> is notionally identical to a T* with the added restriction that it | ||
* can never store nullptr. | ||
* | ||
* The sole conversion rule from T* to NotNull<T> is the single-argument constructor, which | ||
* is intentionally marked explicit. This constructor performs a runtime test to verify | ||
* that the passed pointer is never nullptr. | ||
* | ||
* Pointer arithmetic, increment, decrement, and array indexing are all forbidden. | ||
* | ||
* An implicit coersion from NotNull<T> to T* is afforded, as are the pointer indirection and member | ||
* access operators. (*p and p->prop) | ||
* | ||
* The explicit delete statement is permitted on a NotNull<T> through this implicit conversion. | ||
*/ | ||
template <typename T> | ||
struct NotNull | ||
{ | ||
explicit NotNull(T* t) | ||
: ptr(t) | ||
{ | ||
LUAU_ASSERT(t); | ||
} | ||
|
||
explicit NotNull(std::nullptr_t) = delete; | ||
void operator=(std::nullptr_t) = delete; | ||
|
||
operator T*() const noexcept | ||
{ | ||
return ptr; | ||
} | ||
|
||
T& operator*() const noexcept | ||
{ | ||
return *ptr; | ||
} | ||
|
||
T* operator->() const noexcept | ||
{ | ||
return ptr; | ||
} | ||
|
||
T& operator[](int) = delete; | ||
|
||
T& operator+(int) = delete; | ||
T& operator-(int) = delete; | ||
|
||
T* ptr; | ||
}; | ||
|
||
} | ||
|
||
namespace std | ||
{ | ||
|
||
template <typename T> struct hash<Luau::NotNull<T>> | ||
{ | ||
size_t operator()(const Luau::NotNull<T>& p) const | ||
{ | ||
return std::hash<T*>()(p.ptr); | ||
} | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.