Skip to content

Commit

Permalink
Sync to upstream/release/591 (#1012)
Browse files Browse the repository at this point in the history
* Fix a use-after-free bug in the new type cloning algorithm
* Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f:
(A...) -> R...) -> ((A...) -> R...)`
* Break `.luaurc` out into a separate library target `Luau.Config`. This
makes it easier for applications to reason about config files without
also depending on the type inference engine.
* Move typechecking limits into `FrontendOptions`. This allows embedders
more finely-grained control over autocomplete's internal time limits.
* Fix stability issue with debugger onprotectederror callback allowing
break in non-yieldable contexts

New solver:

* Initial work toward [Local Type
Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md)
* Introduce a new subtyping test. This will be much nicer than the old
test because it is completely separate both from actual type inference
and from error reporting.

Native code generation:

* Added function to compute iterated dominance frontier
* Optimize barriers in SET_UPVALUE when tag is known
* Cache lua_State::global in a register on A64
* Optimize constant stores in A64 lowering
* Track table array size state to optimize array size checks
* Add split tag/value store into a VM register
* Check that spills can outlive the block only in specific conditions

---------

Co-authored-by: Arseny Kapoulkine <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
3 people authored Aug 18, 2023
1 parent a2a4710 commit e25b0a6
Show file tree
Hide file tree
Showing 63 changed files with 1,977 additions and 425 deletions.
2 changes: 0 additions & 2 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,6 @@ struct ConstraintSolver
TypeId errorRecoveryType() const;
TypePackId errorRecoveryTypePack() const;

TypeId unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope, bool unifyFreeTypes);

TypePackId anyifyModuleReturnTypePackGenerics(TypePackId tp);

void throwTimeLimitError();
Expand Down
6 changes: 6 additions & 0 deletions Analysis/include/Luau/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ struct FrontendOptions
std::optional<LintOptions> enabledLintWarnings;

std::shared_ptr<FrontendCancellationToken> cancellationToken;

// Time limit for typechecking a single module
std::optional<double> moduleTimeLimitSec;

// When true, some internal complexity limits will be scaled down for modules that miss the limit set by moduleTimeLimitSec
bool applyInternalLimitScaling = false;
};

struct CheckResult
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 @@ -111,6 +111,7 @@ struct Module
LintResult lintResult;
Mode mode;
SourceCode::Type type;
double checkDurationSec = 0.0;
bool timeout = false;
bool cancelled = false;

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

#include "Luau/Type.h"

#include <vector>
#include <optional>

namespace Luau
{

template<typename A, typename B>
struct TryPair;

class Normalizer;
struct NormalizedType;

struct SubtypingGraph
{
// Did the test succeed?
bool isSubtype = false;
bool isErrorSuppressing = false;
bool normalizationTooComplex = false;

// If so, what constraints are implied by this relation?
// If not, what happened?

SubtypingGraph and_(const SubtypingGraph& other);
SubtypingGraph or_(const SubtypingGraph& other);

static SubtypingGraph and_(const std::vector<SubtypingGraph>& results);
static SubtypingGraph or_(const std::vector<SubtypingGraph>& results);
};

struct Subtyping
{
NotNull<BuiltinTypes> builtinTypes;
NotNull<Normalizer> normalizer;

// TODO cache
// TODO cyclic types
// TODO recursion limits

SubtypingGraph isSubtype(TypeId subTy, TypeId superTy);
SubtypingGraph isSubtype(TypePackId subTy, TypePackId superTy);

private:
template<typename SubTy, typename SuperTy>
SubtypingGraph isSubtype(const TryPair<const SubTy*, const SuperTy*>& pair);

SubtypingGraph isSubtype(TypeId subTy, const UnionType* superUnion);
SubtypingGraph isSubtype(const UnionType* subUnion, TypeId superTy);
SubtypingGraph isSubtype(TypeId subTy, const IntersectionType* superIntersection);
SubtypingGraph isSubtype(const IntersectionType* subIntersection, TypeId superTy);
SubtypingGraph isSubtype(const PrimitiveType* subPrim, const PrimitiveType* superPrim);
SubtypingGraph isSubtype(const SingletonType* subSingleton, const PrimitiveType* superPrim);
SubtypingGraph isSubtype(const SingletonType* subSingleton, const SingletonType* superSingleton);
SubtypingGraph isSubtype(const FunctionType* subFunction, const FunctionType* superFunction);

SubtypingGraph isSubtype(const NormalizedType* subNorm, const NormalizedType* superNorm);
};

} // namespace Luau
9 changes: 9 additions & 0 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,9 +733,17 @@ struct Type final
using SeenSet = std::set<std::pair<const void*, const void*>>;
bool areEqual(SeenSet& seen, const Type& lhs, const Type& rhs);

enum class FollowOption
{
Normal,
DisableLazyTypeThunks,
};

// Follow BoundTypes until we get to something real
TypeId follow(TypeId t);
TypeId follow(TypeId t, FollowOption followOption);
TypeId follow(TypeId t, const void* context, TypeId (*mapper)(const void*, TypeId));
TypeId follow(TypeId t, FollowOption followOption, const void* context, TypeId (*mapper)(const void*, TypeId));

std::vector<TypeId> flattenIntersection(TypeId ty);

Expand Down Expand Up @@ -818,6 +826,7 @@ struct BuiltinTypes
const TypeId optionalNumberType;
const TypeId optionalStringType;

const TypePackId emptyTypePack;
const TypePackId anyTypePack;
const TypePackId neverTypePack;
const TypePackId uninhabitableTypePack;
Expand Down
24 changes: 24 additions & 0 deletions Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@ ErrorSuppression shouldSuppressErrors(NotNull<Normalizer> normalizer, TypeId ty1
*/
ErrorSuppression shouldSuppressErrors(NotNull<Normalizer> normalizer, TypePackId tp1, TypePackId tp2);

// Similar to `std::optional<std::pair<A, B>>`, but whose `sizeof()` is the same as `std::pair<A, B>`
// and cooperates with C++'s `if (auto p = ...)` syntax without the extra fatness of `std::optional`.
template<typename A, typename B>
struct TryPair {
A first;
B second;

operator bool() const
{
return bool(first) && bool(second);
}
};

template<typename A, typename B, typename Ty>
TryPair<const A*, const B*> get2(Ty one, Ty two)
{
const A* a = get<A>(one);
const B* b = get<B>(two);
if (a && b)
return {a, b};
else
return {nullptr, nullptr};
}

template<typename T, typename Ty>
const T* get(std::optional<Ty> ty)
{
Expand Down
3 changes: 1 addition & 2 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include <utility>

LUAU_FASTFLAG(DebugLuauReadWriteProperties)
LUAU_FASTFLAGVARIABLE(LuauDisableCompletionOutsideQuotes, false)
LUAU_FASTFLAGVARIABLE(LuauAnonymousAutofilled1, false);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteLastTypecheck, false)
LUAU_FASTFLAGVARIABLE(LuauAutocompleteHideSelfArg, false)
Expand Down Expand Up @@ -1345,7 +1344,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
return std::nullopt;
}

if (FFlag::LuauDisableCompletionOutsideQuotes && !nodes.back()->is<AstExprError>())
if (!nodes.back()->is<AstExprError>())
{
if (nodes.back()->location.end == position || nodes.back()->location.begin == position)
{
Expand Down
37 changes: 15 additions & 22 deletions Analysis/src/Clone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Luau/NotNull.h"
#include "Luau/RecursionCounter.h"
#include "Luau/TxnLog.h"
#include "Luau/Type.h"
#include "Luau/TypePack.h"
#include "Luau/Unifiable.h"

Expand All @@ -14,7 +15,7 @@ LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)
LUAU_FASTFLAGVARIABLE(LuauCloneCyclicUnions, false)

LUAU_FASTFLAGVARIABLE(LuauStacklessTypeClone, false)
LUAU_FASTFLAGVARIABLE(LuauStacklessTypeClone2, false)
LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)

namespace Luau
Expand Down Expand Up @@ -115,13 +116,15 @@ class TypeCloner2

std::optional<TypeId> find(TypeId ty) const
{
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
if (auto it = types->find(ty); it != types->end())
return it->second;
return std::nullopt;
}

std::optional<TypePackId> find(TypePackId tp) const
{
tp = follow(tp);
if (auto it = packs->find(tp); it != packs->end())
return it->second;
return std::nullopt;
Expand All @@ -143,43 +146,33 @@ class TypeCloner2
private:
TypeId shallowClone(TypeId ty)
{
// We want to [`Luau::follow`] but without forcing the expansion of [`LazyType`]s.
ty = follow(ty, FollowOption::DisableLazyTypeThunks);

if (auto clone = find(ty))
return *clone;
else if (ty->persistent)
return ty;

// We want to [`Luau::follow`] but without forcing the expansion of [`LazyType`]s.
TypeId target = nullptr;
if (auto bt = get<BoundType>(ty))
target = bt->boundTo;
else if (auto tt = get<TableType>(ty); tt && tt->boundTo)
target = *tt->boundTo;
else
{
target = arena->addType(ty->ty);
asMutable(target)->documentationSymbol = ty->documentationSymbol;
}
TypeId target = arena->addType(ty->ty);
asMutable(target)->documentationSymbol = ty->documentationSymbol;

LUAU_ASSERT(target);
(*types)[ty] = target;
queue.push_back(target);
return target;
}

TypePackId shallowClone(TypePackId tp)
{
tp = follow(tp);

if (auto clone = find(tp))
return *clone;
else if (tp->persistent)
return tp;

TypePackId target;
if (auto btp = get<BoundTypePack>(tp))
target = btp->boundTo;
else
target = arena->addTypePack(tp->ty);
TypePackId target = arena->addTypePack(tp->ty);

LUAU_ASSERT(target);
(*packs)[tp] = target;
queue.push_back(target);
return target;
Expand Down Expand Up @@ -883,7 +876,7 @@ TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState)
if (tp->persistent)
return tp;

if (FFlag::LuauStacklessTypeClone)
if (FFlag::LuauStacklessTypeClone2)
{
TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
return cloner.clone(tp);
Expand All @@ -909,7 +902,7 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)
if (typeId->persistent)
return typeId;

if (FFlag::LuauStacklessTypeClone)
if (FFlag::LuauStacklessTypeClone2)
{
TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
return cloner.clone(typeId);
Expand Down Expand Up @@ -938,7 +931,7 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)

TypeFun clone(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState)
{
if (FFlag::LuauStacklessTypeClone)
if (FFlag::LuauStacklessTypeClone2)
{
TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};

Expand Down
35 changes: 0 additions & 35 deletions Analysis/src/ConstraintSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2727,41 +2727,6 @@ TypePackId ConstraintSolver::errorRecoveryTypePack() const
return builtinTypes->errorRecoveryTypePack();
}

TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope, bool unifyFreeTypes)
{
a = follow(a);
b = follow(b);

if (unifyFreeTypes && (get<FreeType>(a) || get<FreeType>(b)))
{
Unifier u{normalizer, scope, Location{}, Covariant};
u.enableNewSolver();
u.tryUnify(b, a);

if (u.errors.empty())
{
u.log.commit();
return a;
}
else
{
return builtinTypes->errorRecoveryType(builtinTypes->anyType);
}
}

if (*a == *b)
return a;

std::vector<TypeId> types = reduceUnion({a, b});
if (types.empty())
return builtinTypes->neverType;

if (types.size() == 1)
return types[0];

return arena->addType(UnionType{types});
}

TypePackId ConstraintSolver::anyifyModuleReturnTypePackGenerics(TypePackId tp)
{
tp = follow(tp);
Expand Down
3 changes: 1 addition & 2 deletions Analysis/src/EmbeddedBuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ declare coroutine: {
resume: <A..., R...>(co: thread, A...) -> (boolean, R...),
running: () -> thread,
status: (co: thread) -> "dead" | "running" | "normal" | "suspended",
-- FIXME: This technically returns a function, but we can't represent this yet.
wrap: <A..., R...>(f: (A...) -> R...) -> any,
wrap: <A..., R...>(f: (A...) -> R...) -> ((A...) -> R...),
yield: <A..., R...>(A...) -> R...,
isyieldable: () -> boolean,
close: (co: thread) -> (boolean, any)
Expand Down
Loading

0 comments on commit e25b0a6

Please sign in to comment.