Skip to content

Commit

Permalink
Sync to upstream/release/561 (#820)
Browse files Browse the repository at this point in the history
* Fix a potential debugger crash by adding checks for invalid stack
index values

---------

Co-authored-by: Arseny Kapoulkine <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
3 people authored Jan 27, 2023
1 parent 4a2e801 commit f763f4c
Showing 63 changed files with 2,334 additions and 762 deletions.
1 change: 1 addition & 0 deletions Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
@@ -89,6 +89,7 @@ struct NameConstraint
{
TypeId namedType;
std::string name;
bool synthetic = false;
};

// target ~ inst target
5 changes: 5 additions & 0 deletions Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
@@ -80,6 +80,8 @@ struct ConstraintGraphBuilder
// A mapping of AST node to TypePackId.
DenseHashMap<const AstExpr*, TypePackId> astTypePacks{nullptr};

DenseHashMap<const AstExpr*, TypeId> astExpectedTypes{nullptr};

// If the node was applied as a function, this is the unspecialized type of
// that expression.
DenseHashMap<const void*, TypeId> astOriginalCallTypes{nullptr};
@@ -88,6 +90,8 @@ struct ConstraintGraphBuilder
// overload that was selected.
DenseHashMap<const void*, TypeId> astOverloadResolvedTypes{nullptr};



// Types resolved from type annotations. Analogous to astTypes.
DenseHashMap<const AstType*, TypeId> astResolvedTypes{nullptr};

@@ -207,6 +211,7 @@ struct ConstraintGraphBuilder
Inference check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
Inference check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType);
Inference check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert);
Inference check(const ScopePtr& scope, AstExprInterpString* interpString);
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
std::tuple<TypeId, TypeId, ConnectiveId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);

3 changes: 2 additions & 1 deletion Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
@@ -253,7 +253,8 @@ struct NormalizedType
TypeId threads;

// The (meta)table part of the type.
// Each element of this set is a (meta)table type.
// Each element of this set is a (meta)table type, or the top `table` type.
// An empty set denotes never.
TypeIds tables;

// The function part of the type.
2 changes: 2 additions & 0 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
@@ -117,6 +117,7 @@ struct PrimitiveType
String,
Thread,
Function,
Table,
};

Type type;
@@ -651,6 +652,7 @@ struct BuiltinTypes
const TypeId threadType;
const TypeId functionType;
const TypeId classType;
const TypeId tableType;
const TypeId trueType;
const TypeId falseType;
const TypeId anyType;
3 changes: 0 additions & 3 deletions Analysis/include/Luau/VisitType.h
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@
#include "Luau/Type.h"

LUAU_FASTINT(LuauVisitRecursionLimit)
LUAU_FASTFLAG(LuauCompleteVisitor);

namespace Luau
{
@@ -322,8 +321,6 @@ struct GenericTypeVisitor
if (visit(ty, *ntv))
traverse(ntv->ty);
}
else if (!FFlag::LuauCompleteVisitor)
return visit_detail::unsee(seen, ty);
else
LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypeId) is not exhaustive!");

56 changes: 13 additions & 43 deletions Analysis/src/BuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
@@ -15,9 +15,7 @@

#include <algorithm>

LUAU_FASTFLAG(LuauUnknownAndNeverType)
LUAU_FASTFLAGVARIABLE(LuauBuiltInMetatableNoBadSynthetic, false)
LUAU_FASTFLAG(LuauReportShadowedTypeAlias)

/** FIXME: Many of these type definitions are not quite completely accurate.
*
@@ -252,11 +250,8 @@ void registerBuiltinTypes(Frontend& frontend)
frontend.getGlobalScope()->addBuiltinTypeBinding("string", TypeFun{{}, frontend.builtinTypes->stringType});
frontend.getGlobalScope()->addBuiltinTypeBinding("boolean", TypeFun{{}, frontend.builtinTypes->booleanType});
frontend.getGlobalScope()->addBuiltinTypeBinding("thread", TypeFun{{}, frontend.builtinTypes->threadType});
if (FFlag::LuauUnknownAndNeverType)
{
frontend.getGlobalScope()->addBuiltinTypeBinding("unknown", TypeFun{{}, frontend.builtinTypes->unknownType});
frontend.getGlobalScope()->addBuiltinTypeBinding("never", TypeFun{{}, frontend.builtinTypes->neverType});
}
frontend.getGlobalScope()->addBuiltinTypeBinding("unknown", TypeFun{{}, frontend.builtinTypes->unknownType});
frontend.getGlobalScope()->addBuiltinTypeBinding("never", TypeFun{{}, frontend.builtinTypes->neverType});
}

void registerBuiltinGlobals(TypeChecker& typeChecker)
@@ -315,7 +310,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker)
FunctionType{
{genericMT},
{},
arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}),
arena.addTypePack(TypePack{{tabTy, genericMT}}),
arena.addTypePack(TypePack{{tableMetaMT}})
}
), "@luau"
@@ -357,8 +352,7 @@ void registerBuiltinGlobals(Frontend& frontend)
LUAU_ASSERT(!frontend.globalTypes.types.isFrozen());
LUAU_ASSERT(!frontend.globalTypes.typePacks.isFrozen());

if (FFlag::LuauReportShadowedTypeAlias)
registerBuiltinTypes(frontend);
registerBuiltinTypes(frontend);

TypeArena& arena = frontend.globalTypes;
NotNull<BuiltinTypes> builtinTypes = frontend.builtinTypes;
@@ -409,7 +403,7 @@ void registerBuiltinGlobals(Frontend& frontend)
FunctionType{
{genericMT},
{},
arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}),
arena.addTypePack(TypePack{{tabTy, genericMT}}),
arena.addTypePack(TypePack{{tableMetaMT}})
}
), "@luau"
@@ -537,11 +531,8 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
{
auto [paramPack, _predicates] = withPredicate;

if (FFlag::LuauUnknownAndNeverType)
{
if (size(paramPack) < 2 && finite(paramPack))
return std::nullopt;
}
if (size(paramPack) < 2 && finite(paramPack))
return std::nullopt;

TypeArena& arena = typechecker.currentModule->internalTypes;

@@ -550,11 +541,8 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
TypeId target = follow(expectedArgs[0]);
TypeId mt = follow(expectedArgs[1]);

if (FFlag::LuauUnknownAndNeverType)
{
typechecker.tablify(target);
typechecker.tablify(mt);
}
typechecker.tablify(target);
typechecker.tablify(mt);

if (const auto& tab = get<TableType>(target))
{
@@ -564,9 +552,6 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
}
else
{
if (!FFlag::LuauUnknownAndNeverType)
typechecker.tablify(mt);

const TableType* mtTtv = get<TableType>(mt);
MetatableType mtv{target, mt};
if ((tab->name || tab->syntheticName) && (mtTtv && (mtTtv->name || mtTtv->syntheticName)))
@@ -583,12 +568,7 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
TypeId mtTy = arena.addType(mtv);

if (expr.args.size < 1)
{
if (FFlag::LuauUnknownAndNeverType)
return std::nullopt;
else
return WithPredicate<TypePackId>{};
}
return std::nullopt;

if (!expr.self)
{
@@ -635,20 +615,10 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionAssert(
if (head.size() > 0)
{
auto [ty, ok] = typechecker.pickTypesFromSense(head[0], true, typechecker.builtinTypes->nilType);
if (FFlag::LuauUnknownAndNeverType)
{
if (get<NeverType>(*ty))
head = {*ty};
else
head[0] = *ty;
}
if (get<NeverType>(*ty))
head = {*ty};
else
{
if (!ty)
head = {typechecker.nilType};
else
head[0] = *ty;
}
head[0] = *ty;
}

return WithPredicate<TypePackId>{arena.addTypePack(TypePack{std::move(head), tail})};
43 changes: 42 additions & 1 deletion Analysis/src/ConstraintGraphBuilder.cpp
Original file line number Diff line number Diff line change
@@ -414,6 +414,10 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
std::vector<TypeId> varTypes;
varTypes.reserve(local->vars.size);

// Used to name the first value type, even if it's not placed in varTypes,
// for the purpose of synthetic name attribution.
std::optional<TypeId> firstValueType;

for (AstLocal* local : local->vars)
{
TypeId ty = nullptr;
@@ -456,6 +460,9 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
else
varTypes[i] = exprType;
}

if (i == 0)
firstValueType = exprType;
}
else
{
@@ -488,6 +495,22 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
}
}

if (local->vars.size == 1 && local->values.size == 1 && firstValueType)
{
AstLocal* var = local->vars.data[0];
AstExpr* value = local->values.data[0];

if (value->is<AstExprTable>())
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
else if (const AstExprCall* call = value->as<AstExprCall>())
{
if (const AstExprGlobal* global = call->func->as<AstExprGlobal>(); global && global->name == "setmetatable")
{
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
}
}
}

for (size_t i = 0; i < local->vars.size; ++i)
{
AstLocal* l = local->vars.data[i];
@@ -1138,7 +1161,13 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
TypeId resultTy = arena->addType(mtv);

if (AstExprLocal* targetLocal = targetExpr->as<AstExprLocal>())
{
scope->bindings[targetLocal->local].typeId = resultTy;
auto def = dfg->getDef(targetLocal->local);
if (def)
scope->dcrRefinements[*def] = resultTy; // TODO: typestates: track this as an assignment
}


return InferencePack{arena->addTypePack({resultTy}), std::move(returnConnectives)};
}
@@ -1248,6 +1277,8 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st
result = check(scope, ifElse, expectedType);
else if (auto typeAssert = expr->as<AstExprTypeAssertion>())
result = check(scope, typeAssert);
else if (auto interpString = expr->as<AstExprInterpString>())
result = check(scope, interpString);
else if (auto err = expr->as<AstExprError>())
{
// Open question: Should we traverse into this?
@@ -1264,6 +1295,8 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st

LUAU_ASSERT(result.ty);
astTypes[expr] = result.ty;
if (expectedType)
astExpectedTypes[expr] = *expectedType;
return result;
}

@@ -1509,6 +1542,14 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTypeAssert
return Inference{resolveType(scope, typeAssert->annotation, /* inTypeArguments */ false)};
}

Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprInterpString* interpString)
{
for (AstExpr* expr : interpString->expressions)
check(scope, expr);

return Inference{builtinTypes->stringType};
}

std::tuple<TypeId, TypeId, ConnectiveId> ConstraintGraphBuilder::checkBinary(
const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
{
@@ -1551,7 +1592,7 @@ std::tuple<TypeId, TypeId, ConnectiveId> ConstraintGraphBuilder::checkBinary(
else if (typeguard->type == "boolean")
discriminantTy = builtinTypes->threadType;
else if (typeguard->type == "table")
discriminantTy = builtinTypes->neverType; // TODO: replace with top table type
discriminantTy = builtinTypes->tableType;
else if (typeguard->type == "function")
discriminantTy = builtinTypes->functionType;
else if (typeguard->type == "userdata")
37 changes: 30 additions & 7 deletions Analysis/src/ConstraintSolver.cpp
Original file line number Diff line number Diff line change
@@ -883,7 +883,12 @@ bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNull<const Constr
return true;

if (TableType* ttv = getMutable<TableType>(target))
ttv->name = c.name;
{
if (c.synthetic && !ttv->name)
ttv->syntheticName = c.name;
else
ttv->name = c.name;
}
else if (MetatableType* mtv = getMutable<MetatableType>(target))
mtv->syntheticName = c.name;
else if (get<IntersectionType>(target) || get<UnionType>(target))
@@ -1594,15 +1599,33 @@ bool ConstraintSolver::tryDispatchIterableFunction(
const TypeId firstIndex = isNil(firstIndexTy) ? arena->freshType(constraint->scope) // FIXME: Surely this should be a union (free | nil)
: firstIndexTy;

// nextTy : (tableTy, indexTy?) -> (indexTy, valueTailTy...)
// nextTy : (tableTy, indexTy?) -> (indexTy?, valueTailTy...)
const TypePackId nextArgPack = arena->addTypePack({tableTy, arena->addType(UnionType{{firstIndex, builtinTypes->nilType}})});
const TypePackId valueTailTy = arena->addTypePack(FreeTypePack{constraint->scope});
const TypePackId nextRetPack = arena->addTypePack(TypePack{{firstIndex}, valueTailTy});

const TypeId expectedNextTy = arena->addType(FunctionType{TypeLevel{}, constraint->scope, nextArgPack, nextRetPack});
unify(nextTy, expectedNextTy, constraint->scope);

pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack});
auto it = begin(nextRetPack);
std::vector<TypeId> modifiedNextRetHead;

// The first value is never nil in the context of the loop, even if it's nil
// in the next function's return type, because the loop will not advance if
// it's nil.
if (it != end(nextRetPack))
{
TypeId firstRet = *it;
TypeId modifiedFirstRet = stripNil(builtinTypes, *arena, firstRet);
modifiedNextRetHead.push_back(modifiedFirstRet);
++it;
}

for (; it != end(nextRetPack); ++it)
modifiedNextRetHead.push_back(*it);

TypePackId modifiedNextRetPack = arena->addTypePack(std::move(modifiedNextRetHead), it.tail());
pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, modifiedNextRetPack});

return true;
}
@@ -1649,8 +1672,8 @@ std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, cons
resultType = parts[0];
else if (parts.size() > 1)
resultType = arena->addType(UnionType{std::move(parts)});
else
LUAU_ASSERT(false); // parts.size() == 0

// otherwise, nothing: no matching property
}
else if (auto itv = get<IntersectionType>(subjectType))
{
@@ -1662,8 +1685,8 @@ std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, cons
resultType = parts[0];
else if (parts.size() > 1)
resultType = arena->addType(IntersectionType{std::move(parts)});
else
LUAU_ASSERT(false); // parts.size() == 0

// otherwise, nothing: no matching property
}

return resultType;
Loading

0 comments on commit f763f4c

Please sign in to comment.