Skip to content

Commit

Permalink
Sync to upstream/release/614 (#1173)
Browse files Browse the repository at this point in the history
# What's changed?
Add program argument passing to scripts run using the Luau REPL! You can
now pass `--program-args` (or shorthand `-a`) to the REPL which will
treat all remaining arguments as arguments to pass to executed scripts.
These values can be accessed through variadic argument expansion. You
can read these values like so:
```
local args = {...} -- gets you an array of all the arguments
```
For example if we run the following script like `luau test.lua -a test1
test2 test3`:
```
-- test.lua
print(...)
```
you should get the output:
```
test1 test2 test3
```

### Native Code Generation

* Improve A64 lowering for vector operations by using vector
instructions
* Fix lowering issue in IR value location tracking! 
- A developer reported a divergence between code run in the VM and
Native Code Generation which we have now fixed

### New Type Solver

* Apply substitution to type families, and emit new constraints to
reduce those further
* More progress on reducing comparison  (`lt/le`)type families
* Resolve two major sources of cyclic types in the new solver

### Miscellaneous
* Turned internal compiler errors (ICE's) into warnings and errors

-------
Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>

---------

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: David Cope <[email protected]>
Co-authored-by: Lily Brown <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
8 people authored Feb 23, 2024
1 parent 80928ac commit 3b0e93b
Show file tree
Hide file tree
Showing 62 changed files with 1,826 additions and 716 deletions.
14 changes: 13 additions & 1 deletion Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@
namespace Luau
{

enum class ValueContext;
struct Scope;

// if resultType is a freeType, assignmentType <: freeType <: resultType bounds
struct EqualityConstraint
{
TypeId resultType;
TypeId assignmentType;
};

// subType <: superType
struct SubtypeConstraint
{
Expand All @@ -40,6 +48,8 @@ struct GeneralizationConstraint
{
TypeId generalizedType;
TypeId sourceType;

std::vector<TypeId> interiorTypes;
};

// subType ~ inst superType
Expand Down Expand Up @@ -145,6 +155,7 @@ struct HasPropConstraint
TypeId resultType;
TypeId subjectType;
std::string prop;
ValueContext context;

// HACK: We presently need types like true|false or string|"hello" when
// deciding whether a particular literal expression should have a singleton
Expand Down Expand Up @@ -256,7 +267,8 @@ struct ReducePackConstraint

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

struct Constraint
{
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/ConstraintGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ struct ConstraintGenerator
void visitModuleRoot(AstStatBlock* block);

private:
std::vector<std::vector<TypeId>> interiorTypes;

/**
* Fabricates a new free type belonging to a given scope.
* @param scope the scope the free type belongs to.
Expand Down
57 changes: 31 additions & 26 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Luau/Location.h"
#include "Luau/Module.h"
#include "Luau/Normalize.h"
#include "Luau/Substitution.h"
#include "Luau/ToString.h"
#include "Luau/Type.h"
#include "Luau/TypeCheckLimits.h"
Expand All @@ -20,6 +21,8 @@
namespace Luau
{

enum class ValueContext;

struct DcrLogger;

// TypeId, TypePackId, or Constraint*. It is impossible to know which, but we
Expand Down Expand Up @@ -110,8 +113,6 @@ struct ConstraintSolver

bool isDone();

void finalizeModule();

/** Attempt to dispatch a constraint. Returns true if it was successful. If
* tryDispatch() returns false, the constraint remains in the unsolved set
* and will be retried later.
Expand All @@ -136,6 +137,7 @@ struct ConstraintSolver
bool tryDispatch(const SetOpConstraint& 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);
bool tryDispatch(const EqualityConstraint& c, NotNull<const Constraint> constraint, bool force);

// for a, ... in some_table do
// also handles __iter metamethod
Expand All @@ -146,9 +148,9 @@ struct ConstraintSolver
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, bool suppressSimplification = false);
TypeId subjectType, const std::string& propName, ValueContext context, bool suppressSimplification = false);
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
TypeId subjectType, const std::string& propName, bool suppressSimplification, DenseHashSet<TypeId>& seen);
TypeId subjectType, const std::string& propName, ValueContext context, bool suppressSimplification, DenseHashSet<TypeId>& seen);

void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
/**
Expand Down Expand Up @@ -208,23 +210,6 @@ struct ConstraintSolver
*/
bool isBlocked(NotNull<const Constraint> constraint);

/**
* Creates a new Unifier and performs a single unification operation. Commits
* the result.
* @param subType the sub-type to unify.
* @param superType the super-type to unify.
* @returns optionally a unification too complex error if unification failed
*/
std::optional<TypeError> unify(NotNull<Scope> scope, Location location, TypeId subType, TypeId superType);

/**
* Creates a new Unifier and performs a single unification operation. Commits
* the result.
* @param subPack the sub-type pack to unify.
* @param superPack the super-type pack to unify.
*/
ErrorVec unify(NotNull<Scope> scope, Location location, TypePackId subPack, TypePackId superPack);

/** Pushes a new solver constraint to the solver.
* @param cv the body of the constraint.
**/
Expand Down Expand Up @@ -253,20 +238,33 @@ struct ConstraintSolver
*/
bool hasUnresolvedConstraints(TypeId ty);

private:
/** Helper used by tryDispatch(SubtypeConstraint) and
* tryDispatch(PackSubtypeConstraint)
/**
* Creates a new Unifier and performs a single unification operation.
*
* Attempts to unify subTy with superTy. If doing so would require unifying
* @param subType the sub-type to unify.
* @param superType the super-type to unify.
* @returns true if the unification succeeded. False if the unification was
* too complex.
*/
template <typename TID>
bool unify(NotNull<Scope> scope, Location location, TID subType, TID superType);

/** Attempts to unify subTy with superTy. If doing so would require unifying
* BlockedTypes, fail and block the constraint on those BlockedTypes.
*
* Note: TID can only be TypeId or TypePackId.
*
* If unification fails, replace all free types with errorType.
*
* If unification succeeds, unblock every type changed by the unification.
*
* @returns true if the unification succeeded. False if the unification was
* too complex.
*/
template<typename TID>
bool tryUnify(NotNull<const Constraint> constraint, TID subTy, TID superTy);
bool unify(NotNull<const Constraint> constraint, TID subTy, TID superTy);

private:
/**
* Bind a BlockedType to another type while taking care not to bind it to
* itself in the case that resultTy == blockedTy. This can happen if we
Expand Down Expand Up @@ -295,6 +293,13 @@ struct ConstraintSolver
**/
void unblock_(BlockedConstraintId progressed);

/**
* Reproduces any constraints necessary for new types that are copied when applying a substitution.
* At the time of writing, this pertains only to type families.
* @param subst the substitution that was applied
**/
void reproduceConstraints(NotNull<Scope> scope, const Location& location, const Substitution& subst);

TypeId errorRecoveryType() const;
TypePackId errorRecoveryTypePack() const;

Expand Down
44 changes: 36 additions & 8 deletions Analysis/include/Luau/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,20 @@ struct NonStrictFunctionDefinitionError
bool operator==(const NonStrictFunctionDefinitionError& rhs) const;
};

struct PropertyAccessViolation
{
TypeId table;
Name key;

enum
{
CannotRead,
CannotWrite
} context;

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

struct CheckedFunctionIncorrectArgs
{
std::string functionName;
Expand All @@ -388,14 +402,28 @@ struct CheckedFunctionIncorrectArgs
bool operator==(const CheckedFunctionIncorrectArgs& 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, TypePackMismatch, DynamicPropertyLookupOnClassesUnsafe, UninhabitedTypeFamily, UninhabitedTypePackFamily,
WhereClauseNeeded, PackWhereClauseNeeded, CheckedFunctionCallError, NonStrictFunctionDefinitionError, CheckedFunctionIncorrectArgs>;
struct UnexpectedTypeInSubtyping
{
TypeId ty;

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

struct UnexpectedTypePackInSubtyping
{
TypePackId tp;

bool operator==(const UnexpectedTypePackInSubtyping& 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, TypePackMismatch, DynamicPropertyLookupOnClassesUnsafe, UninhabitedTypeFamily,
UninhabitedTypePackFamily, WhereClauseNeeded, PackWhereClauseNeeded, CheckedFunctionCallError, NonStrictFunctionDefinitionError,
PropertyAccessViolation, CheckedFunctionIncorrectArgs, UnexpectedTypeInSubtyping, UnexpectedTypePackInSubtyping>;

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

#include "Luau/NotNull.h"
#include "Luau/Substitution.h"
#include "Luau/TxnLog.h"
#include "Luau/TypeFwd.h"
#include "Luau/Unifiable.h"

namespace Luau
{

struct TypeArena;
struct TypeCheckLimits;

struct Replacer : Substitution
{
DenseHashMap<TypeId, TypeId> replacements;
DenseHashMap<TypePackId, TypePackId> replacementPacks;

Replacer(NotNull<TypeArena> arena, DenseHashMap<TypeId, TypeId> replacements, DenseHashMap<TypePackId, TypePackId> replacementPacks)
: Substitution(TxnLog::empty(), arena)
, replacements(std::move(replacements))
, replacementPacks(std::move(replacementPacks))
{
}

bool isDirty(TypeId ty) override
{
return replacements.find(ty) != nullptr;
}

bool isDirty(TypePackId tp) override
{
return replacementPacks.find(tp) != nullptr;
}

TypeId clean(TypeId ty) override
{
return replacements[ty];
}

TypePackId clean(TypePackId tp) override
{
return replacementPacks[tp];
}
};

// A substitution which replaces generic functions by monomorphic functions
struct Instantiation2 : Substitution
{
// Mapping from generic types to free types to be used in instantiation.
DenseHashMap<TypeId, TypeId> genericSubstitutions{nullptr};
// Mapping from generic type packs to `TypePack`s of free types to be used in instantiation.
DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions{nullptr};

Instantiation2(TypeArena* arena, DenseHashMap<TypeId, TypeId> genericSubstitutions, DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions)
: Substitution(TxnLog::empty(), arena)
, genericSubstitutions(std::move(genericSubstitutions))
, genericPackSubstitutions(std::move(genericPackSubstitutions))
{
}

bool isDirty(TypeId ty) override;
bool isDirty(TypePackId tp) override;
TypeId clean(TypeId ty) override;
TypePackId clean(TypePackId tp) override;
};

} // namespace Luau
15 changes: 11 additions & 4 deletions Analysis/include/Luau/Subtyping.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ struct InternalErrorReporter;

class TypeIds;
class Normalizer;
struct NormalizedType;
struct NormalizedClassType;
struct NormalizedStringType;
struct NormalizedFunctionType;
struct TypeArena;
struct TypeCheckLimits;
struct NormalizedStringType;
struct NormalizedType;
struct Property;
struct Scope;
struct TableIndexer;
struct TypeArena;
struct TypeCheckLimits;

enum class SubtypingVariance
{
Expand Down Expand Up @@ -79,6 +80,7 @@ struct SubtypingResult
SubtypingResult& withSubPath(TypePath::Path path);
SubtypingResult& withSuperPath(TypePath::Path path);
SubtypingResult& withErrors(ErrorVec& err);
SubtypingResult& withError(TypeError err);

// Only negates the `isSubtype`.
static SubtypingResult negate(const SubtypingResult& result);
Expand All @@ -102,6 +104,10 @@ struct SubtypingEnvironment
DenseHashMap<TypePackId, TypePackId> mappedGenericPacks{nullptr};

DenseHashMap<std::pair<TypeId, TypeId>, SubtypingResult, TypePairHash> ephemeralCache{{}};

/// Applies `mappedGenerics` to the given type.
/// This is used specifically to substitute for generics in type family instances.
std::optional<TypeId> applyMappedGenerics(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty);
};

struct Subtyping
Expand Down Expand Up @@ -192,6 +198,7 @@ struct Subtyping
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable);

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 NormalizedClassType& subClass, const NormalizedClassType& superClass);
Expand Down
12 changes: 4 additions & 8 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,16 +414,11 @@ struct Property
TypeId type() const;
void setType(TypeId ty);

// Should only be called in RWP!
// We do not assert that `readTy` nor `writeTy` are nullopt or not.
// The invariant is that at least one of them mustn't be nullopt, which we do assert here.
// TODO: Kill this in favor of exposing `readTy`/`writeTy` directly? If we do, we'll lose the asserts which will be useful while debugging.
std::optional<TypeId> readType() const;
std::optional<TypeId> writeType() const;

bool isShared() const;
bool isReadOnly() const;
bool isWriteOnly() const;
bool isReadWrite() const;

private:
std::optional<TypeId> readTy;
std::optional<TypeId> writeTy;
};
Expand Down Expand Up @@ -844,6 +839,7 @@ struct BuiltinTypes

const TypePackId emptyTypePack;
const TypePackId anyTypePack;
const TypePackId unknownTypePack;
const TypePackId neverTypePack;
const TypePackId uninhabitableTypePack;
const TypePackId errorTypePack;
Expand Down
Loading

0 comments on commit 3b0e93b

Please sign in to comment.