From 46e749b08e3856719bbc8dd4951a5db3abc0ddea Mon Sep 17 00:00:00 2001 From: Kyle Into Date: Mon, 13 Oct 2025 13:40:42 -0700 Subject: [PATCH] get_transitive_rdeps should work on in-memory files Summary: it's confusing that callers have to know which type of handle to provide when all handles are allowed. I can't think of a reason someone would call this on an in-memory file and expect no rdeps. Differential Revision: D84531937 --- pyrefly/lib/state/lsp.rs | 47 +++++++++++--------------------------- pyrefly/lib/state/state.rs | 15 +++++++++--- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/pyrefly/lib/state/lsp.rs b/pyrefly/lib/state/lsp.rs index 1796d6deb..ff52f52b2 100644 --- a/pyrefly/lib/state/lsp.rs +++ b/pyrefly/lib/state/lsp.rs @@ -2741,40 +2741,19 @@ impl<'a> CancellableTransaction<'a> { // General strategy: // 1: Compute the set of transitive rdeps. // 2. Find references in each one of them using the index computed during earlier checking - let mut transitive_rdeps = match definition.module.path().details() { - ModulePathDetails::Memory(path_buf) => { - let handle_of_filesystem_counterpart = Handle::new( - definition.module.name(), - ModulePath::filesystem(path_buf.clone()), - sys_info.dupe(), - ); - // In-memory files can never be found through import resolution (no rdeps), - // so we must compute the transitive rdeps of its filesystem counterpart instead. - let mut rdeps = self - .as_ref() - .get_transitive_rdeps(handle_of_filesystem_counterpart.dupe()); - // We still add itself to the rdeps set, so that we will still find local references - // within the file. - rdeps.insert(Handle::new( - definition.module.name(), - definition.module.path().dupe(), - sys_info.dupe(), - )); - rdeps - } - _ => { - let definition_handle = Handle::new( - definition.module.name(), - definition.module.path().dupe(), - sys_info.dupe(), - ); - let rdeps = self.as_ref().get_transitive_rdeps(definition_handle.dupe()); - // We still need to know everything about the definition file, because the index - // only contains non-local references. - self.run(&[definition_handle], Require::Everything)?; - rdeps - } - }; + let handle = Handle::new( + definition.module.name(), + definition.module.path().dupe(), + sys_info.dupe(), + ); + let mut transitive_rdeps = self.as_ref().get_transitive_rdeps(handle); + // We still add itself to the rdeps set, so that we will still find local references + // within the file. + transitive_rdeps.insert(Handle::new( + definition.module.name(), + definition.module.path().dupe(), + sys_info.dupe(), + )); // Remove the filesystem counterpart from candidate list, // otherwise we will have results from both filesystem and in-memory version of the file. for fs_counterpart_of_in_memory_handles in transitive_rdeps diff --git a/pyrefly/lib/state/state.rs b/pyrefly/lib/state/state.rs index ff7019510..e392710cc 100644 --- a/pyrefly/lib/state/state.rs +++ b/pyrefly/lib/state/state.rs @@ -457,10 +457,19 @@ impl<'a> Transaction<'a> { } /// Compute transitive dependency closure for the given handle. - /// Note that for IDE services, if the given handle is an in-memory one, then you are probably - /// not getting what you want, because the set of rdeps of in-memory file for IDE service will - /// only contain itself. pub fn get_transitive_rdeps(&self, handle: Handle) -> HashSet { + // The set of rdeps on an in-memory file is only itself. This is never what callers want, so they + // should not need to convert it themself. + let handle = if let ModulePathDetails::Memory(path) = handle.path().details() { + Handle::new( + handle.module(), + ModulePath::filesystem(path.clone()), + handle.sys_info().dupe(), + ) + } else { + handle + }; + let mut transitive_rdeps = HashSet::new(); let mut work_list = vec![handle]; loop {