From 0707a638538e30fdbd89f487b7ce27631b9e7938 Mon Sep 17 00:00:00 2001
From: Danila Fedorin <daniel.fedorin@hpe.com>
Date: Fri, 3 Jan 2025 10:36:44 -0800
Subject: [PATCH] Resolve auto module visibility statements eagerly

This incurs a penalty up front, but prevents odd ordering properties
in the query system. It's a workaround for a query system bug
detailed in https://github.com/chapel-lang/chapel/pull/26459.

Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
---
 .../resolution/testDeprecationUnstable.cpp    | 29 ++++++++++++++-----
 .../test/resolution/testTypeConstruction.cpp  |  1 -
 frontend/test/test-common.cpp                 | 10 ++++++-
 frontend/test/test-common.h                   |  2 +-
 .../src/method-tables/core-methods.h          |  5 +++-
 5 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/frontend/test/resolution/testDeprecationUnstable.cpp b/frontend/test/resolution/testDeprecationUnstable.cpp
index d5af23883851..bdee292ca3c3 100644
--- a/frontend/test/resolution/testDeprecationUnstable.cpp
+++ b/frontend/test/resolution/testDeprecationUnstable.cpp
@@ -33,13 +33,26 @@ static std::string debugDeclName = "";
 
 static void testDebuggingBreakpoint() {}
 
+static CompilerFlags warnUnstableFlags() {
+  static auto flags = []() {
+    CompilerFlags flags;
+    flags.set(CompilerFlags::WARN_UNSTABLE, true);
+    return flags;
+  }();
+  return flags;
+}
+
 static Context*
-turnOnWarnUnstable(Context* ctx) {
-  CompilerFlags flags;
-  flags.set(CompilerFlags::WARN_UNSTABLE, true);
-  setCompilerFlags(ctx, std::move(flags));
-  assert(isCompilerFlagSet(ctx, CompilerFlags::WARN_UNSTABLE));
-  return ctx;
+buildStdContextWithUnstableWarnings() {
+  auto context = buildStdContext(warnUnstableFlags());
+  assert(isCompilerFlagSet(context, CompilerFlags::WARN_UNSTABLE));
+  return context;
+}
+
+static Context* turnOnWarnUnstable(Context* context) {
+  setCompilerFlags(context, warnUnstableFlags());
+  assert(isCompilerFlagSet(context, CompilerFlags::WARN_UNSTABLE));
+  return context;
 }
 
 static const AstNode*
@@ -430,7 +443,7 @@ static void test1(void) {
 
 // Warnings should not be emitted for method receivers.
 static void test2(void) {
-  Context* ctx = turnOnWarnUnstable(buildStdContext());
+  Context* ctx = buildStdContextWithUnstableWarnings();
   ErrorGuard guard(ctx);
 
   auto path = TEST_NAME(ctx);
@@ -576,7 +589,7 @@ static void test4(ErrorType expectedError) {
         ? "@unstable"
         : "@deprecated";
 
-  Context* ctx = turnOnWarnUnstable(buildStdContext());
+  Context* ctx = buildStdContextWithUnstableWarnings();
   ErrorGuard guard(ctx);
 
   auto path = TEST_NAME(ctx);
diff --git a/frontend/test/resolution/testTypeConstruction.cpp b/frontend/test/resolution/testTypeConstruction.cpp
index d538506c5559..a010f3e93cb9 100644
--- a/frontend/test/resolution/testTypeConstruction.cpp
+++ b/frontend/test/resolution/testTypeConstruction.cpp
@@ -1345,7 +1345,6 @@ static void testRecursiveTypeConstructorMutual() {
   printf("testRecursiveTypeConstructorMutual\n");
   Context* context = buildStdContext();
   ErrorGuard guard(context);
-  setupModuleSearchPaths(context, false, false, {}, {});
 
   auto p = parseTypeAndFieldsOfX(context,
       R"""(
diff --git a/frontend/test/test-common.cpp b/frontend/test/test-common.cpp
index 171c63f995d5..1077059de6cf 100644
--- a/frontend/test/test-common.cpp
+++ b/frontend/test/test-common.cpp
@@ -19,6 +19,7 @@
 
 #include "test-common.h"
 
+#include "chpl/framework/compiler-configuration.h"
 #include "chpl/parsing/parsing-queries.h"
 #include "chpl/resolution/scope-queries.h"
 #include "chpl/uast/post-parse-checks.h"
@@ -81,7 +82,7 @@ const uast::AstNode* findOnlyNamed(const uast::Module* mod, std::string name) {
 
 static std::unique_ptr<Context> _reusedContext;
 
-chpl::Context* buildStdContext() {
+chpl::Context* buildStdContext(chpl::CompilerFlags flags) {
   if (_reusedContext.get() == nullptr) {
     std::string chpl_home;
     if (const char* chpl_home_env = getenv("CHPL_HOME")) {
@@ -100,6 +101,13 @@ chpl::Context* buildStdContext() {
   }
 
   parsing::setupModuleSearchPaths(_reusedContext.get(), false, false, {}, {});
+  setCompilerFlags(_reusedContext.get(), flags);
+
+  // resolve the standard modules from the same "usual" predefined point.
+  // this way, the order in which the modules are traversed is always the same.
+  if (auto autoUseScope = resolution::scopeForAutoModule(_reusedContext.get())) {
+    std::ignore = resolution::resolveVisibilityStmts(_reusedContext.get(), autoUseScope, false);
+  }
 
   return _reusedContext.get();
 }
diff --git a/frontend/test/test-common.h b/frontend/test/test-common.h
index 8203fbf0dba0..aa09f9182eca 100644
--- a/frontend/test/test-common.h
+++ b/frontend/test/test-common.h
@@ -53,6 +53,6 @@ parseStringAndReportErrors(chpl::parsing::Parser* parser, const char* filename,
 
 const chpl::uast::AstNode* findOnlyNamed(const chpl::uast::Module* mod, std::string name);
 
-chpl::Context* buildStdContext();
+chpl::Context* buildStdContext(chpl::CompilerFlags flags = {});
 
 #endif
diff --git a/tools/chapel-py/src/method-tables/core-methods.h b/tools/chapel-py/src/method-tables/core-methods.h
index ac312c9ac7c4..fa6d6e3e0cad 100644
--- a/tools/chapel-py/src/method-tables/core-methods.h
+++ b/tools/chapel-py/src/method-tables/core-methods.h
@@ -49,7 +49,10 @@ CLASS_BEGIN(Context)
 
          auto& paths = std::get<0>(args);
          auto& filenames = std::get<1>(args);
-         parsing::setupModuleSearchPaths(node, false, false, paths, filenames))
+         parsing::setupModuleSearchPaths(node, false, false, paths, filenames);
+         if (auto autoUseScope = resolution::scopeForAutoModule(node)) {
+           std::ignore = resolution::resolveVisibilityStmts(node, autoUseScope, false);
+         })
   METHOD(Context, is_bundled_path, "Check if the given file path is within the bundled (built-in) Chapel files",
          bool(chpl::UniqueString),