Skip to content

Commit

Permalink
Sync to upstream/release/572 (#899)
Browse files Browse the repository at this point in the history
* Fixed exported types not being suggested in autocomplete
* `T...` is now convertible to `...any` (Fixes
#767)
* Fixed issue with `T?` not being convertible to `T | T` or `T?`
(sometimes when internal pointer identity is different)
* Fixed potential crash in missing table key error suggestion to use a
similar existing key
* `lua_topointer` now returns a pointer for strings

C++ API Changes:
* `prepareModuleScope` callback has moved from TypeChecker to Frontend
* For LSPs, AstQuery functions (and `isWithinComment`) can be used
without full Frontend data

A lot of changes in our two experimental components as well.

In our work on the new type-solver, the following issues were fixed:
* Fixed table union and intersection indexing
* Correct custom type environments are now used
* Fixed issue with values of `free & number` type not accepted in
numeric operations

And these are the changes in native code generation (JIT):
* arm64 lowering is almost complete with support for 99% of IR commands
and all fastcalls
* Fixed x64 assembly encoding for extended byte registers
* More external x64 calls are aware of register allocator
* `math.min`/`math.max` with more than 2 arguments are now lowered to IR
as well
* Fixed correctness issues with `math` library calls with multiple
results in variadic context and with x64 register conflicts
* x64 register allocator learnt to restore values from VM memory instead
of always using stack spills
* x64 exception unwind information now supports multiple functions and
fixes function start offset in Dwarf2 info
  • Loading branch information
vegorov-rbx authored Apr 14, 2023
1 parent 7345891 commit d141a5c
Show file tree
Hide file tree
Showing 88 changed files with 2,573 additions and 1,427 deletions.
3 changes: 3 additions & 0 deletions Analysis/include/Luau/AstQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ struct ExprOrLocal
};

std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule& source, Position pos);
std::vector<AstNode*> findAncestryAtPositionForAutocomplete(AstStatBlock* root, Position pos);
std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos, bool includeTypes = false);
std::vector<AstNode*> findAstAncestryOfPosition(AstStatBlock* root, Position pos, bool includeTypes = false);
AstNode* findNodeAtPosition(const SourceModule& source, Position pos);
AstNode* findNodeAtPosition(AstStatBlock* root, Position pos);
AstExpr* findExprAtPosition(const SourceModule& source, Position pos);
ScopePtr findScopeAtPosition(const Module& module, Position pos);
std::optional<Binding> findBindingAtPosition(const Module& module, const SourceModule& source, Position pos);
Expand Down
20 changes: 17 additions & 3 deletions Analysis/include/Luau/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,15 @@ struct Frontend
bool captureComments, bool typeCheckForAutocomplete = false);

private:
ModulePtr check(const SourceModule& sourceModule, Mode mode, std::vector<RequireCycle> requireCycles, bool forAutocomplete = false, bool recordJsonLog = false);
struct TypeCheckLimits
{
std::optional<double> finishTime;
std::optional<int> instantiationChildLimit;
std::optional<int> unifierIterationLimit;
};

ModulePtr check(const SourceModule& sourceModule, Mode mode, std::vector<RequireCycle> requireCycles, std::optional<ScopePtr> environmentScope,
bool forAutocomplete, bool recordJsonLog, TypeCheckLimits typeCheckLimits);

std::pair<SourceNode*, SourceModule*> getSourceNode(const ModuleName& name);
SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions);
Expand All @@ -185,15 +193,21 @@ struct Frontend
const NotNull<BuiltinTypes> builtinTypes;

FileResolver* fileResolver;

FrontendModuleResolver moduleResolver;
FrontendModuleResolver moduleResolverForAutocomplete;

GlobalTypes globals;
GlobalTypes globalsForAutocomplete;
TypeChecker typeChecker;
TypeChecker typeCheckerForAutocomplete;

// TODO: remove with FFlagLuauOnDemandTypecheckers
TypeChecker typeChecker_DEPRECATED;
TypeChecker typeCheckerForAutocomplete_DEPRECATED;

ConfigResolver* configResolver;
FrontendOptions options;
InternalErrorReporter iceHandler;
std::function<void(const ModuleName& name, const ScopePtr& scope, bool forAutocomplete)> prepareModuleScope;

std::unordered_map<ModuleName, SourceNode> sourceNodes;
std::unordered_map<ModuleName, SourceModule> sourceModules;
Expand Down
1 change: 1 addition & 0 deletions Analysis/include/Luau/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct SourceModule
};

bool isWithinComment(const SourceModule& sourceModule, Position pos);
bool isWithinComment(const ParseResult& result, Position pos);

struct RequireCycle
{
Expand Down
14 changes: 14 additions & 0 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ const T* get(TypeId tv)
return get_if<T>(&tv->ty);
}


template<typename T>
T* getMutable(TypeId tv)
{
Expand Down Expand Up @@ -897,6 +898,19 @@ bool hasTag(TypeId ty, const std::string& tagName);
bool hasTag(const Property& prop, const std::string& tagName);
bool hasTag(const Tags& tags, const std::string& tagName); // Do not use in new work.

template<typename T>
bool hasTypeInIntersection(TypeId ty)
{
TypeId tf = follow(ty);
if (get<T>(tf))
return true;
for (auto t : flattenIntersection(tf))
if (get<T>(follow(t)))
return true;
return false;
}

bool hasPrimitiveTypeInIntersection(TypeId ty, PrimitiveType::Type primTy);
/*
* Use this to change the kind of a particular type.
*
Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/Unifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ struct Unifier

public:
// Returns true if the type "needle" already occurs within "haystack" and reports an "infinite type error"
bool occursCheck(TypeId needle, TypeId haystack);
bool occursCheck(TypeId needle, TypeId haystack, bool reversed);
bool occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack);
bool occursCheck(TypePackId needle, TypePackId haystack);
bool occursCheck(TypePackId needle, TypePackId haystack, bool reversed);
bool occursCheck(DenseHashSet<TypePackId>& seen, TypePackId needle, TypePackId haystack);

Unifier makeChildUnifier();
Expand Down
31 changes: 23 additions & 8 deletions Analysis/src/AstQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,33 +211,48 @@ struct FindFullAncestry final : public AstVisitor

std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule& source, Position pos)
{
AutocompleteNodeFinder finder{pos, source.root};
source.root->visit(&finder);
return findAncestryAtPositionForAutocomplete(source.root, pos);
}

std::vector<AstNode*> findAncestryAtPositionForAutocomplete(AstStatBlock* root, Position pos)
{
AutocompleteNodeFinder finder{pos, root};
root->visit(&finder);
return finder.ancestry;
}

std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos, bool includeTypes)
{
const Position end = source.root->location.end;
return findAstAncestryOfPosition(source.root, pos, includeTypes);
}

std::vector<AstNode*> findAstAncestryOfPosition(AstStatBlock* root, Position pos, bool includeTypes)
{
const Position end = root->location.end;
if (pos > end)
pos = end;

FindFullAncestry finder(pos, end, includeTypes);
source.root->visit(&finder);
root->visit(&finder);
return finder.nodes;
}

AstNode* findNodeAtPosition(const SourceModule& source, Position pos)
{
const Position end = source.root->location.end;
if (pos < source.root->location.begin)
return source.root;
return findNodeAtPosition(source.root, pos);
}

AstNode* findNodeAtPosition(AstStatBlock* root, Position pos)
{
const Position end = root->location.end;
if (pos < root->location.begin)
return root;

if (pos > end)
pos = end;

FindNode findNode{pos, end};
findNode.visit(source.root);
findNode.visit(root);
return findNode.best;
}

Expand Down
18 changes: 11 additions & 7 deletions Analysis/src/ConstraintSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,11 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
* make any sense to stop and wait for someone else to do it.
*/

// If any is present, the expression must evaluate to any as well.
bool leftAny = get<AnyType>(leftType) || get<ErrorType>(leftType);
bool rightAny = get<AnyType>(rightType) || get<ErrorType>(rightType);
bool anyPresent = leftAny || rightAny;

if (isBlocked(leftType) && leftType != resultType)
return block(c.leftType, constraint);

Expand All @@ -604,12 +609,12 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
if (!force)
{
// Logical expressions may proceed if the LHS is free.
if (get<FreeType>(leftType) && !isLogical)
if (hasTypeInIntersection<FreeType>(leftType) && !isLogical)
return block(leftType, constraint);
}

// Logical expressions may proceed if the LHS is free.
if (isBlocked(leftType) || (get<FreeType>(leftType) && !isLogical))
if (isBlocked(leftType) || (hasTypeInIntersection<FreeType>(leftType) && !isLogical))
{
asMutable(resultType)->ty.emplace<BoundType>(errorRecoveryType());
unblock(resultType);
Expand Down Expand Up @@ -696,11 +701,6 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// If there's no metamethod available, fall back to primitive behavior.
}

// If any is present, the expression must evaluate to any as well.
bool leftAny = get<AnyType>(leftType) || get<ErrorType>(leftType);
bool rightAny = get<AnyType>(rightType) || get<ErrorType>(rightType);
bool anyPresent = leftAny || rightAny;

switch (c.op)
{
// For arithmetic operators, if the LHS is a number, the RHS must be a
Expand All @@ -711,6 +711,8 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
case AstExprBinary::Op::Div:
case AstExprBinary::Op::Pow:
case AstExprBinary::Op::Mod:
if (hasTypeInIntersection<FreeType>(leftType) && force)
asMutable(leftType)->ty.emplace<BoundType>(anyPresent ? builtinTypes->anyType : builtinTypes->numberType);
if (isNumber(leftType))
{
unify(leftType, rightType, constraint->scope);
Expand All @@ -723,6 +725,8 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// For concatenation, if the LHS is a string, the RHS must be a string as
// well. The result will also be a string.
case AstExprBinary::Op::Concat:
if (hasTypeInIntersection<FreeType>(leftType) && force)
asMutable(leftType)->ty.emplace<BoundType>(anyPresent ? builtinTypes->anyType : builtinTypes->stringType);
if (isString(leftType))
{
unify(leftType, rightType, constraint->scope);
Expand Down
Loading

0 comments on commit d141a5c

Please sign in to comment.