mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
Sync to upstream/release/553 (#751)
* Autocomplete support for interpolated strings. * Improved parse errors in various situations involving interpolated strings.
This commit is contained in:
parent
aa7c64517c
commit
95d9c6d194
@ -132,6 +132,23 @@ struct HasPropConstraint
|
|||||||
std::string prop;
|
std::string prop;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 ~ if isSingleton D then ~D else unknown where D = discriminantType
|
// result ~ if isSingleton D then ~D else unknown where D = discriminantType
|
||||||
struct SingletonOrTopTypeConstraint
|
struct SingletonOrTopTypeConstraint
|
||||||
{
|
{
|
||||||
@ -141,7 +158,7 @@ struct SingletonOrTopTypeConstraint
|
|||||||
|
|
||||||
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint,
|
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint,
|
||||||
BinaryConstraint, IterableConstraint, NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, PrimitiveTypeConstraint,
|
BinaryConstraint, IterableConstraint, NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, PrimitiveTypeConstraint,
|
||||||
HasPropConstraint, SingletonOrTopTypeConstraint>;
|
HasPropConstraint, SetPropConstraint, SingletonOrTopTypeConstraint>;
|
||||||
|
|
||||||
struct Constraint
|
struct Constraint
|
||||||
{
|
{
|
||||||
|
@ -110,6 +110,7 @@ struct ConstraintSolver
|
|||||||
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
|
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
|
||||||
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
|
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
|
||||||
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
|
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
|
||||||
|
bool tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint);
|
||||||
bool tryDispatch(const SingletonOrTopTypeConstraint& c, NotNull<const Constraint> constraint);
|
bool tryDispatch(const SingletonOrTopTypeConstraint& c, NotNull<const Constraint> constraint);
|
||||||
|
|
||||||
// for a, ... in some_table do
|
// for a, ... in some_table do
|
||||||
@ -120,6 +121,8 @@ struct ConstraintSolver
|
|||||||
bool tryDispatchIterableFunction(
|
bool tryDispatchIterableFunction(
|
||||||
TypeId nextTy, TypeId tableTy, TypeId firstIndexTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
|
TypeId nextTy, TypeId tableTy, TypeId firstIndexTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
|
||||||
|
|
||||||
|
std::optional<TypeId> lookupTableProp(TypeId subjectType, const std::string& propName);
|
||||||
|
|
||||||
void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
|
void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
|
||||||
/**
|
/**
|
||||||
* Block a constraint on the resolution of a TypeVar.
|
* Block a constraint on the resolution of a TypeVar.
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "Luau/Scope.h"
|
#include "Luau/Scope.h"
|
||||||
#include "Luau/ToString.h"
|
#include "Luau/ToString.h"
|
||||||
#include "Luau/TypeUtils.h"
|
#include "Luau/TypeUtils.h"
|
||||||
|
#include "Luau/TypeVar.h"
|
||||||
|
|
||||||
LUAU_FASTINT(LuauCheckRecursionLimit);
|
LUAU_FASTINT(LuauCheckRecursionLimit);
|
||||||
LUAU_FASTFLAG(DebugLuauLogSolverToJson);
|
LUAU_FASTFLAG(DebugLuauLogSolverToJson);
|
||||||
@ -1019,7 +1020,22 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
|
|||||||
args.push_back(check(scope, arg).ty);
|
args.push_back(check(scope, arg).ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO self
|
if (call->self)
|
||||||
|
{
|
||||||
|
AstExprIndexName* indexExpr = call->func->as<AstExprIndexName>();
|
||||||
|
if (!indexExpr)
|
||||||
|
ice->ice("method call expression has no 'self'");
|
||||||
|
|
||||||
|
// The call to `check` we already did on `call->func` should have already produced a type for
|
||||||
|
// `indexExpr->expr`, so we can get it from `astTypes` to avoid exponential blow-up.
|
||||||
|
TypeId selfType = astTypes[indexExpr->expr];
|
||||||
|
|
||||||
|
// If we don't have a type for self, it means we had a code too complex error already.
|
||||||
|
if (selfType == nullptr)
|
||||||
|
selfType = singletonTypes->errorRecoveryType();
|
||||||
|
|
||||||
|
args.insert(args.begin(), selfType);
|
||||||
|
}
|
||||||
|
|
||||||
if (matchSetmetatable(*call))
|
if (matchSetmetatable(*call))
|
||||||
{
|
{
|
||||||
@ -1428,13 +1444,6 @@ TypePackId ConstraintGraphBuilder::checkLValues(const ScopePtr& scope, AstArray<
|
|||||||
return arena->addTypePack(std::move(types));
|
return arena->addTypePack(std::move(types));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUnsealedTable(TypeId ty)
|
|
||||||
{
|
|
||||||
ty = follow(ty);
|
|
||||||
const TableTypeVar* ttv = get<TableTypeVar>(ty);
|
|
||||||
return ttv && ttv->state == TableState::Unsealed;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the expr is a dotted set of names, and if the root symbol refers to an
|
* If the expr is a dotted set of names, and if the root symbol refers to an
|
||||||
* unsealed table, return that table type, plus the indeces that follow as a
|
* unsealed table, return that table type, plus the indeces that follow as a
|
||||||
@ -1468,80 +1477,6 @@ static std::optional<std::pair<Symbol, std::vector<const char*>>> extractDottedN
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a shallow copy of `ty` and its properties along `path`. Insert a new
|
|
||||||
* property (the last segment of `path`) into the tail table with the value `t`.
|
|
||||||
*
|
|
||||||
* On success, returns the new outermost table type. If the root table or any
|
|
||||||
* of its subkeys are not unsealed tables, the function fails and returns
|
|
||||||
* std::nullopt.
|
|
||||||
*
|
|
||||||
* TODO: Prove that we completely give up in the face of indexers and
|
|
||||||
* metatables.
|
|
||||||
*/
|
|
||||||
static std::optional<TypeId> updateTheTableType(NotNull<TypeArena> arena, TypeId ty, const std::vector<const char*>& path, TypeId replaceTy)
|
|
||||||
{
|
|
||||||
if (path.empty())
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
// First walk the path and ensure that it's unsealed tables all the way
|
|
||||||
// to the end.
|
|
||||||
{
|
|
||||||
TypeId t = ty;
|
|
||||||
for (size_t i = 0; i < path.size() - 1; ++i)
|
|
||||||
{
|
|
||||||
if (!isUnsealedTable(t))
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
const TableTypeVar* tbl = get<TableTypeVar>(t);
|
|
||||||
auto it = tbl->props.find(path[i]);
|
|
||||||
if (it == tbl->props.end())
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
t = it->second.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The last path segment should not be a property of the table at all.
|
|
||||||
// We are not changing property types. We are only admitting this one
|
|
||||||
// new property to be appended.
|
|
||||||
if (!isUnsealedTable(t))
|
|
||||||
return std::nullopt;
|
|
||||||
const TableTypeVar* tbl = get<TableTypeVar>(t);
|
|
||||||
auto it = tbl->props.find(path.back());
|
|
||||||
if (it != tbl->props.end())
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TypeId res = shallowClone(ty, arena);
|
|
||||||
TypeId t = res;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < path.size() - 1; ++i)
|
|
||||||
{
|
|
||||||
const std::string segment = path[i];
|
|
||||||
|
|
||||||
TableTypeVar* ttv = getMutable<TableTypeVar>(t);
|
|
||||||
LUAU_ASSERT(ttv);
|
|
||||||
|
|
||||||
auto propIt = ttv->props.find(segment);
|
|
||||||
if (propIt != ttv->props.end())
|
|
||||||
{
|
|
||||||
LUAU_ASSERT(isUnsealedTable(propIt->second.type));
|
|
||||||
t = shallowClone(follow(propIt->second.type), arena);
|
|
||||||
ttv->props[segment].type = t;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
TableTypeVar* ttv = getMutable<TableTypeVar>(t);
|
|
||||||
LUAU_ASSERT(ttv);
|
|
||||||
|
|
||||||
const std::string lastSegment = path.back();
|
|
||||||
LUAU_ASSERT(0 == ttv->props.count(lastSegment));
|
|
||||||
ttv->props[lastSegment] = Property{replaceTy};
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is mostly about identifying properties that are being inserted into unsealed tables.
|
* This function is mostly about identifying properties that are being inserted into unsealed tables.
|
||||||
*
|
*
|
||||||
@ -1559,31 +1494,36 @@ TypeId ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExpr* expr)
|
|||||||
return checkLValue(scope, &synthetic);
|
return checkLValue(scope, &synthetic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!expr->is<AstExprIndexName>())
|
||||||
|
return check(scope, expr).ty;
|
||||||
|
|
||||||
auto dottedPath = extractDottedName(expr);
|
auto dottedPath = extractDottedName(expr);
|
||||||
if (!dottedPath)
|
if (!dottedPath)
|
||||||
return check(scope, expr).ty;
|
return check(scope, expr).ty;
|
||||||
const auto [sym, segments] = std::move(*dottedPath);
|
const auto [sym, segments] = std::move(*dottedPath);
|
||||||
|
|
||||||
if (!sym.local)
|
LUAU_ASSERT(!segments.empty());
|
||||||
return check(scope, expr).ty;
|
|
||||||
|
|
||||||
auto lookupResult = scope->lookupEx(sym);
|
auto lookupResult = scope->lookupEx(sym);
|
||||||
if (!lookupResult)
|
if (!lookupResult)
|
||||||
return check(scope, expr).ty;
|
return check(scope, expr).ty;
|
||||||
const auto [ty, symbolScope] = std::move(*lookupResult);
|
const auto [subjectType, symbolScope] = std::move(*lookupResult);
|
||||||
|
|
||||||
TypeId replaceTy = arena->freshType(scope.get());
|
TypeId propTy = freshType(scope);
|
||||||
|
|
||||||
std::optional<TypeId> updatedType = updateTheTableType(arena, ty, segments, replaceTy);
|
std::vector<std::string> segmentStrings(begin(segments), end(segments));
|
||||||
if (!updatedType)
|
|
||||||
return check(scope, expr).ty;
|
TypeId updatedType = arena->addType(BlockedTypeVar{});
|
||||||
|
addConstraint(scope, expr->location, SetPropConstraint{updatedType, subjectType, std::move(segmentStrings), propTy});
|
||||||
|
|
||||||
std::optional<DefId> def = dfg->getDef(sym);
|
std::optional<DefId> def = dfg->getDef(sym);
|
||||||
LUAU_ASSERT(def);
|
LUAU_ASSERT(def);
|
||||||
symbolScope->bindings[sym].typeId = *updatedType;
|
symbolScope->bindings[sym].typeId = updatedType;
|
||||||
symbolScope->dcrRefinements[*def] = *updatedType;
|
symbolScope->dcrRefinements[*def] = updatedType;
|
||||||
return replaceTy;
|
|
||||||
|
astTypes[expr] = propTy;
|
||||||
|
|
||||||
|
return propTy;
|
||||||
}
|
}
|
||||||
|
|
||||||
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Luau/Anyification.h"
|
#include "Luau/Anyification.h"
|
||||||
#include "Luau/ApplyTypeFunction.h"
|
#include "Luau/ApplyTypeFunction.h"
|
||||||
|
#include "Luau/Clone.h"
|
||||||
#include "Luau/ConstraintSolver.h"
|
#include "Luau/ConstraintSolver.h"
|
||||||
#include "Luau/DcrLogger.h"
|
#include "Luau/DcrLogger.h"
|
||||||
#include "Luau/Instantiation.h"
|
#include "Luau/Instantiation.h"
|
||||||
@ -415,6 +416,8 @@ bool ConstraintSolver::tryDispatch(NotNull<const Constraint> constraint, bool fo
|
|||||||
success = tryDispatch(*fcc, constraint);
|
success = tryDispatch(*fcc, constraint);
|
||||||
else if (auto hpc = get<HasPropConstraint>(*constraint))
|
else if (auto hpc = get<HasPropConstraint>(*constraint))
|
||||||
success = tryDispatch(*hpc, constraint);
|
success = tryDispatch(*hpc, constraint);
|
||||||
|
else if (auto spc = get<SetPropConstraint>(*constraint))
|
||||||
|
success = tryDispatch(*spc, constraint);
|
||||||
else if (auto sottc = get<SingletonOrTopTypeConstraint>(*constraint))
|
else if (auto sottc = get<SingletonOrTopTypeConstraint>(*constraint))
|
||||||
success = tryDispatch(*sottc, constraint);
|
success = tryDispatch(*sottc, constraint);
|
||||||
else
|
else
|
||||||
@ -1230,69 +1233,180 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
|
|||||||
if (isBlocked(subjectType) || get<PendingExpansionTypeVar>(subjectType))
|
if (isBlocked(subjectType) || get<PendingExpansionTypeVar>(subjectType))
|
||||||
return block(subjectType, constraint);
|
return block(subjectType, constraint);
|
||||||
|
|
||||||
TypeId resultType = nullptr;
|
std::optional<TypeId> resultType = lookupTableProp(subjectType, c.prop);
|
||||||
|
if (!resultType)
|
||||||
|
return false;
|
||||||
|
|
||||||
auto collectParts = [&](auto&& unionOrIntersection) -> std::pair<bool, std::vector<TypeId>> {
|
if (isBlocked(*resultType))
|
||||||
bool blocked = false;
|
|
||||||
|
|
||||||
std::vector<TypeId> parts;
|
|
||||||
for (TypeId expectedPart : unionOrIntersection)
|
|
||||||
{
|
{
|
||||||
expectedPart = follow(expectedPart);
|
block(*resultType, constraint);
|
||||||
if (isBlocked(expectedPart) || get<PendingExpansionTypeVar>(expectedPart))
|
return false;
|
||||||
{
|
|
||||||
blocked = true;
|
|
||||||
block(expectedPart, constraint);
|
|
||||||
}
|
|
||||||
else if (const TableTypeVar* ttv = get<TableTypeVar>(follow(expectedPart)))
|
|
||||||
{
|
|
||||||
if (auto prop = ttv->props.find(c.prop); prop != ttv->props.end())
|
|
||||||
parts.push_back(prop->second.type);
|
|
||||||
else if (ttv->indexer && maybeString(ttv->indexer->indexType))
|
|
||||||
parts.push_back(ttv->indexer->indexResultType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {blocked, parts};
|
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(*resultType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isUnsealedTable(TypeId ty)
|
||||||
|
{
|
||||||
|
ty = follow(ty);
|
||||||
|
const TableTypeVar* ttv = get<TableTypeVar>(ty);
|
||||||
|
return ttv && ttv->state == TableState::Unsealed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a shallow copy of `ty` and its properties along `path`. Insert a new
|
||||||
|
* property (the last segment of `path`) into the tail table with the value `t`.
|
||||||
|
*
|
||||||
|
* On success, returns the new outermost table type. If the root table or any
|
||||||
|
* of its subkeys are not unsealed tables, the function fails and returns
|
||||||
|
* std::nullopt.
|
||||||
|
*
|
||||||
|
* TODO: Prove that we completely give up in the face of indexers and
|
||||||
|
* metatables.
|
||||||
|
*/
|
||||||
|
static std::optional<TypeId> updateTheTableType(NotNull<TypeArena> arena, TypeId ty, const std::vector<std::string>& path, TypeId replaceTy)
|
||||||
|
{
|
||||||
|
if (path.empty())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
// First walk the path and ensure that it's unsealed tables all the way
|
||||||
|
// to the end.
|
||||||
|
{
|
||||||
|
TypeId t = ty;
|
||||||
|
for (size_t i = 0; i < path.size() - 1; ++i)
|
||||||
|
{
|
||||||
|
if (!isUnsealedTable(t))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const TableTypeVar* tbl = get<TableTypeVar>(t);
|
||||||
|
auto it = tbl->props.find(path[i]);
|
||||||
|
if (it == tbl->props.end())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
t = it->second.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last path segment should not be a property of the table at all.
|
||||||
|
// We are not changing property types. We are only admitting this one
|
||||||
|
// new property to be appended.
|
||||||
|
if (!isUnsealedTable(t))
|
||||||
|
return std::nullopt;
|
||||||
|
const TableTypeVar* tbl = get<TableTypeVar>(t);
|
||||||
|
if (0 != tbl->props.count(path.back()))
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeId res = shallowClone(ty, arena);
|
||||||
|
TypeId t = res;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < path.size() - 1; ++i)
|
||||||
|
{
|
||||||
|
const std::string segment = path[i];
|
||||||
|
|
||||||
|
TableTypeVar* ttv = getMutable<TableTypeVar>(t);
|
||||||
|
LUAU_ASSERT(ttv);
|
||||||
|
|
||||||
|
auto propIt = ttv->props.find(segment);
|
||||||
|
if (propIt != ttv->props.end())
|
||||||
|
{
|
||||||
|
LUAU_ASSERT(isUnsealedTable(propIt->second.type));
|
||||||
|
t = shallowClone(follow(propIt->second.type), arena);
|
||||||
|
ttv->props[segment].type = t;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableTypeVar* ttv = getMutable<TableTypeVar>(t);
|
||||||
|
LUAU_ASSERT(ttv);
|
||||||
|
|
||||||
|
const std::string lastSegment = path.back();
|
||||||
|
LUAU_ASSERT(0 == ttv->props.count(lastSegment));
|
||||||
|
ttv->props[lastSegment] = Property{replaceTy};
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint)
|
||||||
|
{
|
||||||
|
TypeId subjectType = follow(c.subjectType);
|
||||||
|
|
||||||
|
if (isBlocked(subjectType))
|
||||||
|
return block(subjectType, constraint);
|
||||||
|
|
||||||
|
std::optional<TypeId> existingPropType = subjectType;
|
||||||
|
for (const std::string& segment : c.path)
|
||||||
|
{
|
||||||
|
ErrorVec e;
|
||||||
|
std::optional<TypeId> propTy = lookupTableProp(*existingPropType, segment);
|
||||||
|
if (!propTy)
|
||||||
|
{
|
||||||
|
existingPropType = std::nullopt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (isBlocked(*propTy))
|
||||||
|
return block(*propTy, constraint);
|
||||||
|
else
|
||||||
|
existingPropType = follow(*propTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bind = [](TypeId a, TypeId b) {
|
||||||
|
asMutable(a)->ty.emplace<BoundTypeVar>(b);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto ttv = get<TableTypeVar>(subjectType))
|
if (existingPropType)
|
||||||
{
|
{
|
||||||
if (auto prop = ttv->props.find(c.prop); prop != ttv->props.end())
|
unify(c.propType, *existingPropType, constraint->scope);
|
||||||
resultType = prop->second.type;
|
bind(c.resultType, c.subjectType);
|
||||||
else if (ttv->indexer && maybeString(ttv->indexer->indexType))
|
return true;
|
||||||
resultType = ttv->indexer->indexResultType;
|
|
||||||
}
|
}
|
||||||
else if (auto utv = get<UnionTypeVar>(subjectType))
|
|
||||||
{
|
|
||||||
auto [blocked, parts] = collectParts(utv);
|
|
||||||
|
|
||||||
if (blocked)
|
if (get<FreeTypeVar>(subjectType))
|
||||||
return false;
|
{
|
||||||
else if (parts.size() == 1)
|
TypeId ty = arena->freshType(constraint->scope);
|
||||||
resultType = parts[0];
|
|
||||||
else if (parts.size() > 1)
|
// Mint a chain of free tables per c.path
|
||||||
resultType = arena->addType(UnionTypeVar{std::move(parts)});
|
for (auto it = rbegin(c.path); it != rend(c.path); ++it)
|
||||||
|
{
|
||||||
|
TableTypeVar t{TableState::Free, TypeLevel{}, constraint->scope};
|
||||||
|
t.props[*it] = {ty};
|
||||||
|
|
||||||
|
ty = arena->addType(std::move(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
LUAU_ASSERT(ty);
|
||||||
|
|
||||||
|
bind(subjectType, ty);
|
||||||
|
bind(c.resultType, ty);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (auto ttv = getMutable<TableTypeVar>(subjectType))
|
||||||
|
{
|
||||||
|
if (ttv->state == TableState::Free)
|
||||||
|
{
|
||||||
|
ttv->props[c.path[0]] = Property{c.propType};
|
||||||
|
bind(c.resultType, c.subjectType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ttv->state == TableState::Unsealed)
|
||||||
|
{
|
||||||
|
std::optional<TypeId> augmented = updateTheTableType(NotNull{arena}, subjectType, c.path, c.propType);
|
||||||
|
bind(c.resultType, augmented.value_or(subjectType));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LUAU_ASSERT(false); // parts.size() == 0
|
|
||||||
}
|
|
||||||
else if (auto itv = get<IntersectionTypeVar>(subjectType))
|
|
||||||
{
|
{
|
||||||
auto [blocked, parts] = collectParts(itv);
|
bind(c.resultType, subjectType);
|
||||||
|
return true;
|
||||||
if (blocked)
|
}
|
||||||
return false;
|
}
|
||||||
else if (parts.size() == 1)
|
else if (get<AnyTypeVar>(subjectType) || get<ErrorTypeVar>(subjectType))
|
||||||
resultType = parts[0];
|
{
|
||||||
else if (parts.size() > 1)
|
bind(c.resultType, subjectType);
|
||||||
resultType = arena->addType(IntersectionTypeVar{std::move(parts)});
|
return true;
|
||||||
else
|
|
||||||
LUAU_ASSERT(false); // parts.size() == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultType)
|
LUAU_ASSERT(0);
|
||||||
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(resultType);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1481,6 +1595,68 @@ bool ConstraintSolver::tryDispatchIterableFunction(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, const std::string& propName)
|
||||||
|
{
|
||||||
|
auto collectParts = [&](auto&& unionOrIntersection) -> std::pair<std::optional<TypeId>, std::vector<TypeId>> {
|
||||||
|
std::optional<TypeId> blocked;
|
||||||
|
|
||||||
|
std::vector<TypeId> parts;
|
||||||
|
for (TypeId expectedPart : unionOrIntersection)
|
||||||
|
{
|
||||||
|
expectedPart = follow(expectedPart);
|
||||||
|
if (isBlocked(expectedPart) || get<PendingExpansionTypeVar>(expectedPart))
|
||||||
|
blocked = expectedPart;
|
||||||
|
else if (const TableTypeVar* ttv = get<TableTypeVar>(follow(expectedPart)))
|
||||||
|
{
|
||||||
|
if (auto prop = ttv->props.find(propName); prop != ttv->props.end())
|
||||||
|
parts.push_back(prop->second.type);
|
||||||
|
else if (ttv->indexer && maybeString(ttv->indexer->indexType))
|
||||||
|
parts.push_back(ttv->indexer->indexResultType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {blocked, parts};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<TypeId> resultType;
|
||||||
|
|
||||||
|
if (auto ttv = get<TableTypeVar>(subjectType))
|
||||||
|
{
|
||||||
|
if (auto prop = ttv->props.find(propName); prop != ttv->props.end())
|
||||||
|
resultType = prop->second.type;
|
||||||
|
else if (ttv->indexer && maybeString(ttv->indexer->indexType))
|
||||||
|
resultType = ttv->indexer->indexResultType;
|
||||||
|
}
|
||||||
|
else if (auto utv = get<UnionTypeVar>(subjectType))
|
||||||
|
{
|
||||||
|
auto [blocked, parts] = collectParts(utv);
|
||||||
|
|
||||||
|
if (blocked)
|
||||||
|
resultType = *blocked;
|
||||||
|
else if (parts.size() == 1)
|
||||||
|
resultType = parts[0];
|
||||||
|
else if (parts.size() > 1)
|
||||||
|
resultType = arena->addType(UnionTypeVar{std::move(parts)});
|
||||||
|
else
|
||||||
|
LUAU_ASSERT(false); // parts.size() == 0
|
||||||
|
}
|
||||||
|
else if (auto itv = get<IntersectionTypeVar>(subjectType))
|
||||||
|
{
|
||||||
|
auto [blocked, parts] = collectParts(itv);
|
||||||
|
|
||||||
|
if (blocked)
|
||||||
|
resultType = *blocked;
|
||||||
|
else if (parts.size() == 1)
|
||||||
|
resultType = parts[0];
|
||||||
|
else if (parts.size() > 1)
|
||||||
|
resultType = arena->addType(IntersectionTypeVar{std::move(parts)});
|
||||||
|
else
|
||||||
|
LUAU_ASSERT(false); // parts.size() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
void ConstraintSolver::block_(BlockedConstraintId target, NotNull<const Constraint> constraint)
|
void ConstraintSolver::block_(BlockedConstraintId target, NotNull<const Constraint> constraint)
|
||||||
{
|
{
|
||||||
blocked[target].push_back(constraint);
|
blocked[target].push_back(constraint);
|
||||||
|
@ -1487,6 +1487,11 @@ std::string toString(const Constraint& constraint, ToStringOptions& opts)
|
|||||||
{
|
{
|
||||||
return tos(c.resultType) + " ~ hasProp " + tos(c.subjectType) + ", \"" + c.prop + "\"";
|
return tos(c.resultType) + " ~ hasProp " + tos(c.subjectType) + ", \"" + c.prop + "\"";
|
||||||
}
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, SetPropConstraint>)
|
||||||
|
{
|
||||||
|
const std::string pathStr = c.path.size() == 1 ? "\"" + c.path[0] + "\"" : "[\"" + join(c.path, "\", \"") + "\"]";
|
||||||
|
return tos(c.resultType) + " ~ setProp " + tos(c.subjectType) + ", " + pathStr + " " + tos(c.propType);
|
||||||
|
}
|
||||||
else if constexpr (std::is_same_v<T, SingletonOrTopTypeConstraint>)
|
else if constexpr (std::is_same_v<T, SingletonOrTopTypeConstraint>)
|
||||||
{
|
{
|
||||||
std::string result = tos(c.resultType);
|
std::string result = tos(c.resultType);
|
||||||
|
@ -857,6 +857,15 @@ struct TypeChecker2
|
|||||||
args.head.push_back(argTy);
|
args.head.push_back(argTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (call->self)
|
||||||
|
{
|
||||||
|
AstExprIndexName* indexExpr = call->func->as<AstExprIndexName>();
|
||||||
|
if (!indexExpr)
|
||||||
|
ice.ice("method call expression has no 'self'");
|
||||||
|
|
||||||
|
args.head.insert(args.head.begin(), lookupType(indexExpr->expr));
|
||||||
|
}
|
||||||
|
|
||||||
TypePackId argsTp = arena.addTypePack(args);
|
TypePackId argsTp = arena.addTypePack(args);
|
||||||
FunctionTypeVar ftv{argsTp, expectedRetType};
|
FunctionTypeVar ftv{argsTp, expectedRetType};
|
||||||
TypeId expectedType = arena.addType(ftv);
|
TypeId expectedType = arena.addType(ftv);
|
||||||
|
@ -17,8 +17,12 @@ const size_t kPageSize = 4096;
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) && !(_POSIX_C_SOURCE >= 200112L)
|
||||||
|
const size_t kPageSize = getpagesize();
|
||||||
|
#else
|
||||||
const size_t kPageSize = sysconf(_SC_PAGESIZE);
|
const size_t kPageSize = sysconf(_SC_PAGESIZE);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@ -20,8 +20,12 @@ const size_t kPageSize = 4096;
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) && !(_POSIX_C_SOURCE >= 200112L)
|
||||||
|
const size_t kPageSize = getpagesize();
|
||||||
|
#else
|
||||||
const size_t kPageSize = sysconf(_SC_PAGESIZE);
|
const size_t kPageSize = sysconf(_SC_PAGESIZE);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static size_t alignToPageSize(size_t size)
|
static size_t alignToPageSize(size_t size)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,6 @@ inline bool isFlagExperimental(const char* flag)
|
|||||||
static const char* kList[] = {
|
static const char* kList[] = {
|
||||||
"LuauInterpolatedStringBaseSupport",
|
"LuauInterpolatedStringBaseSupport",
|
||||||
"LuauInstantiateInSubtyping", // requires some fixes to lua-apps code
|
"LuauInstantiateInSubtyping", // requires some fixes to lua-apps code
|
||||||
"LuauOptionalNextKey", // waiting for a fix to land in lua-apps
|
|
||||||
"LuauTryhardAnd", // waiting for a fix in graphql-lua -> apollo-client-lia -> lua-apps
|
"LuauTryhardAnd", // waiting for a fix in graphql-lua -> apollo-client-lia -> lua-apps
|
||||||
// makes sure we always have at least one entry
|
// makes sure we always have at least one entry
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -148,7 +148,6 @@ void lua_rawcheckstack(lua_State* L, int size)
|
|||||||
{
|
{
|
||||||
luaD_checkstack(L, size);
|
luaD_checkstack(L, size);
|
||||||
expandstacklimit(L, L->top + size);
|
expandstacklimit(L, L->top + size);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_xmove(lua_State* from, lua_State* to, int n)
|
void lua_xmove(lua_State* from, lua_State* to, int n)
|
||||||
@ -167,8 +166,6 @@ void lua_xmove(lua_State* from, lua_State* to, int n)
|
|||||||
|
|
||||||
from->top = ftop;
|
from->top = ftop;
|
||||||
to->top = ttop + n;
|
to->top = ttop + n;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_xpush(lua_State* from, lua_State* to, int idx)
|
void lua_xpush(lua_State* from, lua_State* to, int idx)
|
||||||
@ -177,7 +174,6 @@ void lua_xpush(lua_State* from, lua_State* to, int idx)
|
|||||||
luaC_threadbarrier(to);
|
luaC_threadbarrier(to);
|
||||||
setobj2s(to, to->top, index2addr(from, idx));
|
setobj2s(to, to->top, index2addr(from, idx));
|
||||||
api_incr_top(to);
|
api_incr_top(to);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_State* lua_newthread(lua_State* L)
|
lua_State* lua_newthread(lua_State* L)
|
||||||
@ -227,7 +223,6 @@ void lua_settop(lua_State* L, int idx)
|
|||||||
api_check(L, -(idx + 1) <= (L->top - L->base));
|
api_check(L, -(idx + 1) <= (L->top - L->base));
|
||||||
L->top += idx + 1; // `subtract' index (index is negative)
|
L->top += idx + 1; // `subtract' index (index is negative)
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_remove(lua_State* L, int idx)
|
void lua_remove(lua_State* L, int idx)
|
||||||
@ -237,7 +232,6 @@ void lua_remove(lua_State* L, int idx)
|
|||||||
while (++p < L->top)
|
while (++p < L->top)
|
||||||
setobj2s(L, p - 1, p);
|
setobj2s(L, p - 1, p);
|
||||||
L->top--;
|
L->top--;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_insert(lua_State* L, int idx)
|
void lua_insert(lua_State* L, int idx)
|
||||||
@ -248,7 +242,6 @@ void lua_insert(lua_State* L, int idx)
|
|||||||
for (StkId q = L->top; q > p; q--)
|
for (StkId q = L->top; q > p; q--)
|
||||||
setobj2s(L, q, q - 1);
|
setobj2s(L, q, q - 1);
|
||||||
setobj2s(L, p, L->top);
|
setobj2s(L, p, L->top);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_replace(lua_State* L, int idx)
|
void lua_replace(lua_State* L, int idx)
|
||||||
@ -277,7 +270,6 @@ void lua_replace(lua_State* L, int idx)
|
|||||||
luaC_barrier(L, curr_func(L), L->top - 1);
|
luaC_barrier(L, curr_func(L), L->top - 1);
|
||||||
}
|
}
|
||||||
L->top--;
|
L->top--;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushvalue(lua_State* L, int idx)
|
void lua_pushvalue(lua_State* L, int idx)
|
||||||
@ -286,7 +278,6 @@ void lua_pushvalue(lua_State* L, int idx)
|
|||||||
StkId o = index2addr(L, idx);
|
StkId o = index2addr(L, idx);
|
||||||
setobj2s(L, L->top, o);
|
setobj2s(L, L->top, o);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -570,28 +561,24 @@ void lua_pushnil(lua_State* L)
|
|||||||
{
|
{
|
||||||
setnilvalue(L->top);
|
setnilvalue(L->top);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushnumber(lua_State* L, double n)
|
void lua_pushnumber(lua_State* L, double n)
|
||||||
{
|
{
|
||||||
setnvalue(L->top, n);
|
setnvalue(L->top, n);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushinteger(lua_State* L, int n)
|
void lua_pushinteger(lua_State* L, int n)
|
||||||
{
|
{
|
||||||
setnvalue(L->top, cast_num(n));
|
setnvalue(L->top, cast_num(n));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushunsigned(lua_State* L, unsigned u)
|
void lua_pushunsigned(lua_State* L, unsigned u)
|
||||||
{
|
{
|
||||||
setnvalue(L->top, cast_num(u));
|
setnvalue(L->top, cast_num(u));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LUA_VECTOR_SIZE == 4
|
#if LUA_VECTOR_SIZE == 4
|
||||||
@ -599,14 +586,12 @@ void lua_pushvector(lua_State* L, float x, float y, float z, float w)
|
|||||||
{
|
{
|
||||||
setvvalue(L->top, x, y, z, w);
|
setvvalue(L->top, x, y, z, w);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void lua_pushvector(lua_State* L, float x, float y, float z)
|
void lua_pushvector(lua_State* L, float x, float y, float z)
|
||||||
{
|
{
|
||||||
setvvalue(L->top, x, y, z, 0.0f);
|
setvvalue(L->top, x, y, z, 0.0f);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -616,7 +601,6 @@ void lua_pushlstring(lua_State* L, const char* s, size_t len)
|
|||||||
luaC_threadbarrier(L);
|
luaC_threadbarrier(L);
|
||||||
setsvalue(L, L->top, luaS_newlstr(L, s, len));
|
setsvalue(L, L->top, luaS_newlstr(L, s, len));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushstring(lua_State* L, const char* s)
|
void lua_pushstring(lua_State* L, const char* s)
|
||||||
@ -661,21 +645,18 @@ void lua_pushcclosurek(lua_State* L, lua_CFunction fn, const char* debugname, in
|
|||||||
setclvalue(L, L->top, cl);
|
setclvalue(L, L->top, cl);
|
||||||
LUAU_ASSERT(iswhite(obj2gco(cl)));
|
LUAU_ASSERT(iswhite(obj2gco(cl)));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushboolean(lua_State* L, int b)
|
void lua_pushboolean(lua_State* L, int b)
|
||||||
{
|
{
|
||||||
setbvalue(L->top, (b != 0)); // ensure that true is 1
|
setbvalue(L->top, (b != 0)); // ensure that true is 1
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_pushlightuserdata(lua_State* L, void* p)
|
void lua_pushlightuserdata(lua_State* L, void* p)
|
||||||
{
|
{
|
||||||
setpvalue(L->top, p);
|
setpvalue(L->top, p);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_pushthread(lua_State* L)
|
int lua_pushthread(lua_State* L)
|
||||||
@ -748,7 +729,6 @@ void lua_createtable(lua_State* L, int narray, int nrec)
|
|||||||
luaC_threadbarrier(L);
|
luaC_threadbarrier(L);
|
||||||
sethvalue(L, L->top, luaH_new(L, narray, nrec));
|
sethvalue(L, L->top, luaH_new(L, narray, nrec));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_setreadonly(lua_State* L, int objindex, int enabled)
|
void lua_setreadonly(lua_State* L, int objindex, int enabled)
|
||||||
@ -758,7 +738,6 @@ void lua_setreadonly(lua_State* L, int objindex, int enabled)
|
|||||||
Table* t = hvalue(o);
|
Table* t = hvalue(o);
|
||||||
api_check(L, t != hvalue(registry(L)));
|
api_check(L, t != hvalue(registry(L)));
|
||||||
t->readonly = bool(enabled);
|
t->readonly = bool(enabled);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_getreadonly(lua_State* L, int objindex)
|
int lua_getreadonly(lua_State* L, int objindex)
|
||||||
@ -776,7 +755,6 @@ void lua_setsafeenv(lua_State* L, int objindex, int enabled)
|
|||||||
api_check(L, ttistable(o));
|
api_check(L, ttistable(o));
|
||||||
Table* t = hvalue(o);
|
Table* t = hvalue(o);
|
||||||
t->safeenv = bool(enabled);
|
t->safeenv = bool(enabled);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_getmetatable(lua_State* L, int objindex)
|
int lua_getmetatable(lua_State* L, int objindex)
|
||||||
@ -822,7 +800,6 @@ void lua_getfenv(lua_State* L, int idx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -836,7 +813,6 @@ void lua_settable(lua_State* L, int idx)
|
|||||||
api_checkvalidindex(L, t);
|
api_checkvalidindex(L, t);
|
||||||
luaV_settable(L, t, L->top - 2, L->top - 1);
|
luaV_settable(L, t, L->top - 2, L->top - 1);
|
||||||
L->top -= 2; // pop index and value
|
L->top -= 2; // pop index and value
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_setfield(lua_State* L, int idx, const char* k)
|
void lua_setfield(lua_State* L, int idx, const char* k)
|
||||||
@ -848,7 +824,6 @@ void lua_setfield(lua_State* L, int idx, const char* k)
|
|||||||
setsvalue(L, &key, luaS_new(L, k));
|
setsvalue(L, &key, luaS_new(L, k));
|
||||||
luaV_settable(L, t, &key, L->top - 1);
|
luaV_settable(L, t, &key, L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_rawsetfield(lua_State* L, int idx, const char* k)
|
void lua_rawsetfield(lua_State* L, int idx, const char* k)
|
||||||
@ -861,7 +836,6 @@ void lua_rawsetfield(lua_State* L, int idx, const char* k)
|
|||||||
setobj2t(L, luaH_setstr(L, hvalue(t), luaS_new(L, k)), L->top - 1);
|
setobj2t(L, luaH_setstr(L, hvalue(t), luaS_new(L, k)), L->top - 1);
|
||||||
luaC_barriert(L, hvalue(t), L->top - 1);
|
luaC_barriert(L, hvalue(t), L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_rawset(lua_State* L, int idx)
|
void lua_rawset(lua_State* L, int idx)
|
||||||
@ -874,7 +848,6 @@ void lua_rawset(lua_State* L, int idx)
|
|||||||
setobj2t(L, luaH_set(L, hvalue(t), L->top - 2), L->top - 1);
|
setobj2t(L, luaH_set(L, hvalue(t), L->top - 2), L->top - 1);
|
||||||
luaC_barriert(L, hvalue(t), L->top - 1);
|
luaC_barriert(L, hvalue(t), L->top - 1);
|
||||||
L->top -= 2;
|
L->top -= 2;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_rawseti(lua_State* L, int idx, int n)
|
void lua_rawseti(lua_State* L, int idx, int n)
|
||||||
@ -887,7 +860,6 @@ void lua_rawseti(lua_State* L, int idx, int n)
|
|||||||
setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top - 1);
|
setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top - 1);
|
||||||
luaC_barriert(L, hvalue(o), L->top - 1);
|
luaC_barriert(L, hvalue(o), L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_setmetatable(lua_State* L, int objindex)
|
int lua_setmetatable(lua_State* L, int objindex)
|
||||||
@ -979,7 +951,6 @@ void lua_call(lua_State* L, int nargs, int nresults)
|
|||||||
luaD_call(L, func, nresults);
|
luaD_call(L, func, nresults);
|
||||||
|
|
||||||
adjustresults(L, nresults);
|
adjustresults(L, nresults);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -995,7 +966,6 @@ static void f_call(lua_State* L, void* ud)
|
|||||||
{
|
{
|
||||||
struct CallS* c = cast_to(struct CallS*, ud);
|
struct CallS* c = cast_to(struct CallS*, ud);
|
||||||
luaD_call(L, c->func, c->nresults);
|
luaD_call(L, c->func, c->nresults);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_pcall(lua_State* L, int nargs, int nresults, int errfunc)
|
int lua_pcall(lua_State* L, int nargs, int nresults, int errfunc)
|
||||||
@ -1273,7 +1243,6 @@ void lua_concat(lua_State* L, int n)
|
|||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
// else n == 1; nothing to do
|
// else n == 1; nothing to do
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* lua_newuserdatatagged(lua_State* L, size_t sz, int tag)
|
void* lua_newuserdatatagged(lua_State* L, size_t sz, int tag)
|
||||||
@ -1397,7 +1366,6 @@ void lua_unref(lua_State* L, int ref)
|
|||||||
TValue* slot = luaH_setnum(L, reg, ref);
|
TValue* slot = luaH_setnum(L, reg, ref);
|
||||||
setnvalue(slot, g->registryfree); // NB: no barrier needed because value isn't collectable
|
setnvalue(slot, g->registryfree); // NB: no barrier needed because value isn't collectable
|
||||||
g->registryfree = ref;
|
g->registryfree = ref;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_setuserdatatag(lua_State* L, int idx, int tag)
|
void lua_setuserdatatag(lua_State* L, int idx, int tag)
|
||||||
|
@ -50,7 +50,7 @@ TEST_CASE_FIXTURE(Fixture, "augment_table")
|
|||||||
const TableTypeVar* tType = get<TableTypeVar>(requireType("t"));
|
const TableTypeVar* tType = get<TableTypeVar>(requireType("t"));
|
||||||
REQUIRE(tType != nullptr);
|
REQUIRE(tType != nullptr);
|
||||||
|
|
||||||
CHECK(1 == tType->props.count("foo"));
|
CHECK("{ foo: string }" == toString(requireType("t"), {true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "augment_nested_table")
|
TEST_CASE_FIXTURE(Fixture, "augment_nested_table")
|
||||||
@ -65,7 +65,7 @@ TEST_CASE_FIXTURE(Fixture, "augment_nested_table")
|
|||||||
const TableTypeVar* pType = get<TableTypeVar>(tType->props["p"].type);
|
const TableTypeVar* pType = get<TableTypeVar>(tType->props["p"].type);
|
||||||
REQUIRE(pType != nullptr);
|
REQUIRE(pType != nullptr);
|
||||||
|
|
||||||
CHECK(pType->props.find("foo") != pType->props.end());
|
CHECK("{ p: { foo: string } }" == toString(requireType("t"), {true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "cannot_augment_sealed_table")
|
TEST_CASE_FIXTURE(Fixture, "cannot_augment_sealed_table")
|
||||||
|
@ -51,7 +51,6 @@ BuiltinTests.dont_add_definitions_to_persistent_types
|
|||||||
BuiltinTests.find_capture_types
|
BuiltinTests.find_capture_types
|
||||||
BuiltinTests.find_capture_types2
|
BuiltinTests.find_capture_types2
|
||||||
BuiltinTests.find_capture_types3
|
BuiltinTests.find_capture_types3
|
||||||
BuiltinTests.gmatch_capture_types2
|
|
||||||
BuiltinTests.gmatch_capture_types_balanced_escaped_parens
|
BuiltinTests.gmatch_capture_types_balanced_escaped_parens
|
||||||
BuiltinTests.gmatch_capture_types_default_capture
|
BuiltinTests.gmatch_capture_types_default_capture
|
||||||
BuiltinTests.gmatch_capture_types_parens_in_sets_are_ignored
|
BuiltinTests.gmatch_capture_types_parens_in_sets_are_ignored
|
||||||
@ -73,9 +72,7 @@ BuiltinTests.string_format_arg_count_mismatch
|
|||||||
BuiltinTests.string_format_as_method
|
BuiltinTests.string_format_as_method
|
||||||
BuiltinTests.string_format_correctly_ordered_types
|
BuiltinTests.string_format_correctly_ordered_types
|
||||||
BuiltinTests.string_format_report_all_type_errors_at_correct_positions
|
BuiltinTests.string_format_report_all_type_errors_at_correct_positions
|
||||||
BuiltinTests.string_format_use_correct_argument
|
|
||||||
BuiltinTests.string_format_use_correct_argument2
|
BuiltinTests.string_format_use_correct_argument2
|
||||||
BuiltinTests.strings_have_methods
|
|
||||||
BuiltinTests.table_freeze_is_generic
|
BuiltinTests.table_freeze_is_generic
|
||||||
BuiltinTests.table_insert_correctly_infers_type_of_array_2_args_overload
|
BuiltinTests.table_insert_correctly_infers_type_of_array_2_args_overload
|
||||||
BuiltinTests.table_insert_correctly_infers_type_of_array_3_args_overload
|
BuiltinTests.table_insert_correctly_infers_type_of_array_3_args_overload
|
||||||
@ -115,7 +112,6 @@ GenericsTests.infer_generic_function_function_argument
|
|||||||
GenericsTests.infer_generic_function_function_argument_overloaded
|
GenericsTests.infer_generic_function_function_argument_overloaded
|
||||||
GenericsTests.infer_generic_methods
|
GenericsTests.infer_generic_methods
|
||||||
GenericsTests.infer_generic_property
|
GenericsTests.infer_generic_property
|
||||||
GenericsTests.instantiate_cyclic_generic_function
|
|
||||||
GenericsTests.instantiated_function_argument_names
|
GenericsTests.instantiated_function_argument_names
|
||||||
GenericsTests.instantiation_sharing_types
|
GenericsTests.instantiation_sharing_types
|
||||||
GenericsTests.no_stack_overflow_from_quantifying
|
GenericsTests.no_stack_overflow_from_quantifying
|
||||||
@ -198,7 +194,6 @@ RefinementTest.x_as_any_if_x_is_instance_elseif_x_is_table
|
|||||||
RefinementTest.x_is_not_instance_or_else_not_part
|
RefinementTest.x_is_not_instance_or_else_not_part
|
||||||
RuntimeLimits.typescript_port_of_Result_type
|
RuntimeLimits.typescript_port_of_Result_type
|
||||||
TableTests.a_free_shape_can_turn_into_a_scalar_directly
|
TableTests.a_free_shape_can_turn_into_a_scalar_directly
|
||||||
TableTests.a_free_shape_can_turn_into_a_scalar_if_it_is_compatible
|
|
||||||
TableTests.a_free_shape_cannot_turn_into_a_scalar_if_it_is_not_compatible
|
TableTests.a_free_shape_cannot_turn_into_a_scalar_if_it_is_not_compatible
|
||||||
TableTests.access_index_metamethod_that_returns_variadic
|
TableTests.access_index_metamethod_that_returns_variadic
|
||||||
TableTests.accidentally_checked_prop_in_opposite_branch
|
TableTests.accidentally_checked_prop_in_opposite_branch
|
||||||
@ -269,7 +264,6 @@ TableTests.reasonable_error_when_adding_a_nonexistent_property_to_an_array_like_
|
|||||||
TableTests.result_is_always_any_if_lhs_is_any
|
TableTests.result_is_always_any_if_lhs_is_any
|
||||||
TableTests.result_is_bool_for_equality_operators_if_lhs_is_any
|
TableTests.result_is_bool_for_equality_operators_if_lhs_is_any
|
||||||
TableTests.right_table_missing_key2
|
TableTests.right_table_missing_key2
|
||||||
TableTests.scalar_is_a_subtype_of_a_compatible_polymorphic_shape_type
|
|
||||||
TableTests.scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type
|
TableTests.scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type
|
||||||
TableTests.shared_selfs
|
TableTests.shared_selfs
|
||||||
TableTests.shared_selfs_from_free_param
|
TableTests.shared_selfs_from_free_param
|
||||||
@ -285,7 +279,6 @@ TableTests.table_subtyping_with_missing_props_dont_report_multiple_errors
|
|||||||
TableTests.tables_get_names_from_their_locals
|
TableTests.tables_get_names_from_their_locals
|
||||||
TableTests.tc_member_function
|
TableTests.tc_member_function
|
||||||
TableTests.tc_member_function_2
|
TableTests.tc_member_function_2
|
||||||
TableTests.type_mismatch_on_massive_table_is_cut_short
|
|
||||||
TableTests.unification_of_unions_in_a_self_referential_type
|
TableTests.unification_of_unions_in_a_self_referential_type
|
||||||
TableTests.unifying_tables_shouldnt_uaf2
|
TableTests.unifying_tables_shouldnt_uaf2
|
||||||
TableTests.used_colon_instead_of_dot
|
TableTests.used_colon_instead_of_dot
|
||||||
@ -343,8 +336,6 @@ TypeInfer.type_infer_recursion_limit_no_ice
|
|||||||
TypeInfer.type_infer_recursion_limit_normalizer
|
TypeInfer.type_infer_recursion_limit_normalizer
|
||||||
TypeInferAnyError.for_in_loop_iterator_is_any2
|
TypeInferAnyError.for_in_loop_iterator_is_any2
|
||||||
TypeInferAnyError.for_in_loop_iterator_is_error2
|
TypeInferAnyError.for_in_loop_iterator_is_error2
|
||||||
TypeInferClasses.call_base_method
|
|
||||||
TypeInferClasses.call_instance_method
|
|
||||||
TypeInferClasses.can_read_prop_of_base_class_using_string
|
TypeInferClasses.can_read_prop_of_base_class_using_string
|
||||||
TypeInferClasses.class_type_mismatch_with_name_conflict
|
TypeInferClasses.class_type_mismatch_with_name_conflict
|
||||||
TypeInferClasses.classes_without_overloaded_operators_cannot_be_added
|
TypeInferClasses.classes_without_overloaded_operators_cannot_be_added
|
||||||
@ -429,10 +420,7 @@ TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection
|
|||||||
TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection_on_rhs
|
TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection_on_rhs
|
||||||
TypeInferOperators.UnknownGlobalCompoundAssign
|
TypeInferOperators.UnknownGlobalCompoundAssign
|
||||||
TypeInferPrimitives.CheckMethodsOfNumber
|
TypeInferPrimitives.CheckMethodsOfNumber
|
||||||
TypeInferPrimitives.singleton_types
|
|
||||||
TypeInferPrimitives.string_function_other
|
|
||||||
TypeInferPrimitives.string_index
|
TypeInferPrimitives.string_index
|
||||||
TypeInferPrimitives.string_method
|
|
||||||
TypeInferUnknownNever.assign_to_global_which_is_never
|
TypeInferUnknownNever.assign_to_global_which_is_never
|
||||||
TypeInferUnknownNever.assign_to_local_which_is_never
|
TypeInferUnknownNever.assign_to_local_which_is_never
|
||||||
TypeInferUnknownNever.assign_to_prop_which_is_never
|
TypeInferUnknownNever.assign_to_prop_which_is_never
|
||||||
|
Loading…
Reference in New Issue
Block a user