mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 06:15:44 +08:00
Sync to upstream/release/643 (#1408)
Pretty small release this week as well. ## New Solver * We now unconditionally generalize functions with explicit generics * Bugfixes for how we run builtin tests ## VM * Fixed running Luau conformance tests in LUA_VECTOR_SIZE == 4 configuration Internal Contributors: Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: James McNellis <jmcnellis@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Junseo Yoo <jyoo@roblox.com>
This commit is contained in:
parent
f2488bdfa4
commit
b765d7bafd
@ -887,9 +887,6 @@ std::optional<TypeId> generalize(
|
||||
if (ty->owningArena != arena || ty->persistent)
|
||||
return ty;
|
||||
|
||||
if (const FunctionType* ft = get<FunctionType>(ty); ft && (!ft->generics.empty() || !ft->genericPacks.empty()))
|
||||
return ty;
|
||||
|
||||
FreeTypeSearcher fts{scope, cachedTypes};
|
||||
fts.traverse(ty);
|
||||
|
||||
@ -912,8 +909,17 @@ std::optional<TypeId> generalize(
|
||||
FunctionType* ftv = getMutable<FunctionType>(ty);
|
||||
if (ftv)
|
||||
{
|
||||
ftv->generics = std::move(gen.generics);
|
||||
ftv->genericPacks = std::move(gen.genericPacks);
|
||||
// If we're generalizing a function type, add any of the newly inferred
|
||||
// generics to the list of existing generic types.
|
||||
for (const auto g : std::move(gen.generics))
|
||||
{
|
||||
ftv->generics.push_back(g);
|
||||
}
|
||||
// Ditto for generic packs.
|
||||
for (const auto gp : std::move(gen.genericPacks))
|
||||
{
|
||||
ftv->genericPacks.push_back(gp);
|
||||
}
|
||||
}
|
||||
|
||||
return ty;
|
||||
|
@ -107,6 +107,7 @@ std::optional<ErrorVec> OverloadResolver::testIsSubtype(const Location& location
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
errors.emplace_back(location, NormalizationTooComplex{});
|
||||
// intentionally fallthrough here since we couldn't prove this was error-suppressing
|
||||
[[fallthrough]];
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
errors.emplace_back(location, TypeMismatch{superTy, subTy});
|
||||
break;
|
||||
@ -136,6 +137,7 @@ std::optional<ErrorVec> OverloadResolver::testIsSubtype(const Location& location
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
errors.emplace_back(location, NormalizationTooComplex{});
|
||||
// intentionally fallthrough here since we couldn't prove this was error-suppressing
|
||||
[[fallthrough]];
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
errors.emplace_back(location, TypePackMismatch{superTy, subTy});
|
||||
break;
|
||||
@ -301,6 +303,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
errors.emplace_back(argLocation, NormalizationTooComplex{});
|
||||
// intentionally fallthrough here since we couldn't prove this was error-suppressing
|
||||
[[fallthrough]];
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
// TODO extract location from the SubtypingResult path and argExprs
|
||||
switch (reason.variance)
|
||||
|
@ -141,6 +141,7 @@ Relation combine(Relation a, Relation b)
|
||||
case Relation::Superset:
|
||||
return Relation::Intersects;
|
||||
}
|
||||
break;
|
||||
case Relation::Coincident:
|
||||
switch (b)
|
||||
{
|
||||
@ -155,6 +156,7 @@ Relation combine(Relation a, Relation b)
|
||||
case Relation::Superset:
|
||||
return Relation::Intersects;
|
||||
}
|
||||
break;
|
||||
case Relation::Superset:
|
||||
switch (b)
|
||||
{
|
||||
@ -169,6 +171,7 @@ Relation combine(Relation a, Relation b)
|
||||
case Relation::Superset:
|
||||
return Relation::Superset;
|
||||
}
|
||||
break;
|
||||
case Relation::Subset:
|
||||
switch (b)
|
||||
{
|
||||
@ -183,6 +186,7 @@ Relation combine(Relation a, Relation b)
|
||||
case Relation::Superset:
|
||||
return Relation::Intersects;
|
||||
}
|
||||
break;
|
||||
case Relation::Intersects:
|
||||
switch (b)
|
||||
{
|
||||
@ -197,6 +201,7 @@ Relation combine(Relation a, Relation b)
|
||||
case Relation::Superset:
|
||||
return Relation::Intersects;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
LUAU_UNREACHABLE();
|
||||
|
@ -1378,7 +1378,7 @@ void TypeChecker2::visitCall(AstExprCall* call)
|
||||
break;
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
reportError(NormalizationTooComplex{}, call->func->location);
|
||||
// fallthrough intentional
|
||||
[[fallthrough]];
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
reportError(OptionalValueAccess{fnTy}, call->func->location);
|
||||
}
|
||||
@ -1582,7 +1582,7 @@ TypeId TypeChecker2::stripFromNilAndReport(TypeId ty, const Location& location)
|
||||
break;
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
reportError(NormalizationTooComplex{}, location);
|
||||
// fallthrough intentional
|
||||
[[fallthrough]];
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
reportError(OptionalValueAccess{ty}, location);
|
||||
}
|
||||
@ -1666,7 +1666,7 @@ void TypeChecker2::visit(AstExprIndexExpr* indexExpr, ValueContext context)
|
||||
break;
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
reportError(NormalizationTooComplex{}, indexExpr->location);
|
||||
// fallthrough intentional
|
||||
[[fallthrough]];
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
reportError(OptionalValueAccess{exprType}, indexExpr->location);
|
||||
}
|
||||
@ -2723,6 +2723,7 @@ void TypeChecker2::explainError(TypeId subTy, TypeId superTy, Location location,
|
||||
return;
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
reportError(NormalizationTooComplex{}, location);
|
||||
break;
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
break;
|
||||
}
|
||||
@ -2741,6 +2742,7 @@ void TypeChecker2::explainError(TypePackId subTy, TypePackId superTy, Location l
|
||||
return;
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
reportError(NormalizationTooComplex{}, location);
|
||||
break;
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
break;
|
||||
}
|
||||
|
@ -2751,7 +2751,7 @@ TypeId TypeChecker::checkRelationalOperation(
|
||||
if (lhsIsAny || rhsIsAny)
|
||||
return booleanType;
|
||||
|
||||
// Fallthrough here is intentional
|
||||
[[fallthrough]];
|
||||
}
|
||||
case AstExprBinary::CompareLt:
|
||||
case AstExprBinary::CompareGt:
|
||||
|
@ -784,6 +784,7 @@ AstStat* Parser::parseAttributeStat()
|
||||
AstExpr* expr = parsePrimaryExpr(/* asStatement= */ true);
|
||||
return parseDeclaration(expr->location, attributes);
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
return reportStatError(
|
||||
lexer.current().location,
|
||||
|
@ -204,7 +204,18 @@ void RequireResolver::substituteAliasIfPresent(std::string& path)
|
||||
{
|
||||
if (path.size() < 1 || path[0] != '@')
|
||||
return;
|
||||
std::string potentialAlias = path.substr(1, path.find_first_of("\\/"));
|
||||
|
||||
// To ignore the '@' alias prefix when processing the alias
|
||||
const size_t aliasStartPos = 1;
|
||||
|
||||
// If a directory separator was found, the length of the alias is the
|
||||
// distance between the start of the alias and the separator. Otherwise,
|
||||
// the whole string after the alias symbol is the alias.
|
||||
size_t aliasLen = path.find_first_of("\\/");
|
||||
if (aliasLen != std::string::npos)
|
||||
aliasLen -= aliasStartPos;
|
||||
|
||||
const std::string potentialAlias = path.substr(aliasStartPos, aliasLen);
|
||||
|
||||
// Not worth searching when potentialAlias cannot be an alias
|
||||
if (!Luau::isValidAlias(potentialAlias))
|
||||
|
@ -111,6 +111,7 @@ if(MSVC)
|
||||
list(APPEND LUAU_OPTIONS "/we4388") # Also signed/unsigned mismatch
|
||||
else()
|
||||
list(APPEND LUAU_OPTIONS -Wall) # All warnings
|
||||
list(APPEND LUAU_OPTIONS -Wimplicit-fallthrough)
|
||||
list(APPEND LUAU_OPTIONS -Wsign-compare) # This looks to be included in -Wall for GCC but not clang
|
||||
endif()
|
||||
|
||||
|
@ -20,6 +20,19 @@
|
||||
#define LUAU_DEBUGBREAK() __builtin_trap()
|
||||
#endif
|
||||
|
||||
// LUAU_FALLTHROUGH is a C++11-compatible alternative to [[fallthrough]] for use in the VM library
|
||||
#if defined(__clang__) && defined(__has_warning)
|
||||
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
||||
#define LUAU_FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
#define LUAU_FALLTHROUGH
|
||||
#endif
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 7
|
||||
#define LUAU_FALLTHROUGH [[gnu::fallthrough]]
|
||||
#else
|
||||
#define LUAU_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define LUAU_BIG_ENDIAN
|
||||
#endif
|
||||
|
@ -552,9 +552,9 @@ init: // using goto's to optimize tail recursion
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '+': // 1 or more repetitions
|
||||
s++; // 1 match already done
|
||||
// go through
|
||||
case '+': // 1 or more repetitions
|
||||
s++; // 1 match already done
|
||||
LUAU_FALLTHROUGH; // go through
|
||||
case '*': // 0 or more repetitions
|
||||
s = max_expand(ms, s, p, ep);
|
||||
break;
|
||||
@ -1480,7 +1480,8 @@ static int str_pack(lua_State* L)
|
||||
break;
|
||||
}
|
||||
case Kpadding:
|
||||
luaL_addchar(&b, LUAL_PACKPADBYTE); // FALLTHROUGH
|
||||
luaL_addchar(&b, LUAL_PACKPADBYTE);
|
||||
LUAU_FALLTHROUGH;
|
||||
case Kpaddalign:
|
||||
case Knop:
|
||||
arg--; // undo increment
|
||||
|
@ -659,7 +659,7 @@ const TValue* luaH_get(Table* t, const TValue* key)
|
||||
luai_num2int(k, n);
|
||||
if (luai_numeq(cast_num(k), nvalue(key))) // index is int?
|
||||
return luaH_getnum(t, k); // use specialized version
|
||||
// else go through
|
||||
LUAU_FALLTHROUGH; // else go through
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
@ -133,7 +133,12 @@ static int lua_vector_cross(lua_State* L)
|
||||
const float* a = luaL_checkvector(L, 1);
|
||||
const float* b = luaL_checkvector(L, 2);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0f);
|
||||
#else
|
||||
lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -144,15 +149,25 @@ static int lua_vector_index(lua_State* L)
|
||||
|
||||
if (strcmp(name, "Magnitude") == 0)
|
||||
{
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]));
|
||||
#else
|
||||
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(name, "Unit") == 0)
|
||||
{
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
||||
|
||||
lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt, v[3] * invSqrt);
|
||||
#else
|
||||
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
|
||||
lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Luau/AstQuery.h"
|
||||
#include "Luau/BuiltinDefinitions.h"
|
||||
#include "Luau/Common.h"
|
||||
#include "Luau/Constraint.h"
|
||||
#include "Luau/ModuleResolver.h"
|
||||
#include "Luau/NotNull.h"
|
||||
@ -25,6 +26,7 @@ static const char* mainModuleName = "MainModule";
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena);
|
||||
LUAU_FASTFLAG(DebugLuauLogSolverToJsonFile)
|
||||
LUAU_FASTFLAG(LuauDCRMagicFunctionTypeChecker);
|
||||
|
||||
extern std::optional<unsigned> randomSeed; // tests/main.cpp
|
||||
|
||||
@ -150,6 +152,8 @@ const Config& TestConfigResolver::getConfig(const ModuleName& name) const
|
||||
|
||||
Fixture::Fixture(bool freeze, bool prepareAutocomplete)
|
||||
: sff_DebugLuauFreezeArena(FFlag::DebugLuauFreezeArena, freeze)
|
||||
// In tests, we *always* want to register the extra magic functions for typechecking `string.format`.
|
||||
, sff_LuauDCRMagicFunctionTypeChecker(FFlag::LuauDCRMagicFunctionTypeChecker, true)
|
||||
, frontend(
|
||||
&fileResolver,
|
||||
&configResolver,
|
||||
|
@ -99,6 +99,7 @@ struct Fixture
|
||||
TypeId requireExportedType(const ModuleName& moduleName, const std::string& name);
|
||||
|
||||
ScopedFastFlag sff_DebugLuauFreezeArena;
|
||||
ScopedFastFlag sff_LuauDCRMagicFunctionTypeChecker;
|
||||
|
||||
TestFileResolver fileResolver;
|
||||
TestConfigResolver configResolver;
|
||||
|
@ -937,6 +937,7 @@ bb_bytecode_0:
|
||||
);
|
||||
}
|
||||
|
||||
#if LUA_VECTOR_SIZE == 3
|
||||
TEST_CASE("FastcallTypeInferThroughLocal")
|
||||
{
|
||||
CHECK_EQ(
|
||||
@ -1045,6 +1046,7 @@ bb_bytecode_1:
|
||||
)"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("LoadAndMoveTypePropagation")
|
||||
{
|
||||
@ -1115,6 +1117,7 @@ bb_bytecode_4:
|
||||
);
|
||||
}
|
||||
|
||||
#if LUA_VECTOR_SIZE == 3
|
||||
TEST_CASE("ArgumentTypeRefinement")
|
||||
{
|
||||
CHECK_EQ(
|
||||
@ -1152,6 +1155,7 @@ bb_bytecode_0:
|
||||
)"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("InlineFunctionType")
|
||||
{
|
||||
@ -1422,6 +1426,7 @@ bb_2:
|
||||
);
|
||||
}
|
||||
|
||||
#if LUA_VECTOR_SIZE == 3
|
||||
TEST_CASE("UnaryTypeResolve")
|
||||
{
|
||||
CHECK_EQ(
|
||||
@ -1443,6 +1448,7 @@ end
|
||||
)"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("ForInManualAnnotation")
|
||||
{
|
||||
|
@ -436,6 +436,12 @@ TEST_CASE_FIXTURE(ReplWithPathFixture, "RequirePathWithParentAlias")
|
||||
assertOutputContainsAll({"true", "result from other_dependency"});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ReplWithPathFixture, "RequirePathWithAliasPointingToDirectory")
|
||||
{
|
||||
std::string path = getLuauDirectory(PathType::Relative) + "/tests/require/with_config/src/directory_alias_requirer";
|
||||
runProtectedRequire(path);
|
||||
assertOutputContainsAll({"true", "result from subdirectory_dependency"});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ReplWithPathFixture, "RequireAliasThatDoesNotExist")
|
||||
{
|
||||
|
@ -843,7 +843,7 @@ TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
CHECK("<a>(a, 'b) -> ()" == toString(requireType("foo")));
|
||||
CHECK("<a>(a, unknown) -> ()" == toString(requireType("foo")));
|
||||
}
|
||||
else
|
||||
CHECK("<a, b>(a, b) -> ()" == toString(requireType("foo")));
|
||||
|
@ -9,7 +9,6 @@
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauDCRMagicFunctionTypeChecker);
|
||||
|
||||
TEST_SUITE_BEGIN("BuiltinTests");
|
||||
|
||||
@ -793,8 +792,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_strin
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "string_format_as_method")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDCRMagicFunctionTypeChecker, true};
|
||||
|
||||
CheckResult result = check("local _ = ('%s'):format(5)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
@ -807,7 +804,6 @@ TEST_CASE_FIXTURE(Fixture, "string_format_as_method")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDCRMagicFunctionTypeChecker, true};
|
||||
CheckResult result = check(R"(
|
||||
local _ = ("%s"):format("%d", "hello")
|
||||
)");
|
||||
@ -819,7 +815,6 @@ TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument2")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDCRMagicFunctionTypeChecker, true};
|
||||
CheckResult result = check(R"(
|
||||
local _ = ("%s %d").format("%d %s", "A type error", 2)
|
||||
)");
|
||||
@ -878,7 +873,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDCRMagicFunctionTypeChecker, true};
|
||||
CheckResult result = check(R"(
|
||||
local fmt = string.format
|
||||
local s = fmt("%d", "oops")
|
||||
@ -938,7 +932,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_report_all_type_errors_at_correct_positions")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDCRMagicFunctionTypeChecker, true};
|
||||
CheckResult result = check(R"(
|
||||
("%s%d%s"):format(1, "hello", true)
|
||||
string.format("%s%d%s", 1, "hello", true)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "Fixture.h"
|
||||
|
||||
#include "ScopedFlags.h"
|
||||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping);
|
||||
@ -1419,10 +1420,19 @@ TEST_CASE_FIXTURE(Fixture, "apply_type_function_nested_generics3")
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "quantify_functions_with_no_generics")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
function foo(f, x)
|
||||
return f(x)
|
||||
end
|
||||
)");
|
||||
|
||||
CHECK("<a, b...>((a) -> (b...), a) -> (b...)" == toString(requireType("foo")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_generic")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function foo<X>(f, x: X)
|
||||
return f(x)
|
||||
@ -1432,6 +1442,17 @@ TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_gen
|
||||
CHECK("<X, a...>((X) -> (a...), X) -> (a...)" == toString(requireType("foo")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "no_extra_quantification_for_generic_functions")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
function foo<X, Y>(f : (X) -> Y, x: X)
|
||||
return f(x)
|
||||
end
|
||||
)");
|
||||
|
||||
CHECK("<X, Y>((X) -> Y, X) -> Y" == toString(requireType("foo")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "do_not_always_instantiate_generic_intersection_types")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
@ -1535,6 +1556,19 @@ TEST_CASE_FIXTURE(Fixture, "missing_generic_type_parameter")
|
||||
REQUIRE(get<UnknownSymbol>(result.errors[1]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_implicit_explicit_name_clash")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check(R"(
|
||||
function apply<a>(func, argument: a)
|
||||
return func(argument)
|
||||
end
|
||||
)");
|
||||
|
||||
CHECK("<a, b...>((a) -> (b...), a) -> (b...)" == toString(requireType("apply")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "generic_type_functions_work_in_subtyping")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
|
@ -1310,9 +1310,7 @@ TEST_CASE_FIXTURE(Fixture, "we_cannot_infer_functions_that_return_inconsistently
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_CHECK_ERROR_COUNT(2, result);
|
||||
|
||||
// The second argument should be unknown. CLI-111111
|
||||
CHECK("<T>({T}, 'b) -> number" == toString(requireType("find_first")));
|
||||
CHECK("<T>({T}, unknown) -> number" == toString(requireType("find_first")));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"paths": ["../ProjectLuauLibraries"],
|
||||
"aliases": {
|
||||
"dep": "dependency"
|
||||
"dep": "dependency",
|
||||
"subdir": "subdirectory"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
return(require("@subdir/subdirectory_dependency"))
|
@ -0,0 +1 @@
|
||||
return {"result from subdirectory_dependency"}
|
Loading…
Reference in New Issue
Block a user