Skip to content

Commit

Permalink
Sync to upstream/release/574 (#910)
Browse files Browse the repository at this point in the history
* Added a limit on how many instructions the Compiler can safely produce
(reported by @TheGreatSageEqualToHeaven)

C++ API Changes:
* With work started on read-only and write-only properties,
`Property::type` member variable has been replaced with `TypeId type()`
and `setType(TypeId)` functions.
* New `LazyType` unwrap callback now has a `void` return type, all
that's required from the callback is to write into `unwrapped` field.

In our work on the new type solver, the following issues were fixed:

* Work has started to support #77 and
#79
* Refinements are no longer applied on l-values, removing some
false-positive errors
* Improved overload resolution against expected result type
* `Frontend::prepareModuleScope` now works in the new solver
* Cofinite strings are now comparable

And these are the changes in native code generation (JIT):

* Fixed MIN_NUM and MAX_NUM constant fold when one of the arguments is
NaN
* Added constant folding for number conversions and bit operations
* Value spilling and rematerialization is now supported on arm64
* Improved FASTCALL2K IR generation to support second argument constant
* Added value numbering and load/store propagation optimizations
* Added STORE_VECTOR on arm64, completing the IR lowering on this target
  • Loading branch information
vegorov-rbx authored Apr 28, 2023
1 parent 8173491 commit 4b267aa
Show file tree
Hide file tree
Showing 84 changed files with 2,235 additions and 1,040 deletions.
12 changes: 9 additions & 3 deletions Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Luau/Refinement.h"
#include "Luau/Symbol.h"
#include "Luau/Type.h"
#include "Luau/TypeUtils.h"
#include "Luau/Variant.h"

#include <memory>
Expand Down Expand Up @@ -91,10 +92,14 @@ struct ConstraintGraphBuilder
const NotNull<InternalErrorReporter> ice;

ScopePtr globalScope;

std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope;

DcrLogger* logger;

ConstraintGraphBuilder(ModulePtr module, TypeArena* arena, NotNull<ModuleResolver> moduleResolver, NotNull<BuiltinTypes> builtinTypes,
NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope, DcrLogger* logger, NotNull<DataFlowGraph> dfg);
NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope, std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
DcrLogger* logger, NotNull<DataFlowGraph> dfg);

/**
* Fabricates a new free type belonging to a given scope.
Expand Down Expand Up @@ -174,11 +179,12 @@ struct ConstraintGraphBuilder
* surrounding context. Used to implement bidirectional type checking.
* @return the type of the expression.
*/
Inference check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType = {}, bool forceSingleton = false);
Inference check(const ScopePtr& scope, AstExpr* expr, ValueContext context = ValueContext::RValue, std::optional<TypeId> expectedType = {},
bool forceSingleton = false);

Inference check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton);
Inference check(const ScopePtr& scope, AstExprConstantBool* bool_, std::optional<TypeId> expectedType, bool forceSingleton);
Inference check(const ScopePtr& scope, AstExprLocal* local);
Inference check(const ScopePtr& scope, AstExprLocal* local, ValueContext context);
Inference check(const ScopePtr& scope, AstExprGlobal* global);
Inference check(const ScopePtr& scope, AstExprIndexName* indexName);
Inference check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
Expand Down
13 changes: 4 additions & 9 deletions Analysis/include/Luau/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ std::optional<ModuleName> pathExprToModuleName(const ModuleName& currentModuleNa
* error when we try during typechecking.
*/
std::optional<ModuleName> pathExprToModuleName(const ModuleName& currentModuleName, const AstExpr& expr);
// TODO: Deprecate this code path when we move away from the old solver
LoadDefinitionFileResult loadDefinitionFileNoDCR(TypeChecker& typeChecker, GlobalTypes& globals, ScopePtr targetScope, std::string_view definition,
const std::string& packageName, bool captureComments);

struct SourceNode
{
bool hasDirtySourceModule() const
Expand Down Expand Up @@ -209,10 +207,6 @@ struct Frontend
GlobalTypes globals;
GlobalTypes globalsForAutocomplete;

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

ConfigResolver* configResolver;
FrontendOptions options;
InternalErrorReporter iceHandler;
Expand All @@ -227,10 +221,11 @@ struct Frontend

ModulePtr check(const SourceModule& sourceModule, const std::vector<RequireCycle>& requireCycles, NotNull<BuiltinTypes> builtinTypes,
NotNull<InternalErrorReporter> iceHandler, NotNull<ModuleResolver> moduleResolver, NotNull<FileResolver> fileResolver,
const ScopePtr& globalScope, FrontendOptions options);
const ScopePtr& globalScope, std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope, FrontendOptions options);

ModulePtr check(const SourceModule& sourceModule, const std::vector<RequireCycle>& requireCycles, NotNull<BuiltinTypes> builtinTypes,
NotNull<InternalErrorReporter> iceHandler, NotNull<ModuleResolver> moduleResolver, NotNull<FileResolver> fileResolver,
const ScopePtr& globalScope, FrontendOptions options, bool recordJsonLog);
const ScopePtr& globalScope, std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope, FrontendOptions options,
bool recordJsonLog);

} // namespace Luau
3 changes: 3 additions & 0 deletions Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,13 @@ class Normalizer
bool intersectTyvarsWithTy(NormalizedTyvars& here, TypeId there);
bool intersectNormals(NormalizedType& here, const NormalizedType& there, int ignoreSmallerTyvars = -1);
bool intersectNormalWithTy(NormalizedType& here, TypeId there);
bool normalizeIntersections(const std::vector<TypeId>& intersections, NormalizedType& outType);

// Check for inhabitance
bool isInhabited(TypeId ty, std::unordered_set<TypeId> seen = {});
bool isInhabited(const NormalizedType* norm, std::unordered_set<TypeId> seen = {});
// Check for intersections being inhabited
bool isIntersectionInhabited(TypeId left, TypeId right);

// -------- Convert back from a normalized type to a type
TypeId typeFromNormal(const NormalizedType& norm);
Expand Down
35 changes: 31 additions & 4 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ struct MagicFunctionCallContext
TypePackId result;
};

using DcrMagicFunction = bool (*)(MagicFunctionCallContext);
using DcrMagicFunction = std::function<bool(MagicFunctionCallContext)>;

struct MagicRefinementContext
{
Expand Down Expand Up @@ -379,12 +379,39 @@ struct TableIndexer

struct Property
{
TypeId type;
static Property readonly(TypeId ty);
static Property writeonly(TypeId ty);
static Property rw(TypeId ty); // Shared read-write type.
static Property rw(TypeId read, TypeId write); // Separate read-write type.
static std::optional<Property> create(std::optional<TypeId> read, std::optional<TypeId> write);

bool deprecated = false;
std::string deprecatedSuggestion;
std::optional<Location> location = std::nullopt;
Tags tags;
std::optional<std::string> documentationSymbol;

// DEPRECATED
// TODO: Kill all constructors in favor of `Property::rw(TypeId read, TypeId write)` and friends.
Property();
Property(TypeId readTy, bool deprecated = false, const std::string& deprecatedSuggestion = "", std::optional<Location> location = std::nullopt,
const Tags& tags = {}, const std::optional<std::string>& documentationSymbol = std::nullopt);

// DEPRECATED: Should only be called in non-RWP! We assert that the `readTy` is not nullopt.
// TODO: Kill once we don't have non-RWP.
TypeId type() const;
void setType(TypeId ty);

// Should only be called in RWP!
// We do not assert that `readTy` nor `writeTy` are nullopt or not.
// The invariant is that at least one of them mustn't be nullopt, which we do assert here.
// TODO: Kill this in favor of exposing `readTy`/`writeTy` directly? If we do, we'll lose the asserts which will be useful while debugging.
std::optional<TypeId> readType() const;
std::optional<TypeId> writeType() const;

private:
std::optional<TypeId> readTy;
std::optional<TypeId> writeTy;
};

struct TableType
Expand Down Expand Up @@ -552,7 +579,7 @@ struct IntersectionType
struct LazyType
{
LazyType() = default;
LazyType(std::function<TypeId()> thunk_DEPRECATED, std::function<TypeId(LazyType&)> unwrap)
LazyType(std::function<TypeId()> thunk_DEPRECATED, std::function<void(LazyType&)> unwrap)
: thunk_DEPRECATED(thunk_DEPRECATED)
, unwrap(unwrap)
{
Expand Down Expand Up @@ -593,7 +620,7 @@ struct LazyType

std::function<TypeId()> thunk_DEPRECATED;

std::function<TypeId(LazyType&)> unwrap;
std::function<void(LazyType&)> unwrap;
std::atomic<TypeId> unwrapped = nullptr;
};

Expand Down
7 changes: 1 addition & 6 deletions Analysis/include/Luau/TypeInfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Luau/TxnLog.h"
#include "Luau/Type.h"
#include "Luau/TypePack.h"
#include "Luau/TypeUtils.h"
#include "Luau/Unifier.h"
#include "Luau/UnifierSharedState.h"

Expand Down Expand Up @@ -58,12 +59,6 @@ class TimeLimitError : public InternalCompilerError
}
};

enum class ValueContext
{
LValue,
RValue
};

struct GlobalTypes
{
GlobalTypes(NotNull<BuiltinTypes> builtinTypes);
Expand Down
6 changes: 6 additions & 0 deletions Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ namespace Luau
struct TxnLog;
struct TypeArena;

enum class ValueContext
{
LValue,
RValue
};

using ScopePtr = std::shared_ptr<struct Scope>;

std::optional<TypeId> findMetatableEntry(
Expand Down
8 changes: 4 additions & 4 deletions Analysis/include/Luau/VisitType.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "Luau/Type.h"

LUAU_FASTINT(LuauVisitRecursionLimit)
LUAU_FASTFLAG(LuauBoundLazyTypes)
LUAU_FASTFLAG(LuauBoundLazyTypes2)

namespace Luau
{
Expand Down Expand Up @@ -242,7 +242,7 @@ struct GenericTypeVisitor
else
{
for (auto& [_name, prop] : ttv->props)
traverse(prop.type);
traverse(prop.type());

if (ttv->indexer)
{
Expand All @@ -265,7 +265,7 @@ struct GenericTypeVisitor
if (visit(ty, *ctv))
{
for (const auto& [name, prop] : ctv->props)
traverse(prop.type);
traverse(prop.type());

if (ctv->parent)
traverse(*ctv->parent);
Expand Down Expand Up @@ -294,7 +294,7 @@ struct GenericTypeVisitor
}
else if (auto ltv = get<LazyType>(ty))
{
if (FFlag::LuauBoundLazyTypes)
if (FFlag::LuauBoundLazyTypes2)
{
if (TypeId unwrapped = ltv->unwrapped)
traverse(unwrapped);
Expand Down
4 changes: 2 additions & 2 deletions Analysis/src/AstQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,12 +501,12 @@ std::optional<DocumentationSymbol> getDocumentationSymbolAtPosition(const Source
if (const TableType* ttv = get<TableType>(parentTy))
{
if (auto propIt = ttv->props.find(indexName->index.value); propIt != ttv->props.end())
return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol);
return checkOverloadedDocumentationSymbol(module, propIt->second.type(), parentExpr, propIt->second.documentationSymbol);
}
else if (const ClassType* ctv = get<ClassType>(parentTy))
{
if (auto propIt = ctv->props.find(indexName->index.value); propIt != ctv->props.end())
return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol);
return checkOverloadedDocumentationSymbol(module, propIt->second.type(), parentExpr, propIt->second.documentationSymbol);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
// already populated, it takes precedence over the property we found just now.
if (result.count(name) == 0 && name != kParseNameError)
{
Luau::TypeId type = Luau::follow(prop.type);
Luau::TypeId type = Luau::follow(prop.type());
TypeCorrectKind typeCorrect = indexType == PropIndexType::Key
? TypeCorrectKind::Correct
: checkTypeCorrectKind(module, typeArena, builtinTypes, nodes.back(), {{}, {}}, type);
Expand All @@ -287,7 +287,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
auto indexIt = mtable->props.find("__index");
if (indexIt != mtable->props.end())
{
TypeId followed = follow(indexIt->second.type);
TypeId followed = follow(indexIt->second.type());
if (get<TableType>(followed) || get<MetatableType>(followed))
{
autocompleteProps(module, typeArena, builtinTypes, rootTy, followed, indexType, nodes, result, seen);
Expand Down
7 changes: 4 additions & 3 deletions Analysis/src/BuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ TypeId makeIntersection(TypeArena& arena, std::vector<TypeId>&& types)

TypeId makeOption(NotNull<BuiltinTypes> builtinTypes, TypeArena& arena, TypeId t)
{
LUAU_ASSERT(t);
return makeUnion(arena, {builtinTypes->nilType, t});
}

Expand Down Expand Up @@ -236,7 +237,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
auto it = stringMetatableTable->props.find("__index");
LUAU_ASSERT(it != stringMetatableTable->props.end());

addGlobalBinding(globals, "string", it->second.type, "@luau");
addGlobalBinding(globals, "string", it->second.type(), "@luau");

// next<K, V>(t: Table<K, V>, i: K?) -> (K?, V)
TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(builtinTypes, arena, genericK)}});
Expand Down Expand Up @@ -301,8 +302,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
ttv->props["foreach"].deprecated = true;
ttv->props["foreachi"].deprecated = true;

attachMagicFunction(ttv->props["pack"].type, magicFunctionPack);
attachDcrMagicFunction(ttv->props["pack"].type, dcrMagicFunctionPack);
attachMagicFunction(ttv->props["pack"].type(), magicFunctionPack);
attachDcrMagicFunction(ttv->props["pack"].type(), dcrMagicFunctionPack);
}

attachMagicFunction(getGlobalBinding(globals, "require"), magicFunctionRequire);
Expand Down
39 changes: 37 additions & 2 deletions Analysis/src/Clone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

LUAU_FASTFLAG(DebugLuauCopyBeforeNormalizing)
LUAU_FASTFLAG(LuauClonePublicInterfaceLess2)
LUAU_FASTFLAG(DebugLuauReadWriteProperties)

LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)

Expand All @@ -17,6 +18,40 @@ namespace Luau
namespace
{

Property clone(const Property& prop, TypeArena& dest, CloneState& cloneState)
{
if (FFlag::DebugLuauReadWriteProperties)
{
std::optional<TypeId> cloneReadTy;
if (auto ty = prop.readType())
cloneReadTy = clone(*ty, dest, cloneState);

std::optional<TypeId> cloneWriteTy;
if (auto ty = prop.writeType())
cloneWriteTy = clone(*ty, dest, cloneState);

std::optional<Property> cloned = Property::create(cloneReadTy, cloneWriteTy);
LUAU_ASSERT(cloned);
cloned->deprecated = prop.deprecated;
cloned->deprecatedSuggestion = prop.deprecatedSuggestion;
cloned->location = prop.location;
cloned->tags = prop.tags;
cloned->documentationSymbol = prop.documentationSymbol;
return *cloned;
}
else
{
return Property{
clone(prop.type(), dest, cloneState),
prop.deprecated,
prop.deprecatedSuggestion,
prop.location,
prop.tags,
prop.documentationSymbol,
};
}
}

struct TypePackCloner;

/*
Expand Down Expand Up @@ -251,7 +286,7 @@ void TypeCloner::operator()(const TableType& t)
ttv->boundTo = clone(*t.boundTo, dest, cloneState);

for (const auto& [name, prop] : t.props)
ttv->props[name] = {clone(prop.type, dest, cloneState), prop.deprecated, {}, prop.location, prop.tags};
ttv->props[name] = clone(prop, dest, cloneState);

if (t.indexer)
ttv->indexer = TableIndexer{clone(t.indexer->indexType, dest, cloneState), clone(t.indexer->indexResultType, dest, cloneState)};
Expand Down Expand Up @@ -285,7 +320,7 @@ void TypeCloner::operator()(const ClassType& t)
seenTypes[typeId] = result;

for (const auto& [name, prop] : t.props)
ctv->props[name] = {clone(prop.type, dest, cloneState), prop.deprecated, {}, prop.location, prop.tags};
ctv->props[name] = clone(prop, dest, cloneState);

if (t.parent)
ctv->parent = clone(*t.parent, dest, cloneState);
Expand Down
Loading

0 comments on commit 4b267aa

Please sign in to comment.