Skip to content

Commit

Permalink
Sync to upstream/release/648 (#1477)
Browse files Browse the repository at this point in the history
## What's new

* Added `math.map` function to the standard library, based on
https://rfcs.luau-lang.org/function-math-map.html
* `FileResolver` can provide an implementation of
`getRequireSuggestions` to provide auto-complete suggestions for
require-by-string

## New Solver

* In user-defined type functions, `readproperty` and `writeproperty`
will return `nil` instead of erroring if property is not found
* Fixed incorrect scope of variadic arguments in the data-flow graph
* Fixed multiple assertion failures

---

Internal Contributors:

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Hunter Goldstein <[email protected]>
Co-authored-by: Varun Saini <[email protected]>
Co-authored-by: Vighnesh Vijay <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
6 people authored Oct 18, 2024
1 parent d7842e0 commit e491128
Show file tree
Hide file tree
Showing 44 changed files with 1,588 additions and 522 deletions.
1 change: 1 addition & 0 deletions Analysis/include/Luau/Autocomplete.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum class AutocompleteEntryKind
Type,
Module,
GeneratedFunction,
RequirePath,
};

enum class ParenthesesRecommendation
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/BuiltinDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
namespace Luau
{

static constexpr char kRequireTagName[] = "require";

struct Frontend;
struct GlobalTypes;
struct TypeChecker;
Expand Down
183 changes: 111 additions & 72 deletions Analysis/include/Luau/DataFlowGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ struct DataFlowGraph
DenseHashMap<const AstExpr*, const Def*> compoundAssignDefs{nullptr};

DenseHashMap<const AstExpr*, const RefinementKey*> astRefinementKeys{nullptr};

friend struct DataFlowGraphBuilder;
};

Expand All @@ -83,6 +82,7 @@ struct DfgScope

DfgScope* parent;
ScopeType scopeType;
Location location;

using Bindings = DenseHashMap<Symbol, const Def*>;
using Props = DenseHashMap<const Def*, std::unordered_map<std::string, const Def*>>;
Expand All @@ -105,10 +105,44 @@ struct DataFlowResult
const RefinementKey* parent = nullptr;
};

using ScopeStack = std::vector<DfgScope*>;

struct DataFlowGraphBuilder
{
static DataFlowGraph build(AstStatBlock* root, NotNull<struct InternalErrorReporter> handle);

/**
* This method is identical to the build method above, but returns a pair of dfg, scopes as the data flow graph
* here is intended to live on the module between runs of typechecking. Before, the DFG only needed to live as
* long as the typecheck, but in a world with incremental typechecking, we need the information on the dfg to incrementally
* typecheck small fragments of code.
* @param block - pointer to the ast to build the dfg for
* @param handle - for raising internal errors while building the dfg
*/
static std::pair<std::shared_ptr<DataFlowGraph>, std::vector<std::unique_ptr<DfgScope>>> buildShared(
AstStatBlock* block,
NotNull<InternalErrorReporter> handle
);

/**
* Takes a stale graph along with a list of scopes, a small fragment of the ast, and a cursor position
* and constructs the DataFlowGraph for just that fragment. This method will fabricate defs in the final
* DFG for things that have been referenced and exist in the stale dfg.
* For example, the fragment local z = x + y will populate defs for x and y from the stale graph.
* @param staleGraph - the old DFG
* @param scopes - the old DfgScopes in the graph
* @param fragment - the Ast Fragment to re-build the root for
* @param cursorPos - the current location of the cursor - used to determine which scope we are currently in
* @param handle - for internal compiler errors
*/
static DataFlowGraph updateGraph(
const DataFlowGraph& staleGraph,
const std::vector<std::unique_ptr<DfgScope>>& scopes,
AstStatBlock* fragment,
const Position& cursorPos,
NotNull<InternalErrorReporter> handle
);

private:
DataFlowGraphBuilder() = default;

Expand All @@ -120,10 +154,15 @@ struct DataFlowGraphBuilder
NotNull<RefinementKeyArena> keyArena{&graph.keyArena};

struct InternalErrorReporter* handle = nullptr;
DfgScope* moduleScope = nullptr;

/// The arena owning all of the scope allocations for the dataflow graph being built.
std::vector<std::unique_ptr<DfgScope>> scopes;

/// A stack of scopes used by the visitor to see where we are.
ScopeStack scopeStack;

DfgScope* currentScope();

struct FunctionCapture
{
std::vector<DefId> captureDefs;
Expand All @@ -134,81 +173,81 @@ struct DataFlowGraphBuilder
DenseHashMap<Symbol, FunctionCapture> captures{Symbol{}};
void resolveCaptures();

DfgScope* childScope(DfgScope* scope, DfgScope::ScopeType scopeType = DfgScope::Linear);
DfgScope* makeChildScope(Location loc, DfgScope::ScopeType scopeType = DfgScope::Linear);

void join(DfgScope* p, DfgScope* a, DfgScope* b);
void joinBindings(DfgScope* p, const DfgScope& a, const DfgScope& b);
void joinProps(DfgScope* p, const DfgScope& a, const DfgScope& b);

DefId lookup(DfgScope* scope, Symbol symbol);
DefId lookup(DfgScope* scope, DefId def, const std::string& key);

ControlFlow visit(DfgScope* scope, AstStatBlock* b);
ControlFlow visitBlockWithoutChildScope(DfgScope* scope, AstStatBlock* b);

ControlFlow visit(DfgScope* scope, AstStat* s);
ControlFlow visit(DfgScope* scope, AstStatIf* i);
ControlFlow visit(DfgScope* scope, AstStatWhile* w);
ControlFlow visit(DfgScope* scope, AstStatRepeat* r);
ControlFlow visit(DfgScope* scope, AstStatBreak* b);
ControlFlow visit(DfgScope* scope, AstStatContinue* c);
ControlFlow visit(DfgScope* scope, AstStatReturn* r);
ControlFlow visit(DfgScope* scope, AstStatExpr* e);
ControlFlow visit(DfgScope* scope, AstStatLocal* l);
ControlFlow visit(DfgScope* scope, AstStatFor* f);
ControlFlow visit(DfgScope* scope, AstStatForIn* f);
ControlFlow visit(DfgScope* scope, AstStatAssign* a);
ControlFlow visit(DfgScope* scope, AstStatCompoundAssign* c);
ControlFlow visit(DfgScope* scope, AstStatFunction* f);
ControlFlow visit(DfgScope* scope, AstStatLocalFunction* l);
ControlFlow visit(DfgScope* scope, AstStatTypeAlias* t);
ControlFlow visit(DfgScope* scope, AstStatTypeFunction* f);
ControlFlow visit(DfgScope* scope, AstStatDeclareGlobal* d);
ControlFlow visit(DfgScope* scope, AstStatDeclareFunction* d);
ControlFlow visit(DfgScope* scope, AstStatDeclareClass* d);
ControlFlow visit(DfgScope* scope, AstStatError* error);

DataFlowResult visitExpr(DfgScope* scope, AstExpr* e);
DataFlowResult visitExpr(DfgScope* scope, AstExprGroup* group);
DataFlowResult visitExpr(DfgScope* scope, AstExprLocal* l);
DataFlowResult visitExpr(DfgScope* scope, AstExprGlobal* g);
DataFlowResult visitExpr(DfgScope* scope, AstExprCall* c);
DataFlowResult visitExpr(DfgScope* scope, AstExprIndexName* i);
DataFlowResult visitExpr(DfgScope* scope, AstExprIndexExpr* i);
DataFlowResult visitExpr(DfgScope* scope, AstExprFunction* f);
DataFlowResult visitExpr(DfgScope* scope, AstExprTable* t);
DataFlowResult visitExpr(DfgScope* scope, AstExprUnary* u);
DataFlowResult visitExpr(DfgScope* scope, AstExprBinary* b);
DataFlowResult visitExpr(DfgScope* scope, AstExprTypeAssertion* t);
DataFlowResult visitExpr(DfgScope* scope, AstExprIfElse* i);
DataFlowResult visitExpr(DfgScope* scope, AstExprInterpString* i);
DataFlowResult visitExpr(DfgScope* scope, AstExprError* error);

void visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprError* e, DefId incomingDef);

void visitType(DfgScope* scope, AstType* t);
void visitType(DfgScope* scope, AstTypeReference* r);
void visitType(DfgScope* scope, AstTypeTable* t);
void visitType(DfgScope* scope, AstTypeFunction* f);
void visitType(DfgScope* scope, AstTypeTypeof* t);
void visitType(DfgScope* scope, AstTypeUnion* u);
void visitType(DfgScope* scope, AstTypeIntersection* i);
void visitType(DfgScope* scope, AstTypeError* error);

void visitTypePack(DfgScope* scope, AstTypePack* p);
void visitTypePack(DfgScope* scope, AstTypePackExplicit* e);
void visitTypePack(DfgScope* scope, AstTypePackVariadic* v);
void visitTypePack(DfgScope* scope, AstTypePackGeneric* g);

void visitTypeList(DfgScope* scope, AstTypeList l);

void visitGenerics(DfgScope* scope, AstArray<AstGenericType> g);
void visitGenericPacks(DfgScope* scope, AstArray<AstGenericTypePack> g);
DefId lookup(Symbol symbol);
DefId lookup(DefId def, const std::string& key);

ControlFlow visit(AstStatBlock* b);
ControlFlow visitBlockWithoutChildScope(AstStatBlock* b);

ControlFlow visit(AstStat* s);
ControlFlow visit(AstStatIf* i);
ControlFlow visit(AstStatWhile* w);
ControlFlow visit(AstStatRepeat* r);
ControlFlow visit(AstStatBreak* b);
ControlFlow visit(AstStatContinue* c);
ControlFlow visit(AstStatReturn* r);
ControlFlow visit(AstStatExpr* e);
ControlFlow visit(AstStatLocal* l);
ControlFlow visit(AstStatFor* f);
ControlFlow visit(AstStatForIn* f);
ControlFlow visit(AstStatAssign* a);
ControlFlow visit(AstStatCompoundAssign* c);
ControlFlow visit(AstStatFunction* f);
ControlFlow visit(AstStatLocalFunction* l);
ControlFlow visit(AstStatTypeAlias* t);
ControlFlow visit(AstStatTypeFunction* f);
ControlFlow visit(AstStatDeclareGlobal* d);
ControlFlow visit(AstStatDeclareFunction* d);
ControlFlow visit(AstStatDeclareClass* d);
ControlFlow visit(AstStatError* error);

DataFlowResult visitExpr(AstExpr* e);
DataFlowResult visitExpr(AstExprGroup* group);
DataFlowResult visitExpr(AstExprLocal* l);
DataFlowResult visitExpr(AstExprGlobal* g);
DataFlowResult visitExpr(AstExprCall* c);
DataFlowResult visitExpr(AstExprIndexName* i);
DataFlowResult visitExpr(AstExprIndexExpr* i);
DataFlowResult visitExpr(AstExprFunction* f);
DataFlowResult visitExpr(AstExprTable* t);
DataFlowResult visitExpr(AstExprUnary* u);
DataFlowResult visitExpr(AstExprBinary* b);
DataFlowResult visitExpr(AstExprTypeAssertion* t);
DataFlowResult visitExpr(AstExprIfElse* i);
DataFlowResult visitExpr(AstExprInterpString* i);
DataFlowResult visitExpr(AstExprError* error);

void visitLValue(AstExpr* e, DefId incomingDef);
DefId visitLValue(AstExprLocal* l, DefId incomingDef);
DefId visitLValue(AstExprGlobal* g, DefId incomingDef);
DefId visitLValue(AstExprIndexName* i, DefId incomingDef);
DefId visitLValue(AstExprIndexExpr* i, DefId incomingDef);
DefId visitLValue(AstExprError* e, DefId incomingDef);

void visitType(AstType* t);
void visitType(AstTypeReference* r);
void visitType(AstTypeTable* t);
void visitType(AstTypeFunction* f);
void visitType(AstTypeTypeof* t);
void visitType(AstTypeUnion* u);
void visitType(AstTypeIntersection* i);
void visitType(AstTypeError* error);

void visitTypePack(AstTypePack* p);
void visitTypePack(AstTypePackExplicit* e);
void visitTypePack(AstTypePackVariadic* v);
void visitTypePack(AstTypePackGeneric* g);

void visitTypeList(AstTypeList l);

void visitGenerics(AstArray<AstGenericType> g);
void visitGenericPacks(AstArray<AstGenericTypePack> g);
};

} // namespace Luau
9 changes: 9 additions & 0 deletions Analysis/include/Luau/FileResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <string>
#include <optional>
#include <vector>

namespace Luau
{
Expand Down Expand Up @@ -31,6 +32,9 @@ struct ModuleInfo
bool optional = false;
};

using RequireSuggestion = std::string;
using RequireSuggestions = std::vector<RequireSuggestion>;

struct FileResolver
{
virtual ~FileResolver() {}
Expand All @@ -51,6 +55,11 @@ struct FileResolver
{
return std::nullopt;
}

virtual std::optional<RequireSuggestions> getRequireSuggestions(const ModuleName& requirer, const std::optional<std::string>& pathString) const
{
return std::nullopt;
}
};

struct NullFileResolver : FileResolver
Expand Down
28 changes: 25 additions & 3 deletions Analysis/include/Luau/FragmentAutocomplete.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "Luau/DenseHash.h"
#include "Luau/Ast.h"
#include "Luau/Parser.h"
#include "Luau/Autocomplete.h"
#include "Luau/DenseHash.h"
#include "Luau/Module.h"

#include <memory>
#include <vector>


namespace Luau
{

Expand All @@ -15,9 +18,28 @@ struct FragmentAutocompleteAncestryResult
DenseHashMap<AstName, AstLocal*> localMap{AstName()};
std::vector<AstLocal*> localStack;
std::vector<AstNode*> ancestry;
AstStat* nearestStatement;
AstStat* nearestStatement = nullptr;
};

struct FragmentParseResult
{
std::string fragmentToParse;
AstStatBlock* root = nullptr;
std::vector<AstNode*> ancestry;
std::unique_ptr<Allocator> alloc = std::make_unique<Allocator>();
};

FragmentAutocompleteAncestryResult findAncestryForFragmentParse(AstStatBlock* root, const Position& cursorPos);

FragmentParseResult parseFragment(const SourceModule& srcModule, std::string_view src, const Position& cursorPos);

AutocompleteResult fragmentAutocomplete(
Frontend& frontend,
std::string_view src,
const ModuleName& moduleName,
Position& cursorPosition,
StringCompletionCallback callback
);


} // namespace Luau
4 changes: 4 additions & 0 deletions Analysis/include/Luau/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Luau/Scope.h"
#include "Luau/TypeArena.h"
#include "Luau/AnyTypeSummary.h"
#include "Luau/DataFlowGraph.h"

#include <memory>
#include <vector>
Expand Down Expand Up @@ -131,6 +132,9 @@ struct Module

TypePackId returnType = nullptr;
std::unordered_map<Name, TypeFun> exportedTypeBindings;
// We also need to keep DFG data alive between runs
std::shared_ptr<DataFlowGraph> dataFlowGraph = nullptr;
std::vector<std::unique_ptr<DfgScope>> dfgScopes;

bool hasModuleScope() const;
ScopePtr getModuleScope() const;
Expand Down
7 changes: 7 additions & 0 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,11 @@ struct AnyType
{
};

// A special, trivial type for the refinement system that is always eliminated from intersections.
struct NoRefineType
{
};

// `T | U`
struct UnionType
{
Expand Down Expand Up @@ -755,6 +760,7 @@ using TypeVariant = Unifiable::Variant<
UnknownType,
NeverType,
NegationType,
NoRefineType,
TypeFunctionInstanceType>;

struct Type final
Expand Down Expand Up @@ -949,6 +955,7 @@ struct BuiltinTypes
const TypeId unknownType;
const TypeId neverType;
const TypeId errorType;
const TypeId noRefineType;
const TypeId falsyType;
const TypeId truthyType;

Expand Down
Loading

0 comments on commit e491128

Please sign in to comment.