mirror of
https://github.com/luau-lang/luau.git
synced 2025-04-03 18:30:54 +01:00
Fix Solver from not pushing Type Functions reduce constraints after the type function constraint itself
This commit is contained in:
parent
e8a7acb802
commit
ed3dff25c9
3 changed files with 102 additions and 2 deletions
|
@ -98,6 +98,13 @@ struct ConstraintSolver
|
|||
DenseHashSet<TypeId> generalizedTypes_{nullptr};
|
||||
const NotNull<DenseHashSet<TypeId>> generalizedTypes{&generalizedTypes_};
|
||||
|
||||
// The current Constraint that is being processed, can be nullptr.
|
||||
const Constraint* currentConstraintRef;
|
||||
|
||||
// Offset of current pushed constraints
|
||||
// Used to ensure things are pushes in an order within a vector.
|
||||
int curUnsolvedConstraintPushOffset;
|
||||
|
||||
// Recorded errors that take place within the solver.
|
||||
ErrorVec errors;
|
||||
|
||||
|
@ -296,6 +303,21 @@ public:
|
|||
**/
|
||||
NotNull<Constraint> pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv);
|
||||
|
||||
/** Push a Constraint right at the position after a specific constraint.
|
||||
* @param cv the body of the constraint.
|
||||
* @param afterConstraint The constraint to find in unsolvedConstraints to insert the new constraint after at.
|
||||
* @param b_isFromRecursive
|
||||
Whether this function is being called from the current dispatch through a recursive context
|
||||
to apply insert offset.
|
||||
**/
|
||||
NotNull<Constraint> pushConstraintAfter(
|
||||
NotNull<Scope> scope,
|
||||
const Location& location,
|
||||
ConstraintV cv,
|
||||
const Constraint& afterConstraint,
|
||||
bool b_isFromRecursive = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Attempts to resolve a module from its module information. Returns the
|
||||
* module-level return type of the module, or the error type if one cannot
|
||||
|
|
|
@ -305,7 +305,7 @@ struct InstantiationQueuer : TypeOnceVisitor
|
|||
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
solver->pushConstraint(scope, location, ReduceConstraint{ty});
|
||||
solver->pushConstraintAfter(scope, location, ReduceConstraint{ty}, *solver->currentConstraintRef, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -426,6 +426,11 @@ void ConstraintSolver::run()
|
|||
snapshot = logger->prepareStepSnapshot(rootScope, c, force, unsolvedConstraints);
|
||||
}
|
||||
|
||||
// Set current constraint
|
||||
// This is used for pushing new Constraints with "pushConstraintAfter"
|
||||
currentConstraintRef = c.get();
|
||||
curUnsolvedConstraintPushOffset = 0; // Reset
|
||||
|
||||
bool success = tryDispatch(c, force);
|
||||
|
||||
progress |= success;
|
||||
|
@ -926,7 +931,9 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
|
||||
// Adding ReduceConstraint on type function for the constraint solver
|
||||
if (auto typeFn = get<TypeFunctionInstanceType>(follow(tf->type)))
|
||||
pushConstraint(NotNull(constraint->scope.get()), constraint->location, ReduceConstraint{tf->type});
|
||||
pushConstraintAfter(
|
||||
NotNull(constraint->scope.get()), constraint->location, ReduceConstraint{tf->type}, *constraint.get()
|
||||
);
|
||||
|
||||
// If there are no parameters to the type function we can just use the type
|
||||
// directly.
|
||||
|
@ -2852,6 +2859,47 @@ NotNull<Constraint> ConstraintSolver::pushConstraint(NotNull<Scope> scope, const
|
|||
return borrow;
|
||||
}
|
||||
|
||||
NotNull<Constraint> ConstraintSolver::pushConstraintAfter(
|
||||
NotNull<Scope> scope,
|
||||
const Location& location,
|
||||
ConstraintV cv,
|
||||
const Constraint& afterConstraint,
|
||||
bool b_isFromRecursive // optional
|
||||
)
|
||||
{
|
||||
std::unique_ptr<Constraint> c = std::make_unique<Constraint>(scope, location, std::move(cv));
|
||||
NotNull<Constraint> borrow = NotNull(c.get());
|
||||
|
||||
// Get the location of the constraint from the unsolvedConstraints.
|
||||
auto it = std::find(unsolvedConstraints.begin(), unsolvedConstraints.end(), NotNull(&afterConstraint));
|
||||
// If not at the end
|
||||
if (it != unsolvedConstraints.end())
|
||||
{
|
||||
// Increment index by 1, to insert after found constraint.
|
||||
it += 1;
|
||||
|
||||
if (b_isFromRecursive)
|
||||
{
|
||||
// Increment based on offset
|
||||
// Because they get inserted like so C, B, A
|
||||
// And we want A, B, C
|
||||
// for some reason I have to +1 this as well to work
|
||||
it += curUnsolvedConstraintPushOffset + 1;
|
||||
|
||||
// Increase offset
|
||||
// This resets every dispatch.
|
||||
curUnsolvedConstraintPushOffset += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
LUAU_ASSERT("The provided \"afterConstraint\" was not found in \"unsolvedConstraints\".");
|
||||
|
||||
solverConstraints.push_back(std::move(c));
|
||||
unsolvedConstraints.insert(it, borrow);
|
||||
|
||||
return borrow;
|
||||
}
|
||||
|
||||
TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& location)
|
||||
{
|
||||
if (info.name.empty())
|
||||
|
|
|
@ -953,6 +953,36 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_wait_for_pending_no_crash")
|
|||
// Should not crash!
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_andGeneralTypeFunction_dependency_issue1")
|
||||
{
|
||||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
// Explanation https://devforum.roblox.com/t/new-type-solver-beta/3155804/97
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
||||
local PlayerData = {
|
||||
Coins = 0,
|
||||
Level = 1,
|
||||
Exp = 0,
|
||||
MaxExp = 100
|
||||
}
|
||||
|
||||
type Keys = keyof<typeof(PlayerData)>
|
||||
|
||||
-- This function makes it think that there's going to be a pending expansion
|
||||
local function UpdateData(key: Keys, value)
|
||||
PlayerData[key] = value
|
||||
end
|
||||
|
||||
UpdateData("Coins", 2)
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_array")
|
||||
{
|
||||
if (!FFlag::LuauSolverV2)
|
||||
|
|
Loading…
Add table
Reference in a new issue