mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
3b0e93bec9
# 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 <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
309 lines
8.4 KiB
C++
309 lines
8.4 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#pragma once
|
|
|
|
#include "Luau/Ast.h" // Used for some of the enumerations
|
|
#include "Luau/DenseHash.h"
|
|
#include "Luau/NotNull.h"
|
|
#include "Luau/Variant.h"
|
|
#include "Luau/TypeFwd.h"
|
|
|
|
#include <string>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
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
|
|
{
|
|
TypeId subType;
|
|
TypeId superType;
|
|
};
|
|
|
|
// subPack <: superPack
|
|
struct PackSubtypeConstraint
|
|
{
|
|
TypePackId subPack;
|
|
TypePackId superPack;
|
|
|
|
// HACK!! TODO clip.
|
|
// We need to know which of `PackSubtypeConstraint` are emitted from `AstStatReturn` vs any others.
|
|
// Then we force these specific `PackSubtypeConstraint` to only dispatch in the order of the `return`s.
|
|
bool returns = false;
|
|
};
|
|
|
|
// generalizedType ~ gen sourceType
|
|
struct GeneralizationConstraint
|
|
{
|
|
TypeId generalizedType;
|
|
TypeId sourceType;
|
|
|
|
std::vector<TypeId> interiorTypes;
|
|
};
|
|
|
|
// subType ~ inst superType
|
|
struct InstantiationConstraint
|
|
{
|
|
TypeId subType;
|
|
TypeId superType;
|
|
};
|
|
|
|
// variables ~ iterate iterator
|
|
// Unpack the iterator, figure out what types it iterates over, and bind those types to variables.
|
|
struct IterableConstraint
|
|
{
|
|
TypePackId iterator;
|
|
TypePackId variables;
|
|
|
|
const AstNode* nextAstFragment;
|
|
DenseHashMap<const AstNode*, TypeId>* astForInNextTypes;
|
|
};
|
|
|
|
// name(namedType) = name
|
|
struct NameConstraint
|
|
{
|
|
TypeId namedType;
|
|
std::string name;
|
|
bool synthetic = false;
|
|
std::vector<TypeId> typeParameters;
|
|
std::vector<TypePackId> typePackParameters;
|
|
};
|
|
|
|
// target ~ inst target
|
|
struct TypeAliasExpansionConstraint
|
|
{
|
|
// Must be a PendingExpansionType.
|
|
TypeId target;
|
|
};
|
|
|
|
struct FunctionCallConstraint
|
|
{
|
|
TypeId fn;
|
|
TypePackId argsPack;
|
|
TypePackId result;
|
|
class AstExprCall* callSite = nullptr;
|
|
std::vector<std::optional<TypeId>> discriminantTypes;
|
|
|
|
// When we dispatch this constraint, we update the key at this map to record
|
|
// the overload that we selected.
|
|
DenseHashMap<const AstNode*, TypeId>* astOverloadResolvedTypes = nullptr;
|
|
};
|
|
|
|
// function_check fn argsPack
|
|
//
|
|
// If fn is a function type and argsPack is a partially solved
|
|
// pack of arguments to be supplied to the function, propagate the argument
|
|
// types of fn into the types of argsPack. This is used to implement
|
|
// bidirectional inference of lambda arguments.
|
|
struct FunctionCheckConstraint
|
|
{
|
|
TypeId fn;
|
|
TypePackId argsPack;
|
|
|
|
class AstExprCall* callSite = nullptr;
|
|
NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes;
|
|
};
|
|
|
|
// prim FreeType ExpectedType PrimitiveType
|
|
//
|
|
// FreeType is bounded below by the singleton type and above by PrimitiveType
|
|
// initially. When this constraint is resolved, it will check that the bounds
|
|
// of the free type are well-formed by subtyping.
|
|
//
|
|
// If they are not well-formed, then FreeType is replaced by its lower bound
|
|
//
|
|
// If they are well-formed and ExpectedType is potentially a singleton (an
|
|
// actual singleton or a union that contains a singleton),
|
|
// then FreeType is replaced by its lower bound
|
|
//
|
|
// else FreeType is replaced by PrimitiveType
|
|
struct PrimitiveTypeConstraint
|
|
{
|
|
TypeId freeType;
|
|
|
|
// potentially gets used to force the lower bound?
|
|
std::optional<TypeId> expectedType;
|
|
|
|
// the primitive type to check against
|
|
TypeId primitiveType;
|
|
};
|
|
|
|
// result ~ hasProp type "prop_name"
|
|
//
|
|
// If the subject is a table, bind the result to the named prop. If the table
|
|
// has an indexer, bind it to the index result type. If the subject is a union,
|
|
// bind the result to the union of its constituents' properties.
|
|
//
|
|
// It would be nice to get rid of this constraint and someday replace it with
|
|
//
|
|
// T <: {p: X}
|
|
//
|
|
// Where {} describes an inexact shape type.
|
|
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
|
|
// 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
|
|
//
|
|
// If the subject is a table or table-like thing that already has the named
|
|
// property chain, we unify propType with that existing property type.
|
|
//
|
|
// If the subject is a free table, we augment it in place.
|
|
//
|
|
// If the subject is an unsealed table, result is an augmented table that
|
|
// includes that new prop.
|
|
struct SetPropConstraint
|
|
{
|
|
TypeId resultType;
|
|
TypeId subjectType;
|
|
std::vector<std::string> path;
|
|
TypeId propType;
|
|
};
|
|
|
|
// result ~ setIndexer subjectType indexType propType
|
|
//
|
|
// If the subject is a table or table-like thing that already has an indexer,
|
|
// unify its indexType and propType with those from this constraint.
|
|
//
|
|
// If the table is a free or unsealed table, we augment it with a new indexer.
|
|
struct SetIndexerConstraint
|
|
{
|
|
TypeId resultType;
|
|
TypeId subjectType;
|
|
TypeId indexType;
|
|
TypeId propType;
|
|
};
|
|
|
|
// if negation:
|
|
// result ~ if isSingleton D then ~D else unknown where D = discriminantType
|
|
// if not negation:
|
|
// result ~ if isSingleton D then D else unknown where D = discriminantType
|
|
struct SingletonOrTopTypeConstraint
|
|
{
|
|
TypeId resultType;
|
|
TypeId discriminantType;
|
|
bool negated;
|
|
};
|
|
|
|
// resultType ~ unpack sourceTypePack
|
|
//
|
|
// Similar to PackSubtypeConstraint, but with one important difference: If the
|
|
// sourcePack is blocked, this constraint blocks.
|
|
struct UnpackConstraint
|
|
{
|
|
TypePackId resultPack;
|
|
TypePackId sourcePack;
|
|
|
|
// UnpackConstraint is sometimes used to resolve the types of assignments.
|
|
// When this is the case, any LocalTypes in resultPack can have their
|
|
// domains extended by the corresponding type from sourcePack.
|
|
bool resultIsLValue = false;
|
|
};
|
|
|
|
// resultType ~ T0 op T1 op ... op TN
|
|
//
|
|
// op is either union or intersection. If any of the input types are blocked,
|
|
// this constraint will block unless forced.
|
|
struct SetOpConstraint
|
|
{
|
|
enum
|
|
{
|
|
Intersection,
|
|
Union
|
|
} mode;
|
|
|
|
TypeId resultType;
|
|
std::vector<TypeId> types;
|
|
};
|
|
|
|
// ty ~ reduce ty
|
|
//
|
|
// Try to reduce ty, if it is a TypeFamilyInstanceType. Otherwise, do nothing.
|
|
struct ReduceConstraint
|
|
{
|
|
TypeId ty;
|
|
};
|
|
|
|
// tp ~ reduce tp
|
|
//
|
|
// Analogous to ReduceConstraint, but for type packs.
|
|
struct ReducePackConstraint
|
|
{
|
|
TypePackId tp;
|
|
};
|
|
|
|
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, IterableConstraint,
|
|
NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint,
|
|
SetPropConstraint, SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, SetOpConstraint, ReduceConstraint, ReducePackConstraint,
|
|
EqualityConstraint>;
|
|
|
|
struct Constraint
|
|
{
|
|
Constraint(NotNull<Scope> scope, const Location& location, ConstraintV&& c);
|
|
|
|
Constraint(const Constraint&) = delete;
|
|
Constraint& operator=(const Constraint&) = delete;
|
|
|
|
NotNull<Scope> scope;
|
|
Location location;
|
|
ConstraintV c;
|
|
|
|
std::vector<NotNull<Constraint>> dependencies;
|
|
|
|
DenseHashSet<TypeId> getFreeTypes() const;
|
|
};
|
|
|
|
using ConstraintPtr = std::unique_ptr<Constraint>;
|
|
|
|
inline Constraint& asMutable(const Constraint& c)
|
|
{
|
|
return const_cast<Constraint&>(c);
|
|
}
|
|
|
|
template<typename T>
|
|
T* getMutable(Constraint& c)
|
|
{
|
|
return ::Luau::get_if<T>(&c.c);
|
|
}
|
|
|
|
template<typename T>
|
|
const T* get(const Constraint& c)
|
|
{
|
|
return getMutable<T>(asMutable(c));
|
|
}
|
|
|
|
} // namespace Luau
|