Skip to content

Commit

Permalink
Sync to upstream/release/552 (#735)
Browse files Browse the repository at this point in the history
* Reduce the stack utilization of type checking.
* Improve the error message that's reported when a delimiting comma is
missing from a table literal. eg
```lua
local t = {
    first = 1
    second = 2
}```
  • Loading branch information
andyfriesen authored Nov 4, 2022
1 parent e43a9e9 commit c33700e
Show file tree
Hide file tree
Showing 78 changed files with 3,124 additions and 3,049 deletions.
68 changes: 68 additions & 0 deletions Analysis/include/Luau/Connective.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "Luau/Def.h"
#include "Luau/TypedAllocator.h"
#include "Luau/TypeVar.h"
#include "Luau/Variant.h"

#include <memory>

namespace Luau
{

struct Negation;
struct Conjunction;
struct Disjunction;
struct Equivalence;
struct Proposition;
using Connective = Variant<Negation, Conjunction, Disjunction, Equivalence, Proposition>;
using ConnectiveId = Connective*; // Can and most likely is nullptr.

struct Negation
{
ConnectiveId connective;
};

struct Conjunction
{
ConnectiveId lhs;
ConnectiveId rhs;
};

struct Disjunction
{
ConnectiveId lhs;
ConnectiveId rhs;
};

struct Equivalence
{
ConnectiveId lhs;
ConnectiveId rhs;
};

struct Proposition
{
DefId def;
TypeId discriminantTy;
};

template<typename T>
const T* get(ConnectiveId connective)
{
return get_if<T>(connective);
}

struct ConnectiveArena
{
TypedAllocator<Connective> allocator;

ConnectiveId negation(ConnectiveId connective);
ConnectiveId conjunction(ConnectiveId lhs, ConnectiveId rhs);
ConnectiveId disjunction(ConnectiveId lhs, ConnectiveId rhs);
ConnectiveId equivalence(ConnectiveId lhs, ConnectiveId rhs);
ConnectiveId proposition(DefId def, TypeId discriminantTy);
};

} // namespace Luau
7 changes: 4 additions & 3 deletions Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,16 @@ struct HasPropConstraint
std::string prop;
};

struct RefinementConstraint
// result ~ if isSingleton D then ~D else unknown where D = discriminantType
struct SingletonOrTopTypeConstraint
{
DefId def;
TypeId resultType;
TypeId discriminantType;
};

using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint,
BinaryConstraint, IterableConstraint, NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, PrimitiveTypeConstraint,
HasPropConstraint, RefinementConstraint>;
HasPropConstraint, SingletonOrTopTypeConstraint>;

struct Constraint
{
Expand Down
19 changes: 14 additions & 5 deletions Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include "Luau/Ast.h"
#include "Luau/Connective.h"
#include "Luau/Constraint.h"
#include "Luau/DataFlowGraphBuilder.h"
#include "Luau/Module.h"
Expand All @@ -26,23 +27,27 @@ struct DcrLogger;
struct Inference
{
TypeId ty = nullptr;
ConnectiveId connective = nullptr;

Inference() = default;

explicit Inference(TypeId ty)
explicit Inference(TypeId ty, ConnectiveId connective = nullptr)
: ty(ty)
, connective(connective)
{
}
};

struct InferencePack
{
TypePackId tp = nullptr;
std::vector<ConnectiveId> connectives;

InferencePack() = default;

explicit InferencePack(TypePackId tp)
explicit InferencePack(TypePackId tp, const std::vector<ConnectiveId>& connectives = {})
: tp(tp)
, connectives(connectives)
{
}
};
Expand Down Expand Up @@ -73,6 +78,7 @@ struct ConstraintGraphBuilder
// Defining scopes for AST nodes.
DenseHashMap<const AstStatTypeAlias*, ScopePtr> astTypeAliasDefiningScopes{nullptr};
NotNull<const DataFlowGraph> dfg;
ConnectiveArena connectiveArena;

int recursionCount = 0;

Expand Down Expand Up @@ -126,6 +132,8 @@ struct ConstraintGraphBuilder
*/
NotNull<Constraint> addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c);

void applyRefinements(const ScopePtr& scope, Location location, ConnectiveId connective);

/**
* The entry point to the ConstraintGraphBuilder. This will construct a set
* of scopes, constraints, and free types that can be solved later.
Expand Down Expand Up @@ -167,10 +175,10 @@ 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 = {});
Inference check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType = {}, bool forceSingleton = false);

Inference check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType);
Inference check(const ScopePtr& scope, AstExprConstantBool* bool_, std::optional<TypeId> expectedType);
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, AstExprGlobal* global);
Inference check(const ScopePtr& scope, AstExprIndexName* indexName);
Expand All @@ -180,6 +188,7 @@ struct ConstraintGraphBuilder
Inference check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType);
Inference check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert);
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
std::tuple<TypeId, TypeId, ConnectiveId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);

TypePackId checkLValues(const ScopePtr& scope, AstArray<AstExpr*> exprs);

Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ struct ConstraintSolver
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const RefinementConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const SingletonOrTopTypeConstraint& c, NotNull<const Constraint> constraint);

// for a, ... in some_table do
// also handles __iter metamethod
Expand Down
40 changes: 27 additions & 13 deletions Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ struct SingletonTypes;

using ModulePtr = std::shared_ptr<Module>;

bool isSubtype(
TypeId subTy, TypeId superTy, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice, bool anyIsTop = true);
bool isSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice,
bool anyIsTop = true);
bool isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice);
bool isSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice);

class TypeIds
{
Expand Down Expand Up @@ -169,12 +167,26 @@ struct NormalizedStringType

bool isSubtype(const NormalizedStringType& subStr, const NormalizedStringType& superStr);

// A normalized function type is either `never` (represented by `nullopt`)
// A normalized function type can be `never`, the top function type `function`,
// or an intersection of function types.
// NOTE: type normalization can fail on function types with generics
// (e.g. because we do not support unions and intersections of generic type packs),
// so this type may contain `error`.
using NormalizedFunctionType = std::optional<TypeIds>;
//
// NOTE: type normalization can fail on function types with generics (e.g.
// because we do not support unions and intersections of generic type packs), so
// this type may contain `error`.
struct NormalizedFunctionType
{
NormalizedFunctionType();

bool isTop = false;
// TODO: Remove this wrapping optional when clipping
// FFlagLuauNegatedFunctionTypes.
std::optional<TypeIds> parts;

void resetToNever();
void resetToTop();

bool isNever() const;
};

// A normalized generic/free type is a union, where each option is of the form (X & T) where
// * X is either a free type or a generic
Expand Down Expand Up @@ -234,12 +246,14 @@ struct NormalizedType

NormalizedType(NotNull<SingletonTypes> singletonTypes);

NormalizedType(const NormalizedType&) = delete;
NormalizedType(NormalizedType&&) = default;
NormalizedType() = delete;
~NormalizedType() = default;

NormalizedType(const NormalizedType&) = delete;
NormalizedType& operator=(const NormalizedType&) = delete;

NormalizedType(NormalizedType&&) = default;
NormalizedType& operator=(NormalizedType&&) = default;
NormalizedType& operator=(NormalizedType&) = delete;
};

class Normalizer
Expand Down Expand Up @@ -291,7 +305,7 @@ class Normalizer
bool unionNormalWithTy(NormalizedType& here, TypeId there, int ignoreSmallerTyvars = -1);

// ------- Negations
NormalizedType negateNormal(const NormalizedType& here);
std::optional<NormalizedType> negateNormal(const NormalizedType& here);
TypeIds negateAll(const TypeIds& theres);
TypeId negate(TypeId there);
void subtractPrimitive(NormalizedType& here, TypeId ty);
Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ std::vector<TypeId> flatten(TypeArena& arena, NotNull<SingletonTypes> singletonT
* identity) types.
* @param types the input type list to reduce.
* @returns the reduced type list.
*/
*/
std::vector<TypeId> reduceUnion(const std::vector<TypeId>& types);

/**
Expand All @@ -45,7 +45,7 @@ std::vector<TypeId> reduceUnion(const std::vector<TypeId>& types);
* @param arena the type arena to allocate the new type in, if necessary
* @param ty the type to remove nil from
* @returns a type with nil removed, or nil itself if that were the only option.
*/
*/
TypeId stripNil(NotNull<SingletonTypes> singletonTypes, TypeArena& arena, TypeId ty);

} // namespace Luau
18 changes: 6 additions & 12 deletions Analysis/include/Luau/TypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ struct PrimitiveTypeVar
Number,
String,
Thread,
Function,
};

Type type;
Expand Down Expand Up @@ -504,14 +505,6 @@ struct NeverTypeVar
{
};

// Invariant 1: there should never be a reason why such UseTypeVar exists without it mapping to another type.
// Invariant 2: UseTypeVar should always disappear across modules.
struct UseTypeVar
{
DefId def;
NotNull<Scope> scope;
};

// ~T
// TODO: Some simplification step that overwrites the type graph to make sure negation
// types disappear from the user's view, and (?) a debug flag to disable that
Expand All @@ -522,9 +515,9 @@ struct NegationTypeVar

using ErrorTypeVar = Unifiable::Error;

using TypeVariant = Unifiable::Variant<TypeId, PrimitiveTypeVar, BlockedTypeVar, PendingExpansionTypeVar, SingletonTypeVar, FunctionTypeVar,
TableTypeVar, MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar, UnknownTypeVar, NeverTypeVar,
UseTypeVar, NegationTypeVar>;
using TypeVariant =
Unifiable::Variant<TypeId, PrimitiveTypeVar, BlockedTypeVar, PendingExpansionTypeVar, SingletonTypeVar, FunctionTypeVar, TableTypeVar,
MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar, UnknownTypeVar, NeverTypeVar, NegationTypeVar>;

struct TypeVar final
{
Expand Down Expand Up @@ -644,13 +637,14 @@ struct SingletonTypes
const TypeId stringType;
const TypeId booleanType;
const TypeId threadType;
const TypeId functionType;
const TypeId trueType;
const TypeId falseType;
const TypeId anyType;
const TypeId unknownType;
const TypeId neverType;
const TypeId errorType;
const TypeId falsyType; // No type binding!
const TypeId falsyType; // No type binding!
const TypeId truthyType; // No type binding!

const TypePackId anyTypePack;
Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/Unifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ struct Unifier
ErrorVec errors;
Location location;
Variance variance = Covariant;
bool anyIsTop = false; // If true, we consider any to be a top type. If false, it is a familiar but weird mix of top and bottom all at once.
bool normalize; // Normalize unions and intersections if necessary
bool useScopes = false; // If true, we use the scope hierarchy rather than TypeLevels
CountMismatch::Context ctx = CountMismatch::Arg;
Expand Down Expand Up @@ -131,6 +130,7 @@ struct Unifier
Unifier makeChildUnifier();

void reportError(TypeError err);
LUAU_NOINLINE void reportError(Location location, TypeErrorData data);

private:
bool isNonstrictMode() const;
Expand Down
7 changes: 4 additions & 3 deletions Analysis/include/Luau/Variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ class Variant

constexpr int tid = getTypeId<T>();
typeId = tid;
new (&storage) TT(value);
new (&storage) TT(std::forward<T>(value));
}

Variant(const Variant& other)
{
static constexpr FnCopy table[sizeof...(Ts)] = {&fnCopy<Ts>...};

typeId = other.typeId;
tableCopy[typeId](&storage, &other.storage);
table[typeId](&storage, &other.storage);
}

Variant(Variant&& other)
Expand Down Expand Up @@ -192,7 +194,6 @@ class Variant
return *static_cast<const T*>(lhs) == *static_cast<const T*>(rhs);
}

static constexpr FnCopy tableCopy[sizeof...(Ts)] = {&fnCopy<Ts>...};
static constexpr FnMove tableMove[sizeof...(Ts)] = {&fnMove<Ts>...};
static constexpr FnDtor tableDtor[sizeof...(Ts)] = {&fnDtor<Ts>...};

Expand Down
6 changes: 0 additions & 6 deletions Analysis/include/Luau/VisitTypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,6 @@ struct GenericTypeVarVisitor
{
return visit(ty);
}
virtual bool visit(TypeId ty, const UseTypeVar& utv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const NegationTypeVar& ntv)
{
return visit(ty);
Expand Down Expand Up @@ -321,8 +317,6 @@ struct GenericTypeVarVisitor
traverse(a);
}
}
else if (auto utv = get<UseTypeVar>(ty))
visit(ty, *utv);
else if (auto ntv = get<NegationTypeVar>(ty))
visit(ty, *ntv);
else if (!FFlag::LuauCompleteVisitor)
Expand Down
3 changes: 1 addition & 2 deletions Analysis/src/BuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,7 @@ static bool dcrMagicFunctionPack(MagicFunctionCallContext context)
result = arena->addType(UnionTypeVar{std::move(options)});

TypeId numberType = context.solver->singletonTypes->numberType;
TypeId packedTable = arena->addType(
TableTypeVar{{{"n", {numberType}}}, TableIndexer(numberType, result), {}, TableState::Sealed});
TypeId packedTable = arena->addType(TableTypeVar{{{"n", {numberType}}}, TableIndexer(numberType, result), {}, TableState::Sealed});

TypePackId tableTypePack = arena->addTypePack({packedTable});
asMutable(context.result)->ty.emplace<BoundTypePack>(tableTypePack);
Expand Down
Loading

0 comments on commit c33700e

Please sign in to comment.