Skip to content

Commit

Permalink
Sync to upstream/release/577 (#934)
Browse files Browse the repository at this point in the history
Lots of things going on this week:

* Fix a crash that could occur in the presence of a cyclic union. We
shouldn't be creating cyclic unions, but we shouldn't be crashing when
they arise either.
* Minor cleanup of `luau_precall`
* Internal change to make L->top handling slightly more uniform
* Optimize SETGLOBAL & GETGLOBAL fallback C functions.
* #929
* The syntax to the `luau-reduce` commandline tool has changed. It now
accepts a script, a command to execute, and an error to search for. It
no longer automatically passes the script to the command which makes it
a lot more flexible. Also be warned that it edits the script it is
passed **in place**. Do not point it at something that is not in source
control!

New solver

* Switch to a greedier but more fallible algorithm for simplifying union
and intersection types that are created as part of refinement
calculation. This has much better and more predictable performance.
* Fix a constraint cycle in recursive function calls.
* Much improved inference of binary addition. Functions like `function
add(x, y) return x + y end` can now be inferred without annotations. We
also accurately typecheck calls to functions like this.
* Many small bugfixes surrounding things like table indexers
* Add support for indexers on class types. This was previously added to
the old solver; we now add it to the new one for feature parity.

JIT

* #931
* Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64
* Implement remaining aliases of BFM for A64
* Implement new callinfo flag for A64
* Add instruction simplification for int->num->int conversion chains
* Don't even load execdata for X64 calls
* Treat opcode fallbacks the same as manually written fallbacks

---------

Co-authored-by: Arseny Kapoulkine <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
3 people authored May 19, 2023
1 parent da0458b commit 721f6e1
Show file tree
Hide file tree
Showing 85 changed files with 4,057 additions and 4,493 deletions.
44 changes: 40 additions & 4 deletions Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@ struct HasPropConstraint
TypeId resultType;
TypeId subjectType;
std::string prop;

// HACK: We presently need types like true|false or string|"hello" when
// deciding whether a particular literal expression should have a singleton
// type. This boolean is set to true when extracting the property type of a
// value that may be a union of tables.
//
// For example, in the following code fragment, we want the lookup of the
// success property to yield true|false when extracting an expectedType in
// this expression:
//
// type Result<T, E> = {success:true, result: T} | {success:false, error: E}
//
// local r: Result<number, string> = {success=true, result=9}
//
// If we naively simplify the expectedType to boolean, we will erroneously
// compute the type boolean for the success property of the table literal.
// This causes type checking to fail.
bool suppressSimplification = false;
};

// result ~ setProp subjectType ["prop", "prop2", ...] propType
Expand Down Expand Up @@ -198,6 +216,24 @@ struct UnpackConstraint
TypePackId sourcePack;
};

// resultType ~ refine type mode discriminant
//
// Compute type & discriminant (or type | discriminant) as soon as possible (but
// no sooner), simplify, and bind resultType to that type.
struct RefineConstraint
{
enum
{
Intersection,
Union
} mode;

TypeId resultType;

TypeId type;
TypeId discriminant;
};

// ty ~ reduce ty
//
// Try to reduce ty, if it is a TypeFamilyInstanceType. Otherwise, do nothing.
Expand All @@ -214,10 +250,10 @@ struct ReducePackConstraint
TypePackId tp;
};

using ConstraintV =
Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint, BinaryConstraint,
IterableConstraint, NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, PrimitiveTypeConstraint, HasPropConstraint,
SetPropConstraint, SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, ReduceConstraint, ReducePackConstraint>;
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint,
BinaryConstraint, IterableConstraint, NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, PrimitiveTypeConstraint,
HasPropConstraint, SetPropConstraint, SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, RefineConstraint, ReduceConstraint,
ReducePackConstraint>;

struct Constraint
{
Expand Down
4 changes: 3 additions & 1 deletion Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ struct ConstraintGraphBuilder
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, AstExprFunction* func, std::optional<TypeId> expectedType);
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);
Expand All @@ -213,7 +214,8 @@ struct ConstraintGraphBuilder
ScopePtr bodyScope;
};

FunctionSignature checkFunctionSignature(const ScopePtr& parent, AstExprFunction* fn, std::optional<TypeId> expectedType = {});
FunctionSignature checkFunctionSignature(
const ScopePtr& parent, AstExprFunction* fn, std::optional<TypeId> expectedType = {}, std::optional<Location> originalName = {});

/**
* Checks the body of a function expression.
Expand Down
28 changes: 21 additions & 7 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "Luau/Normalize.h"
#include "Luau/ToString.h"
#include "Luau/Type.h"
#include "Luau/TypeReduction.h"
#include "Luau/Variant.h"

#include <vector>
Expand Down Expand Up @@ -121,6 +120,7 @@ struct ConstraintSolver
bool tryDispatch(const SetIndexerConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const SingletonOrTopTypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const UnpackConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const RefineConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force);

Expand All @@ -132,8 +132,10 @@ struct ConstraintSolver
bool tryDispatchIterableFunction(
TypeId nextTy, TypeId tableTy, TypeId firstIndexTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);

std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(TypeId subjectType, const std::string& propName);
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(TypeId subjectType, const std::string& propName, std::unordered_set<TypeId>& seen);
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
TypeId subjectType, const std::string& propName, bool suppressSimplification = false);
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
TypeId subjectType, const std::string& propName, bool suppressSimplification, std::unordered_set<TypeId>& seen);

void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
/**
Expand All @@ -143,6 +145,16 @@ struct ConstraintSolver
bool block(TypeId target, NotNull<const Constraint> constraint);
bool block(TypePackId target, NotNull<const Constraint> constraint);

// Block on every target
template<typename T>
bool block(const T& targets, NotNull<const Constraint> constraint)
{
for (TypeId target : targets)
block(target, constraint);

return false;
}

/**
* For all constraints that are blocked on one constraint, make them block
* on a new constraint.
Expand All @@ -151,15 +163,15 @@ struct ConstraintSolver
*/
void inheritBlocks(NotNull<const Constraint> source, NotNull<const Constraint> addition);

// Traverse the type. If any blocked or pending types are found, block
// the constraint on them.
// Traverse the type. If any pending types are found, block the constraint
// on them.
//
// Returns false if a type blocks the constraint.
//
// FIXME: This use of a boolean for the return result is an appalling
// interface.
bool recursiveBlock(TypeId target, NotNull<const Constraint> constraint);
bool recursiveBlock(TypePackId target, NotNull<const Constraint> constraint);
bool blockOnPendingTypes(TypeId target, NotNull<const Constraint> constraint);
bool blockOnPendingTypes(TypePackId target, NotNull<const Constraint> constraint);

void unblock(NotNull<const Constraint> progressed);
void unblock(TypeId progressed);
Expand Down Expand Up @@ -255,6 +267,8 @@ struct ConstraintSolver

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

TypePackId anyifyModuleReturnTypePackGenerics(TypePackId tp);

ToStringOptions opts;
};

Expand Down
3 changes: 0 additions & 3 deletions Analysis/include/Luau/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,11 @@ struct Module
DenseHashMap<const AstNode*, TypeId> astOverloadResolvedTypes{nullptr};

DenseHashMap<const AstType*, TypeId> astResolvedTypes{nullptr};
DenseHashMap<const AstType*, TypeId> astOriginalResolvedTypes{nullptr};
DenseHashMap<const AstTypePack*, TypePackId> astResolvedTypePacks{nullptr};

// Map AST nodes to the scope they create. Cannot be NotNull<Scope> because we need a sentinel value for the map.
DenseHashMap<const AstNode*, Scope*> astScopes{nullptr};

std::unique_ptr<struct TypeReduction> reduction;

std::unordered_map<Name, TypeId> declaredGlobals;
ErrorVec errors;
LintResult lintResult;
Expand Down
10 changes: 10 additions & 0 deletions Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,18 @@ struct NormalizedType

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

// IsType functions

/// Returns true if the type is a subtype of function. This includes any and unknown.
bool isFunction() const;

/// Returns true if the type is a subtype of number. This includes any and unknown.
bool isNumber() const;
};



class Normalizer
{
std::unordered_map<TypeId, std::unique_ptr<NormalizedType>> cachedNormals;
Expand Down
36 changes: 36 additions & 0 deletions Analysis/include/Luau/Simplify.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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 <set>

namespace Luau
{

struct TypeArena;
struct BuiltinTypes;

struct SimplifyResult
{
TypeId result;

std::set<TypeId> blockedTypes;
};

SimplifyResult simplifyIntersection(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty, TypeId discriminant);
SimplifyResult simplifyUnion(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty, TypeId discriminant);

enum class Relation
{
Disjoint, // No A is a B or vice versa
Coincident, // Every A is in B and vice versa
Intersects, // Some As are in B and some Bs are in A. ex (number | string) <-> (string | boolean)
Subset, // Every A is in B
Superset, // Every B is in A
};

Relation relate(TypeId left, TypeId right);

} // namespace Luau
5 changes: 1 addition & 4 deletions Analysis/include/Luau/ToString.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,7 @@ inline std::string toString(const Constraint& c, ToStringOptions&& opts)
return toString(c, opts);
}

inline std::string toString(const Constraint& c)
{
return toString(c, ToStringOptions{});
}
std::string toString(const Constraint& c);

std::string toString(const Type& tv, ToStringOptions& opts);
std::string toString(const TypePackVar& tp, ToStringOptions& opts);
Expand Down
6 changes: 6 additions & 0 deletions Analysis/include/Luau/TxnLog.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ struct TxnLog
// used. Else we use the embedded Scope*.
bool useScopes = false;

// It is sometimes the case under DCR that we speculatively rebind
// GenericTypes to other types as though they were free. We mark logs that
// contain these kinds of substitutions as radioactive so that we know that
// we must never commit one.
bool radioactive = false;

// Used to avoid infinite recursion when types are cyclic.
// Shared with all the descendent TxnLogs.
std::vector<std::pair<TypeOrPackId, TypeOrPackId>>* sharedSeen;
Expand Down
6 changes: 4 additions & 2 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,9 @@ struct FunctionType
DcrMagicFunction dcrMagicFunction = nullptr;
DcrMagicRefinement dcrMagicRefinement = nullptr;
bool hasSelf;
bool hasNoGenerics = false;
// `hasNoFreeOrGenericTypes` should be true if and only if the type does not have any free or generic types present inside it.
// this flag is used as an optimization to exit early from procedures that manipulate free or generic types.
bool hasNoFreeOrGenericTypes = false;
};

enum class TableState
Expand Down Expand Up @@ -530,7 +532,7 @@ struct ClassType
*/
struct TypeFamilyInstanceType
{
NotNull<TypeFamily> family;
NotNull<const TypeFamily> family;

std::vector<TypeId> typeArguments;
std::vector<TypePackId> packArguments;
Expand Down
26 changes: 18 additions & 8 deletions Analysis/include/Luau/TypeFamily.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ using TypePackId = const TypePackVar*;
struct TypeArena;
struct BuiltinTypes;
struct TxnLog;
class Normalizer;

/// Represents a reduction result, which may have successfully reduced the type,
/// may have concretely failed to reduce the type, or may simply be stuck
Expand Down Expand Up @@ -52,8 +53,8 @@ struct TypeFamily
std::string name;

/// The reducer function for the type family.
std::function<TypeFamilyReductionResult<TypeId>(
std::vector<TypeId>, std::vector<TypePackId>, NotNull<TypeArena>, NotNull<BuiltinTypes>, NotNull<const TxnLog> log)>
std::function<TypeFamilyReductionResult<TypeId>(std::vector<TypeId>, std::vector<TypePackId>, NotNull<TypeArena>, NotNull<BuiltinTypes>,
NotNull<TxnLog>, NotNull<Scope>, NotNull<Normalizer>)>
reducer;
};

Expand All @@ -66,8 +67,8 @@ struct TypePackFamily
std::string name;

/// The reducer function for the type pack family.
std::function<TypeFamilyReductionResult<TypePackId>(
std::vector<TypeId>, std::vector<TypePackId>, NotNull<TypeArena>, NotNull<BuiltinTypes>, NotNull<const TxnLog> log)>
std::function<TypeFamilyReductionResult<TypePackId>(std::vector<TypeId>, std::vector<TypePackId>, NotNull<TypeArena>, NotNull<BuiltinTypes>,
NotNull<TxnLog>, NotNull<Scope>, NotNull<Normalizer>)>
reducer;
};

Expand All @@ -93,8 +94,8 @@ struct FamilyGraphReductionResult
* against the TxnLog, otherwise substitutions will directly mutate the type
* graph. Do not provide the empty TxnLog, as a result.
*/
FamilyGraphReductionResult reduceFamilies(
TypeId entrypoint, Location location, NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, TxnLog* log = nullptr, bool force = false);
FamilyGraphReductionResult reduceFamilies(TypeId entrypoint, Location location, NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins,
NotNull<Scope> scope, NotNull<Normalizer> normalizer, TxnLog* log = nullptr, bool force = false);

/**
* Attempt to reduce all instances of any type or type pack family in the type
Expand All @@ -109,7 +110,16 @@ FamilyGraphReductionResult reduceFamilies(
* against the TxnLog, otherwise substitutions will directly mutate the type
* graph. Do not provide the empty TxnLog, as a result.
*/
FamilyGraphReductionResult reduceFamilies(
TypePackId entrypoint, Location location, NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, TxnLog* log = nullptr, bool force = false);
FamilyGraphReductionResult reduceFamilies(TypePackId entrypoint, Location location, NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins,
NotNull<Scope> scope, NotNull<Normalizer> normalizer, TxnLog* log = nullptr, bool force = false);

struct BuiltinTypeFamilies
{
BuiltinTypeFamilies();

TypeFamily addFamily;
};

const BuiltinTypeFamilies kBuiltinTypeFamilies{};

} // namespace Luau
Loading

0 comments on commit 721f6e1

Please sign in to comment.