Skip to content

Commit

Permalink
Sync to upstream/release/651 (#1513)
Browse files Browse the repository at this point in the history
### What's New?

* Fragment Autocomplete: a new API allows for type checking a small
fragment of code against an existing file, significantly speeding up
autocomplete performance in large files.

### New Solver

* E-Graphs have landed: this is an ongoing approach to make the new type
solver simplify types in a more consistent and principled manner, based
on similar work (see: https://egraphs-good.github.io/).
* Adds support for exporting / local user type functions (previously
they were always exported).
* Fixes a set of bugs in which the new solver will fail to complete
inference for simple expressions with just literals and operators.

### General Updates
* Requiring a path with a ".lua" or ".luau" extension will now have a
bespoke error suggesting to remove said extension.
* Fixes a bug in which whether two `Luau::Symbol`s are equal depends on
whether the new solver is enabled.

---

Internal Contributors:

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: David Cope <[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
7 people authored Nov 8, 2024
1 parent 26b2307 commit a36a3c4
Show file tree
Hide file tree
Showing 62 changed files with 7,315 additions and 2,456 deletions.
86 changes: 2 additions & 84 deletions Analysis/include/Luau/Autocomplete.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "Luau/AutocompleteTypes.h"
#include "Luau/Location.h"
#include "Luau/Type.h"

#include <unordered_map>
#include <string>
#include <memory>
#include <optional>
Expand All @@ -16,90 +16,8 @@ struct Frontend;
struct SourceModule;
struct Module;
struct TypeChecker;

using ModulePtr = std::shared_ptr<Module>;

enum class AutocompleteContext
{
Unknown,
Expression,
Statement,
Property,
Type,
Keyword,
String,
};

enum class AutocompleteEntryKind
{
Property,
Binding,
Keyword,
String,
Type,
Module,
GeneratedFunction,
RequirePath,
};

enum class ParenthesesRecommendation
{
None,
CursorAfter,
CursorInside,
};

enum class TypeCorrectKind
{
None,
Correct,
CorrectFunctionResult,
};

struct AutocompleteEntry
{
AutocompleteEntryKind kind = AutocompleteEntryKind::Property;
// Nullopt if kind is Keyword
std::optional<TypeId> type = std::nullopt;
bool deprecated = false;
// Only meaningful if kind is Property.
bool wrongIndexType = false;
// Set if this suggestion matches the type expected in the context
TypeCorrectKind typeCorrect = TypeCorrectKind::None;

std::optional<const ClassType*> containingClass = std::nullopt;
std::optional<const Property*> prop = std::nullopt;
std::optional<std::string> documentationSymbol = std::nullopt;
Tags tags;
ParenthesesRecommendation parens = ParenthesesRecommendation::None;
std::optional<std::string> insertText;

// Only meaningful if kind is Property.
bool indexedWithSelf = false;
};

using AutocompleteEntryMap = std::unordered_map<std::string, AutocompleteEntry>;
struct AutocompleteResult
{
AutocompleteEntryMap entryMap;
std::vector<AstNode*> ancestry;
AutocompleteContext context = AutocompleteContext::Unknown;

AutocompleteResult() = default;
AutocompleteResult(AutocompleteEntryMap entryMap, std::vector<AstNode*> ancestry, AutocompleteContext context)
: entryMap(std::move(entryMap))
, ancestry(std::move(ancestry))
, context(context)
{
}
};

using ModuleName = std::string;
using StringCompletionCallback =
std::function<std::optional<AutocompleteEntryMap>(std::string tag, std::optional<const ClassType*> ctx, std::optional<std::string> contents)>;
struct FileResolver;

AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName, Position position, StringCompletionCallback callback);

constexpr char kGeneratedAnonymousFunctionEntryName[] = "function (anonymous autofilled)";

} // namespace Luau
92 changes: 92 additions & 0 deletions Analysis/include/Luau/AutocompleteTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "Luau/Ast.h"
#include "Luau/Type.h"

#include <unordered_map>

namespace Luau
{

enum class AutocompleteContext
{
Unknown,
Expression,
Statement,
Property,
Type,
Keyword,
String,
};

enum class AutocompleteEntryKind
{
Property,
Binding,
Keyword,
String,
Type,
Module,
GeneratedFunction,
RequirePath,
};

enum class ParenthesesRecommendation
{
None,
CursorAfter,
CursorInside,
};

enum class TypeCorrectKind
{
None,
Correct,
CorrectFunctionResult,
};

struct AutocompleteEntry
{
AutocompleteEntryKind kind = AutocompleteEntryKind::Property;
// Nullopt if kind is Keyword
std::optional<TypeId> type = std::nullopt;
bool deprecated = false;
// Only meaningful if kind is Property.
bool wrongIndexType = false;
// Set if this suggestion matches the type expected in the context
TypeCorrectKind typeCorrect = TypeCorrectKind::None;

std::optional<const ClassType*> containingClass = std::nullopt;
std::optional<const Property*> prop = std::nullopt;
std::optional<std::string> documentationSymbol = std::nullopt;
Tags tags;
ParenthesesRecommendation parens = ParenthesesRecommendation::None;
std::optional<std::string> insertText;

// Only meaningful if kind is Property.
bool indexedWithSelf = false;
};

using AutocompleteEntryMap = std::unordered_map<std::string, AutocompleteEntry>;
struct AutocompleteResult
{
AutocompleteEntryMap entryMap;
std::vector<AstNode*> ancestry;
AutocompleteContext context = AutocompleteContext::Unknown;

AutocompleteResult() = default;
AutocompleteResult(AutocompleteEntryMap entryMap, std::vector<AstNode*> ancestry, AutocompleteContext context)
: entryMap(std::move(entryMap))
, ancestry(std::move(ancestry))
, context(context)
{
}
};

using StringCompletionCallback =
std::function<std::optional<AutocompleteEntryMap>(std::string tag, std::optional<const ClassType*> ctx, std::optional<std::string> contents)>;

constexpr char kGeneratedAnonymousFunctionEntryName[] = "function (anonymous autofilled)";

} // namespace Luau
9 changes: 8 additions & 1 deletion Analysis/include/Luau/ConstraintGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Luau/Constraint.h"
#include "Luau/ControlFlow.h"
#include "Luau/DataFlowGraph.h"
#include "Luau/EqSatSimplification.h"
#include "Luau/InsertionOrderedMap.h"
#include "Luau/Module.h"
#include "Luau/ModuleResolver.h"
Expand All @@ -15,7 +16,6 @@
#include "Luau/TypeFwd.h"
#include "Luau/TypeUtils.h"
#include "Luau/Variant.h"
#include "Luau/Normalize.h"

#include <memory>
#include <vector>
Expand Down Expand Up @@ -109,6 +109,9 @@ struct ConstraintGenerator

// Needed to be able to enable error-suppression preservation for immediate refinements.
NotNull<Normalizer> normalizer;

NotNull<Simplifier> simplifier;

// Needed to register all available type functions for execution at later stages.
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
// Needed to resolve modules to make 'require' import types properly.
Expand All @@ -128,6 +131,7 @@ struct ConstraintGenerator
ConstraintGenerator(
ModulePtr module,
NotNull<Normalizer> normalizer,
NotNull<Simplifier> simplifier,
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
NotNull<ModuleResolver> moduleResolver,
NotNull<BuiltinTypes> builtinTypes,
Expand Down Expand Up @@ -405,6 +409,7 @@ struct ConstraintGenerator
TypeId makeUnion(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
// make an intersect type function of these two types
TypeId makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
void prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program);

/** Scan the program for global definitions.
*
Expand Down Expand Up @@ -435,6 +440,8 @@ struct ConstraintGenerator
const ScopePtr& scope,
Location location
);

TypeId simplifyUnion(const ScopePtr& scope, Location location, TypeId left, TypeId right);
};

/** Borrow a vector of pointers from a vector of owning pointers to constraints.
Expand Down
7 changes: 7 additions & 0 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Luau/Constraint.h"
#include "Luau/DataFlowGraph.h"
#include "Luau/DenseHash.h"
#include "Luau/EqSatSimplification.h"
#include "Luau/Error.h"
#include "Luau/Location.h"
#include "Luau/Module.h"
Expand Down Expand Up @@ -64,6 +65,7 @@ struct ConstraintSolver
NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter iceReporter;
NotNull<Normalizer> normalizer;
NotNull<Simplifier> simplifier;
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
// The entire set of constraints that the solver is trying to resolve.
std::vector<NotNull<Constraint>> constraints;
Expand Down Expand Up @@ -117,6 +119,7 @@ struct ConstraintSolver

explicit ConstraintSolver(
NotNull<Normalizer> normalizer,
NotNull<Simplifier> simplifier,
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
NotNull<Scope> rootScope,
std::vector<NotNull<Constraint>> constraints,
Expand Down Expand Up @@ -384,6 +387,10 @@ struct ConstraintSolver
**/
void reproduceConstraints(NotNull<Scope> scope, const Location& location, const Substitution& subst);

TypeId simplifyIntersection(NotNull<Scope> scope, Location location, TypeId left, TypeId right);
TypeId simplifyIntersection(NotNull<Scope> scope, Location location, std::set<TypeId> parts);
TypeId simplifyUnion(NotNull<Scope> scope, Location location, TypeId left, TypeId right);

TypeId errorRecoveryType() const;
TypePackId errorRecoveryTypePack() const;

Expand Down
50 changes: 50 additions & 0 deletions Analysis/include/Luau/EqSatSimplification.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details

#pragma once

#include "Luau/TypeFwd.h"
#include "Luau/NotNull.h"
#include "Luau/DenseHash.h"

#include <memory>
#include <optional>
#include <vector>

namespace Luau
{
struct TypeArena;
}

// The EqSat stuff is pretty template heavy, so we go to some lengths to prevent
// the complexity from leaking outside its implementation sources.
namespace Luau::EqSatSimplification
{

struct Simplifier;

using SimplifierPtr = std::unique_ptr<Simplifier, void (*)(Simplifier*)>;

SimplifierPtr newSimplifier(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes);

} // namespace Luau::EqSatSimplification

namespace Luau
{

struct EqSatSimplificationResult
{
TypeId result;

// New type function applications that were created by the reduction phase.
// We return these so that the ConstraintSolver can know to try to reduce
// them.
std::vector<TypeId> newTypeFunctions;
};

using EqSatSimplification::newSimplifier; // NOLINT: clang-tidy thinks these are unused. It is incorrect.
using Luau::EqSatSimplification::Simplifier; // NOLINT
using Luau::EqSatSimplification::SimplifierPtr;

std::optional<EqSatSimplificationResult> eqSatSimplify(NotNull<Simplifier> simplifier, TypeId ty);

} // namespace Luau
Loading

0 comments on commit a36a3c4

Please sign in to comment.