Skip to content

Commit

Permalink
Sync to upstream/release/621 (#1229)
Browse files Browse the repository at this point in the history
# What's changed?

* Support for new 'require by string' RFC with relative paths and
aliases in now enabled in Luau REPL application

### New Type Solver

* Fixed assertion failure on generic table keys (`[expr] = value`)
* Fixed an issue with type substitution traversing into the substituted
parts during type instantiation
* Fixed crash in union simplification when that union contained
uninhabited unions and other types inside
* Union types in binary type families like `add<a | b, c>` are expanded
into `add<a, c> | add<b, c>` to handle
* Added handling for type family solving creating new type families
* Fixed a bug with normalization operation caching types with unsolved
parts
* Tables with uninhabited properties are now simplified to `never`
* Fixed failures found by fuzzer

### Native Code Generation

* Added support for shared code generation between multiple Luau VM
instances
* Fixed issue in load-store propagation and new tagged LOAD_TVALUE
instructions
* Fixed issues with partial register dead store elimination causing
failures in GC assists

---

### Internal Contributors

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: James McNellis <[email protected]>
Co-authored-by: Vighnesh Vijay <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
7 people authored Apr 12, 2024
1 parent 67e16cb commit 9c21462
Show file tree
Hide file tree
Showing 78 changed files with 2,775 additions and 1,668 deletions.
2 changes: 0 additions & 2 deletions Analysis/include/Luau/Clone.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ struct CloneState

SeenTypes seenTypes;
SeenTypePacks seenTypePacks;

int recursionCount = 0;
};

TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState);
Expand Down
8 changes: 2 additions & 6 deletions Analysis/include/Luau/ConstraintGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ struct ConstraintGenerator
// will enqueue them during solving.
std::vector<ConstraintPtr> unqueuedConstraints;

// Type family instances created by the generator. This is used to ensure
// that these instances are reduced fully by the solver.
std::vector<TypeId> familyInstances;

// The private scope of type aliases for which the type parameters belong to.
DenseHashMap<const AstStatTypeAlias*, ScopePtr> astTypeAliasDefiningScopes{nullptr};

Expand Down Expand Up @@ -264,8 +260,8 @@ struct ConstraintGenerator
std::optional<TypeId> assignedTy;
};

LValueBounds checkLValue(const ScopePtr& scope, AstExpr* expr, bool transform);
LValueBounds checkLValue(const ScopePtr& scope, AstExprLocal* local, bool transform);
LValueBounds checkLValue(const ScopePtr& scope, AstExpr* expr);
LValueBounds checkLValue(const ScopePtr& scope, AstExprLocal* local);
LValueBounds checkLValue(const ScopePtr& scope, AstExprGlobal* global);
LValueBounds checkLValue(const ScopePtr& scope, AstExprIndexName* indexName);
LValueBounds checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
Expand Down
5 changes: 1 addition & 4 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ struct ConstraintSolver
// A constraint can be both blocked and unsolved, for instance.
std::vector<NotNull<const Constraint>> unsolvedConstraints;

// This is a set of type families that need to be reduced after all constraints have been dispatched.
DenseHashSet<TypeId> familyInstances{nullptr};

// A mapping of constraint pointer to how many things the constraint is
// blocked on. Can be empty or 0 for constraints that are not blocked on
// anything.
Expand Down Expand Up @@ -137,7 +134,7 @@ struct ConstraintSolver
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint);

bool tryDispatchHasIndexer(int& recursionDepth, NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId resultType);
bool tryDispatchHasIndexer(int& recursionDepth, NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId resultType, Set<TypeId>& seen);
bool tryDispatch(const HasIndexerConstraint& c, NotNull<const Constraint> constraint);

/// (dispatched, found) where
Expand Down
22 changes: 21 additions & 1 deletion Analysis/include/Luau/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,26 @@ struct CheckedFunctionIncorrectArgs
bool operator==(const CheckedFunctionIncorrectArgs& rhs) const;
};

struct CannotAssignToNever
{
// type of the rvalue being assigned
TypeId rhsType;

// Originating type.
std::vector<TypeId> cause;

enum class Reason
{
// when assigning to a property in a union of tables, the properties type
// is narrowed to the intersection of its type in each variant.
PropertyNarrowed,
};

Reason reason;

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

struct UnexpectedTypeInSubtyping
{
TypeId ty;
Expand All @@ -427,7 +447,7 @@ 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,
DeprecatedApiUsed, ModuleHasCyclicDependency, IllegalRequire, FunctionExitsWithoutReturning, DuplicateGenericParameter, CannotAssignToNever,
CannotInferBinaryOperation, MissingProperties, SwappedGenericTypeParameter, OptionalValueAccess, MissingUnionProperty, TypesAreUnrelated,
NormalizationTooComplex, TypePackMismatch, DynamicPropertyLookupOnClassesUnsafe, UninhabitedTypeFamily, UninhabitedTypePackFamily,
WhereClauseNeeded, PackWhereClauseNeeded, CheckedFunctionCallError, NonStrictFunctionDefinitionError, PropertyAccessViolation,
Expand Down
15 changes: 13 additions & 2 deletions Analysis/include/Luau/Instantiation2.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,18 @@ struct Replacer : Substitution

TypeId clean(TypeId ty) override
{
return replacements[ty];
TypeId res = replacements[ty];
LUAU_ASSERT(res);
dontTraverseInto(res);
return res;
}

TypePackId clean(TypePackId tp) override
{
return replacementPacks[tp];
TypePackId res = replacementPacks[tp];
LUAU_ASSERT(res);
dontTraverseInto(res);
return res;
}
};

Expand All @@ -68,4 +74,9 @@ struct Instantiation2 : Substitution
TypePackId clean(TypePackId tp) override;
};

std::optional<TypeId> instantiate2(
TypeArena* arena, DenseHashMap<TypeId, TypeId> genericSubstitutions, DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions, TypeId ty);
std::optional<TypePackId> instantiate2(TypeArena* arena, DenseHashMap<TypeId, TypeId> genericSubstitutions,
DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions, TypePackId tp);

} // namespace Luau
10 changes: 8 additions & 2 deletions Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ struct NormalizedType
// The generic/free part of the type.
NormalizedTyvars tyvars;

// Free types, blocked types, and certain other types change shape as type
// inference is done. If we were to cache the normalization of these types,
// we'd be reusing bad, stale data.
bool isCacheable = true;

NormalizedType(NotNull<BuiltinTypes> builtinTypes);

NormalizedType() = delete;
Expand Down Expand Up @@ -330,7 +335,7 @@ struct NormalizedType

class Normalizer
{
std::unordered_map<TypeId, std::unique_ptr<NormalizedType>> cachedNormals;
std::unordered_map<TypeId, std::shared_ptr<NormalizedType>> cachedNormals;
std::unordered_map<const TypeIds*, TypeId> cachedIntersections;
std::unordered_map<const TypeIds*, TypeId> cachedUnions;
std::unordered_map<const TypeIds*, std::unique_ptr<TypeIds>> cachedTypeIds;
Expand All @@ -355,7 +360,8 @@ class Normalizer
Normalizer& operator=(Normalizer&) = delete;

// If this returns null, the typechecker should emit a "too complex" error
const NormalizedType* normalize(TypeId ty);
const NormalizedType* DEPRECATED_normalize(TypeId ty);
std::shared_ptr<const NormalizedType> normalize(TypeId ty);
void clearNormal(NormalizedType& norm);

// ------- Cached TypeIds
Expand Down
25 changes: 18 additions & 7 deletions Analysis/include/Luau/Substitution.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,21 @@ struct Tarjan
struct Substitution : Tarjan
{
protected:
Substitution(const TxnLog* log_, TypeArena* arena)
: arena(arena)
{
log = log_;
LUAU_ASSERT(log);
LUAU_ASSERT(arena);
}
Substitution(const TxnLog* log_, TypeArena* arena);

/*
* By default, Substitution assumes that the types produced by clean() are
* freshly allocated types that are safe to mutate.
*
* If your clean() implementation produces a type that is not safe to
* mutate, you must call dontTraverseInto on this type (or type pack) to
* prevent Substitution from attempting to perform substitutions within the
* cleaned type.
*
* See the test weird_cyclic_instantiation for an example.
*/
void dontTraverseInto(TypeId ty);
void dontTraverseInto(TypePackId tp);

public:
TypeArena* arena;
Expand All @@ -198,6 +206,9 @@ struct Substitution : Tarjan
DenseHashSet<TypeId> replacedTypes{nullptr};
DenseHashSet<TypePackId> replacedTypePacks{nullptr};

DenseHashSet<TypeId> noTraverseTypes{nullptr};
DenseHashSet<TypePackId> noTraverseTypePacks{nullptr};

std::optional<TypeId> substitute(TypeId ty);
std::optional<TypePackId> substitute(TypePackId tp);

Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/Subtyping.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ struct Subtyping
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableIndexer& subIndexer, const TableIndexer& superIndexer);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const Property& subProperty, const Property& superProperty, const std::string& name);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedType* subNorm, const NormalizedType* superNorm);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const std::shared_ptr<const NormalizedType>& subNorm, const std::shared_ptr<const NormalizedType>& superNorm);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const NormalizedClassType& superClass);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const NormalizedStringType& superString);
Expand Down
14 changes: 3 additions & 11 deletions Analysis/include/Luau/TableLiteralInference.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,7 @@ struct BuiltinTypes;
struct Unifier2;
class AstExpr;

TypeId matchLiteralType(
NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes,
NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes,
NotNull<BuiltinTypes> builtinTypes,
NotNull<TypeArena> arena,
NotNull<Unifier2> unifier,
TypeId expectedType,
TypeId exprType,
const AstExpr* expr
);

TypeId matchLiteralType(NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes, NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes,
NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, NotNull<Unifier2> unifier, TypeId expectedType, TypeId exprType,
const AstExpr* expr, std::vector<TypeId>& toBlock);
}
19 changes: 18 additions & 1 deletion Analysis/include/Luau/TypeFamily.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ struct TypeArena;
struct TxnLog;
class Normalizer;

struct TypeFamilyQueue
{
NotNull<VecDeque<TypeId>> queuedTys;
NotNull<VecDeque<TypePackId>> queuedTps;

void add(TypeId instanceTy);
void add(TypePackId instanceTp);

template<typename T>
void add(const std::vector<T>& ts)
{
for (const T& t : ts)
enqueue(t);
}
};

struct TypeFamilyContext
{
NotNull<TypeArena> arena;
Expand Down Expand Up @@ -60,6 +76,7 @@ struct TypeFamilyContext

NotNull<Constraint> pushConstraint(ConstraintV&& c);
};

/// Represents a reduction result, which may have successfully reduced the type,
/// may have concretely failed to reduce the type, or may simply be stuck
/// without more information.
Expand All @@ -83,7 +100,7 @@ struct TypeFamilyReductionResult

template<typename T>
using ReducerFunction =
std::function<TypeFamilyReductionResult<T>(T, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;
std::function<TypeFamilyReductionResult<T>(T, NotNull<TypeFamilyQueue>, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;

/// Represents a type function that may be applied to map a series of types and
/// type packs to a single output type.
Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/TypeFamilyReductionGuesser.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ struct TypeFamilyReductionGuesser
bool operandIsAssignable(TypeId ty);
std::optional<TypeId> tryAssignOperandType(TypeId ty);

const NormalizedType* normalize(TypeId ty);
std::shared_ptr<const NormalizedType> normalize(TypeId ty);
void step();
void infer();
bool done();
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ std::optional<TypeId> findTablePropertyRespectingMeta(
std::optional<TypeId> findTablePropertyRespectingMeta(
NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, ValueContext context, Location location);

bool occursCheck(TypeId needle, TypeId haystack);

// Returns the minimum and maximum number of types the argument list can accept.
std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp, bool includeHiddenVariadics = false);

Expand Down
Loading

0 comments on commit 9c21462

Please sign in to comment.