Merge branch 'upstream' into merge

This commit is contained in:
Andy Friesen 2022-11-18 10:52:52 -08:00
commit 3ac3798e79
12 changed files with 301 additions and 188 deletions

View file

@ -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
{ {

View file

@ -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.

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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>

View file

@ -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)
{ {

View file

@ -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,

View file

@ -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)

View file

@ -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")

View file

@ -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