Skip to content

Commit af8f442

Browse files
BurntSushiAlexWaygood
authored andcommitted
[ty] Restructure submodule query around File dependency
This makes caching of submodules independent of whether `Module` is itself a Salsa ingredient. In fact, this makes the work done in the prior commit superfluous. But we're possibly keeping it as an ingredient for now since it's a bit of a tedious change and we might need it in the near future. Ref #19495 (review)
1 parent 2f1e5e0 commit af8f442

File tree

1 file changed

+83
-80
lines changed
  • crates/ty_python_semantic/src/module_resolver

1 file changed

+83
-80
lines changed

crates/ty_python_semantic/src/module_resolver/module.rs

Lines changed: 83 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -95,24 +95,10 @@ impl<'db> Module<'db> {
9595
/// The names returned correspond to the "base" name of the module.
9696
/// That is, `{self.name}.{basename}` should give the full module name.
9797
pub fn all_submodules(self, db: &'db dyn Db) -> &'db [Name] {
98-
self.all_submodules_inner(db).as_deref().unwrap_or_default()
98+
self.all_submodules_inner(db).unwrap_or_default()
9999
}
100100

101-
#[allow(clippy::ref_option)]
102-
#[salsa::tracked(returns(ref))]
103-
fn all_submodules_inner(self, db: &'db dyn Db) -> Option<Vec<Name>> {
104-
fn is_submodule(
105-
is_dir: bool,
106-
is_file: bool,
107-
basename: Option<&str>,
108-
extension: Option<&str>,
109-
) -> bool {
110-
is_dir
111-
|| (is_file
112-
&& matches!(extension, Some("py" | "pyi"))
113-
&& !matches!(basename, Some("__init__.py" | "__init__.pyi")))
114-
}
115-
101+
fn all_submodules_inner(self, db: &'db dyn Db) -> Option<&'db [Name]> {
116102
// It would be complex and expensive to compute all submodules for
117103
// namespace packages, since a namespace package doesn't correspond
118104
// to a single file; it can span multiple directories across multiple
@@ -124,55 +110,68 @@ impl<'db> Module<'db> {
124110
if !matches!(module.kind(db), ModuleKind::Package) {
125111
return None;
126112
}
113+
all_submodule_names_for_package(db, module.file(db)).as_deref()
114+
}
115+
}
116+
117+
impl std::fmt::Debug for Module<'_> {
118+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
119+
salsa::with_attached_database(|db| {
120+
f.debug_struct("Module")
121+
.field("name", &self.name(db))
122+
.field("kind", &self.kind(db))
123+
.field("file", &self.file(db))
124+
.field("search_path", &self.search_path(db))
125+
.field("known", &self.known(db))
126+
.finish()
127+
})
128+
.unwrap_or_else(|| f.debug_tuple("Module").field(&self.as_id()).finish())
129+
}
130+
}
131+
132+
#[allow(clippy::ref_option)]
133+
#[salsa::tracked(returns(ref))]
134+
fn all_submodule_names_for_package(db: &dyn Db, file: File) -> Option<Vec<Name>> {
135+
fn is_submodule(
136+
is_dir: bool,
137+
is_file: bool,
138+
basename: Option<&str>,
139+
extension: Option<&str>,
140+
) -> bool {
141+
is_dir
142+
|| (is_file
143+
&& matches!(extension, Some("py" | "pyi"))
144+
&& !matches!(basename, Some("__init__.py" | "__init__.pyi")))
145+
}
127146

128-
let path = SystemOrVendoredPathRef::try_from_file(db, module.file(db))?;
129-
debug_assert!(
130-
matches!(path.file_name(), Some("__init__.py" | "__init__.pyi")),
131-
"expected package file `{:?}` to be `__init__.py` or `__init__.pyi`",
132-
path.file_name(),
133-
);
134-
135-
Some(match path.parent()? {
136-
SystemOrVendoredPathRef::System(parent_directory) => {
137-
// Read the revision on the corresponding file root to
138-
// register an explicit dependency on this directory
139-
// tree. When the revision gets bumped, the cache
140-
// that Salsa creates does for this routine will be
141-
// invalidated.
142-
if let Some(root) = db.files().root(db, parent_directory) {
143-
let _ = root.revision(db);
144-
}
145-
146-
db.system()
147-
.read_directory(parent_directory)
148-
.inspect_err(|err| {
149-
tracing::debug!(
150-
"Failed to read {parent_directory:?} when looking for \
151-
its possible submodules: {err}"
152-
);
153-
})
154-
.ok()?
155-
.flatten()
156-
.filter(|entry| {
157-
let ty = entry.file_type();
158-
let path = entry.path();
159-
is_submodule(
160-
ty.is_directory(),
161-
ty.is_file(),
162-
path.file_name(),
163-
path.extension(),
164-
)
165-
})
166-
.filter_map(|entry| {
167-
let stem = entry.path().file_stem()?;
168-
is_identifier(stem).then(|| Name::from(stem))
169-
})
170-
.collect()
147+
let path = SystemOrVendoredPathRef::try_from_file(db, file)?;
148+
debug_assert!(
149+
matches!(path.file_name(), Some("__init__.py" | "__init__.pyi")),
150+
"expected package file `{:?}` to be `__init__.py` or `__init__.pyi`",
151+
path.file_name(),
152+
);
153+
154+
Some(match path.parent()? {
155+
SystemOrVendoredPathRef::System(parent_directory) => {
156+
// Read the revision on the corresponding file root to
157+
// register an explicit dependency on this directory
158+
// tree. When the revision gets bumped, the cache
159+
// that Salsa creates does for this routine will be
160+
// invalidated.
161+
if let Some(root) = db.files().root(db, parent_directory) {
162+
let _ = root.revision(db);
171163
}
172-
SystemOrVendoredPathRef::Vendored(parent_directory) => db
173-
.vendored()
164+
165+
db.system()
174166
.read_directory(parent_directory)
175-
.into_iter()
167+
.inspect_err(|err| {
168+
tracing::debug!(
169+
"Failed to read {parent_directory:?} when looking for \
170+
its possible submodules: {err}"
171+
);
172+
})
173+
.ok()?
174+
.flatten()
176175
.filter(|entry| {
177176
let ty = entry.file_type();
178177
let path = entry.path();
@@ -187,24 +186,28 @@ impl<'db> Module<'db> {
187186
let stem = entry.path().file_stem()?;
188187
is_identifier(stem).then(|| Name::from(stem))
189188
})
190-
.collect(),
191-
})
192-
}
193-
}
194-
195-
impl std::fmt::Debug for Module<'_> {
196-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
197-
salsa::with_attached_database(|db| {
198-
f.debug_struct("Module")
199-
.field("name", &self.name(db))
200-
.field("kind", &self.kind(db))
201-
.field("file", &self.file(db))
202-
.field("search_path", &self.search_path(db))
203-
.field("known", &self.known(db))
204-
.finish()
205-
})
206-
.unwrap_or_else(|| f.debug_tuple("Module").field(&self.as_id()).finish())
207-
}
189+
.collect()
190+
}
191+
SystemOrVendoredPathRef::Vendored(parent_directory) => db
192+
.vendored()
193+
.read_directory(parent_directory)
194+
.into_iter()
195+
.filter(|entry| {
196+
let ty = entry.file_type();
197+
let path = entry.path();
198+
is_submodule(
199+
ty.is_directory(),
200+
ty.is_file(),
201+
path.file_name(),
202+
path.extension(),
203+
)
204+
})
205+
.filter_map(|entry| {
206+
let stem = entry.path().file_stem()?;
207+
is_identifier(stem).then(|| Name::from(stem))
208+
})
209+
.collect(),
210+
})
208211
}
209212

210213
/// A module that resolves to a file (`lib.py` or `package/__init__.py`)

0 commit comments

Comments
 (0)