From c4c120513ff965b117bc006be6f98e227b74e1ae Mon Sep 17 00:00:00 2001 From: JohnnyMorganz Date: Thu, 20 Oct 2022 17:07:00 +0100 Subject: [PATCH] Fix reverse deps > 1 node away not correctly marked as dirty (#719) `Frontend.markDirty()` does not correctly mark reverse dependencies that are not immediate as dirty. This is because it would keep adding the reverse deps of `name` into the queue to mark as dirty, instead of the reverse deps of `next` --- Analysis/src/Frontend.cpp | 24 +++++++++++++++++++----- tests/Frontend.test.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp index 5705ac1..cfe710d 100644 --- a/Analysis/src/Frontend.cpp +++ b/Analysis/src/Frontend.cpp @@ -30,6 +30,7 @@ LUAU_FASTFLAGVARIABLE(LuauAutocompleteDynamicLimits, false) LUAU_FASTINTVARIABLE(LuauAutocompleteCheckTimeoutMs, 100) LUAU_FASTFLAGVARIABLE(DebugLuauDeferredConstraintResolution, false) LUAU_FASTFLAG(DebugLuauLogSolverToJson); +LUAU_FASTFLAGVARIABLE(LuauFixMarkDirtyReverseDeps, false) namespace Luau { @@ -807,13 +808,26 @@ void Frontend::markDirty(const ModuleName& name, std::vector* marked sourceNode.dirtyModule = true; sourceNode.dirtyModuleForAutocomplete = true; - if (0 == reverseDeps.count(name)) - continue; + if (FFlag::LuauFixMarkDirtyReverseDeps) + { + if (0 == reverseDeps.count(next)) + continue; - sourceModules.erase(name); + sourceModules.erase(next); - const std::vector& dependents = reverseDeps[name]; - queue.insert(queue.end(), dependents.begin(), dependents.end()); + const std::vector& dependents = reverseDeps[next]; + queue.insert(queue.end(), dependents.begin(), dependents.end()); + } + else + { + if (0 == reverseDeps.count(name)) + continue; + + sourceModules.erase(name); + + const std::vector& dependents = reverseDeps[name]; + queue.insert(queue.end(), dependents.begin(), dependents.end()); + } } } diff --git a/tests/Frontend.test.cpp b/tests/Frontend.test.cpp index 957f3c7..df0abdc 100644 --- a/tests/Frontend.test.cpp +++ b/tests/Frontend.test.cpp @@ -517,6 +517,33 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_is_dirty") CHECK_EQ("{| b_value: string |}", toString(*bExports)); } +TEST_CASE_FIXTURE(FrontendFixture, "mark_non_immediate_reverse_deps_as_dirty") +{ + ScopedFastFlag sff[] = { + {"LuauFixMarkDirtyReverseDeps", true}, + }; + + fileResolver.source["game/Gui/Modules/A"] = "return {hello=5, world=true}"; + fileResolver.source["game/Gui/Modules/B"] = R"( + return require(game:GetService('Gui').Modules.A) + )"; + fileResolver.source["game/Gui/Modules/C"] = R"( + local Modules = game:GetService('Gui').Modules + local B = require(Modules.B) + return {c_value = B.hello} + )"; + + frontend.check("game/Gui/Modules/C"); + + std::vector markedDirty; + frontend.markDirty("game/Gui/Modules/A", &markedDirty); + + REQUIRE(markedDirty.size() == 3); + CHECK(std::find(markedDirty.begin(), markedDirty.end(), "game/Gui/Modules/A") != markedDirty.end()); + CHECK(std::find(markedDirty.begin(), markedDirty.end(), "game/Gui/Modules/B") != markedDirty.end()); + CHECK(std::find(markedDirty.begin(), markedDirty.end(), "game/Gui/Modules/C") != markedDirty.end()); +} + #if 0 // Does not work yet. :( TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_has_a_parse_error")