Sync to upstream/release/682 (#1912)

# What's changed?

Another somewhat quiet week! Don't let the large PR fool you, this is
mostly ...

## New Solver
* The code for type functions has been re-organized: instead of
_everything_ living in `TypeFunction.h` and `TypeFunction.cpp`, we now
have separate files for the type function inference machinery
(`TypeFunction.h`), definitions of built-in type functions
(`BuiltinTypeFunctions.h`), and the implementation of user defined type
functions (`UserDefinedTypeFunction.h`).
* Refinements against `*no-refine*`, a sentinel type indicating that no
refinements should occur, are now _always_ resolved, even if the target
of the refinement would be otherwise pending, such as another type
function.

## Autocomplete
* Fixed autocomplete to prefer table property completion to string
singleton completion. In the below example, the types associated with
each member of `foo` will be displayed in autocomplete popups.
```
local foo = {
    ["Item/Foo"] = 42,
    ["Item/Bar"] = "it's true",
    ["Item/Baz"] = true,
}
foo["|"] -- cursor at `|`
```

## Native Codegen
* Fixed native compilation lowering of the new global lookup
instruction, which caused code generation to fail with an error or to
evaluate incorrect results. Issue affected 678-681 releases when all
flags were enabled.

---

Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Ariel Weiss <aaronweiss@roblox.com>
Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com>
Co-authored-by: Sora Kanosue <skanosue@roblox.com>
Co-authored-by: Talha Pathan <tpathan@roblox.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
This commit is contained in:
Hunter Goldstein 2025-07-11 11:36:47 -07:00 committed by GitHub
parent 60cd88af32
commit 6ff0650a8d
Signed by: DevComp
GPG key ID: B5690EEEBB952194
54 changed files with 3794 additions and 3941 deletions

View file

@ -0,0 +1,56 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "Luau/TypeFunction.h"
namespace Luau
{
struct BuiltinTypeFunctions
{
BuiltinTypeFunctions();
TypeFunction userFunc;
TypeFunction notFunc;
TypeFunction lenFunc;
TypeFunction unmFunc;
TypeFunction addFunc;
TypeFunction subFunc;
TypeFunction mulFunc;
TypeFunction divFunc;
TypeFunction idivFunc;
TypeFunction powFunc;
TypeFunction modFunc;
TypeFunction concatFunc;
TypeFunction andFunc;
TypeFunction orFunc;
TypeFunction ltFunc;
TypeFunction leFunc;
TypeFunction eqFunc;
TypeFunction refineFunc;
TypeFunction singletonFunc;
TypeFunction unionFunc;
TypeFunction intersectFunc;
TypeFunction keyofFunc;
TypeFunction rawkeyofFunc;
TypeFunction indexFunc;
TypeFunction rawgetFunc;
TypeFunction setmetatableFunc;
TypeFunction getmetatableFunc;
TypeFunction weakoptionalFunc;
void addToScope(NotNull<TypeArena> arena, NotNull<Scope> scope) const;
};
const BuiltinTypeFunctions& builtinTypeFunctions();
}

View file

@ -25,43 +25,7 @@ struct TypeFunctionRuntimeBuilderState;
struct TypeFunctionContext; struct TypeFunctionContext;
class Normalizer; class Normalizer;
using StateRef = std::unique_ptr<lua_State, void (*)(lua_State*)>; struct TypeFunctionRuntime;
struct TypeFunctionRuntime
{
TypeFunctionRuntime(NotNull<InternalErrorReporter> ice, NotNull<TypeCheckLimits> limits);
~TypeFunctionRuntime();
// Return value is an error message if registration failed
std::optional<std::string> registerFunction(AstStatTypeFunction* function);
// For user-defined type functions, we store all generated types and packs for the duration of the typecheck
TypedAllocator<TypeFunctionType> typeArena;
TypedAllocator<TypeFunctionTypePackVar> typePackArena;
NotNull<InternalErrorReporter> ice;
NotNull<TypeCheckLimits> limits;
StateRef state;
// Set of functions which have their environment table initialized
DenseHashSet<AstStatTypeFunction*> initialized{nullptr};
// Evaluation of type functions should only be performed in the absence of parse errors in the source module
bool allowEvaluation = true;
// Root scope in which the type function operates in, set up by ConstraintGenerator
ScopePtr rootScope;
// Output created by 'print' function
std::vector<std::string> messages;
// Type builder, valid for the duration of a single evaluation
TypeFunctionRuntimeBuilderState* runtimeBuilder = nullptr;
private:
void prepareState();
};
struct TypeFunctionContext struct TypeFunctionContext
{ {
@ -203,7 +167,7 @@ struct FunctionGraphReductionResult
* @param normalizer the normalizer to use when normalizing types * @param normalizer the normalizer to use when normalizing types
* @param ice the internal error reporter to use for ICEs * @param ice the internal error reporter to use for ICEs
*/ */
FunctionGraphReductionResult reduceTypeFunctions(TypeId entrypoint, Location location, TypeFunctionContext, bool force = false); FunctionGraphReductionResult reduceTypeFunctions(TypeId entrypoint, Location location, NotNull<TypeFunctionContext> ctx, bool force = false);
/** /**
* Attempt to reduce all instances of any type or type pack functions in the type * Attempt to reduce all instances of any type or type pack functions in the type
@ -217,53 +181,13 @@ FunctionGraphReductionResult reduceTypeFunctions(TypeId entrypoint, Location loc
* @param normalizer the normalizer to use when normalizing types * @param normalizer the normalizer to use when normalizing types
* @param ice the internal error reporter to use for ICEs * @param ice the internal error reporter to use for ICEs
*/ */
FunctionGraphReductionResult reduceTypeFunctions(TypePackId entrypoint, Location location, TypeFunctionContext, bool force = false); FunctionGraphReductionResult reduceTypeFunctions(TypePackId entrypoint, Location location, NotNull<TypeFunctionContext> ctx, bool force = false);
struct BuiltinTypeFunctions /* Returns true if the type provided should block a type function from reducing.
{ *
BuiltinTypeFunctions(); * Most type functions cannot dispatch if one of their operands is a
* BlockedType, a PendingExpansionType, or an unsolved TypeFunctionInstanceType.
TypeFunction userFunc; */
bool isPending(TypeId ty, ConstraintSolver* solver);
TypeFunction notFunc;
TypeFunction lenFunc;
TypeFunction unmFunc;
TypeFunction addFunc;
TypeFunction subFunc;
TypeFunction mulFunc;
TypeFunction divFunc;
TypeFunction idivFunc;
TypeFunction powFunc;
TypeFunction modFunc;
TypeFunction concatFunc;
TypeFunction andFunc;
TypeFunction orFunc;
TypeFunction ltFunc;
TypeFunction leFunc;
TypeFunction eqFunc;
TypeFunction refineFunc;
TypeFunction singletonFunc;
TypeFunction unionFunc;
TypeFunction intersectFunc;
TypeFunction keyofFunc;
TypeFunction rawkeyofFunc;
TypeFunction indexFunc;
TypeFunction rawgetFunc;
TypeFunction setmetatableFunc;
TypeFunction getmetatableFunc;
TypeFunction weakoptionalFunc;
void addToScope(NotNull<TypeArena> arena, NotNull<Scope> scope) const;
};
const BuiltinTypeFunctions& builtinTypeFunctions();
} // namespace Luau } // namespace Luau

View file

@ -2,8 +2,10 @@
#pragma once #pragma once
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/Scope.h"
#include "Luau/TypeFunctionRuntimeBuilder.h"
#include "Luau/Type.h"
#include "Luau/Variant.h" #include "Luau/Variant.h"
#include "Luau/TypeFwd.h"
#include <optional> #include <optional>
#include <string> #include <string>
@ -15,17 +17,22 @@ using lua_State = struct lua_State;
namespace Luau namespace Luau
{ {
struct TypeFunctionRuntime; struct InternalErrorReporter;
struct TypeCheckLimits;
struct TypeFunctionRuntimeBuilderState;
struct LuauTempThreadPopper
{
explicit LuauTempThreadPopper(lua_State* L);
~LuauTempThreadPopper();
lua_State* L = nullptr;
};
using StateRef = std::unique_ptr<lua_State, void (*)(lua_State*)>;
void* typeFunctionAlloc(void* ud, void* ptr, size_t osize, size_t nsize); void* typeFunctionAlloc(void* ud, void* ptr, size_t osize, size_t nsize);
// Replica of types from Type.h
struct TypeFunctionType;
using TypeFunctionTypeId = const TypeFunctionType*;
struct TypeFunctionTypePackVar;
using TypeFunctionTypePackId = const TypeFunctionTypePackVar*;
struct TypeFunctionPrimitiveType struct TypeFunctionPrimitiveType
{ {
enum Type enum Type
@ -274,6 +281,42 @@ T* getMutable(TypeFunctionTypeId tv)
return tv ? Luau::get_if<T>(&const_cast<TypeFunctionType*>(tv)->type) : nullptr; return tv ? Luau::get_if<T>(&const_cast<TypeFunctionType*>(tv)->type) : nullptr;
} }
struct TypeFunctionRuntime
{
TypeFunctionRuntime(NotNull<InternalErrorReporter> ice, NotNull<TypeCheckLimits> limits);
~TypeFunctionRuntime();
// Return value is an error message if registration failed
std::optional<std::string> registerFunction(AstStatTypeFunction* function);
// For user-defined type functions, we store all generated types and packs for the duration of the typecheck
TypedAllocator<TypeFunctionType> typeArena;
TypedAllocator<TypeFunctionTypePackVar> typePackArena;
NotNull<InternalErrorReporter> ice;
NotNull<TypeCheckLimits> limits;
StateRef state;
// Set of functions which have their environment table initialized
DenseHashSet<AstStatTypeFunction*> initialized{nullptr};
// Evaluation of type functions should only be performed in the absence of parse errors in the source module
bool allowEvaluation = true;
// Root scope in which the type function operates in, set up by ConstraintGenerator
ScopePtr rootScope;
// Output created by 'print' function
std::vector<std::string> messages;
// Type builder, valid for the duration of a single evaluation
TypeFunctionRuntimeBuilderState* runtimeBuilder = nullptr;
private:
void prepareState();
};
std::optional<std::string> checkResultForError(lua_State* L, const char* typeFunctionName, int luaResult); std::optional<std::string> checkResultForError(lua_State* L, const char* typeFunctionName, int luaResult);
TypeFunctionRuntime* getTypeFunctionRuntime(lua_State* L); TypeFunctionRuntime* getTypeFunctionRuntime(lua_State* L);

View file

@ -1,20 +1,12 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once #pragma once
#include "Luau/Type.h"
#include "Luau/TypeFunction.h" #include "Luau/TypeFunction.h"
#include "Luau/TypeFunctionRuntime.h"
namespace Luau namespace Luau
{ {
using Kind = Variant<TypeId, TypePackId>; struct TypeFunctionContext;
template<typename T>
const T* get(const Kind& kind)
{
return get_if<T>(&kind);
}
using TypeFunctionKind = Variant<TypeFunctionTypeId, TypeFunctionTypePackId>; using TypeFunctionKind = Variant<TypeFunctionTypeId, TypeFunctionTypePackId>;

View file

@ -56,4 +56,10 @@ struct BuiltinTypes;
using TypeOrPack = Variant<TypeId, TypePackId>; using TypeOrPack = Variant<TypeId, TypePackId>;
struct TypeFunctionType;
using TypeFunctionTypeId = const TypeFunctionType*;
struct TypeFunctionTypePackVar;
using TypeFunctionTypePackId = const TypeFunctionTypePackVar*;
} // namespace Luau } // namespace Luau

View file

@ -0,0 +1,17 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "Luau/TypeFunction.h"
#include "Luau/TypeFwd.h"
namespace Luau
{
TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
TypeId instance,
const std::vector<TypeId>& typeParams,
const std::vector<TypePackId>& packParams,
NotNull<TypeFunctionContext> ctx
);
}

View file

@ -26,7 +26,7 @@ LUAU_FASTINT(LuauTypeInferIterationLimit)
LUAU_FASTINT(LuauTypeInferRecursionLimit) LUAU_FASTINT(LuauTypeInferRecursionLimit)
LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames) LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames)
LUAU_FASTFLAGVARIABLE(LuauAutocompleteMissingFollows) LUAU_FASTFLAGVARIABLE(LuauAutocompleteMissingFollows)
LUAU_FASTFLAG(LuauImplicitTableIndexerKeys2) LUAU_FASTFLAG(LuauImplicitTableIndexerKeys3)
static const std::unordered_set<std::string> kStatementStartingKeywords = static const std::unordered_set<std::string> kStatementStartingKeywords =
{"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"}; {"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
@ -578,6 +578,29 @@ static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AstNode* node
ty = follow(ty); ty = follow(ty);
if (FFlag::LuauImplicitTableIndexerKeys3)
{
if (auto ss = get<StringSingleton>(get<SingletonType>(ty)))
{
// This is purposefully `try_emplace` as we don't want to override any existing entries.
result.try_emplace(formatKey(ss->value), AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct});
}
else if (auto uty = get<UnionType>(ty))
{
for (auto el : uty)
{
if (auto ss = get<StringSingleton>(get<SingletonType>(el)))
{
// This is purposefully `try_emplace` as we don't want to override any existing entries.
result.try_emplace(
formatKey(ss->value), AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}
);
}
}
}
}
else
{
if (auto ss = get<StringSingleton>(get<SingletonType>(ty))) if (auto ss = get<StringSingleton>(get<SingletonType>(ty)))
{ {
result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}; result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct};
@ -590,6 +613,7 @@ static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AstNode* node
result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}; result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct};
} }
} }
}
}; };
static bool canSuggestInferredType(ScopePtr scope, TypeId ty) static bool canSuggestInferredType(ScopePtr scope, TypeId ty)
@ -2030,7 +2054,7 @@ AutocompleteResult autocomplete_(
{ {
AutocompleteEntryMap result; AutocompleteEntryMap result;
if (!FFlag::LuauImplicitTableIndexerKeys2) if (!FFlag::LuauImplicitTableIndexerKeys3)
{ {
if (auto it = module->astExpectedTypes.find(node->asExpr())) if (auto it = module->astExpectedTypes.find(node->asExpr()))
autocompleteStringSingleton(*it, false, node, position, result); autocompleteStringSingleton(*it, false, node, position, result);
@ -2053,7 +2077,7 @@ AutocompleteResult autocomplete_(
} }
} }
if (FFlag::LuauImplicitTableIndexerKeys2) if (FFlag::LuauImplicitTableIndexerKeys3)
{ {
if (auto it = module->astExpectedTypes.find(node->asExpr())) if (auto it = module->astExpectedTypes.find(node->asExpr()))
autocompleteStringSingleton(*it, false, node, position, result); autocompleteStringSingleton(*it, false, node, position, result);

View file

@ -2,6 +2,7 @@
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/Ast.h" #include "Luau/Ast.h"
#include "Luau/BuiltinTypeFunctions.h"
#include "Luau/Clone.h" #include "Luau/Clone.h"
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/ConstraintGenerator.h" #include "Luau/ConstraintGenerator.h"
@ -35,7 +36,6 @@ LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps) LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3) LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3)
LUAU_FASTFLAGVARIABLE(LuauStringFormatImprovements) LUAU_FASTFLAGVARIABLE(LuauStringFormatImprovements)
LUAU_FASTFLAGVARIABLE(LuauMagicFreezeCheckBlocked2)
LUAU_FASTFLAGVARIABLE(LuauUpdateSetMetatableTypeSignature) LUAU_FASTFLAGVARIABLE(LuauUpdateSetMetatableTypeSignature)
LUAU_FASTFLAGVARIABLE(LuauUpdateGetMetatableTypeSignature) LUAU_FASTFLAGVARIABLE(LuauUpdateGetMetatableTypeSignature)
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver) LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
@ -1781,8 +1781,6 @@ bool MagicFreeze::infer(const MagicFunctionCallContext& context)
std::optional<DefId> resultDef = dfg->getDefOptional(targetExpr); std::optional<DefId> resultDef = dfg->getDefOptional(targetExpr);
std::optional<TypeId> resultTy = resultDef ? scope->lookup(*resultDef) : std::nullopt; std::optional<TypeId> resultTy = resultDef ? scope->lookup(*resultDef) : std::nullopt;
if (FFlag::LuauMagicFreezeCheckBlocked2)
{
if (resultTy && !get<BlockedType>(follow(resultTy))) if (resultTy && !get<BlockedType>(follow(resultTy)))
{ {
// If there's an existing result type, but it's _not_ blocked, then // If there's an existing result type, but it's _not_ blocked, then
@ -1790,7 +1788,6 @@ bool MagicFreeze::infer(const MagicFunctionCallContext& context)
// regular inference. // regular inference.
return false; return false;
} }
}
std::optional<TypeId> frozenType = freezeTable(inputType, context); std::optional<TypeId> frozenType = freezeTable(inputType, context);

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/Type.h" #include "Luau/Type.h"
#include "Luau/TypeOrPack.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/Unifiable.h" #include "Luau/Unifiable.h"
#include "Luau/VisitType.h" #include "Luau/VisitType.h"
@ -20,14 +21,6 @@ namespace Luau
namespace namespace
{ {
using Kind = Variant<TypeId, TypePackId>;
template<typename T>
const T* get(const Kind& kind)
{
return get_if<T>(&kind);
}
class TypeCloner class TypeCloner
{ {
@ -38,7 +31,7 @@ protected:
// A queue of kinds where we cloned it, but whose interior types hasn't // A queue of kinds where we cloned it, but whose interior types hasn't
// been updated to point to new clones. Once all of its interior types // been updated to point to new clones. Once all of its interior types
// has been updated, it gets removed from the queue. // has been updated, it gets removed from the queue.
std::vector<Kind> queue; std::vector<TypeOrPack> queue;
NotNull<SeenTypes> types; NotNull<SeenTypes> types;
NotNull<SeenTypePacks> packs; NotNull<SeenTypePacks> packs;
@ -116,7 +109,7 @@ private:
if (hasExceededIterationLimit()) if (hasExceededIterationLimit())
break; break;
Kind kind = queue.back(); TypeOrPack kind = queue.back();
queue.pop_back(); queue.pop_back();
if (find(kind)) if (find(kind))
@ -147,7 +140,7 @@ protected:
return std::nullopt; return std::nullopt;
} }
std::optional<Kind> find(Kind kind) const std::optional<TypeOrPack> find(TypeOrPack kind) const
{ {
if (auto ty = get<TypeId>(kind)) if (auto ty = get<TypeId>(kind))
return find(*ty); return find(*ty);
@ -265,7 +258,7 @@ private:
); );
} }
void cloneChildren(Kind kind) void cloneChildren(TypeOrPack kind)
{ {
if (auto ty = get<TypeId>(kind)) if (auto ty = get<TypeId>(kind))
return cloneChildren(*ty); return cloneChildren(*ty);

View file

@ -3,6 +3,7 @@
#include "Luau/Ast.h" #include "Luau/Ast.h"
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/BuiltinTypeFunctions.h"
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/Constraint.h" #include "Luau/Constraint.h"
#include "Luau/ControlFlow.h" #include "Luau/ControlFlow.h"
@ -38,8 +39,6 @@ LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation) LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation)
LUAU_FASTFLAGVARIABLE(LuauEnableWriteOnlyProperties) LUAU_FASTFLAGVARIABLE(LuauEnableWriteOnlyProperties)
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
LUAU_FASTFLAGVARIABLE(LuauAvoidDoubleNegation) LUAU_FASTFLAGVARIABLE(LuauAvoidDoubleNegation)
LUAU_FASTFLAGVARIABLE(LuauSimplifyOutOfLine2) LUAU_FASTFLAGVARIABLE(LuauSimplifyOutOfLine2)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
@ -1330,8 +1329,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatForIn* forI
loopScope, getLocation(forIn->values), IterableConstraint{iterator, variableTypes, forIn->values.data[0], &module->astForInNextTypes} loopScope, getLocation(forIn->values), IterableConstraint{iterator, variableTypes, forIn->values.data[0], &module->astForInNextTypes}
); );
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
// Add an intersection ReduceConstraint for the key variable to denote that it can't be nil // Add an intersection ReduceConstraint for the key variable to denote that it can't be nil
AstLocal* keyVar = *forIn->vars.begin(); AstLocal* keyVar = *forIn->vars.begin();
const DefId keyDef = dfg->getDef(keyVar); const DefId keyDef = dfg->getDef(keyVar);
@ -1345,7 +1342,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatForIn* forI
auto c = addConstraint(loopScope, keyVar->location, ReduceConstraint{intersectionTy}); auto c = addConstraint(loopScope, keyVar->location, ReduceConstraint{intersectionTy});
c->dependencies.push_back(iterable); c->dependencies.push_back(iterable);
}
for (TypeId var : variableTypes) for (TypeId var : variableTypes)
{ {
@ -3302,7 +3298,7 @@ void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprLocal* local
if (ty) if (ty)
{ {
TypeIds* localDomain = localTypes.find(*ty); TypeIds* localDomain = localTypes.find(*ty);
if (localDomain && !(FFlag::LuauDoNotAddUpvalueTypesToLocalType && local->upvalue)) if (localDomain && !local->upvalue)
localDomain->insert(rhsType); localDomain->insert(rhsType);
} }
else else
@ -3333,10 +3329,6 @@ void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprLocal* local
if (annotatedTy) if (annotatedTy)
addConstraint(scope, local->location, SubtypeConstraint{rhsType, *annotatedTy}); addConstraint(scope, local->location, SubtypeConstraint{rhsType, *annotatedTy});
// This is vestigial.
if (!FFlag::LuauDoNotAddUpvalueTypesToLocalType)
if (TypeIds* localDomain = localTypes.find(*ty))
localDomain->insert(rhsType);
} }
void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType) void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType)

View file

@ -34,7 +34,6 @@ LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification) LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch) LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
LUAU_FASTFLAGVARIABLE(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion2) LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion2)
LUAU_FASTFLAGVARIABLE(LuauInsertErrorTypesIntoIndexerResult) LUAU_FASTFLAGVARIABLE(LuauInsertErrorTypesIntoIndexerResult)
LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck) LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
@ -633,8 +632,9 @@ void ConstraintSolver::finalizeTypeFunctions()
TypeId ty = follow(t); TypeId ty = follow(t);
if (get<TypeFunctionInstanceType>(ty)) if (get<TypeFunctionInstanceType>(ty))
{ {
TypeFunctionContext context{NotNull{this}, constraint->scope, NotNull{constraint}};
FunctionGraphReductionResult result = FunctionGraphReductionResult result =
reduceTypeFunctions(t, constraint->location, TypeFunctionContext{NotNull{this}, constraint->scope, NotNull{constraint}}, true); reduceTypeFunctions(t, constraint->location, NotNull{&context}, true);
for (TypeId r : result.reducedTypes) for (TypeId r : result.reducedTypes)
unblock(r, constraint->location); unblock(r, constraint->location);
@ -2772,8 +2772,9 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull<const Cons
bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force) bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force)
{ {
TypeId ty = follow(c.ty); TypeId ty = follow(c.ty);
FunctionGraphReductionResult result =
reduceTypeFunctions(ty, constraint->location, TypeFunctionContext{NotNull{this}, constraint->scope, constraint}, force); TypeFunctionContext context{NotNull{this}, constraint->scope, constraint};
FunctionGraphReductionResult result = reduceTypeFunctions(ty, constraint->location, NotNull{&context}, force);
for (TypeId r : result.reducedTypes) for (TypeId r : result.reducedTypes)
unblock(r, constraint->location); unblock(r, constraint->location);
@ -2824,8 +2825,9 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Cons
bool ConstraintSolver::tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force) bool ConstraintSolver::tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force)
{ {
TypePackId tp = follow(c.tp); TypePackId tp = follow(c.tp);
FunctionGraphReductionResult result =
reduceTypeFunctions(tp, constraint->location, TypeFunctionContext{NotNull{this}, constraint->scope, constraint}, force); TypeFunctionContext context{NotNull{this}, constraint->scope, constraint};
FunctionGraphReductionResult result = reduceTypeFunctions(tp, constraint->location, NotNull{&context}, force);
for (TypeId r : result.reducedTypes) for (TypeId r : result.reducedTypes)
unblock(r, constraint->location); unblock(r, constraint->location);
@ -3204,8 +3206,6 @@ bool ConstraintSolver::tryDispatchIterableFunction(TypeId nextTy, TypeId tableTy
// the type of the `nextAstFragment` is the `nextTy`. // the type of the `nextAstFragment` is the `nextTy`.
(*c.astForInNextTypes)[c.nextAstFragment] = nextTy; (*c.astForInNextTypes)[c.nextAstFragment] = nextTy;
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
// Construct a FunctionCallConstraint, to help us learn about the type of the loop variables being assigned to in this iterable // Construct a FunctionCallConstraint, to help us learn about the type of the loop variables being assigned to in this iterable
TypePackId tableTyPack = arena->addTypePack({tableTy}); TypePackId tableTyPack = arena->addTypePack({tableTy});
@ -3220,34 +3220,6 @@ bool ConstraintSolver::tryDispatchIterableFunction(TypeId nextTy, TypeId tableTy
inheritBlocks(constraint, callConstraint); inheritBlocks(constraint, callConstraint);
inheritBlocks(unpackConstraint, callConstraint); inheritBlocks(unpackConstraint, callConstraint);
}
else
{
const TypePackId nextRetPack = nextFn->retTypes;
TypePackIterator 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());
auto unpackConstraint = unpackAndAssign(c.variables, modifiedNextRetPack, constraint);
inheritBlocks(constraint, unpackConstraint);
}
return true; return true;
} }

View file

@ -14,8 +14,6 @@
LUAU_FASTFLAG(DebugLuauFreezeArena) LUAU_FASTFLAG(DebugLuauFreezeArena)
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAGVARIABLE(LuauDfgScopeStackNotNull) LUAU_FASTFLAGVARIABLE(LuauDfgScopeStackNotNull)
LUAU_FASTFLAGVARIABLE(LuauDoNotAddUpvalueTypesToLocalType)
LUAU_FASTFLAGVARIABLE(LuauDfgIfBlocksShouldRespectControlFlow)
LUAU_FASTFLAGVARIABLE(LuauDfgAllowUpdatesInLoops) LUAU_FASTFLAGVARIABLE(LuauDfgAllowUpdatesInLoops)
LUAU_FASTFLAG(LuauFragmentAutocompleteTracksRValueRefinements) LUAU_FASTFLAG(LuauFragmentAutocompleteTracksRValueRefinements)
LUAU_FASTFLAGVARIABLE(LuauDfgForwardNilFromAndOr) LUAU_FASTFLAGVARIABLE(LuauDfgForwardNilFromAndOr)
@ -510,8 +508,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatIf* i)
} }
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED(); DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
if (FFlag::LuauDfgIfBlocksShouldRespectControlFlow)
{
// If the control flow from the `if` or `else` block is non-linear, // If the control flow from the `if` or `else` block is non-linear,
// then we should assume that the _other_ branch is the one taken. // then we should assume that the _other_ branch is the one taken.
if (thencf != ControlFlow::None && elsecf == ControlFlow::None) if (thencf != ControlFlow::None && elsecf == ControlFlow::None)
@ -520,16 +516,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatIf* i)
scope->inherit(thenScope); scope->inherit(thenScope);
else if ((thencf | elsecf) == ControlFlow::None) else if ((thencf | elsecf) == ControlFlow::None)
join(scope, thenScope, elseScope); join(scope, thenScope, elseScope);
}
else
{
if (thencf != ControlFlow::None && elsecf == ControlFlow::None)
join(scope, scope, elseScope);
else if (thencf == ControlFlow::None && elsecf != ControlFlow::None)
join(scope, thenScope, scope);
else if ((thencf | elsecf) == ControlFlow::None)
join(scope, thenScope, elseScope);
}
if (thencf == elsecf) if (thencf == elsecf)
return thencf; return thencf;
@ -1311,7 +1297,7 @@ DefId DataFlowGraphBuilder::visitLValue(AstExprLocal* l, DefId incomingDef)
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED(); DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
// In order to avoid alias tracking, we need to clip the reference to the parent def. // In order to avoid alias tracking, we need to clip the reference to the parent def.
if (scope->canUpdateDefinition(l->local) && !(FFlag::LuauDoNotAddUpvalueTypesToLocalType && l->upvalue)) if (scope->canUpdateDefinition(l->local) && !l->upvalue)
{ {
DefId updated = defArena->freshCell(l->local, l->location, containsSubscriptedDefinition(incomingDef)); DefId updated = defArena->freshCell(l->local, l->location, containsSubscriptedDefinition(incomingDef));
scope->bindings[l->local] = updated; scope->bindings[l->local] = updated;

View file

@ -8,7 +8,7 @@
#include "Luau/TypeUtils.h" #include "Luau/TypeUtils.h"
#include "Luau/VisitType.h" #include "Luau/VisitType.h"
LUAU_FASTFLAGVARIABLE(LuauImplicitTableIndexerKeys2) LUAU_FASTFLAGVARIABLE(LuauImplicitTableIndexerKeys3)
namespace Luau namespace Luau
{ {
@ -147,7 +147,7 @@ struct IndexCollector : public TypeOnceVisitor
bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr) bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
{ {
if (!FFlag::LuauImplicitTableIndexerKeys2) if (!FFlag::LuauImplicitTableIndexerKeys3)
return true; return true;
if (auto ty = astTypes->find(expr->expr)) if (auto ty = astTypes->find(expr->expr))

View file

@ -22,7 +22,6 @@
LUAU_FASTFLAG(DebugLuauMagicTypes) LUAU_FASTFLAG(DebugLuauMagicTypes)
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictVisitTypes2)
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictFixGenericTypePacks) LUAU_FASTFLAGVARIABLE(LuauNewNonStrictFixGenericTypePacks)
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictMoreUnknownSymbols) LUAU_FASTFLAGVARIABLE(LuauNewNonStrictMoreUnknownSymbols)
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictNoErrorsPassingNever) LUAU_FASTFLAGVARIABLE(LuauNewNonStrictNoErrorsPassingNever)
@ -240,14 +239,8 @@ struct NonStrictTypeChecker
if (noTypeFunctionErrors.find(instance)) if (noTypeFunctionErrors.find(instance))
return instance; return instance;
ErrorVec errors = TypeFunctionContext context{arena, builtinTypes, stack.back(), simplifier, NotNull{&normalizer}, typeFunctionRuntime, ice, limits};
reduceTypeFunctions( ErrorVec errors = reduceTypeFunctions(instance, location, NotNull{&context}, true).errors;
instance,
location,
TypeFunctionContext{arena, builtinTypes, stack.back(), simplifier, NotNull{&normalizer}, typeFunctionRuntime, ice, limits},
true
)
.errors;
if (errors.empty()) if (errors.empty())
noTypeFunctionErrors.insert(instance); noTypeFunctionErrors.insert(instance);
@ -340,7 +333,6 @@ struct NonStrictTypeChecker
{ {
ctx.remove(dfg->getDef(local)); ctx.remove(dfg->getDef(local));
if (FFlag::LuauNewNonStrictVisitTypes2)
visit(local->annotation); visit(local->annotation);
} }
} }
@ -426,7 +418,6 @@ struct NonStrictTypeChecker
NonStrictContext visit(AstStatFor* forStatement) NonStrictContext visit(AstStatFor* forStatement)
{ {
if (FFlag::LuauNewNonStrictVisitTypes2)
visit(forStatement->var->annotation); visit(forStatement->var->annotation);
// TODO: throwing out context based on same principle as existing code? // TODO: throwing out context based on same principle as existing code?
@ -440,12 +431,9 @@ struct NonStrictTypeChecker
} }
NonStrictContext visit(AstStatForIn* forInStatement) NonStrictContext visit(AstStatForIn* forInStatement)
{
if (FFlag::LuauNewNonStrictVisitTypes2)
{ {
for (auto var : forInStatement->vars) for (auto var : forInStatement->vars)
visit(var->annotation); visit(var->annotation);
}
for (AstExpr* rhs : forInStatement->values) for (AstExpr* rhs : forInStatement->values)
visit(rhs, ValueContext::RValue); visit(rhs, ValueContext::RValue);
@ -481,12 +469,9 @@ struct NonStrictTypeChecker
} }
NonStrictContext visit(AstStatTypeAlias* typeAlias) NonStrictContext visit(AstStatTypeAlias* typeAlias)
{
if (FFlag::LuauNewNonStrictVisitTypes2)
{ {
visitGenerics(typeAlias->generics, typeAlias->genericPacks); visitGenerics(typeAlias->generics, typeAlias->genericPacks);
visit(typeAlias->type); visit(typeAlias->type);
}
return {}; return {};
} }
@ -497,28 +482,22 @@ struct NonStrictTypeChecker
} }
NonStrictContext visit(AstStatDeclareFunction* declFn) NonStrictContext visit(AstStatDeclareFunction* declFn)
{
if (FFlag::LuauNewNonStrictVisitTypes2)
{ {
visitGenerics(declFn->generics, declFn->genericPacks); visitGenerics(declFn->generics, declFn->genericPacks);
visit(declFn->params); visit(declFn->params);
visit(declFn->retTypes); visit(declFn->retTypes);
}
return {}; return {};
} }
NonStrictContext visit(AstStatDeclareGlobal* declGlobal) NonStrictContext visit(AstStatDeclareGlobal* declGlobal)
{ {
if (FFlag::LuauNewNonStrictVisitTypes2)
visit(declGlobal->type); visit(declGlobal->type);
return {}; return {};
} }
NonStrictContext visit(AstStatDeclareExternType* declClass) NonStrictContext visit(AstStatDeclareExternType* declClass)
{
if (FFlag::LuauNewNonStrictVisitTypes2)
{ {
if (declClass->indexer) if (declClass->indexer)
{ {
@ -528,7 +507,6 @@ struct NonStrictTypeChecker
for (auto prop : declClass->props) for (auto prop : declClass->props)
visit(prop.ty); visit(prop.ty);
}
return {}; return {};
} }
@ -793,19 +771,15 @@ struct NonStrictTypeChecker
} }
remainder.remove(dfg->getDef(local)); remainder.remove(dfg->getDef(local));
if (FFlag::LuauNewNonStrictVisitTypes2)
visit(local->annotation); visit(local->annotation);
} }
if (FFlag::LuauNewNonStrictVisitTypes2)
{
visitGenerics(exprFn->generics, exprFn->genericPacks); visitGenerics(exprFn->generics, exprFn->genericPacks);
visit(exprFn->returnAnnotation); visit(exprFn->returnAnnotation);
if (exprFn->varargAnnotation) if (exprFn->varargAnnotation)
visit(exprFn->varargAnnotation); visit(exprFn->varargAnnotation);
}
return remainder; return remainder;
} }
@ -836,7 +810,6 @@ struct NonStrictTypeChecker
NonStrictContext visit(AstExprTypeAssertion* typeAssertion) NonStrictContext visit(AstExprTypeAssertion* typeAssertion)
{ {
if (FFlag::LuauNewNonStrictVisitTypes2)
visit(typeAssertion->annotation); visit(typeAssertion->annotation);
return visit(typeAssertion->expr, ValueContext::RValue); return visit(typeAssertion->expr, ValueContext::RValue);
@ -868,8 +841,6 @@ struct NonStrictTypeChecker
void visit(AstType* ty) void visit(AstType* ty)
{ {
LUAU_ASSERT(FFlag::LuauNewNonStrictVisitTypes2);
// If this node is `nullptr`, early exit. // If this node is `nullptr`, early exit.
if (!ty) if (!ty)
return; return;
@ -1081,8 +1052,6 @@ struct NonStrictTypeChecker
void visit(AstTypePack* pack) void visit(AstTypePack* pack)
{ {
LUAU_ASSERT(FFlag::LuauNewNonStrictVisitTypes2);
// If there is no pack node, early exit. // If there is no pack node, early exit.
if (!pack) if (!pack)
return; return;

View file

@ -246,8 +246,9 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
const std::vector<AstExpr*>* argExprs const std::vector<AstExpr*>* argExprs
) )
{ {
TypeFunctionContext context{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, ice, limits};
FunctionGraphReductionResult result = reduceTypeFunctions( FunctionGraphReductionResult result = reduceTypeFunctions(
fnTy, callLoc, TypeFunctionContext{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, ice, limits}, /*force=*/true fnTy, callLoc, NotNull{&context}, /*force=*/true
); );
if (!result.errors.empty()) if (!result.errors.empty())
return {OverloadIsNonviable, result.errors}; return {OverloadIsNonviable, result.errors};

View file

@ -2151,7 +2151,7 @@ std::pair<TypeId, ErrorVec> Subtyping::handleTypeFunctionReductionResult(const T
{ {
TypeFunctionContext context{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, iceReporter, NotNull{&limits}}; TypeFunctionContext context{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, iceReporter, NotNull{&limits}};
TypeId function = arena->addType(*functionInstance); TypeId function = arena->addType(*functionInstance);
FunctionGraphReductionResult result = reduceTypeFunctions(function, {}, context, true); FunctionGraphReductionResult result = reduceTypeFunctions(function, {}, NotNull{&context}, true);
ErrorVec errors; ErrorVec errors;
if (result.blockedTypes.size() != 0 || result.blockedPacks.size() != 0) if (result.blockedTypes.size() != 0 || result.blockedPacks.size() != 0)
{ {

View file

@ -16,7 +16,6 @@
#include "Luau/TypeOrPack.h" #include "Luau/TypeOrPack.h"
#include <algorithm> #include <algorithm>
#include <stdexcept>
#include <string> #include <string>
LUAU_FASTFLAGVARIABLE(LuauEnableDenseTableAlias) LUAU_FASTFLAGVARIABLE(LuauEnableDenseTableAlias)

View file

@ -30,10 +30,8 @@
LUAU_FASTFLAG(DebugLuauMagicTypes) LUAU_FASTFLAG(DebugLuauMagicTypes)
LUAU_FASTFLAGVARIABLE(LuauTypeCheckerStricterIndexCheck)
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties) LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks) LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks)
LUAU_FASTFLAGVARIABLE(LuauReportSubtypingErrors)
LUAU_FASTFLAGVARIABLE(LuauSkipMalformedTypeAliases) LUAU_FASTFLAGVARIABLE(LuauSkipMalformedTypeAliases)
LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeSpecificCheck2)
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch) LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
@ -499,16 +497,11 @@ TypeId TypeChecker2::checkForTypeFunctionInhabitance(TypeId instance, Location l
return instance; return instance;
seenTypeFunctionInstances.insert(instance); seenTypeFunctionInstances.insert(instance);
ErrorVec errors = TypeFunctionContext context{
reduceTypeFunctions(
instance,
location,
TypeFunctionContext{
NotNull{&module->internalTypes}, builtinTypes, stack.back(), simplifier, NotNull{&normalizer}, typeFunctionRuntime, ice, limits NotNull{&module->internalTypes}, builtinTypes, stack.back(), simplifier, NotNull{&normalizer}, typeFunctionRuntime, ice, limits
}, };
true
) ErrorVec errors = reduceTypeFunctions(instance, location, NotNull{&context}, true).errors;
.errors;
if (!isErrorSuppressing(location, instance)) if (!isErrorSuppressing(location, instance))
reportErrors(std::move(errors)); reportErrors(std::move(errors));
return instance; return instance;
@ -1417,8 +1410,6 @@ void TypeChecker2::visit(AstExprConstantBool* expr)
NotNull<Scope> scope{findInnermostScope(expr->location)}; NotNull<Scope> scope{findInnermostScope(expr->location)};
SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope); SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope);
if (FFlag::LuauReportSubtypingErrors)
{
if (!isErrorSuppressing(expr->location, inferredType)) if (!isErrorSuppressing(expr->location, inferredType))
{ {
if (!r.isSubtype) if (!r.isSubtype)
@ -1430,12 +1421,6 @@ void TypeChecker2::visit(AstExprConstantBool* expr)
} }
reportErrors(r.errors); reportErrors(r.errors);
} }
}
else
{
if (!r.isSubtype && !isErrorSuppressing(expr->location, inferredType))
reportError(TypeMismatch{inferredType, bestType}, expr->location);
}
} }
void TypeChecker2::visit(AstExprConstantNumber* expr) void TypeChecker2::visit(AstExprConstantNumber* expr)
@ -1459,8 +1444,6 @@ void TypeChecker2::visit(AstExprConstantString* expr)
NotNull<Scope> scope{findInnermostScope(expr->location)}; NotNull<Scope> scope{findInnermostScope(expr->location)};
SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope); SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope);
if (FFlag::LuauReportSubtypingErrors)
{
if (!isErrorSuppressing(expr->location, inferredType)) if (!isErrorSuppressing(expr->location, inferredType))
{ {
if (!r.isSubtype) if (!r.isSubtype)
@ -1472,12 +1455,6 @@ void TypeChecker2::visit(AstExprConstantString* expr)
} }
reportErrors(r.errors); reportErrors(r.errors);
} }
}
else
{
if (!r.isSubtype && !isErrorSuppressing(expr->location, inferredType))
reportError(TypeMismatch{inferredType, bestType}, expr->location);
}
} }
void TypeChecker2::visit(AstExprLocal* expr) void TypeChecker2::visit(AstExprLocal* expr)
@ -1545,8 +1522,6 @@ void TypeChecker2::visitCall(AstExprCall* call)
if (result.isSubtype) if (result.isSubtype)
fnTy = follow(*selectedOverloadTy); fnTy = follow(*selectedOverloadTy);
if (FFlag::LuauReportSubtypingErrors)
{
if (!isErrorSuppressing(call->location, *selectedOverloadTy)) if (!isErrorSuppressing(call->location, *selectedOverloadTy))
if (FFlag::LuauSubtypingCheckFunctionGenericCounts) if (FFlag::LuauSubtypingCheckFunctionGenericCounts)
{ {
@ -1554,8 +1529,6 @@ void TypeChecker2::visitCall(AstExprCall* call)
e.location = call->location; e.location = call->location;
} }
reportErrors(std::move(result.errors)); reportErrors(std::move(result.errors));
}
if (result.normalizationTooComplex) if (result.normalizationTooComplex)
{ {
reportError(NormalizationTooComplex{}, call->func->location); reportError(NormalizationTooComplex{}, call->func->location);
@ -3220,8 +3193,6 @@ bool TypeChecker2::testIsSubtype(TypeId subTy, TypeId superTy, Location location
NotNull<Scope> scope{findInnermostScope(location)}; NotNull<Scope> scope{findInnermostScope(location)};
SubtypingResult r = subtyping->isSubtype(subTy, superTy, scope); SubtypingResult r = subtyping->isSubtype(subTy, superTy, scope);
if (FFlag::LuauReportSubtypingErrors)
{
if (!isErrorSuppressing(location, subTy)) if (!isErrorSuppressing(location, subTy))
if (FFlag::LuauSubtypingCheckFunctionGenericCounts) if (FFlag::LuauSubtypingCheckFunctionGenericCounts)
{ {
@ -3229,8 +3200,6 @@ bool TypeChecker2::testIsSubtype(TypeId subTy, TypeId superTy, Location location
e.location = location; e.location = location;
} }
reportErrors(std::move(r.errors)); reportErrors(std::move(r.errors));
}
if (r.normalizationTooComplex) if (r.normalizationTooComplex)
reportError(NormalizationTooComplex{}, location); reportError(NormalizationTooComplex{}, location);
@ -3245,8 +3214,6 @@ bool TypeChecker2::testIsSubtype(TypePackId subTy, TypePackId superTy, Location
NotNull<Scope> scope{findInnermostScope(location)}; NotNull<Scope> scope{findInnermostScope(location)};
SubtypingResult r = subtyping->isSubtype(subTy, superTy, scope); SubtypingResult r = subtyping->isSubtype(subTy, superTy, scope);
if (FFlag::LuauReportSubtypingErrors)
{
if (!isErrorSuppressing(location, subTy)) if (!isErrorSuppressing(location, subTy))
if (FFlag::LuauSubtypingCheckFunctionGenericCounts) if (FFlag::LuauSubtypingCheckFunctionGenericCounts)
{ {
@ -3254,8 +3221,6 @@ bool TypeChecker2::testIsSubtype(TypePackId subTy, TypePackId superTy, Location
e.location = location; e.location = location;
} }
reportErrors(std::move(r.errors)); reportErrors(std::move(r.errors));
}
if (r.normalizationTooComplex) if (r.normalizationTooComplex)
reportError(NormalizationTooComplex{}, location); reportError(NormalizationTooComplex{}, location);
@ -3501,18 +3466,8 @@ PropertyType TypeChecker2::hasIndexTypeFromType(
return {NormalizationResult::True, {tt->indexer->indexResultType}}; return {NormalizationResult::True, {tt->indexer->indexResultType}};
} }
if (FFlag::LuauTypeCheckerStricterIndexCheck)
{
return {NormalizationResult::False, {builtinTypes->unknownType}}; return {NormalizationResult::False, {builtinTypes->unknownType}};
} }
else
{
// if we are in a conditional context, we treat the property as present and `unknown` because
// we may be _refining_ `tableTy` to include that property. we will want to revisit this a bit
// in the future once luau has support for exact tables since this only applies when inexact.
return {inConditional(typeContext) ? NormalizationResult::True : NormalizationResult::False, {builtinTypes->unknownType}};
}
}
else if (const ExternType* cls = get<ExternType>(ty)) else if (const ExternType* cls = get<ExternType>(ty))
{ {
// If the property doesn't exist on the class, we consult the indexer // If the property doesn't exist on the class, we consult the indexer

File diff suppressed because it is too large Load diff

View file

@ -2,9 +2,16 @@
#include "Luau/TypeFunctionRuntime.h" #include "Luau/TypeFunctionRuntime.h"
#include "Luau/Allocator.h"
#include "Luau/Lexer.h"
#include "Luau/BuiltinTypeFunctions.h"
#include "Luau/BytecodeBuilder.h"
#include "Luau/ParseResult.h"
#include "Luau/Compiler.h"
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
#include "Luau/StringUtils.h" #include "Luau/StringUtils.h"
#include "Luau/TypeFunction.h" #include "Luau/TypeFunction.h"
#include "Luau/TypeFunctionRuntimeBuilder.h"
#include "lua.h" #include "lua.h"
#include "lualib.h" #include "lualib.h"
@ -19,6 +26,133 @@ LUAU_FASTFLAGVARIABLE(LuauTypeFunOptional)
namespace Luau namespace Luau
{ {
LuauTempThreadPopper::LuauTempThreadPopper(lua_State* L)
: L(L)
{
}
LuauTempThreadPopper::~LuauTempThreadPopper()
{
lua_pop(L, 1);
}
static void dummyStateClose(lua_State*) {}
TypeFunctionRuntime::TypeFunctionRuntime(NotNull<InternalErrorReporter> ice, NotNull<TypeCheckLimits> limits)
: ice(ice)
, limits(limits)
, state(nullptr, dummyStateClose)
{
}
TypeFunctionRuntime::~TypeFunctionRuntime() {}
std::optional<std::string> TypeFunctionRuntime::registerFunction(AstStatTypeFunction* function)
{
// If evaluation is disabled, we do not generate additional error messages
if (!allowEvaluation)
return std::nullopt;
// Do not evaluate type functions with parse errors inside
if (function->hasErrors)
return std::nullopt;
prepareState();
lua_State* global = state.get();
// Fetch to check if function is already registered
lua_pushlightuserdata(global, function);
lua_gettable(global, LUA_REGISTRYINDEX);
if (!lua_isnil(global, -1))
{
lua_pop(global, 1);
return std::nullopt;
}
lua_pop(global, 1);
AstName name = function->name;
// Construct ParseResult containing the type function
Allocator allocator;
AstNameTable names(allocator);
AstExpr* exprFunction = function->body;
AstArray<AstExpr*> exprReturns{&exprFunction, 1};
AstStatReturn stmtReturn{Location{}, exprReturns};
AstStat* stmtArray[] = {&stmtReturn};
AstArray<AstStat*> stmts{stmtArray, 1};
AstStatBlock exec{Location{}, stmts};
ParseResult parseResult{&exec, 1, {}, {}, {}, CstNodeMap{nullptr}};
BytecodeBuilder builder;
try
{
compileOrThrow(builder, parseResult, names);
}
catch (CompileError& e)
{
return format("'%s' type function failed to compile with error message: %s", name.value, e.what());
}
std::string bytecode = builder.getBytecode();
// Separate sandboxed thread for individual execution and private globals
lua_State* L = lua_newthread(global);
LuauTempThreadPopper popper(global);
// Create individual environment for the type function
luaL_sandboxthread(L);
// Do not allow global writes to that environment
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setreadonly(L, -1, true);
lua_pop(L, 1);
// Load bytecode into Luau state
if (auto error = checkResultForError(L, name.value, luau_load(L, name.value, bytecode.data(), bytecode.size(), 0)))
return error;
// Execute the global function which should return our user-defined type function
if (auto error = checkResultForError(L, name.value, lua_resume(L, nullptr, 0)))
return error;
if (!lua_isfunction(L, -1))
{
lua_pop(L, 1);
return format("Could not find '%s' type function in the global scope", name.value);
}
// Store resulting function in the registry
lua_pushlightuserdata(global, function);
lua_xmove(L, global, 1);
lua_settable(global, LUA_REGISTRYINDEX);
return std::nullopt;
}
void TypeFunctionRuntime::prepareState()
{
if (state)
return;
state = StateRef(lua_newstate(typeFunctionAlloc, nullptr), lua_close);
lua_State* L = state.get();
lua_setthreaddata(L, this);
setTypeFunctionEnvironment(L);
registerTypeUserData(L);
registerTypesLibrary(L);
luaL_sandbox(L);
luaL_sandboxthread(L);
}
constexpr int kTypeUserdataTag = 42; constexpr int kTypeUserdataTag = 42;
void* typeFunctionAlloc(void* ud, void* ptr, size_t osize, size_t nsize) void* typeFunctionAlloc(void* ud, void* ptr, size_t osize, size_t nsize)
@ -2108,13 +2242,6 @@ bool TypeFunctionProperty::isWriteOnly() const
* Below is a helper class for type.copy() * Below is a helper class for type.copy()
* Forked version of Clone.cpp * Forked version of Clone.cpp
*/ */
using TypeFunctionKind = Variant<TypeFunctionTypeId, TypeFunctionTypePackId>;
template<typename T>
const T* get(const TypeFunctionKind& kind)
{
return get_if<T>(&kind);
}
class TypeFunctionCloner class TypeFunctionCloner
{ {

View file

@ -2,7 +2,6 @@
#include "Luau/TypeFunctionRuntimeBuilder.h" #include "Luau/TypeFunctionRuntimeBuilder.h"
#include "Luau/Ast.h"
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
@ -12,6 +11,7 @@
#include "Luau/TypeFwd.h" #include "Luau/TypeFwd.h"
#include "Luau/TypeFunctionRuntime.h" #include "Luau/TypeFunctionRuntime.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeOrPack.h"
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include <optional> #include <optional>
@ -41,7 +41,7 @@ class TypeFunctionSerializer
// queue.back() should always return two of same type in their respective sides // queue.back() should always return two of same type in their respective sides
// For example `auto [first, second] = queue.back()`: if first is PrimitiveType, // For example `auto [first, second] = queue.back()`: if first is PrimitiveType,
// second must be TypeFunctionPrimitiveType; else there should be an error // second must be TypeFunctionPrimitiveType; else there should be an error
std::vector<std::tuple<Kind, TypeFunctionKind>> queue; std::vector<std::tuple<TypeOrPack, TypeFunctionKind>> queue;
SeenTypes types; // Mapping of TypeIds that have been shallow serialized to TypeFunctionTypeIds SeenTypes types; // Mapping of TypeIds that have been shallow serialized to TypeFunctionTypeIds
SeenTypePacks packs; // Mapping of TypePackIds that have been shallow serialized to TypeFunctionTypePackIds SeenTypePacks packs; // Mapping of TypePackIds that have been shallow serialized to TypeFunctionTypePackIds
@ -121,7 +121,7 @@ private:
return std::nullopt; return std::nullopt;
} }
std::optional<TypeFunctionKind> find(Kind kind) const std::optional<TypeFunctionKind> find(TypeOrPack kind) const
{ {
if (auto ty = get<TypeId>(kind)) if (auto ty = get<TypeId>(kind))
return find(*ty); return find(*ty);
@ -316,7 +316,7 @@ private:
} }
} }
void serializeChildren(Kind kind, TypeFunctionKind tfkind) void serializeChildren(TypeOrPack kind, TypeFunctionKind tfkind)
{ {
if (auto [ty, tfty] = std::tuple{get<TypeId>(kind), get<TypeFunctionTypeId>(tfkind)}; ty && tfty) if (auto [ty, tfty] = std::tuple{get<TypeId>(kind), get<TypeFunctionTypeId>(tfkind)}; ty && tfty)
serializeChildren(*ty, *tfty); serializeChildren(*ty, *tfty);
@ -496,7 +496,7 @@ class TypeFunctionDeserializer
// queue.back() should always return two of same type in their respective sides // queue.back() should always return two of same type in their respective sides
// For example `auto [first, second] = queue.back()`: if first is TypeFunctionPrimitiveType, // For example `auto [first, second] = queue.back()`: if first is TypeFunctionPrimitiveType,
// second must be PrimitiveType; else there should be an error // second must be PrimitiveType; else there should be an error
std::vector<std::tuple<TypeFunctionKind, Kind>> queue; std::vector<std::tuple<TypeFunctionKind, TypeOrPack>> queue;
// Generic types and packs currently in scope // Generic types and packs currently in scope
// Generics are resolved by name even if runtime generic type pointers are different // Generics are resolved by name even if runtime generic type pointers are different
@ -600,7 +600,7 @@ private:
return std::nullopt; return std::nullopt;
} }
std::optional<Kind> find(TypeFunctionKind kind) const std::optional<TypeOrPack> find(TypeFunctionKind kind) const
{ {
if (auto ty = get<TypeFunctionTypeId>(kind)) if (auto ty = get<TypeFunctionTypeId>(kind))
return find(*ty); return find(*ty);
@ -824,7 +824,7 @@ private:
state->ctx->ice->ice("Deserializing user defined type function arguments: mysterious type is being deserialized"); state->ctx->ice->ice("Deserializing user defined type function arguments: mysterious type is being deserialized");
} }
void deserializeChildren(TypeFunctionKind tfkind, Kind kind) void deserializeChildren(TypeFunctionKind tfkind, TypeOrPack kind)
{ {
if (auto [ty, tfty] = std::tuple{get<TypeId>(kind), get<TypeFunctionTypeId>(tfkind)}; ty && tfty) if (auto [ty, tfty] = std::tuple{get<TypeId>(kind), get<TypeFunctionTypeId>(tfkind)}; ty && tfty)
deserializeChildren(*tfty, *ty); deserializeChildren(*tfty, *ty);

View file

@ -737,8 +737,6 @@ std::string toString(const TypePath::Path& path, bool prefixDot)
std::string toStringHuman(const TypePath::Path& path) std::string toStringHuman(const TypePath::Path& path)
{ {
LUAU_ASSERT(FFlag::LuauSolverV2);
enum class State enum class State
{ {
Initial, Initial,

View file

@ -0,0 +1,391 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/ApplyTypeFunction.h"
#include "Luau/BuiltinTypeFunctions.h"
#include "Luau/ConstraintSolver.h"
#include "Luau/Normalize.h"
#include "Luau/StringUtils.h"
#include "Luau/TimeTrace.h"
#include "Luau/UserDefinedTypeFunction.h"
#include "Luau/VisitType.h"
#include "lua.h"
#include "lualib.h"
LUAU_FASTFLAG(LuauUserTypeFunctionAliases)
namespace Luau
{
namespace
{
template<typename T>
class ScopedAssign
{
public:
ScopedAssign(T& target, const T& value)
: target(&target)
, oldValue(target)
{
target = value;
}
~ScopedAssign()
{
*target = oldValue;
}
private:
T* target = nullptr;
T oldValue;
};
}
struct FindUserTypeFunctionBlockers : TypeOnceVisitor
{
NotNull<TypeFunctionContext> ctx;
DenseHashSet<TypeId> blockingTypeMap{nullptr};
std::vector<TypeId> blockingTypes;
explicit FindUserTypeFunctionBlockers(NotNull<TypeFunctionContext> ctx)
: TypeOnceVisitor(/* skipBoundTypes */ true)
, ctx(ctx)
{
}
bool visit(TypeId ty) override
{
if (isPending(ty, ctx->solver))
{
if (!blockingTypeMap.contains(ty))
{
blockingTypeMap.insert(ty);
blockingTypes.push_back(ty);
}
}
return true;
}
bool visit(TypePackId tp) override
{
return true;
}
bool visit(TypeId ty, const ExternType&) override
{
return false;
}
};
static int evaluateTypeAliasCall(lua_State* L)
{
TypeFun* tf = static_cast<TypeFun*>(lua_tolightuserdata(L, lua_upvalueindex(1)));
TypeFunctionRuntime* runtime = getTypeFunctionRuntime(L);
TypeFunctionRuntimeBuilderState* runtimeBuilder = runtime->runtimeBuilder;
ApplyTypeFunction applyTypeFunction{runtimeBuilder->ctx->arena};
int argumentCount = lua_gettop(L);
std::vector<TypeId> rawTypeArguments;
for (int i = 0; i < argumentCount; i++)
{
TypeFunctionTypeId tfty = getTypeUserData(L, i + 1);
TypeId ty = deserialize(tfty, runtimeBuilder);
if (!runtimeBuilder->errors.empty())
luaL_error(L, "failed to deserialize type at argument %d", i + 1);
rawTypeArguments.push_back(ty);
}
// Check if we have enough arguments, by typical typechecking rules
size_t typesRequired = tf->typeParams.size();
size_t packsRequired = tf->typePackParams.size();
size_t typesProvided = rawTypeArguments.size() > typesRequired ? typesRequired : rawTypeArguments.size();
size_t extraTypes = rawTypeArguments.size() > typesRequired ? rawTypeArguments.size() - typesRequired : 0;
size_t packsProvided = 0;
if (extraTypes != 0 && packsProvided == 0)
{
// Extra types are only collected into a pack if a pack is expected
if (packsRequired != 0)
packsProvided += 1;
else
typesProvided += extraTypes;
}
for (size_t i = typesProvided; i < typesRequired; ++i)
{
if (tf->typeParams[i].defaultValue)
typesProvided += 1;
}
for (size_t i = packsProvided; i < packsRequired; ++i)
{
if (tf->typePackParams[i].defaultValue)
packsProvided += 1;
}
if (extraTypes == 0 && packsProvided + 1 == packsRequired)
packsProvided += 1;
if (typesProvided != typesRequired || packsProvided != packsRequired)
luaL_error(L, "not enough arguments to call");
// Prepare final types and packs
auto [types, packs] = saturateArguments(runtimeBuilder->ctx->arena, runtimeBuilder->ctx->builtins, *tf, rawTypeArguments, {});
for (size_t i = 0; i < types.size(); ++i)
applyTypeFunction.typeArguments[tf->typeParams[i].ty] = types[i];
for (size_t i = 0; i < packs.size(); ++i)
applyTypeFunction.typePackArguments[tf->typePackParams[i].tp] = packs[i];
std::optional<TypeId> maybeInstantiated = applyTypeFunction.substitute(tf->type);
if (!maybeInstantiated.has_value())
{
luaL_error(L, "failed to instantiate type alias");
return 1;
}
TypeId target = follow(*maybeInstantiated);
FunctionGraphReductionResult result = reduceTypeFunctions(target, Location{}, runtimeBuilder->ctx);
if (!result.errors.empty())
luaL_error(L, "failed to reduce type function with: %s", toString(result.errors.front()).c_str());
TypeFunctionTypeId serializedTy = serialize(follow(target), runtimeBuilder);
if (!runtimeBuilder->errors.empty())
luaL_error(L, "%s", runtimeBuilder->errors.front().c_str());
allocTypeUserData(L, serializedTy->type);
return 1;
}
TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
TypeId instance,
const std::vector<TypeId>& typeParams,
const std::vector<TypePackId>& packParams,
NotNull<TypeFunctionContext> ctx
)
{
auto typeFunction = getMutable<TypeFunctionInstanceType>(instance);
if (typeFunction->userFuncData.owner.expired())
{
ctx->ice->ice("user-defined type function module has expired");
return {std::nullopt, Reduction::Erroneous, {}, {}};
}
if (!typeFunction->userFuncName || !typeFunction->userFuncData.definition)
{
ctx->ice->ice("all user-defined type functions must have an associated function definition");
return {std::nullopt, Reduction::Erroneous, {}, {}};
}
// If type functions cannot be evaluated because of errors in the code, we do not generate any additional ones
if (!ctx->typeFunctionRuntime->allowEvaluation || typeFunction->userFuncData.definition->hasErrors)
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
FindUserTypeFunctionBlockers check{ctx};
for (auto typeParam : typeParams)
check.traverse(follow(typeParam));
if (FFlag::LuauUserTypeFunctionAliases)
{
// Check that our environment doesn't depend on any type aliases that are blocked
for (auto& [name, definition] : typeFunction->userFuncData.environmentAlias)
{
if (definition.first->typeParams.empty() && definition.first->typePackParams.empty())
check.traverse(follow(definition.first->type));
}
}
if (!check.blockingTypes.empty())
return {std::nullopt, Reduction::MaybeOk, check.blockingTypes, {}};
// Ensure that whole type function environment is registered
for (auto& [name, definition] : typeFunction->userFuncData.environmentFunction)
{
// Cannot evaluate if a potential dependency couldn't be parsed
if (definition.first->hasErrors)
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
if (std::optional<std::string> error = ctx->typeFunctionRuntime->registerFunction(definition.first))
{
// Failure to register at this point means that original definition had to error out and should not have been present in the
// environment
ctx->ice->ice("user-defined type function reference cannot be registered");
return {std::nullopt, Reduction::Erroneous, {}, {}};
}
}
AstName name = typeFunction->userFuncData.definition->name;
lua_State* global = ctx->typeFunctionRuntime->state.get();
if (global == nullptr)
return {std::nullopt, Reduction::Erroneous, {}, {}, format("'%s' type function: cannot be evaluated in this context", name.value)};
// Separate sandboxed thread for individual execution and private globals
lua_State* L = lua_newthread(global);
LuauTempThreadPopper popper(global);
std::unique_ptr<TypeFunctionRuntimeBuilderState> runtimeBuilder = std::make_unique<TypeFunctionRuntimeBuilderState>(ctx);
ScopedAssign setRuntimeBuilder(ctx->typeFunctionRuntime->runtimeBuilder, runtimeBuilder.get());
ScopedAssign enableReduction(ctx->normalizer->sharedState->reentrantTypeReduction, false);
// Build up the environment table of each function we have visible
for (auto& [_, curr] : typeFunction->userFuncData.environmentFunction)
{
// Environment table has to be filled only once in the current execution context
if (ctx->typeFunctionRuntime->initialized.find(curr.first))
continue;
ctx->typeFunctionRuntime->initialized.insert(curr.first);
lua_pushlightuserdata(L, curr.first);
lua_gettable(L, LUA_REGISTRYINDEX);
if (!lua_isfunction(L, -1))
{
ctx->ice->ice("user-defined type function reference cannot be found in the registry");
return {std::nullopt, Reduction::Erroneous, {}, {}};
}
// Build up the environment of the current function, where some might not be visible
lua_getfenv(L, -1);
lua_setreadonly(L, -1, false);
for (auto& [name, definition] : typeFunction->userFuncData.environmentFunction)
{
// Filter visibility based on original scope depth
if (definition.second >= curr.second)
{
lua_pushlightuserdata(L, definition.first);
lua_gettable(L, LUA_REGISTRYINDEX);
if (!lua_isfunction(L, -1))
break; // Don't have to report an error here, we will visit each function in outer loop
lua_setfield(L, -2, name.c_str());
}
}
if (FFlag::LuauUserTypeFunctionAliases)
{
for (auto& [name, definition] : typeFunction->userFuncData.environmentAlias)
{
// Filter visibility based on original scope depth
if (definition.second >= curr.second)
{
if (definition.first->typeParams.empty() && definition.first->typePackParams.empty())
{
TypeId ty = follow(definition.first->type);
// This is checked at the top of the function, and should still be true.
LUAU_ASSERT(!isPending(ty, ctx->solver));
TypeFunctionTypeId serializedTy = serialize(ty, runtimeBuilder.get());
// Only register aliases that are representable in type environment
if (runtimeBuilder->errors.empty())
{
allocTypeUserData(L, serializedTy->type);
lua_setfield(L, -2, name.c_str());
}
}
else
{
lua_pushlightuserdata(L, definition.first);
lua_pushcclosure(L, evaluateTypeAliasCall, name.c_str(), 1);
lua_setfield(L, -2, name.c_str());
}
}
}
}
lua_setreadonly(L, -1, true);
lua_pop(L, 2);
}
// Fetch the function we want to evaluate
lua_pushlightuserdata(L, typeFunction->userFuncData.definition);
lua_gettable(L, LUA_REGISTRYINDEX);
if (!lua_isfunction(L, -1))
{
ctx->ice->ice("user-defined type function reference cannot be found in the registry");
return {std::nullopt, Reduction::Erroneous, {}, {}};
}
resetTypeFunctionState(L);
// Push serialized arguments onto the stack
for (auto typeParam : typeParams)
{
TypeId ty = follow(typeParam);
// This is checked at the top of the function, and should still be true.
LUAU_ASSERT(!isPending(ty, ctx->solver));
TypeFunctionTypeId serializedTy = serialize(ty, runtimeBuilder.get());
// Check if there were any errors while serializing
if (runtimeBuilder->errors.size() != 0)
return {std::nullopt, Reduction::Erroneous, {}, {}, runtimeBuilder->errors.front()};
allocTypeUserData(L, serializedTy->type);
}
// Set up an interrupt handler for type functions to respect type checking limits and LSP cancellation requests.
lua_callbacks(L)->interrupt = [](lua_State* L, int gc)
{
auto ctx = static_cast<const TypeFunctionRuntime*>(lua_getthreaddata(lua_mainthread(L)));
if (ctx->limits->finishTime && TimeTrace::getClock() > *ctx->limits->finishTime)
throw TimeLimitError(ctx->ice->moduleName);
if (ctx->limits->cancellationToken && ctx->limits->cancellationToken->requested())
throw UserCancelError(ctx->ice->moduleName);
};
ctx->typeFunctionRuntime->messages.clear();
if (auto error = checkResultForError(L, name.value, lua_pcall(L, int(typeParams.size()), 1, 0)))
return {std::nullopt, Reduction::Erroneous, {}, {}, std::move(error), ctx->typeFunctionRuntime->messages};
// If the return value is not a type userdata, return with error message
if (!isTypeUserData(L, 1))
{
return {
std::nullopt,
Reduction::Erroneous,
{},
{},
format("'%s' type function: returned a non-type value", name.value),
ctx->typeFunctionRuntime->messages
};
}
TypeFunctionTypeId retTypeFunctionTypeId = getTypeUserData(L, 1);
// No errors should be present here since we should've returned already if any were raised during serialization.
LUAU_ASSERT(runtimeBuilder->errors.size() == 0);
TypeId retTypeId = deserialize(retTypeFunctionTypeId, runtimeBuilder.get());
// At least 1 error occurred while deserializing
if (runtimeBuilder->errors.size() > 0)
return {std::nullopt, Reduction::Erroneous, {}, {}, runtimeBuilder->errors.front(), ctx->typeFunctionRuntime->messages};
return {retTypeId, Reduction::MaybeOk, {}, {}, std::nullopt, ctx->typeFunctionRuntime->messages};
}
}

View file

@ -20,7 +20,6 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
LUAU_FASTFLAGVARIABLE(LuauSolverV2) LUAU_FASTFLAGVARIABLE(LuauSolverV2)
LUAU_FASTFLAGVARIABLE(LuauDeclareExternType) LUAU_FASTFLAGVARIABLE(LuauDeclareExternType)
LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer) LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer)
LUAU_FASTFLAGVARIABLE(LuauCSTForReturnTypeFunctionTail)
LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit) LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit)
LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false) LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false)
@ -1903,10 +1902,8 @@ AstTypePack* Parser::parseReturnType()
// possibly () -> ReturnType // possibly () -> ReturnType
if (lexer.current().type != ')') if (lexer.current().type != ')')
{ {
if (FFlag::LuauCSTForReturnTypeFunctionTail && options.storeCstData) if (options.storeCstData)
varargAnnotation = parseTypeList(result, resultNames, &commaPositions, &nameColonPositions); varargAnnotation = parseTypeList(result, resultNames, &commaPositions, &nameColonPositions);
else if (options.storeCstData)
varargAnnotation = parseTypeList(result, resultNames, &commaPositions);
else else
varargAnnotation = parseTypeList(result, resultNames); varargAnnotation = parseTypeList(result, resultNames);
} }
@ -1950,7 +1947,7 @@ AstTypePack* Parser::parseReturnType()
Position returnArrowPosition = lexer.current().location.begin; Position returnArrowPosition = lexer.current().location.begin;
AstType* tail = parseFunctionTypeTail(begin, {nullptr, 0}, {}, {}, copy(result), copy(resultNames), varargAnnotation); AstType* tail = parseFunctionTypeTail(begin, {nullptr, 0}, {}, {}, copy(result), copy(resultNames), varargAnnotation);
if (FFlag::LuauCSTForReturnTypeFunctionTail && options.storeCstData && tail->is<AstTypeFunction>()) if (options.storeCstData && tail->is<AstTypeFunction>())
{ {
cstNodeMap[tail] = allocator.alloc<CstTypeFunction>( cstNodeMap[tail] = allocator.alloc<CstTypeFunction>(
Position{0, 0}, Position{0, 0},

View file

@ -392,7 +392,7 @@ enum class IrCmd : uint8_t
// C: Rn or unsigned int (key) // C: Rn or unsigned int (key)
SET_TABLE, SET_TABLE,
// TODO: remove with FFlagLuauCodeGenSimplifyImport // TODO: remove with FFlagLuauCodeGenSimplifyImport2
// Lookup a value in the environment // Lookup a value in the environment
// A: Rn (where to store the result) // A: Rn (where to store the result)
// B: unsigned int (import path) // B: unsigned int (import path)

View file

@ -1384,7 +1384,10 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
break; break;
case IrCmd::GET_CACHED_IMPORT: case IrCmd::GET_CACHED_IMPORT:
{ {
regs.spill(build, index);
Label skip, exit; Label skip, exit;
RegisterA64 tempTag = regs.allocTemp(KindA64::w); RegisterA64 tempTag = regs.allocTemp(KindA64::w);
AddressA64 addrConstTag = tempAddr(inst.b, offsetof(TValue, tt)); AddressA64 addrConstTag = tempAddr(inst.b, offsetof(TValue, tt));
@ -1395,8 +1398,6 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
build.cbnz(tempTag, skip); build.cbnz(tempTag, skip);
{ {
size_t spills = regs.spill(build, index);
build.mov(x0, rState); build.mov(x0, rState);
build.add(x1, rBase, uint16_t(vmRegOp(inst.a) * sizeof(TValue))); build.add(x1, rBase, uint16_t(vmRegOp(inst.a) * sizeof(TValue)));
build.mov(w2, importOp(inst.c)); build.mov(w2, importOp(inst.c));
@ -1404,16 +1405,14 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
build.ldr(x4, mem(rNativeContext, offsetof(NativeContext, getImport))); build.ldr(x4, mem(rNativeContext, offsetof(NativeContext, getImport)));
build.blr(x4); build.blr(x4);
regs.restore(build, spills); // Need to restore before skip so that registers are in a consistent state
emitUpdateBase(build); emitUpdateBase(build);
build.b(exit); build.b(exit);
} }
RegisterA64 tempTv = regs.allocTemp(KindA64::q);
build.setLabel(skip); build.setLabel(skip);
RegisterA64 tempTv = regs.allocTemp(KindA64::q);
AddressA64 addrConst = tempAddr(inst.b, 0); AddressA64 addrConst = tempAddr(inst.b, 0);
build.ldr(tempTv, addrConst); build.ldr(tempTv, addrConst);

View file

@ -1221,6 +1221,9 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
} }
case IrCmd::GET_CACHED_IMPORT: case IrCmd::GET_CACHED_IMPORT:
{ {
regs.assertAllFree();
regs.assertNoSpills();
Label skip, exit; Label skip, exit;
// If the constant for the import is set, we will use it directly, otherwise we have to call an import path lookup function // If the constant for the import is set, we will use it directly, otherwise we have to call an import path lookup function
@ -1241,9 +1244,10 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
emitUpdateBase(build); emitUpdateBase(build);
build.jmp(exit); build.jmp(exit);
build.setLabel(skip);
ScopedRegX64 tmp1{regs, SizeX64::xmmword}; ScopedRegX64 tmp1{regs, SizeX64::xmmword};
build.setLabel(skip);
build.vmovups(tmp1.reg, luauConstant(vmConstOp(inst.b))); build.vmovups(tmp1.reg, luauConstant(vmConstOp(inst.b)));
build.vmovups(luauReg(vmRegOp(inst.a)), tmp1.reg); build.vmovups(luauReg(vmRegOp(inst.a)), tmp1.reg);
build.setLabel(exit); build.setLabel(exit);

View file

@ -12,7 +12,7 @@
#include "lstate.h" #include "lstate.h"
#include "ltm.h" #include "ltm.h"
LUAU_FASTFLAGVARIABLE(LuauCodeGenSimplifyImport) LUAU_FASTFLAGVARIABLE(LuauCodeGenSimplifyImport2)
namespace Luau namespace Luau
{ {
@ -1217,7 +1217,7 @@ void translateInstGetImport(IrBuilder& build, const Instruction* pc, int pcpos)
int k = LUAU_INSN_D(*pc); int k = LUAU_INSN_D(*pc);
uint32_t aux = pc[1]; uint32_t aux = pc[1];
if (FFlag::LuauCodeGenSimplifyImport) if (FFlag::LuauCodeGenSimplifyImport2)
{ {
build.inst(IrCmd::CHECK_SAFE_ENV, build.vmExit(pcpos)); build.inst(IrCmd::CHECK_SAFE_ENV, build.vmExit(pcpos));
build.inst(IrCmd::GET_CACHED_IMPORT, build.vmReg(ra), build.vmConst(k), build.constImport(aux), build.constUint(pcpos + 1)); build.inst(IrCmd::GET_CACHED_IMPORT, build.vmReg(ra), build.vmConst(k), build.constImport(aux), build.constUint(pcpos + 1));

View file

@ -1545,6 +1545,8 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction&
// Outside of safe environment, environment traversal for an import can execute custom code // Outside of safe environment, environment traversal for an import can execute custom code
if (!state.inSafeEnv) if (!state.inSafeEnv)
state.invalidateUserCall(); state.invalidateUserCall();
state.invalidateValuePropagation();
break; break;
case IrCmd::CONCAT: case IrCmd::CONCAT:
state.invalidateRegisterRange(vmRegOp(inst.a), function.uintOp(inst.b)); state.invalidateRegisterRange(vmRegOp(inst.a), function.uintOp(inst.b));

View file

@ -4300,8 +4300,6 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c
} }
// computes type information for all functions based on type annotations // computes type information for all functions based on type annotations
if (FFlag::LuauSeparateCompilerTypeInfo)
{
if (options.typeInfoLevel >= 1 || options.optimizationLevel >= 2) if (options.typeInfoLevel >= 1 || options.optimizationLevel >= 2)
buildTypeMap( buildTypeMap(
compiler.functionTypes, compiler.functionTypes,
@ -4316,24 +4314,6 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c
options.libraryMemberTypeCb, options.libraryMemberTypeCb,
bytecode bytecode
); );
}
else
{
if (options.typeInfoLevel >= 1)
buildTypeMap(
compiler.functionTypes,
compiler.localTypes,
compiler.exprTypes,
root,
options.vectorType,
compiler.userdataTypes,
compiler.builtinTypes,
compiler.builtins,
compiler.globals,
options.libraryMemberTypeCb,
bytecode
);
}
for (AstExprFunction* expr : functions) for (AstExprFunction* expr : functions)
{ {

View file

@ -175,6 +175,7 @@ target_sources(Luau.Analysis PRIVATE
Analysis/include/Luau/Autocomplete.h Analysis/include/Luau/Autocomplete.h
Analysis/include/Luau/AutocompleteTypes.h Analysis/include/Luau/AutocompleteTypes.h
Analysis/include/Luau/BuiltinDefinitions.h Analysis/include/Luau/BuiltinDefinitions.h
Analysis/include/Luau/BuiltinTypeFunctions.h
Analysis/include/Luau/Cancellation.h Analysis/include/Luau/Cancellation.h
Analysis/include/Luau/Clone.h Analysis/include/Luau/Clone.h
Analysis/include/Luau/Constraint.h Analysis/include/Luau/Constraint.h
@ -248,6 +249,7 @@ target_sources(Luau.Analysis PRIVATE
Analysis/include/Luau/Unifier.h Analysis/include/Luau/Unifier.h
Analysis/include/Luau/Unifier2.h Analysis/include/Luau/Unifier2.h
Analysis/include/Luau/UnifierSharedState.h Analysis/include/Luau/UnifierSharedState.h
Analysis/include/Luau/UserDefinedTypeFunction.h
Analysis/include/Luau/VisitType.h Analysis/include/Luau/VisitType.h
Analysis/src/Anyification.cpp Analysis/src/Anyification.cpp
@ -257,6 +259,7 @@ target_sources(Luau.Analysis PRIVATE
Analysis/src/Autocomplete.cpp Analysis/src/Autocomplete.cpp
Analysis/src/AutocompleteCore.cpp Analysis/src/AutocompleteCore.cpp
Analysis/src/BuiltinDefinitions.cpp Analysis/src/BuiltinDefinitions.cpp
Analysis/src/BuiltinTypeFunctions.cpp
Analysis/src/Clone.cpp Analysis/src/Clone.cpp
Analysis/src/Constraint.cpp Analysis/src/Constraint.cpp
Analysis/src/ConstraintGenerator.cpp Analysis/src/ConstraintGenerator.cpp
@ -316,6 +319,7 @@ target_sources(Luau.Analysis PRIVATE
Analysis/src/Unifiable.cpp Analysis/src/Unifiable.cpp
Analysis/src/Unifier.cpp Analysis/src/Unifier.cpp
Analysis/src/Unifier2.cpp Analysis/src/Unifier2.cpp
Analysis/src/UserDefinedTypeFunction.cpp
) )
# Luau.EqSat Sources # Luau.EqSat Sources

View file

@ -21,7 +21,7 @@ LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
LUAU_FASTINT(LuauTypeInferRecursionLimit) LUAU_FASTINT(LuauTypeInferRecursionLimit)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauExpectedTypeVisitor) LUAU_FASTFLAG(LuauExpectedTypeVisitor)
LUAU_FASTFLAG(LuauImplicitTableIndexerKeys2) LUAU_FASTFLAG(LuauImplicitTableIndexerKeys3)
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement) LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
using namespace Luau; using namespace Luau;
@ -4622,7 +4622,7 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr")
// Somewhat surprisingly, the old solver didn't cover this case. // Somewhat surprisingly, the old solver didn't cover this case.
{FFlag::LuauSolverV2, true}, {FFlag::LuauSolverV2, true},
{FFlag::LuauExpectedTypeVisitor, true}, {FFlag::LuauExpectedTypeVisitor, true},
{FFlag::LuauImplicitTableIndexerKeys2, true}, {FFlag::LuauImplicitTableIndexerKeys3, true},
}; };
check(R"( check(R"(
@ -4649,7 +4649,7 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr_witho
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{FFlag::LuauSolverV2, true}, {FFlag::LuauSolverV2, true},
{FFlag::LuauExpectedTypeVisitor, true}, {FFlag::LuauExpectedTypeVisitor, true},
{FFlag::LuauImplicitTableIndexerKeys2, false}, {FFlag::LuauImplicitTableIndexerKeys3, true},
}; };
check(R"( check(R"(

View file

@ -13,7 +13,6 @@
using namespace Luau; using namespace Luau;
LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauSolverV2);
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops) LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
struct DataFlowGraphFixture struct DataFlowGraphFixture
@ -447,8 +446,6 @@ TEST_CASE_FIXTURE(DataFlowGraphFixture, "property_lookup_on_a_phi_node_3")
TEST_CASE_FIXTURE(DataFlowGraphFixture, "function_captures_are_phi_nodes_of_all_versions") TEST_CASE_FIXTURE(DataFlowGraphFixture, "function_captures_are_phi_nodes_of_all_versions")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
dfg(R"( dfg(R"(
local x = 5 local x = 5

View file

@ -1,6 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once #pragma once
#include "Luau/BuiltinTypeFunctions.h"
#include "Luau/Config.h" #include "Luau/Config.h"
#include "Luau/EqSatSimplification.h" #include "Luau/EqSatSimplification.h"
#include "Luau/Error.h" #include "Luau/Error.h"

View file

@ -16,7 +16,6 @@ using namespace Luau;
LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauSolverV2);
LUAU_FASTFLAG(DebugLuauFreezeArena) LUAU_FASTFLAG(DebugLuauFreezeArena)
LUAU_FASTFLAG(DebugLuauMagicTypes) LUAU_FASTFLAG(DebugLuauMagicTypes)
LUAU_FASTFLAG(LuauNewNonStrictVisitTypes2)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
namespace namespace
@ -977,9 +976,6 @@ TEST_CASE_FIXTURE(FrontendFixture, "environments")
LUAU_REQUIRE_NO_ERRORS(resultA); LUAU_REQUIRE_NO_ERRORS(resultA);
CheckResult resultB = getFrontend().check("B"); CheckResult resultB = getFrontend().check("B");
if (FFlag::LuauSolverV2 && !FFlag::LuauNewNonStrictVisitTypes2)
LUAU_REQUIRE_NO_ERRORS(resultB);
else
LUAU_REQUIRE_ERROR_COUNT(1, resultB); LUAU_REQUIRE_ERROR_COUNT(1, resultB);
CheckResult resultC = getFrontend().check("C"); CheckResult resultC = getFrontend().check("C");

View file

@ -16,7 +16,7 @@
#include <memory> #include <memory>
#include <string_view> #include <string_view>
LUAU_FASTFLAG(LuauCodeGenSimplifyImport) LUAU_FASTFLAG(LuauCodeGenSimplifyImport2)
static void luauLibraryConstantLookup(const char* library, const char* member, Luau::CompileConstant* constant) static void luauLibraryConstantLookup(const char* library, const char* member, Luau::CompileConstant* constant)
{ {
@ -500,7 +500,7 @@ bb_bytecode_1:
TEST_CASE("DseInitialStackState") TEST_CASE("DseInitialStackState")
{ {
ScopedFastFlag luauCodeGenSimplifyImport{FFlag::LuauCodeGenSimplifyImport, true}; ScopedFastFlag luauCodeGenSimplifyImport{FFlag::LuauCodeGenSimplifyImport2, true};
CHECK_EQ( CHECK_EQ(
"\n" + getCodegenAssembly(R"( "\n" + getCodegenAssembly(R"(
@ -1567,7 +1567,7 @@ end
TEST_CASE("ForInManualAnnotation") TEST_CASE("ForInManualAnnotation")
{ {
ScopedFastFlag luauCodeGenSimplifyImport{FFlag::LuauCodeGenSimplifyImport, true}; ScopedFastFlag luauCodeGenSimplifyImport{FFlag::LuauCodeGenSimplifyImport2, true};
CHECK_EQ( CHECK_EQ(
"\n" + getCodegenAssembly( "\n" + getCodegenAssembly(

View file

@ -15,7 +15,6 @@
#include "doctest.h" #include "doctest.h"
#include <iostream> #include <iostream>
LUAU_FASTFLAG(LuauNewNonStrictVisitTypes2)
LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks) LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks)
LUAU_FASTFLAG(LuauNewNonStrictMoreUnknownSymbols) LUAU_FASTFLAG(LuauNewNonStrictMoreUnknownSymbols)
LUAU_FASTFLAG(LuauNewNonStrictNoErrorsPassingNever) LUAU_FASTFLAG(LuauNewNonStrictNoErrorsPassingNever)
@ -737,8 +736,6 @@ TEST_CASE_FIXTURE(Fixture, "unknown_globals_in_non_strict_1")
TEST_CASE_FIXTURE(BuiltinsFixture, "unknown_types_in_non_strict") TEST_CASE_FIXTURE(BuiltinsFixture, "unknown_types_in_non_strict")
{ {
ScopedFastFlag sff{FFlag::LuauNewNonStrictVisitTypes2, true};
CheckResult result = check(Mode::Nonstrict, R"( CheckResult result = check(Mode::Nonstrict, R"(
--!nonstrict --!nonstrict
local foo: Foo = 1 local foo: Foo = 1
@ -752,8 +749,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unknown_types_in_non_strict")
TEST_CASE_FIXTURE(BuiltinsFixture, "unknown_types_in_non_strict_2") TEST_CASE_FIXTURE(BuiltinsFixture, "unknown_types_in_non_strict_2")
{ {
ScopedFastFlag sff{FFlag::LuauNewNonStrictVisitTypes2, true};
CheckResult result = check(Mode::Nonstrict, R"( CheckResult result = check(Mode::Nonstrict, R"(
--!nonstrict --!nonstrict
local foo = 1 :: Foo local foo = 1 :: Foo

View file

@ -12,8 +12,6 @@
using namespace Luau; using namespace Luau;
LUAU_FASTFLAG(LuauCSTForReturnTypeFunctionTail)
TEST_SUITE_BEGIN("TranspilerTests"); TEST_SUITE_BEGIN("TranspilerTests");
TEST_CASE("test_1") TEST_CASE("test_1")
@ -2055,9 +2053,6 @@ TEST_CASE("transpile_type_function_return_types")
TEST_CASE("transpile_chained_function_types") TEST_CASE("transpile_chained_function_types")
{ {
ScopedFastFlag fflags[] = {
{FFlag::LuauCSTForReturnTypeFunctionTail, true},
};
std::string code = R"( type Foo = () -> () -> () )"; std::string code = R"( type Foo = () -> () -> () )";
CHECK_EQ(code, transpile(code, {}, true).code); CHECK_EQ(code, transpile(code, {}, true).code);

View file

@ -1813,7 +1813,7 @@ struct TFFixture
BuiltinTypeFunctions builtinTypeFunctions; BuiltinTypeFunctions builtinTypeFunctions;
TypeFunctionContext tfc{ TypeFunctionContext tfc_{
arena, arena,
getBuiltins(), getBuiltins(),
NotNull{globalScope.get()}, NotNull{globalScope.get()},
@ -1823,6 +1823,8 @@ struct TFFixture
NotNull{&ice}, NotNull{&ice},
NotNull{&limits} NotNull{&limits}
}; };
NotNull<TypeFunctionContext> tfc{&tfc_};
}; };
TEST_CASE_FIXTURE(TFFixture, "refine<G, ~(false?)>") TEST_CASE_FIXTURE(TFFixture, "refine<G, ~(false?)>")

View file

@ -10,7 +10,6 @@
using namespace Luau; using namespace Luau;
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauNewNonStrictVisitTypes2)
LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion2) LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion2)
LUAU_FASTFLAG(LuauSkipMalformedTypeAliases) LUAU_FASTFLAG(LuauSkipMalformedTypeAliases)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
@ -1180,10 +1179,7 @@ TEST_CASE_FIXTURE(Fixture, "bound_type_in_alias_segfault")
export type FieldConfigMap<TSource, TContext> = Map<string, FieldConfig<TSource, TContext>> export type FieldConfigMap<TSource, TContext> = Map<string, FieldConfig<TSource, TContext>>
)"); )");
if (FFlag::LuauNewNonStrictVisitTypes2)
LUAU_CHECK_ERROR_COUNT(2, result); LUAU_CHECK_ERROR_COUNT(2, result);
else
LUAU_CHECK_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "gh1632_no_infinite_recursion_in_normalization") TEST_CASE_FIXTURE(BuiltinsFixture, "gh1632_no_infinite_recursion_in_normalization")

View file

@ -14,7 +14,6 @@
using namespace Luau; using namespace Luau;
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops) LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps) LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
@ -36,16 +35,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauSolverV2) if (FFlag::LuauSolverV2)
{
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
CHECK("(*error-type* | ~nil)?" == toString(requireType("a"))); CHECK("(*error-type* | ~nil)?" == toString(requireType("a")));
}
else
{
CHECK("any?" == toString(requireType("a")));
}
}
else else
CHECK(getBuiltins()->anyType == requireType("a")); CHECK(getBuiltins()->anyType == requireType("a"));
} }
@ -66,16 +56,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any2")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauSolverV2) if (FFlag::LuauSolverV2)
{
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
CHECK("(*error-type* | ~nil)?" == toString(requireType("a"))); CHECK("(*error-type* | ~nil)?" == toString(requireType("a")));
}
else
{
CHECK("any?" == toString(requireType("a")));
}
}
else else
CHECK("any" == toString(requireType("a"))); CHECK("any" == toString(requireType("a")));
} }
@ -94,16 +75,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauSolverV2) if (FFlag::LuauSolverV2)
{
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
CHECK("(*error-type* | ~nil)?" == toString(requireType("a"))); CHECK("(*error-type* | ~nil)?" == toString(requireType("a")));
}
else
{
CHECK("any?" == toString(requireType("a")));
}
}
else else
CHECK("any" == toString(requireType("a"))); CHECK("any" == toString(requireType("a")));
} }
@ -120,16 +92,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any2")
)"); )");
if (FFlag::LuauSolverV2) if (FFlag::LuauSolverV2)
{
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
CHECK("(*error-type* | ~nil)?" == toString(requireType("a"))); CHECK("(*error-type* | ~nil)?" == toString(requireType("a")));
}
else
{
CHECK("any?" == toString(requireType("a")));
}
}
else else
CHECK("any" == toString(requireType("a"))); CHECK("any" == toString(requireType("a")));
} }
@ -148,16 +111,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any_pack")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauSolverV2) if (FFlag::LuauSolverV2)
{
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
CHECK("(*error-type* | ~nil)?" == toString(requireType("a"))); CHECK("(*error-type* | ~nil)?" == toString(requireType("a")));
}
else
{
CHECK("any?" == toString(requireType("a")));
}
}
else else
CHECK("any" == toString(requireType("a"))); CHECK("any" == toString(requireType("a")));
} }

View file

@ -18,7 +18,6 @@ LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
LUAU_FASTFLAG(LuauWriteOnlyPropertyMangling) LUAU_FASTFLAG(LuauWriteOnlyPropertyMangling)
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties) LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls) LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
LUAU_FASTFLAG(LuauTypeCheckerStricterIndexCheck)
LUAU_FASTFLAG(LuauSuppressErrorsForMultipleNonviableOverloads) LUAU_FASTFLAG(LuauSuppressErrorsForMultipleNonviableOverloads)
TEST_SUITE_BEGIN("BuiltinTests"); TEST_SUITE_BEGIN("BuiltinTests");
@ -1767,8 +1766,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "read_refinements_on_persistent_tables_known_
TEST_CASE_FIXTURE(BuiltinsFixture, "read_refinements_on_persistent_tables_unknown_property") TEST_CASE_FIXTURE(BuiltinsFixture, "read_refinements_on_persistent_tables_unknown_property")
{ {
ScopedFastFlag _{FFlag::LuauTypeCheckerStricterIndexCheck, true};
CheckResult results = check(R"( CheckResult results = check(R"(
if bit32.scrambleEggs then if bit32.scrambleEggs then
end end

View file

@ -25,7 +25,6 @@ LUAU_FASTFLAG(DebugLuauEqSatSimplification)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments) LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
LUAU_FASTFLAG(LuauFormatUseLastPosition) LUAU_FASTFLAG(LuauFormatUseLastPosition)
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
LUAU_FASTFLAG(LuauSimplifyOutOfLine2) LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch) LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
@ -3162,7 +3161,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_function_calls_should_not_use_the_generali
TEST_CASE_FIXTURE(Fixture, "fuzz_unwind_mutually_recursive_union_type_func") TEST_CASE_FIXTURE(Fixture, "fuzz_unwind_mutually_recursive_union_type_func")
{ {
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauDoNotAddUpvalueTypesToLocalType, true}}; ScopedFastFlag _{FFlag::LuauSolverV2, true};
// Previously, this block minted a type like: // Previously, this block minted a type like:
// //

View file

@ -9,12 +9,10 @@
LUAU_FASTFLAG(LuauInstantiateInSubtyping) LUAU_FASTFLAG(LuauInstantiateInSubtyping)
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping) LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
LUAU_FASTFLAG(LuauIntersectNotNil) LUAU_FASTFLAG(LuauIntersectNotNil)
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts) LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
LUAU_FASTFLAG(LuauReportSubtypingErrors)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch) LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps) LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
@ -785,7 +783,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names_old_solver")
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_types") TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_types")
{ {
ScopedFastFlag sffs[] = {{FFlag::LuauReportSubtypingErrors, true}, {FFlag::LuauSubtypingCheckFunctionGenericCounts, true}}; ScopedFastFlag _{FFlag::LuauSubtypingCheckFunctionGenericCounts, true};
CheckResult result = check(R"( CheckResult result = check(R"(
type C = () -> () type C = () -> ()
@ -818,7 +816,7 @@ local d: D = c
} }
TEST_CASE_FIXTURE(Fixture, "generic_function_mismatch_with_argument") TEST_CASE_FIXTURE(Fixture, "generic_function_mismatch_with_argument")
{ {
ScopedFastFlag sffs[] = {{FFlag::LuauReportSubtypingErrors, true}, {FFlag::LuauSubtypingCheckFunctionGenericCounts, true}}; ScopedFastFlag _{FFlag::LuauSubtypingCheckFunctionGenericCounts, true};
CheckResult result = check(R"( CheckResult result = check(R"(
type C = (number) -> () type C = (number) -> ()
@ -852,7 +850,7 @@ local d: D = c
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_pack") TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_pack")
{ {
ScopedFastFlag sffs[] = {{FFlag::LuauReportSubtypingErrors, true}, {FFlag::LuauSubtypingCheckFunctionGenericCounts, true}}; ScopedFastFlag _{FFlag::LuauSubtypingCheckFunctionGenericCounts, true};
CheckResult result = check(R"( CheckResult result = check(R"(
type C = () -> () type C = () -> ()
@ -1530,7 +1528,6 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded"
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_infer_generic_functions") TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_infer_generic_functions")
{ {
ScopedFastFlag _[] = { ScopedFastFlag _[] = {
{FFlag::LuauReportSubtypingErrors, true},
{FFlag::LuauSubtypingCheckFunctionGenericCounts, true}, {FFlag::LuauSubtypingCheckFunctionGenericCounts, true},
{FFlag::LuauEagerGeneralization4, true}, {FFlag::LuauEagerGeneralization4, true},
}; };

View file

@ -15,9 +15,7 @@
using namespace Luau; using namespace Luau;
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAG(LuauSimplifyOutOfLine2) LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
LUAU_FASTFLAG(LuauDfgIfBlocksShouldRespectControlFlow)
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops) LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
TEST_SUITE_BEGIN("TypeInferLoops"); TEST_SUITE_BEGIN("TypeInferLoops");
@ -158,7 +156,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop")
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next")
{ {
ScopedFastFlag _{FFlag::LuauAddCallConstraintForIterableFunctions, true};
CheckResult result = check(R"( CheckResult result = check(R"(
local n local n
local s local s
@ -187,7 +184,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next")
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next_and_multiple_elements") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next_and_multiple_elements")
{ {
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{FFlag::LuauAddCallConstraintForIterableFunctions, true},
{FFlag::LuauSimplifyOutOfLine2, true}, {FFlag::LuauSimplifyOutOfLine2, true},
{FFlag::LuauDfgAllowUpdatesInLoops, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true},
}; };
@ -289,14 +285,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_a_custom_iterator_should_type_ch
end end
)"); )");
if (FFlag::LuauSolverV2 && FFlag::LuauAddCallConstraintForIterableFunctions) if (FFlag::LuauSolverV2)
{
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
}
else else
{
LUAU_REQUIRE_ERROR_COUNT(1, result); LUAU_REQUIRE_ERROR_COUNT(1, result);
}
} }
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error") TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
@ -1286,7 +1278,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "forin_metatable_iter_mm")
TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_preserves_error_suppression") TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_preserves_error_suppression")
{ {
ScopedFastFlag _{FFlag::LuauAddCallConstraintForIterableFunctions, true};
ScopedFastFlag v1{FFlag::LuauSolverV2, true}; ScopedFastFlag v1{FFlag::LuauSolverV2, true};
CheckResult result = check(R"( CheckResult result = check(R"(
@ -1504,10 +1495,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_is_linearish")
if (!FFlag::LuauSolverV2) if (!FFlag::LuauSolverV2)
return; return;
ScopedFastFlag sffs[] = { ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true},
{FFlag::LuauDfgAllowUpdatesInLoops, true},
};
LUAU_REQUIRE_NO_ERRORS(check(R"( LUAU_REQUIRE_NO_ERRORS(check(R"(
local x = nil local x = nil

View file

@ -12,7 +12,6 @@
LUAU_FASTFLAG(LuauInstantiateInSubtyping) LUAU_FASTFLAG(LuauInstantiateInSubtyping)
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping) LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)

View file

@ -9,6 +9,8 @@
using namespace Luau; using namespace Luau;
LUAU_FASTFLAG(LuauEagerGeneralization4)
namespace namespace
{ {
@ -50,9 +52,8 @@ TEST_CASE_FIXTURE(NegationFixture, "string_is_not_a_subtype_of_negated_string")
TEST_CASE_FIXTURE(Fixture, "cofinite_strings_can_be_compared_for_equality") TEST_CASE_FIXTURE(Fixture, "cofinite_strings_can_be_compared_for_equality")
{ {
// CLI-117082 Cofinite strings cannot be compared for equality because normalization produces a large type with cycles ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
if (FFlag::LuauSolverV2)
return;
CheckResult result = check(R"( CheckResult result = check(R"(
function f(e) function f(e)
if e == 'strictEqual' then if e == 'strictEqual' then

View file

@ -12,15 +12,14 @@ LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(DebugLuauEqSatSimplification) LUAU_FASTFLAG(DebugLuauEqSatSimplification)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauFunctionCallsAreNotNilable) LUAU_FASTFLAG(LuauFunctionCallsAreNotNilable)
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
LUAU_FASTFLAG(LuauSimplificationTableExternType) LUAU_FASTFLAG(LuauSimplificationTableExternType)
LUAU_FASTFLAG(LuauBetterCannotCallFunctionPrimitive) LUAU_FASTFLAG(LuauBetterCannotCallFunctionPrimitive)
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch) LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
LUAU_FASTFLAG(LuauTypeCheckerStricterIndexCheck)
LUAU_FASTFLAG(LuauNormalizationIntersectTablesPreservesExternTypes) LUAU_FASTFLAG(LuauNormalizationIntersectTablesPreservesExternTypes)
LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect) LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect)
LUAU_FASTFLAG(LuauAvoidDoubleNegation) LUAU_FASTFLAG(LuauAvoidDoubleNegation)
LUAU_FASTFLAG(LuauRefineTablesWithReadType) LUAU_FASTFLAG(LuauRefineTablesWithReadType)
LUAU_FASTFLAG(LuauRefineNoRefineAlways)
using namespace Luau; using namespace Luau;
@ -1944,10 +1943,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_clone_it")
TEST_CASE_FIXTURE(RefinementExternTypeFixture, "refine_a_param_that_got_resolved_during_constraint_solving_stage") TEST_CASE_FIXTURE(RefinementExternTypeFixture, "refine_a_param_that_got_resolved_during_constraint_solving_stage")
{ {
// CLI-117134 - Applying a refinement causes an optional value access error.
if (FFlag::LuauSolverV2)
return;
CheckResult result = check(R"( CheckResult result = check(R"(
type Id<T> = T type Id<T> = T
@ -2216,14 +2211,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauAddCallConstraintForIterableFunctions)
{
CHECK_EQ("(unknown) -> (~nil, unknown)", toString(requireType("f"))); CHECK_EQ("(unknown) -> (~nil, unknown)", toString(requireType("f")));
}
else
{
CHECK_EQ("(unknown) -> (unknown, unknown)", toString(requireType("f")));
}
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "conditional_refinement_should_stay_error_suppressing") TEST_CASE_FIXTURE(BuiltinsFixture, "conditional_refinement_should_stay_error_suppressing")
@ -2713,7 +2701,6 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "cannot_call_a_function_single")
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{FFlag::LuauSolverV2, true}, {FFlag::LuauSolverV2, true},
{FFlag::LuauBetterCannotCallFunctionPrimitive, true}, {FFlag::LuauBetterCannotCallFunctionPrimitive, true},
{FFlag::LuauTypeCheckerStricterIndexCheck, true},
{FFlag::LuauRefineTablesWithReadType, true}, {FFlag::LuauRefineTablesWithReadType, true},
}; };
@ -2734,7 +2721,6 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "cannot_call_a_function_union")
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{FFlag::LuauSolverV2, true}, {FFlag::LuauSolverV2, true},
{FFlag::LuauBetterCannotCallFunctionPrimitive, true}, {FFlag::LuauBetterCannotCallFunctionPrimitive, true},
{FFlag::LuauTypeCheckerStricterIndexCheck, true},
{FFlag::LuauRefineTablesWithReadType, true}, {FFlag::LuauRefineTablesWithReadType, true},
}; };
@ -2830,4 +2816,34 @@ TEST_CASE_FIXTURE(Fixture, "limit_complexity_of_arithmetic_type_functions" * doc
LUAU_REQUIRE_ERRORS(result); LUAU_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "refine_by_no_refine_should_always_reduce")
{
ScopedFastFlag _{FFlag::LuauSolverV2, true};
ScopedFastFlag refineNoRefineAlways{FFlag::LuauRefineNoRefineAlways, true};
CheckResult result = check(R"(
function foo(t): boolean return true end
function select<K, V>(t: { [K]: V }, columns: { K }): { [K]: V }
local result = {}
if foo(t) then
for k, v in t do
if table.find(columns, k) then
result[k] = v -- was TypeError: Type function instance refine<intersect<K, ~nil>, *no-refine*> is uninhabited
end
end
else
for k, v in pairs(t) do
if table.find(columns, k) then
result[k] = v
end
end
end
return result
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END(); TEST_SUITE_END();

View file

@ -23,8 +23,6 @@ LUAU_FASTFLAG(LuauInstantiateInSubtyping)
LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering) LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint) LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
LUAU_FASTFLAG(LuauTypeCheckerStricterIndexCheck)
LUAU_FASTFLAG(LuauReportSubtypingErrors)
LUAU_FASTFLAG(LuauSimplifyOutOfLine2) LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties) LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
@ -3818,10 +3816,7 @@ TEST_CASE_FIXTURE(Fixture, "scalar_is_a_subtype_of_a_compatible_polymorphic_shap
TEST_CASE_FIXTURE(Fixture, "scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type") TEST_CASE_FIXTURE(Fixture, "scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag _{FFlag::LuauEagerGeneralization4, true};
{FFlag::LuauReportSubtypingErrors, true},
{FFlag::LuauEagerGeneralization4, true},
};
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(s) local function f(s)
@ -5696,7 +5691,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "function_call_in_indexer_with_compound_assig
TEST_CASE_FIXTURE(Fixture, "stop_refining_new_table_indices_for_non_primitive_tables") TEST_CASE_FIXTURE(Fixture, "stop_refining_new_table_indices_for_non_primitive_tables")
{ {
ScopedFastFlag _{FFlag::LuauSolverV2, true}; ScopedFastFlag _{FFlag::LuauSolverV2, true};
ScopedFastFlag stricterIndexCheck{FFlag::LuauTypeCheckerStricterIndexCheck, true};
CheckResult result = check(R"( CheckResult result = check(R"(
local foo:{val:number} = {val = 1} local foo:{val:number} = {val = 1}

View file

@ -24,9 +24,7 @@ LUAU_FASTINT(LuauNormalizeCacheLimit)
LUAU_FASTINT(LuauRecursionLimit) LUAU_FASTINT(LuauRecursionLimit)
LUAU_FASTINT(LuauTypeInferTypePackLoopLimit) LUAU_FASTINT(LuauTypeInferTypePackLoopLimit)
LUAU_FASTINT(LuauTypeInferRecursionLimit) LUAU_FASTINT(LuauTypeInferRecursionLimit)
LUAU_FASTFLAG(LuauMagicFreezeCheckBlocked2)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauReportSubtypingErrors)
LUAU_FASTFLAG(LuauAvoidDoubleNegation) LUAU_FASTFLAG(LuauAvoidDoubleNegation)
LUAU_FASTFLAG(LuauInsertErrorTypesIntoIndexerResult) LUAU_FASTFLAG(LuauInsertErrorTypesIntoIndexerResult)
LUAU_FASTFLAG(LuauSimplifyOutOfLine2) LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
@ -1213,8 +1211,6 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer")
REQUIRE_MESSAGE(!result.errors.empty(), getErrors(result)); REQUIRE_MESSAGE(!result.errors.empty(), getErrors(result));
if (FFlag::LuauSolverV2) if (FFlag::LuauSolverV2)
{
if (FFlag::LuauReportSubtypingErrors)
{ {
CHECK(4 == result.errors.size()); CHECK(4 == result.errors.size());
CHECK(Location{{2, 22}, {2, 42}} == result.errors[0].location); CHECK(Location{{2, 22}, {2, 42}} == result.errors[0].location);
@ -1226,17 +1222,6 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer")
CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(e)); CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(e));
} }
else else
{
CHECK(3 == result.errors.size());
CHECK(Location{{2, 22}, {2, 42}} == result.errors[0].location);
CHECK(Location{{3, 22}, {3, 42}} == result.errors[1].location);
CHECK(Location{{3, 22}, {3, 41}} == result.errors[2].location);
CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0]));
CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[1]));
CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[2]));
}
}
else
{ {
CHECK(1 == result.errors.size()); CHECK(1 == result.errors.size());
@ -1986,7 +1971,7 @@ TEST_CASE_FIXTURE(Fixture, "assert_allows_singleton_union_or_intersection")
TEST_CASE_FIXTURE(BuiltinsFixture, "assert_table_freeze_constraint_solving") TEST_CASE_FIXTURE(BuiltinsFixture, "assert_table_freeze_constraint_solving")
{ {
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauMagicFreezeCheckBlocked2, true}}; ScopedFastFlag _{FFlag::LuauSolverV2, true};
LUAU_REQUIRE_NO_ERRORS(check(R"( LUAU_REQUIRE_NO_ERRORS(check(R"(
local f = table.freeze local f = table.freeze
f(table) f(table)
@ -1995,7 +1980,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_table_freeze_constraint_solving")
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_assert_table_freeze_constraint_solving") TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_assert_table_freeze_constraint_solving")
{ {
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauMagicFreezeCheckBlocked2, true}}; ScopedFastFlag _ {FFlag::LuauSolverV2, true};
// This is the original fuzzer version of the above issue. // This is the original fuzzer version of the above issue.
CheckResult results = check(R"( CheckResult results = check(R"(
local function l0() local function l0()
@ -2116,8 +2101,6 @@ local _
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_missing_follow_table_freeze") TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_missing_follow_table_freeze")
{ {
ScopedFastFlag _{FFlag::LuauMagicFreezeCheckBlocked2, true};
LUAU_REQUIRE_ERRORS(check(R"( LUAU_REQUIRE_ERRORS(check(R"(
if _:freeze(_)[_][_] then if _:freeze(_)[_][_] then
else else

View file

@ -13,7 +13,6 @@ LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauInstantiateInSubtyping) LUAU_FASTFLAG(LuauInstantiateInSubtyping)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauReportSubtypingErrors)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
LUAU_FASTFLAG(LuauFixEmptyTypePackStringification) LUAU_FASTFLAG(LuauFixEmptyTypePackStringification)
@ -1063,8 +1062,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks")
TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2") TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2")
{ {
ScopedFastFlag _{FFlag::LuauReportSubtypingErrors, true};
CheckResult result = check(R"( CheckResult result = check(R"(
function _(l0:((typeof((pcall)))|((((t0)->())|(typeof(-67108864)))|(any)))|(any),...):(((typeof(0))|(any))|(any),typeof(-67108864),any) function _(l0:((typeof((pcall)))|((((t0)->())|(typeof(-67108864)))|(any)))|(any),...):(((typeof(0))|(any))|(any),typeof(-67108864),any)
xpcall(_,_,_) xpcall(_,_,_)

View file

@ -4,9 +4,6 @@
#include "doctest.h" #include "doctest.h"
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
LUAU_FASTFLAG(LuauDfgIfBlocksShouldRespectControlFlow)
LUAU_FASTFLAG(LuauReportSubtypingErrors)
LUAU_FASTFLAG(LuauEagerGeneralization4) LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2) LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops) LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
@ -269,8 +266,6 @@ TEST_CASE_FIXTURE(TypeStateFixture, "local_assigned_in_only_one_branch_that_fall
TEST_CASE_FIXTURE(TypeStateFixture, "then_branch_assigns_and_else_branch_also_assigns_but_is_met_with_return") TEST_CASE_FIXTURE(TypeStateFixture, "then_branch_assigns_and_else_branch_also_assigns_but_is_met_with_return")
{ {
ScopedFastFlag _{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true};
CheckResult result = check(R"( CheckResult result = check(R"(
local x = nil local x = nil
if math.random() > 0.5 then if math.random() > 0.5 then
@ -288,8 +283,6 @@ TEST_CASE_FIXTURE(TypeStateFixture, "then_branch_assigns_and_else_branch_also_as
TEST_CASE_FIXTURE(TypeStateFixture, "then_branch_assigns_but_is_met_with_return_and_else_branch_assigns") TEST_CASE_FIXTURE(TypeStateFixture, "then_branch_assigns_but_is_met_with_return_and_else_branch_assigns")
{ {
ScopedFastFlag _{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true};
CheckResult result = check(R"( CheckResult result = check(R"(
local x = nil local x = nil
if math.random() > 0.5 then if math.random() > 0.5 then
@ -350,7 +343,6 @@ TEST_CASE_FIXTURE(TypeStateFixture, "local_t_is_assigned_a_fresh_table_with_x_as
TEST_CASE_FIXTURE(TypeStateFixture, "captured_locals_do_not_mutate_upvalue_type") TEST_CASE_FIXTURE(TypeStateFixture, "captured_locals_do_not_mutate_upvalue_type")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
CheckResult result = check(R"( CheckResult result = check(R"(
local x = nil local x = nil
@ -372,7 +364,6 @@ TEST_CASE_FIXTURE(TypeStateFixture, "captured_locals_do_not_mutate_upvalue_type"
TEST_CASE_FIXTURE(TypeStateFixture, "captured_locals_do_not_mutate_upvalue_type_2") TEST_CASE_FIXTURE(TypeStateFixture, "captured_locals_do_not_mutate_upvalue_type_2")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
CheckResult result = check(R"( CheckResult result = check(R"(
local t = {x = nil} local t = {x = nil}
@ -413,7 +404,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "prototyped_recursive_functions_but_has_futur
{ {
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{FFlag::LuauSolverV2, true}, {FFlag::LuauSolverV2, true},
{FFlag::LuauReportSubtypingErrors, true},
{FFlag::LuauEagerGeneralization4, true}, {FFlag::LuauEagerGeneralization4, true},
}; };
@ -477,25 +467,6 @@ TEST_CASE_FIXTURE(TypeStateFixture, "typestates_preserve_error_suppression")
CHECK("*error-type* | string" == toString(requireTypeAtPosition({3, 14}), {true})); CHECK("*error-type* | string" == toString(requireTypeAtPosition({3, 14}), {true}));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_preserve_error_suppression_properties")
{
// early return if the flag isn't set since this is blocking gated commits
// unconditional return
// CLI-117098 Type states with error suppressing properties doesn't infer the correct type for properties.
if (!FFlag::LuauSolverV2 || FFlag::LuauSolverV2)
return;
CheckResult result = check(R"(
local a: {x: any} = {x = 51}
a.x = "pickles" -- We'll have a new DefId for this iteration of `a.x`. Its type must also be error-suppressing
print(a.x)
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK("*error-type* | string" == toString(requireTypeAtPosition({3, 16}), {true}));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_do_not_apply_to_the_initial_local_definition") TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_do_not_apply_to_the_initial_local_definition")
{ {
// early return if the flag isn't set since this is blocking gated commits // early return if the flag isn't set since this is blocking gated commits
@ -577,8 +548,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "fuzzer_normalized_type_variables_are_bad" *
TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1547_simple") TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1547_simple")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
LUAU_REQUIRE_NO_ERRORS(check(R"( LUAU_REQUIRE_NO_ERRORS(check(R"(
local rand = 0 local rand = 0
@ -594,8 +563,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1547_simple")
TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1547") TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1547")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
LUAU_REQUIRE_NO_ERRORS(check(R"( LUAU_REQUIRE_NO_ERRORS(check(R"(
local rand = 0 local rand = 0
@ -629,8 +596,6 @@ TEST_CASE_FIXTURE(Fixture, "modify_captured_table_field")
TEST_CASE_FIXTURE(Fixture, "oss_1561") TEST_CASE_FIXTURE(Fixture, "oss_1561")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
loadDefinition(R"( loadDefinition(R"(
declare class Vector3 declare class Vector3
X: number X: number
@ -655,8 +620,6 @@ TEST_CASE_FIXTURE(Fixture, "oss_1561")
TEST_CASE_FIXTURE(Fixture, "oss_1575") TEST_CASE_FIXTURE(Fixture, "oss_1575")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
LUAU_REQUIRE_NO_ERRORS(check(R"( LUAU_REQUIRE_NO_ERRORS(check(R"(
local flag = true local flag = true
local function Flip() local function Flip()
@ -667,8 +630,6 @@ TEST_CASE_FIXTURE(Fixture, "oss_1575")
TEST_CASE_FIXTURE(Fixture, "capture_upvalue_in_returned_function") TEST_CASE_FIXTURE(Fixture, "capture_upvalue_in_returned_function")
{ {
ScopedFastFlag _{FFlag::LuauDoNotAddUpvalueTypesToLocalType, true};
LUAU_REQUIRE_NO_ERRORS(check(R"( LUAU_REQUIRE_NO_ERRORS(check(R"(
function def() function def()
local i : number = 0 local i : number = 0
@ -684,8 +645,6 @@ TEST_CASE_FIXTURE(Fixture, "capture_upvalue_in_returned_function")
TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_else_branch") TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_else_branch")
{ {
ScopedFastFlag _{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
local x local x
@ -707,8 +666,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_else_branch")
TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_if_branch") TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_if_branch")
{ {
ScopedFastFlag _{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
local x local x
@ -731,8 +688,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_if_branch")
TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring") TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring")
{ {
ScopedFastFlag _{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
type Payload = { payload: number } type Payload = { payload: number }
@ -756,7 +711,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring")
TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop") TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop")
{ {
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{FFlag::LuauSolverV2, true}, {FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true} {FFlag::LuauSolverV2, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true}
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -778,8 +733,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop")
TEST_CASE_FIXTURE(BuiltinsFixture, "type_refinement_in_loop") TEST_CASE_FIXTURE(BuiltinsFixture, "type_refinement_in_loop")
{ {
ScopedFastFlag _{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
local function onEachString(t: { string | number }) local function onEachString(t: { string | number })
@ -800,10 +753,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_refinement_in_loop")
TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_if_branch_and_do_nothing_in_else") TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_if_branch_and_do_nothing_in_else")
{ {
ScopedFastFlag sffs[] = { ScopedFastFlag _{FFlag::LuauSolverV2, true};
{FFlag::LuauSolverV2, true},
{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true},
};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
@ -825,10 +775,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "throw_in_if_branch_and_do_nothing_in_else")
TEST_CASE_FIXTURE(BuiltinsFixture, "assign_in_an_if_branch_without_else") TEST_CASE_FIXTURE(BuiltinsFixture, "assign_in_an_if_branch_without_else")
{ {
ScopedFastFlag sffs[] = { ScopedFastFlag _{FFlag::LuauSolverV2, true};
{FFlag::LuauSolverV2, true},
{FFlag::LuauDfgIfBlocksShouldRespectControlFlow, true},
};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict

View file

@ -513,6 +513,23 @@ end
assert(extramath3(2) == "number") assert(extramath3(2) == "number")
assert(extramath3("2") == "number") assert(extramath3("2") == "number")
local function scopedrestorefailurea(format: string, b: buffer): (string, buffer)
local H1F, H2F, H3F, H4F = buffer.readu32(b, 0), buffer.readu32(b, 8), buffer.readu32(b, 16), buffer.readu32(b, 24)
local H5F, H6F, _, _ = buffer.readu32(b, 32), buffer.readu32(b, 40), buffer.readu32(b, 48), buffer.readu32(b, 56)
local H1B, H2B, H3B, H4B = buffer.readu32(b, 4), buffer.readu32(b, 12), buffer.readu32(b, 20), buffer.readu32(b, 28)
local H5B, H6B, _, _ = buffer.readu32(b, 36), buffer.readu32(b, 44), buffer.readu32(b, 52), buffer.readu32(b, 60)
return string.format(format, H1F, H1B, H2F, H2B, H3F, H3B, H4F, H4B, H5F, H5B, H6F, H6B), b
end
local function scopedrestorefailureb()
local data = buffer.create(64)
buffer.fill(data, 0, 0x12, 64)
assert(scopedrestorefailurea(string.rep("%08x", 12), data) == string.rep("12", 48))
end
scopedrestorefailureb()
local function slotcachelimit1() local function slotcachelimit1()
local tbl = { local tbl = {
f1 = function() return 1 end, f1 = function() return 1 end,