From 2621488abea019bb1c22a84e784aadd3f1bc4cad Mon Sep 17 00:00:00 2001 From: Matheus <175355178+vvatheus@users.noreply.github.com> Date: Mon, 24 Mar 2025 13:27:13 -0300 Subject: [PATCH] Fix singleton parameters in overloaded functions (#1694) - Fixes #1691 - Fixes #1589 --------- Co-authored-by: Math <175355178+maffeus@users.noreply.github.com> Co-authored-by: ariel Co-authored-by: Matheus <175355178+m4fh@users.noreply.github.com> Co-authored-by: ariel --- Analysis/src/ConstraintGenerator.cpp | 15 +++++++++++++-- tests/TypeInfer.singletons.test.cpp | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Analysis/src/ConstraintGenerator.cpp b/Analysis/src/ConstraintGenerator.cpp index 1972d559..6b686e6e 100644 --- a/Analysis/src/ConstraintGenerator.cpp +++ b/Analysis/src/ConstraintGenerator.cpp @@ -33,6 +33,7 @@ LUAU_FASTINT(LuauCheckRecursionLimit) LUAU_FASTFLAG(DebugLuauLogSolverToJson) LUAU_FASTFLAG(DebugLuauMagicTypes) LUAU_FASTFLAG(LuauPreserveUnionIntersectionNodeForLeadingTokenSingleType) +LUAU_FASTFLAGVARIABLE(LuauPropagateExpectedTypesForCalls) LUAU_FASTFLAG(DebugLuauGreedyGeneralization) LUAU_FASTFLAGVARIABLE(LuauTrackInteriorFreeTypesOnScope) @@ -2148,13 +2149,23 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall* } else if (i < exprArgs.size() - 1 || !(arg->is() || arg->is())) { - auto [ty, refinement] = check(scope, arg, /*expectedType*/ std::nullopt, /*forceSingleton*/ false, /*generalize*/ false); + std::optional expectedType = std::nullopt; + if (FFlag::LuauPropagateExpectedTypesForCalls && i < expectedTypesForCall.size()) + { + expectedType = expectedTypesForCall[i]; + } + auto [ty, refinement] = check(scope, arg, expectedType, /*forceSingleton*/ false, /*generalize*/ false); args.push_back(ty); argumentRefinements.push_back(refinement); } else { - auto [tp, refis] = checkPack(scope, arg, {}); + std::vector> expectedTypes = {}; + if (FFlag::LuauPropagateExpectedTypesForCalls && i < expectedTypesForCall.size()) + { + expectedTypes.insert(expectedTypes.end(), expectedTypesForCall.begin() + i, expectedTypesForCall.end()); + } + auto [tp, refis] = checkPack(scope, arg, expectedTypes); argTail = tp; argumentRefinements.insert(argumentRefinements.end(), refis.begin(), refis.end()); } diff --git a/tests/TypeInfer.singletons.test.cpp b/tests/TypeInfer.singletons.test.cpp index 91192eb1..9d3e0338 100644 --- a/tests/TypeInfer.singletons.test.cpp +++ b/tests/TypeInfer.singletons.test.cpp @@ -7,6 +7,7 @@ using namespace Luau; LUAU_FASTFLAG(LuauSolverV2) +LUAU_FASTFLAG(LuauPropagateExpectedTypesForCalls) LUAU_FASTFLAG(LuauImproveTypePathsInErrors) TEST_SUITE_BEGIN("TypeSingletons"); @@ -152,6 +153,26 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons") LUAU_REQUIRE_NO_ERRORS(result); } +TEST_CASE_FIXTURE(Fixture, "overloaded_function_resolution_singleton_parameters") +{ + ScopedFastFlag sff{FFlag::LuauPropagateExpectedTypesForCalls, true}; + + CheckResult result = check(R"( + type A = ("A") -> string + type B = ("B") -> number + + local function foo(f: A & B) + return f("A"), f("B") + end + )"); + LUAU_REQUIRE_NO_ERRORS(result); + TypeId t = requireType("foo"); + const FunctionType* fooType = get(requireType("foo")); + REQUIRE(fooType != nullptr); + + CHECK(toString(t) == "(((\"A\") -> string) & ((\"B\") -> number)) -> (string, number)"); +} + TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch") { DOES_NOT_PASS_NEW_SOLVER_GUARD();