Skip to content

Commit

Permalink
Sync to upstream/release/551 (#727)
Browse files Browse the repository at this point in the history
* luau-lang/luau#719
* Improved `Failed to unify type packs` error message to be reported as
`Type pack 'X' could not be converted into 'Y'`
* luau-lang/luau#722
* 1% reduction in executed instruction count by removing a check in fast
call dispatch
* Additional fixes to reported error location of OOM errors in VM
* Improve `math.sqrt`, `math.floor` and `math.ceil` performance on
additional compilers and platforms (1-2% geomean improvement including
8-9% on math-cordic)
* All thrown exceptions by Luau analysis are derived from
`Luau::InternalCompilerError`
* When a call site has fewer arguments than required, error now reports
the location of the function name instead of the argument to the
function
* luau-lang/luau#724
* Fixed luau-lang/luau#725

Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
  • Loading branch information
3 people committed Oct 28, 2022
1 parent c1987e2 commit 09e76ef
Show file tree
Hide file tree
Showing 65 changed files with 3,059 additions and 882 deletions.
57 changes: 42 additions & 15 deletions Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,30 @@ using ScopePtr = std::shared_ptr<Scope>;

struct DcrLogger;

struct Inference
{
TypeId ty = nullptr;

Inference() = default;

explicit Inference(TypeId ty)
: ty(ty)
{
}
};

struct InferencePack
{
TypePackId tp = nullptr;

InferencePack() = default;

explicit InferencePack(TypePackId tp)
: tp(tp)
{
}
};

struct ConstraintGraphBuilder
{
// A list of all the scopes in the module. This vector holds ownership of the
Expand Down Expand Up @@ -130,8 +154,10 @@ struct ConstraintGraphBuilder
void visit(const ScopePtr& scope, AstStatDeclareFunction* declareFunction);
void visit(const ScopePtr& scope, AstStatError* error);

TypePackId checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<TypeId>& expectedTypes = {});
TypePackId checkPack(const ScopePtr& scope, AstExpr* expr, const std::vector<TypeId>& expectedTypes = {});
InferencePack checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<TypeId>& expectedTypes = {});
InferencePack checkPack(const ScopePtr& scope, AstExpr* expr, const std::vector<TypeId>& expectedTypes = {});

InferencePack checkPack(const ScopePtr& scope, AstExprCall* call, const std::vector<TypeId>& expectedTypes);

/**
* Checks an expression that is expected to evaluate to one type.
Expand All @@ -141,18 +167,19 @@ struct ConstraintGraphBuilder
* surrounding context. Used to implement bidirectional type checking.
* @return the type of the expression.
*/
TypeId check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType = {});

TypeId check(const ScopePtr& scope, AstExprLocal* local);
TypeId check(const ScopePtr& scope, AstExprGlobal* global);
TypeId check(const ScopePtr& scope, AstExprIndexName* indexName);
TypeId check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
TypeId check(const ScopePtr& scope, AstExprUnary* unary);
TypeId check_(const ScopePtr& scope, AstExprUnary* unary);
TypeId check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
TypeId check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType);
TypeId check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert);
TypeId check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
Inference check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType = {});

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, AstExprLocal* local);
Inference check(const ScopePtr& scope, AstExprGlobal* global);
Inference check(const ScopePtr& scope, AstExprIndexName* indexName);
Inference check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
Inference check(const ScopePtr& scope, AstExprUnary* unary);
Inference check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
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);

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

Expand Down Expand Up @@ -202,7 +229,7 @@ struct ConstraintGraphBuilder
std::vector<std::pair<Name, GenericTypeDefinition>> createGenerics(const ScopePtr& scope, AstArray<AstGenericType> generics);
std::vector<std::pair<Name, GenericTypePackDefinition>> createGenericPacks(const ScopePtr& scope, AstArray<AstGenericTypePack> packs);

TypeId flattenPack(const ScopePtr& scope, Location location, TypePackId tp);
Inference flattenPack(const ScopePtr& scope, Location location, InferencePack pack);

void reportError(Location location, TypeErrorData err);
void reportCodeTooComplex(Location location);
Expand Down
24 changes: 22 additions & 2 deletions Analysis/include/Luau/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "Luau/Variant.h"
#include "Luau/TypeArena.h"

LUAU_FASTFLAG(LuauIceExceptionInheritanceChange)

namespace Luau
{
struct TypeError;
Expand Down Expand Up @@ -302,12 +304,20 @@ struct NormalizationTooComplex
}
};

struct TypePackMismatch
{
TypePackId wantedTp;
TypePackId givenTp;

bool operator==(const TypePackMismatch& rhs) const;
};

using TypeErrorData = Variant<TypeMismatch, UnknownSymbol, UnknownProperty, NotATable, CannotExtendTable, OnlyTablesCanHaveMethods,
DuplicateTypeDefinition, CountMismatch, FunctionDoesNotTakeSelf, FunctionRequiresSelf, OccursCheckFailed, UnknownRequire,
IncorrectGenericParameterCount, SyntaxError, CodeTooComplex, UnificationTooComplex, UnknownPropButFoundLikeProp, GenericError, InternalError,
CannotCallNonFunction, ExtraInformation, DeprecatedApiUsed, ModuleHasCyclicDependency, IllegalRequire, FunctionExitsWithoutReturning,
DuplicateGenericParameter, CannotInferBinaryOperation, MissingProperties, SwappedGenericTypeParameter, OptionalValueAccess, MissingUnionProperty,
TypesAreUnrelated, NormalizationTooComplex>;
TypesAreUnrelated, NormalizationTooComplex, TypePackMismatch>;

struct TypeError
{
Expand Down Expand Up @@ -374,6 +384,10 @@ struct InternalErrorReporter
class InternalCompilerError : public std::exception
{
public:
explicit InternalCompilerError(const std::string& message)
: message(message)
{
}
explicit InternalCompilerError(const std::string& message, const std::string& moduleName)
: message(message)
, moduleName(moduleName)
Expand All @@ -388,8 +402,14 @@ class InternalCompilerError : public std::exception
virtual const char* what() const throw();

const std::string message;
const std::string moduleName;
const std::optional<std::string> moduleName;
const std::optional<Location> location;
};

// These two function overloads only exist to facilitate fast flagging a change to InternalCompilerError
// Both functions can be removed when FFlagLuauIceExceptionInheritanceChange is removed and calling code
// can directly throw InternalCompilerError.
[[noreturn]] void throwRuntimeError(const std::string& message);
[[noreturn]] void throwRuntimeError(const std::string& message, const std::string& moduleName);

} // namespace Luau
75 changes: 70 additions & 5 deletions Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,68 @@ struct std::equal_to<const Luau::TypeIds*>
namespace Luau
{

// A normalized string type is either `string` (represented by `nullopt`)
// or a union of string singletons.
using NormalizedStringType = std::optional<std::map<std::string, TypeId>>;
/** A normalized string type is either `string` (represented by `nullopt`) or a
* union of string singletons.
*
* When FFlagLuauNegatedStringSingletons is unset, the representation is as
* follows:
*
* * The `string` data type is represented by the option `singletons` having the
* value `std::nullopt`.
* * The type `never` is represented by `singletons` being populated with an
* empty map.
* * A union of string singletons is represented by a map populated by the names
* and TypeIds of the singletons contained therein.
*
* When FFlagLuauNegatedStringSingletons is set, the representation is as
* follows:
*
* * A union of string singletons is finite and includes the singletons named by
* the `singletons` field.
* * An intersection of negated string singletons is cofinite and includes the
* singletons excluded by the `singletons` field. It is implied that cofinite
* values are exclusions from `string` itself.
* * The `string` data type is a cofinite set minus zero elements.
* * The `never` data type is a finite set plus zero elements.
*/
struct NormalizedStringType
{
// When false, this type represents a union of singleton string types.
// eg "a" | "b" | "c"
//
// When true, this type represents string intersected with negated string
// singleton types.
// eg string & ~"a" & ~"b" & ...
bool isCofinite = false;

// TODO: This field cannot be nullopt when FFlagLuauNegatedStringSingletons
// is set. When clipping that flag, we can remove the wrapping optional.
std::optional<std::map<std::string, TypeId>> singletons;

void resetToString();
void resetToNever();

bool isNever() const;
bool isString() const;

/// Returns true if the string has finite domain.
///
/// Important subtlety: This method returns true for `never`. The empty set
/// is indeed an empty set.
bool isUnion() const;

/// Returns true if the string has infinite domain.
bool isIntersection() const;

bool includes(const std::string& str) const;

static const NormalizedStringType never;

NormalizedStringType() = default;
NormalizedStringType(bool isCofinite, std::optional<std::map<std::string, TypeId>> singletons);
};

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

// A normalized function type is either `never` (represented by `nullopt`)
// or an intersection of function types.
Expand Down Expand Up @@ -157,7 +216,7 @@ struct NormalizedType

// The string part of the type.
// This may be the `string` type, or a union of singletons.
NormalizedStringType strings = std::map<std::string, TypeId>{};
NormalizedStringType strings;

// The thread part of the type.
// This type is either never or thread.
Expand Down Expand Up @@ -231,8 +290,14 @@ class Normalizer
bool unionNormals(NormalizedType& here, const NormalizedType& there, int ignoreSmallerTyvars = -1);
bool unionNormalWithTy(NormalizedType& here, TypeId there, int ignoreSmallerTyvars = -1);

// ------- Negations
NormalizedType negateNormal(const NormalizedType& here);
TypeIds negateAll(const TypeIds& theres);
TypeId negate(TypeId there);
void subtractPrimitive(NormalizedType& here, TypeId ty);
void subtractSingleton(NormalizedType& here, TypeId ty);

// ------- Normalizing intersections
void intersectTysWithTy(TypeIds& here, TypeId there);
TypeId intersectionOfTops(TypeId here, TypeId there);
TypeId intersectionOfBools(TypeId here, TypeId there);
void intersectClasses(TypeIds& heres, const TypeIds& theres);
Expand Down
22 changes: 20 additions & 2 deletions Analysis/include/Luau/RecursionCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,28 @@
#pragma once

#include "Luau/Common.h"
#include "Luau/Error.h"

#include <stdexcept>
#include <exception>

namespace Luau
{

struct RecursionLimitException : public std::exception
struct RecursionLimitException : public InternalCompilerError
{
RecursionLimitException()
: InternalCompilerError("Internal recursion counter limit exceeded")
{
LUAU_ASSERT(FFlag::LuauIceExceptionInheritanceChange);
}
};

struct RecursionLimitException_DEPRECATED : public std::exception
{
const char* what() const noexcept
{
LUAU_ASSERT(!FFlag::LuauIceExceptionInheritanceChange);
return "Internal recursion counter limit exceeded";
}
};
Expand Down Expand Up @@ -42,7 +53,14 @@ struct RecursionLimiter : RecursionCounter
{
if (limit > 0 && *count > limit)
{
throw RecursionLimitException();
if (FFlag::LuauIceExceptionInheritanceChange)
{
throw RecursionLimitException();
}
else
{
throw RecursionLimitException_DEPRECATED();
}
}
}
};
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/ToString.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ inline std::string toStringNamedFunction(const std::string& funcName, const Func
return toStringNamedFunction(funcName, ftv, opts);
}

std::optional<std::string> getFunctionNameAsString(const AstExpr& expr);

// It could be useful to see the text representation of a type during a debugging session instead of exploring the content of the class
// These functions will dump the type to stdout and can be evaluated in Watch/Immediate windows or as gdb/lldb expression
std::string dump(TypeId ty);
Expand Down
13 changes: 12 additions & 1 deletion Analysis/include/Luau/TypeInfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,17 @@ struct HashBoolNamePair
size_t operator()(const std::pair<bool, Name>& pair) const;
};

class TimeLimitError : public std::exception
class TimeLimitError : public InternalCompilerError
{
public:
explicit TimeLimitError(const std::string& moduleName)
: InternalCompilerError("Typeinfer failed to complete in allotted time", moduleName)
{
LUAU_ASSERT(FFlag::LuauIceExceptionInheritanceChange);
}
};

class TimeLimitError_DEPRECATED : public std::exception
{
public:
virtual const char* what() const throw();
Expand Down Expand Up @@ -236,6 +246,7 @@ struct TypeChecker

[[noreturn]] void ice(const std::string& message, const Location& location);
[[noreturn]] void ice(const std::string& message);
[[noreturn]] void throwTimeLimitError();

ScopePtr childFunctionScope(const ScopePtr& parent, const Location& location, int subLevel = 0);
ScopePtr childScope(const ScopePtr& parent, const Location& location);
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/Unifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ struct Unifier
void tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed);
void tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed);
void tryUnifyWithClass(TypeId subTy, TypeId superTy, bool reversed);
void tryUnifyTypeWithNegation(TypeId subTy, TypeId superTy);
void tryUnifyNegationWithType(TypeId subTy, TypeId superTy);

TypePackId tryApplyOverloadedFunction(TypeId function, const NormalizedFunctionType& overloads, TypePackId args);

Expand Down

0 comments on commit 09e76ef

Please sign in to comment.