Skip to content

Commit

Permalink
Sync to upstream/release/545 (#674)
Browse files Browse the repository at this point in the history
- Improve type error messages for argument count mismatch in certain
cases
- Fix type checking variadic returns when the type is incompatible which
type checked in certain cases
- Reduce size of upvalue objects by 8 bytes on 64-bit platforms
- Reduce I$ footprint of interpreter by 1.5KB
- Reduce GC pause during atomic stage for programs with a lot of threads
- Remove support for bytecode v2
  • Loading branch information
zeux authored Sep 15, 2022
1 parent 6fbea7c commit 3d74a8f
Show file tree
Hide file tree
Showing 57 changed files with 1,497 additions and 796 deletions.
3 changes: 3 additions & 0 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ struct ConstraintSolver
**/
void unblock_(BlockedConstraintId progressed);

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

ToStringOptions opts;
};

Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ struct CountMismatch
Return,
};
size_t expected;
std::optional<size_t> maximum;
size_t actual;
Context context = Arg;
bool isVariadic = false;
std::string function;

bool operator==(const CountMismatch& rhs) const;
};
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/ToString.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ inline std::string toString(const Constraint& c)
return toString(c, ToStringOptions{});
}

std::string toString(const LValue& lvalue);

std::string toString(const TypeVar& tv, ToStringOptions& opts);
std::string toString(const TypePackVar& tp, ToStringOptions& opts);

Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/TypeInfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ struct TypeChecker
std::optional<Location> originalNameLoc, std::optional<TypeId> selfType, std::optional<TypeId> expectedType);
void checkFunctionBody(const ScopePtr& scope, TypeId type, const AstExprFunction& function);

void checkArgumentList(
const ScopePtr& scope, Unifier& state, TypePackId paramPack, TypePackId argPack, const std::vector<Location>& argLocations);
void checkArgumentList(const ScopePtr& scope, const AstExpr& funName, Unifier& state, TypePackId paramPack, TypePackId argPack,
const std::vector<Location>& argLocations);

WithPredicate<TypePackId> checkExprPack(const ScopePtr& scope, const AstExpr& expr);

Expand Down
3 changes: 3 additions & 0 deletions Analysis/include/Luau/TypePack.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp,
bool isVariadic(TypePackId tp);
bool isVariadic(TypePackId tp, const TxnLog& log);

// Returns true if the TypePack is Generic or Variadic. Does not walk TypePacks!!
bool isVariadicTail(TypePackId tp, const TxnLog& log, bool includeHiddenVariadics = false);

bool containsNever(TypePackId tp);

} // namespace Luau
2 changes: 1 addition & 1 deletion Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, ErrorVec& erro
TypeId type, const std::string& prop, const Location& location, bool addErrors, InternalErrorReporter& handle);

// Returns the minimum and maximum number of types the argument list can accept.
std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp);
std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp, bool includeHiddenVariadics = false);

} // namespace Luau
36 changes: 33 additions & 3 deletions Analysis/src/ConstraintGraphBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,11 @@ TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* exp

if (AstExprCall* call = expr->as<AstExprCall>())
{
TypeId fnType = check(scope, call->func);

const size_t constraintIndex = scope->constraints.size();
const size_t scopeIndex = scopes.size();

std::vector<TypeId> args;

for (AstExpr* arg : call->args)
Expand All @@ -738,7 +743,8 @@ TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* exp

// TODO self

TypeId fnType = check(scope, call->func);
const size_t constraintEndIndex = scope->constraints.size();
const size_t scopeEndIndex = scopes.size();

astOriginalCallTypes[call->func] = fnType;

Expand All @@ -753,7 +759,23 @@ TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* exp

scope->unqueuedConstraints.push_back(
std::make_unique<Constraint>(NotNull{scope.get()}, call->func->location, SubtypeConstraint{inferredFnType, instantiatedType}));
NotNull<const Constraint> sc(scope->unqueuedConstraints.back().get());
NotNull<Constraint> sc(scope->unqueuedConstraints.back().get());

// We force constraints produced by checking function arguments to wait
// until after we have resolved the constraint on the function itself.
// This ensures, for instance, that we start inferring the contents of
// lambdas under the assumption that their arguments and return types
// will be compatible with the enclosing function call.
for (size_t ci = constraintIndex; ci < constraintEndIndex; ++ci)
scope->constraints[ci]->dependencies.push_back(sc);

for (size_t si = scopeIndex; si < scopeEndIndex; ++si)
{
for (auto& c : scopes[si].second->constraints)
{
c->dependencies.push_back(sc);
}
}

addConstraint(scope, call->func->location,
FunctionCallConstraint{
Expand Down Expand Up @@ -1080,7 +1102,7 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
signatureScope = bodyScope;
}

std::optional<TypePackId> varargPack;
TypePackId varargPack = nullptr;

if (fn->vararg)
{
Expand All @@ -1096,6 +1118,14 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS

signatureScope->varargPack = varargPack;
}
else
{
varargPack = arena->addTypePack(VariadicTypePack{singletonTypes->anyType, /*hidden*/ true});
// We do not add to signatureScope->varargPack because ... is not valid
// in functions without an explicit ellipsis.
}

LUAU_ASSERT(nullptr != varargPack);

if (fn->returnAnnotation)
{
Expand Down
77 changes: 57 additions & 20 deletions Analysis/src/ConstraintSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ void dump(ConstraintSolver* cs, ToStringOptions& opts)
int blockCount = it == cs->blockedConstraints.end() ? 0 : int(it->second);
printf("\t%d\t\t%s\n", blockCount, toString(*dep, opts).c_str());
}

if (auto fcc = get<FunctionCallConstraint>(*c))
{
for (NotNull<const Constraint> inner : fcc->innerConstraints)
printf("\t\t\t%s\n", toString(*inner, opts).c_str());
}
}
}

Expand Down Expand Up @@ -522,7 +528,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons

if (isBlocked(leftType))
{
asMutable(resultType)->ty.emplace<BoundTypeVar>(singletonTypes->errorRecoveryType());
asMutable(resultType)->ty.emplace<BoundTypeVar>(errorRecoveryType());
// reportError(constraint->location, CannotInferBinaryOperation{c.op, std::nullopt, CannotInferBinaryOperation::Operation});
return true;
}
Expand Down Expand Up @@ -574,10 +580,24 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull<const Co
if (iteratorTail)
return block_(*iteratorTail);

{
bool blocked = false;
for (TypeId t : iteratorTypes)
{
if (isBlocked(t))
{
block(t, constraint);
blocked = true;
}
}

if (blocked)
return false;
}

if (0 == iteratorTypes.size())
{
Anyification anyify{
arena, constraint->scope, singletonTypes, &iceReporter, singletonTypes->errorRecoveryType(), singletonTypes->errorRecoveryTypePack()};
Anyification anyify{arena, constraint->scope, singletonTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()};
std::optional<TypePackId> anyified = anyify.substitute(c.variables);
LUAU_ASSERT(anyified);
unify(*anyified, c.variables, constraint->scope);
Expand Down Expand Up @@ -704,7 +724,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
if (!tf.has_value())
{
reportError(UnknownSymbol{petv->name.value, UnknownSymbol::Context::Type}, constraint->location);
bindResult(singletonTypes->errorRecoveryType());
bindResult(errorRecoveryType());
return true;
}

Expand Down Expand Up @@ -763,7 +783,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
if (itf.foundInfiniteType)
{
// TODO (CLI-56761): Report an error.
bindResult(singletonTypes->errorRecoveryType());
bindResult(errorRecoveryType());
return true;
}

Expand All @@ -786,7 +806,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
if (!maybeInstantiated.has_value())
{
// TODO (CLI-56761): Report an error.
bindResult(singletonTypes->errorRecoveryType());
bindResult(errorRecoveryType());
return true;
}

Expand Down Expand Up @@ -863,13 +883,21 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
usedMagic = ftv->dcrMagicFunction(NotNull(this), result, c.astFragment);
}

if (!usedMagic)
if (usedMagic)
{
for (const auto& inner : c.innerConstraints)
{
unsolvedConstraints.push_back(inner);
}

// There are constraints that are blocked on these constraints. If we
// are never going to even examine them, then we should not block
// anything else on them.
//
// TODO CLI-58842
#if 0
for (auto& c: c.innerConstraints)
unblock(c);
#endif
}
else
{
unsolvedConstraints.insert(end(unsolvedConstraints), begin(c.innerConstraints), end(c.innerConstraints));
asMutable(c.result)->ty.emplace<FreeTypePack>(constraint->scope);
}

Expand Down Expand Up @@ -909,8 +937,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
};

auto errorify = [&](auto ty) {
Anyification anyify{
arena, constraint->scope, singletonTypes, &iceReporter, singletonTypes->errorRecoveryType(), singletonTypes->errorRecoveryTypePack()};
Anyification anyify{arena, constraint->scope, singletonTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()};
std::optional errorified = anyify.substitute(ty);
if (!errorified)
reportError(CodeTooComplex{}, constraint->location);
Expand Down Expand Up @@ -1119,7 +1146,7 @@ void ConstraintSolver::unify(TypeId subType, TypeId superType, NotNull<Scope> sc

if (!u.errors.empty())
{
TypeId errorType = singletonTypes->errorRecoveryType();
TypeId errorType = errorRecoveryType();
u.tryUnify(subType, errorType);
u.tryUnify(superType, errorType);
}
Expand Down Expand Up @@ -1160,7 +1187,7 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l
if (info.name.empty())
{
reportError(UnknownRequire{}, location);
return singletonTypes->errorRecoveryType();
return errorRecoveryType();
}

std::string humanReadableName = moduleResolver->getHumanReadableModuleName(info.name);
Expand All @@ -1177,24 +1204,24 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l
if (!moduleResolver->moduleExists(info.name) && !info.optional)
reportError(UnknownRequire{humanReadableName}, location);

return singletonTypes->errorRecoveryType();
return errorRecoveryType();
}

if (module->type != SourceCode::Type::Module)
{
reportError(IllegalRequire{humanReadableName, "Module is not a ModuleScript. It cannot be required."}, location);
return singletonTypes->errorRecoveryType();
return errorRecoveryType();
}

TypePackId modulePack = module->getModuleScope()->returnType;
if (get<Unifiable::Error>(modulePack))
return singletonTypes->errorRecoveryType();
return errorRecoveryType();

std::optional<TypeId> moduleType = first(modulePack);
if (!moduleType)
{
reportError(IllegalRequire{humanReadableName, "Module does not return exactly 1 value. It cannot be required."}, location);
return singletonTypes->errorRecoveryType();
return errorRecoveryType();
}

return *moduleType;
Expand All @@ -1212,4 +1239,14 @@ void ConstraintSolver::reportError(TypeError e)
errors.back().moduleName = currentModuleName;
}

TypeId ConstraintSolver::errorRecoveryType() const
{
return singletonTypes->errorRecoveryType();
}

TypePackId ConstraintSolver::errorRecoveryTypePack() const
{
return singletonTypes->errorRecoveryTypePack();
}

} // namespace Luau
21 changes: 15 additions & 6 deletions Analysis/src/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
LUAU_FASTFLAGVARIABLE(LuauTypeMismatchModuleNameResolution, false)
LUAU_FASTFLAGVARIABLE(LuauUseInternalCompilerErrorException, false)

static std::string wrongNumberOfArgsString(size_t expectedCount, size_t actualCount, const char* argPrefix = nullptr, bool isVariadic = false)
static std::string wrongNumberOfArgsString(
size_t expectedCount, std::optional<size_t> maximumCount, size_t actualCount, const char* argPrefix = nullptr, bool isVariadic = false)
{
std::string s = "expects ";

Expand All @@ -19,11 +20,14 @@ static std::string wrongNumberOfArgsString(size_t expectedCount, size_t actualCo

s += std::to_string(expectedCount) + " ";

if (maximumCount && expectedCount != *maximumCount)
s += "to " + std::to_string(*maximumCount) + " ";

if (argPrefix)
s += std::string(argPrefix) + " ";

s += "argument";
if (expectedCount != 1)
if ((maximumCount ? *maximumCount : expectedCount) != 1)
s += "s";

s += ", but ";
Expand Down Expand Up @@ -185,7 +189,12 @@ struct ErrorConverter
return "Function only returns " + std::to_string(e.expected) + " value" + expectedS + ". " + std::to_string(e.actual) +
" are required here";
case CountMismatch::Arg:
return "Argument count mismatch. Function " + wrongNumberOfArgsString(e.expected, e.actual, /*argPrefix*/ nullptr, e.isVariadic);
if (!e.function.empty())
return "Argument count mismatch. Function '" + e.function + "' " +
wrongNumberOfArgsString(e.expected, e.maximum, e.actual, /*argPrefix*/ nullptr, e.isVariadic);
else
return "Argument count mismatch. Function " +
wrongNumberOfArgsString(e.expected, e.maximum, e.actual, /*argPrefix*/ nullptr, e.isVariadic);
}

LUAU_ASSERT(!"Unknown context");
Expand Down Expand Up @@ -247,10 +256,10 @@ struct ErrorConverter

if (e.typeFun.typeParams.size() != e.actualParameters)
return "Generic type '" + name + "' " +
wrongNumberOfArgsString(e.typeFun.typeParams.size(), e.actualParameters, "type", !e.typeFun.typePackParams.empty());
wrongNumberOfArgsString(e.typeFun.typeParams.size(), std::nullopt, e.actualParameters, "type", !e.typeFun.typePackParams.empty());

return "Generic type '" + name + "' " +
wrongNumberOfArgsString(e.typeFun.typePackParams.size(), e.actualPackParameters, "type pack", /*isVariadic*/ false);
wrongNumberOfArgsString(e.typeFun.typePackParams.size(), std::nullopt, e.actualPackParameters, "type pack", /*isVariadic*/ false);
}

std::string operator()(const Luau::SyntaxError& e) const
Expand Down Expand Up @@ -547,7 +556,7 @@ bool DuplicateTypeDefinition::operator==(const DuplicateTypeDefinition& rhs) con

bool CountMismatch::operator==(const CountMismatch& rhs) const
{
return expected == rhs.expected && actual == rhs.actual && context == rhs.context;
return expected == rhs.expected && maximum == rhs.maximum && actual == rhs.actual && context == rhs.context && function == rhs.function;
}

bool FunctionDoesNotTakeSelf::operator==(const FunctionDoesNotTakeSelf&) const
Expand Down
16 changes: 16 additions & 0 deletions Analysis/src/ToString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1529,4 +1529,20 @@ std::string dump(const Constraint& c)
return s;
}

std::string toString(const LValue& lvalue)
{
std::string s;
for (const LValue* current = &lvalue; current; current = baseof(*current))
{
if (auto field = get<Field>(*current))
s = "." + field->key + s;
else if (auto symbol = get<Symbol>(*current))
s = toString(*symbol) + s;
else
LUAU_ASSERT(!"Unknown LValue");
}

return s;
}

} // namespace Luau
Loading

0 comments on commit 3d74a8f

Please sign in to comment.