Skip to content

Commit

Permalink
Sync to upstream/release/650 (#1502)
Browse files Browse the repository at this point in the history
* New `vector` library! See https://rfcs.luau.org/vector-library.html
for details
* Replace the use of non-portable `strnlen` with `memchr`. `strnlen` is
not part of any C or C++ standard.
* Introduce `lua_newuserdatataggedwithmetatable` for faster tagged
userdata creation of userdata with metatables registered with
`lua_setuserdatametatable`

Old Solver

* It used to be the case that a module's result type would
unconditionally be inferred to be `any` if it imported any module that
participates in any import cycle. This is now fixed.

New Solver

* Improve inference of `table.freeze`: We now infer read-only properties
on tables after they have been frozen.
* We now correctly flag cases where `string.format` is called with 0
arguments.
* Fix a bug in user-defined type functions where table properties could
be lost if the table had a metatable
* Reset the random number seed for each evaluation of a type function
* We now retry subtyping arguments if it failed due to hidden variadics.

---------

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Vighnesh <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: David Cope <[email protected]>
Co-authored-by: Lily Brown <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
Co-authored-by: Junseo Yoo <[email protected]>
  • Loading branch information
9 people authored Nov 1, 2024
1 parent db80939 commit a251bc6
Show file tree
Hide file tree
Showing 86 changed files with 2,217 additions and 407 deletions.
2 changes: 2 additions & 0 deletions Analysis/include/Luau/TypeFunctionRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,6 @@ void registerTypeUserData(lua_State* L);

void setTypeFunctionEnvironment(lua_State* L);

void resetTypeFunctionState(lua_State* L);

} // namespace Luau
4 changes: 2 additions & 2 deletions Analysis/src/AnyTypeSummary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

#include <stdio.h>

LUAU_FASTFLAGVARIABLE(StudioReportLuauAny2, false);
LUAU_FASTFLAGVARIABLE(StudioReportLuauAny2);
LUAU_FASTINTVARIABLE(LuauAnySummaryRecursionLimit, 300);

LUAU_FASTFLAG(DebugLuauMagicTypes);
Expand Down Expand Up @@ -161,7 +161,7 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatReturn* ret, const Module*
typeInfo.push_back(ti);
}
}

if (ret->list.size > 1 && !seenTP)
{
if (containsAny(retScope->returnType))
Expand Down
2 changes: 1 addition & 1 deletion Analysis/src/AstQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

LUAU_FASTFLAG(LuauSolverV2)

LUAU_FASTFLAGVARIABLE(LuauDocumentationAtPosition, false)
LUAU_FASTFLAGVARIABLE(LuauDocumentationAtPosition)

namespace Luau
{
Expand Down
2 changes: 1 addition & 1 deletion Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <utility>

LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAGVARIABLE(AutocompleteRequirePathSuggestions, false)
LUAU_FASTFLAGVARIABLE(AutocompleteRequirePathSuggestions)

LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
LUAU_FASTINT(LuauTypeInferIterationLimit)
Expand Down
95 changes: 64 additions & 31 deletions Analysis/src/BuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "Luau/Ast.h"
#include "Luau/Clone.h"
#include "Luau/DenseHash.h"
#include "Luau/Error.h"
#include "Luau/Frontend.h"
#include "Luau/Symbol.h"
Expand All @@ -29,8 +30,8 @@

LUAU_FASTFLAG(LuauSolverV2)
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
LUAU_FASTFLAGVARIABLE(LuauTypestateBuiltins, false)
LUAU_FASTFLAGVARIABLE(LuauStringFormatArityFix, false)
LUAU_FASTFLAGVARIABLE(LuauTypestateBuiltins2)
LUAU_FASTFLAGVARIABLE(LuauStringFormatArityFix)

LUAU_FASTFLAG(AutocompleteRequirePathSuggestions)

Expand Down Expand Up @@ -421,7 +422,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC

attachMagicFunction(ttv->props["pack"].type(), magicFunctionPack);
attachDcrMagicFunction(ttv->props["pack"].type(), dcrMagicFunctionPack);
if (FFlag::LuauTypestateBuiltins)
if (FFlag::LuauTypestateBuiltins2)
attachDcrMagicFunction(ttv->props["freeze"].type(), dcrMagicFunctionFreeze);
}

Expand Down Expand Up @@ -1338,54 +1339,86 @@ static bool dcrMagicFunctionPack(MagicFunctionCallContext context)
return true;
}

static std::optional<TypeId> freezeTable(TypeId inputType, MagicFunctionCallContext& context)
{
TypeArena* arena = context.solver->arena;

if (auto mt = get<MetatableType>(inputType))
{
std::optional<TypeId> frozenTable = freezeTable(mt->table, context);

if (!frozenTable)
return std::nullopt;

TypeId resultType = arena->addType(MetatableType{*frozenTable, mt->metatable, mt->syntheticName});

return resultType;
}

if (get<TableType>(inputType))
{
// Clone the input type, this will become our final result type after we mutate it.
CloneState cloneState{context.solver->builtinTypes};
TypeId resultType = shallowClone(inputType, *arena, cloneState);
auto tableTy = getMutable<TableType>(resultType);
// `clone` should not break this.
LUAU_ASSERT(tableTy);
tableTy->state = TableState::Sealed;

// We'll mutate the table to make every property type read-only.
for (auto iter = tableTy->props.begin(); iter != tableTy->props.end();)
{
if (iter->second.isWriteOnly())
iter = tableTy->props.erase(iter);
else
{
iter->second.writeTy = std::nullopt;
iter++;
}
}

return resultType;
}

context.solver->reportError(TypeMismatch{context.solver->builtinTypes->tableType, inputType}, context.callSite->argLocation);
return std::nullopt;
}

static bool dcrMagicFunctionFreeze(MagicFunctionCallContext context)
{
LUAU_ASSERT(FFlag::LuauTypestateBuiltins);
LUAU_ASSERT(FFlag::LuauTypestateBuiltins2);

TypeArena* arena = context.solver->arena;
const DataFlowGraph* dfg = context.solver->dfg.get();
Scope* scope = context.constraint->scope.get();

const auto& [paramTypes, paramTail] = extendTypePack(*arena, context.solver->builtinTypes, context.arguments, 1);
LUAU_ASSERT(paramTypes.size() >= 1);

TypeId inputType = follow(paramTypes.at(0));

// we'll check if it's a table first since this magic function also produces the error if it's not until we have bounded generics
if (!get<TableType>(inputType))
if (paramTypes.empty() || context.callSite->args.size == 0)
{
context.solver->reportError(TypeMismatch{context.solver->builtinTypes->tableType, inputType}, context.callSite->argLocation);
context.solver->reportError(CountMismatch{1, std::nullopt, 0}, context.callSite->argLocation);
return false;
}

TypeId inputType = follow(paramTypes[0]);

AstExpr* targetExpr = context.callSite->args.data[0];
std::optional<DefId> resultDef = dfg->getDefOptional(targetExpr);
std::optional<TypeId> resultTy = resultDef ? scope->lookup(*resultDef) : std::nullopt;

// Clone the input type, this will become our final result type after we mutate it.
CloneState cloneState{context.solver->builtinTypes};
TypeId clonedType = shallowClone(inputType, *arena, cloneState);
auto tableTy = getMutable<TableType>(clonedType);
// `clone` should not break this.
LUAU_ASSERT(tableTy);
tableTy->state = TableState::Sealed;
tableTy->syntheticName = std::nullopt;

// We'll mutate the table to make every property type read-only.
for (auto iter = tableTy->props.begin(); iter != tableTy->props.end();)
std::optional<TypeId> frozenType = freezeTable(inputType, context);

if (!frozenType)
{
if (iter->second.isWriteOnly())
iter = tableTy->props.erase(iter);
else
{
iter->second.writeTy = std::nullopt;
iter++;
}
if (resultTy)
asMutable(*resultTy)->ty.emplace<BoundType>(context.solver->builtinTypes->errorType);
asMutable(context.result)->ty.emplace<BoundTypePack>(context.solver->builtinTypes->errorTypePack);

return true;
}

if (resultTy)
asMutable(*resultTy)->ty.emplace<BoundType>(clonedType);
asMutable(context.result)->ty.emplace<BoundTypePack>(arena->addTypePack({clonedType}));
asMutable(*resultTy)->ty.emplace<BoundType>(*frozenType);
asMutable(context.result)->ty.emplace<BoundTypePack>(arena->addTypePack({*frozenType}));

return true;
}
Expand Down
12 changes: 6 additions & 6 deletions Analysis/src/ConstraintGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ LUAU_FASTINT(LuauCheckRecursionLimit)
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
LUAU_FASTFLAG(DebugLuauMagicTypes)
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
LUAU_FASTFLAG(LuauTypestateBuiltins)
LUAU_FASTFLAG(LuauTypestateBuiltins2)

LUAU_FASTFLAGVARIABLE(LuauNewSolverVisitErrorExprLvalues, false)
LUAU_FASTFLAGVARIABLE(LuauNewSolverVisitErrorExprLvalues)

namespace Luau
{
Expand Down Expand Up @@ -1078,7 +1078,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocal* stat
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
else if (const AstExprCall* call = value->as<AstExprCall>())
{
if (FFlag::LuauTypestateBuiltins)
if (FFlag::LuauTypestateBuiltins2)
{
if (matchSetMetatable(*call))
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
Expand Down Expand Up @@ -2062,7 +2062,7 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
return InferencePack{arena->addTypePack({resultTy}), {refinementArena.variadic(returnRefinements)}};
}

if (FFlag::LuauTypestateBuiltins && shouldTypestateForFirstArgument(*call) && call->args.size > 0 && isLValue(call->args.data[0]))
if (FFlag::LuauTypestateBuiltins2 && shouldTypestateForFirstArgument(*call) && call->args.size > 0 && isLValue(call->args.data[0]))
{
AstExpr* targetExpr = call->args.data[0];
auto resultTy = arena->addType(BlockedType{});
Expand Down Expand Up @@ -2913,7 +2913,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
std::vector<TypeId> toBlock;
if (DFInt::LuauTypeSolverRelease >= 648)
{
// This logic is incomplete as we want to re-run this
// This logic is incomplete as we want to re-run this
// _after_ blocked types have resolved, but this
// allows us to do some bidirectional inference.
toBlock = findBlockedTypesIn(expr, NotNull{&module->astTypes});
Expand All @@ -2931,7 +2931,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
toBlock
);
// The visitor we ran prior should ensure that there are no
// blocked types that we would encounter while matching on
// blocked types that we would encounter while matching on
// this expression.
LUAU_ASSERT(toBlock.empty());
}
Expand Down
10 changes: 5 additions & 5 deletions Analysis/src/ConstraintSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
#include <algorithm>
#include <utility>

LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver, false)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies, false)
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings, false)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies)
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
LUAU_FASTFLAGVARIABLE(LuauRemoveNotAnyHack, false)
LUAU_FASTFLAGVARIABLE(LuauRemoveNotAnyHack)

namespace Luau
{
Expand Down Expand Up @@ -1337,7 +1337,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNull<con
{
// This is expensive as we need to traverse a (potentially large)
// literal up front in order to determine if there are any blocked
// types, otherwise we may run `matchTypeLiteral` multiple times,
// types, otherwise we may run `matchTypeLiteral` multiple times,
// which right now may fail due to being non-idempotent (it
// destructively updates the underlying literal type).
auto blockedTypes = findBlockedArgTypesIn(c.callSite, c.astTypes);
Expand Down
4 changes: 2 additions & 2 deletions Analysis/src/DataFlowGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

LUAU_FASTFLAG(DebugLuauFreezeArena)
LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauTypestateBuiltins)
LUAU_FASTFLAG(LuauTypestateBuiltins2)

namespace Luau
{
Expand Down Expand Up @@ -939,7 +939,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprCall* c)
{
visitExpr(c->func);

if (FFlag::LuauTypestateBuiltins && shouldTypestateForFirstArgument(*c) && c->args.size > 1 && isLValue(*c->args.begin()))
if (FFlag::LuauTypestateBuiltins2 && shouldTypestateForFirstArgument(*c) && c->args.size > 1 && isLValue(*c->args.begin()))
{
AstExpr* firstArg = *c->args.begin();

Expand Down
32 changes: 32 additions & 0 deletions Analysis/src/EmbeddedBuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

LUAU_FASTFLAG(LuauMathMap)

LUAU_FASTFLAGVARIABLE(LuauVectorDefinitions)

namespace Luau
{

Expand Down Expand Up @@ -450,9 +452,39 @@ declare buffer: {
)BUILTIN_SRC";

static const std::string kBuiltinDefinitionVectorSrc = R"BUILTIN_SRC(
-- TODO: this will be replaced with a built-in primitive type
declare class vector end
declare vector: {
create: @checked (x: number, y: number, z: number) -> vector,
magnitude: @checked (vec: vector) -> number,
normalize: @checked (vec: vector) -> vector,
cross: @checked (vec1: vector, vec2: vector) -> vector,
dot: @checked (vec1: vector, vec2: vector) -> number,
angle: @checked (vec1: vector, vec2: vector, axis: vector?) -> number,
floor: @checked (vec: vector) -> vector,
ceil: @checked (vec: vector) -> vector,
abs: @checked (vec: vector) -> vector,
sign: @checked (vec: vector) -> vector,
clamp: @checked (vec: vector, min: vector, max: vector) -> vector,
max: @checked (vector, ...vector) -> vector,
min: @checked (vector, ...vector) -> vector,
zero: vector,
one: vector,
}
)BUILTIN_SRC";

std::string getBuiltinDefinitionSource()
{
std::string result = FFlag::LuauMathMap ? kBuiltinDefinitionLuaSrcChecked : kBuiltinDefinitionLuaSrcChecked_DEPRECATED;

if (FFlag::LuauVectorDefinitions)
result += kBuiltinDefinitionVectorSrc;

return result;
}

Expand Down
20 changes: 10 additions & 10 deletions Analysis/src/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,20 @@ LUAU_FASTINT(LuauTypeInferIterationLimit)
LUAU_FASTINT(LuauTypeInferRecursionLimit)
LUAU_FASTINT(LuauTarjanChildLimit)
LUAU_FASTFLAG(LuauInferInNoCheckMode)
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false)
LUAU_FASTFLAGVARIABLE(LuauStoreCommentsForDefinitionFiles, false)
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3)
LUAU_FASTFLAGVARIABLE(LuauStoreCommentsForDefinitionFiles)
LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile, false)
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes, false)
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode, false)
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode, false)
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionNoEvaluation, false)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile)
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes)
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode)
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode)
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionNoEvaluation)
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauRunCustomModuleChecks, false)
LUAU_FASTFLAGVARIABLE(LuauMoreThoroughCycleDetection, false)
LUAU_FASTFLAGVARIABLE(LuauMoreThoroughCycleDetection)

LUAU_FASTFLAG(StudioReportLuauAny2)
LUAU_FASTFLAGVARIABLE(LuauStoreDFGOnModule2, false)
LUAU_FASTFLAGVARIABLE(LuauStoreDFGOnModule2)

namespace Luau
{
Expand Down
2 changes: 1 addition & 1 deletion Analysis/src/Linter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ LUAU_FASTFLAG(LuauSolverV2)

LUAU_FASTFLAG(LuauAttribute)
LUAU_FASTFLAG(LuauNativeAttribute)
LUAU_FASTFLAGVARIABLE(LintRedundantNativeAttribute, false)
LUAU_FASTFLAGVARIABLE(LintRedundantNativeAttribute)

namespace Luau
{
Expand Down
6 changes: 5 additions & 1 deletion Analysis/src/NonStrictTypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <iostream>
#include <iterator>

LUAU_FASTFLAGVARIABLE(LuauUserTypeFunNonstrict)

namespace Luau
{

Expand Down Expand Up @@ -421,7 +423,9 @@ struct NonStrictTypeChecker

NonStrictContext visit(AstStatTypeFunction* typeFunc)
{
reportError(GenericError{"This syntax is not supported"}, typeFunc->location);
if (!FFlag::LuauUserTypeFunNonstrict)
reportError(GenericError{"This syntax is not supported"}, typeFunc->location);

return {};
}

Expand Down
Loading

0 comments on commit a251bc6

Please sign in to comment.