Skip to content

Commit d62a617

Browse files
authored
red-knot: Don't refer to Module instances as IDs (#11649)
1 parent 16a926d commit d62a617

File tree

2 files changed

+51
-40
lines changed

2 files changed

+51
-40
lines changed

crates/red_knot/src/module.rs

+50-39
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use crate::files::FileId;
1212
use crate::symbols::Dependency;
1313
use crate::FxDashMap;
1414

15-
/// ID uniquely identifying a module.
15+
/// Representation of a Python module.
16+
///
17+
/// The inner type wrapped by this struct is a unique identifier for the module
18+
/// that is used by the struct's methods to lazily query information about the module.
1619
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1720
pub struct Module(u32);
1821

@@ -100,7 +103,8 @@ impl Module {
100103

101104
/// A module name, e.g. `foo.bar`.
102105
///
103-
/// Always normalized to the absolute form (never a relative module name).
106+
/// Always normalized to the absolute form
107+
/// (never a relative module name, i.e., never `.foo`).
104108
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
105109
pub struct ModuleName(smol_str::SmolStr);
106110

@@ -250,9 +254,11 @@ pub struct ModuleData {
250254
// Queries
251255
//////////////////////////////////////////////////////
252256

253-
/// Resolves a module name to a module id
254-
/// TODO: This would not work with Salsa because `ModuleName` isn't an ingredient and, therefore, cannot be used as part of a query.
255-
/// For this to work with salsa, it would be necessary to intern all `ModuleName`s.
257+
/// Resolves a module name to a module.
258+
///
259+
/// TODO: This would not work with Salsa because `ModuleName` isn't an ingredient
260+
/// and, therefore, cannot be used as part of a query.
261+
/// For this to work with salsa, it would be necessary to intern all `ModuleName`s.
256262
#[tracing::instrument(level = "debug", skip(db))]
257263
pub fn resolve_module(db: &dyn SemanticDb, name: ModuleName) -> QueryResult<Option<Module>> {
258264
let jar: &SemanticJar = db.jar()?;
@@ -274,15 +280,15 @@ pub fn resolve_module(db: &dyn SemanticDb, name: ModuleName) -> QueryResult<Opti
274280
let file_id = db.file_id(&normalized);
275281
let path = ModulePath::new(root_path.clone(), file_id);
276282

277-
let id = Module(
283+
let module = Module(
278284
modules
279285
.next_module_id
280286
.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
281287
);
282288

283289
modules
284290
.modules
285-
.insert(id, Arc::from(ModuleData { name, path, kind }));
291+
.insert(module, Arc::from(ModuleData { name, path, kind }));
286292

287293
// A path can map to multiple modules because of symlinks:
288294
// ```
@@ -291,33 +297,33 @@ pub fn resolve_module(db: &dyn SemanticDb, name: ModuleName) -> QueryResult<Opti
291297
// ```
292298
// Here, both `foo` and `bar` resolve to the same module but through different paths.
293299
// That's why we need to insert the absolute path and not the normalized path here.
294-
let absolute_id = if absolute_path == normalized {
300+
let absolute_file_id = if absolute_path == normalized {
295301
file_id
296302
} else {
297303
db.file_id(&absolute_path)
298304
};
299305

300-
modules.by_file.insert(absolute_id, id);
306+
modules.by_file.insert(absolute_file_id, module);
301307

302-
entry.insert_entry(id);
308+
entry.insert_entry(module);
303309

304-
Ok(Some(id))
310+
Ok(Some(module))
305311
}
306312
}
307313
}
308314

309-
/// Resolves the module id for the given path.
315+
/// Resolves the module for the given path.
310316
///
311-
/// Returns `None` if the path is not a module in `sys.path`.
317+
/// Returns `None` if the path is not a module locatable via `sys.path`.
312318
#[tracing::instrument(level = "debug", skip(db))]
313319
pub fn path_to_module(db: &dyn SemanticDb, path: &Path) -> QueryResult<Option<Module>> {
314320
let file = db.file_id(path);
315321
file_to_module(db, file)
316322
}
317323

318-
/// Resolves the module id for the file with the given id.
324+
/// Resolves the module for the file with the given id.
319325
///
320-
/// Returns `None` if the file is not a module in `sys.path`.
326+
/// Returns `None` if the file is not a module locatable via `sys.path`.
321327
#[tracing::instrument(level = "debug", skip(db))]
322328
pub fn file_to_module(db: &dyn SemanticDb, file: FileId) -> QueryResult<Option<Module>> {
323329
let jar: &SemanticJar = db.jar()?;
@@ -344,12 +350,12 @@ pub fn file_to_module(db: &dyn SemanticDb, file: FileId) -> QueryResult<Option<M
344350

345351
// Resolve the module name to see if Python would resolve the name to the same path.
346352
// If it doesn't, then that means that multiple modules have the same in different
347-
// root paths, but that the module corresponding to the past path is in a lower priority path,
353+
// root paths, but that the module corresponding to the past path is in a lower priority search path,
348354
// in which case we ignore it.
349-
let Some(module_id) = resolve_module(db, module_name)? else {
355+
let Some(module) = resolve_module(db, module_name)? else {
350356
return Ok(None);
351357
};
352-
let module_path = module_id.path(db)?;
358+
let module_path = module.path(db)?;
353359

354360
if module_path.root() == &root_path {
355361
let Ok(normalized) = path.canonicalize() else {
@@ -369,7 +375,7 @@ pub fn file_to_module(db: &dyn SemanticDb, file: FileId) -> QueryResult<Option<M
369375
}
370376

371377
// Path has been inserted by `resolved`
372-
Ok(Some(module_id))
378+
Ok(Some(module))
373379
} else {
374380
// This path is for a module with the same name but in a module search path with a lower priority.
375381
// Ignore it.
@@ -388,19 +394,22 @@ pub fn set_module_search_paths(db: &mut dyn SemanticDb, search_paths: Vec<Module
388394
jar.module_resolver = ModuleResolver::new(search_paths);
389395
}
390396

391-
/// Adds a module to the resolver.
397+
/// Adds a module located at `path` to the resolver.
392398
///
393399
/// Returns `None` if the path doesn't resolve to a module.
394400
///
395-
/// Returns `Some` with the id of the module and the ids of the modules that need re-resolving
396-
/// because they were part of a namespace package and might now resolve differently.
401+
/// Returns `Some(module, other_modules)`, where `module` is the resolved module
402+
/// with file location `path`, and `other_modules` is a `Vec` of `ModuleData` instances.
403+
/// Each element in `other_modules` provides information regarding a single module that needs
404+
/// re-resolving because it was part of a namespace package and might now resolve differently.
405+
///
397406
/// Note: This won't work with salsa because `Path` is not an ingredient.
398407
pub fn add_module(db: &mut dyn SemanticDb, path: &Path) -> Option<(Module, Vec<Arc<ModuleData>>)> {
399408
// No locking is required because we're holding a mutable reference to `modules`.
400409

401410
// TODO This needs tests
402411

403-
// Note: Intentionally by-pass caching here. Module should not be in the cache yet.
412+
// Note: Intentionally bypass caching here. Module should not be in the cache yet.
404413
let module = path_to_module(db, path).ok()??;
405414

406415
// The code below is to handle the addition of `__init__.py` files.
@@ -424,15 +433,15 @@ pub fn add_module(db: &mut dyn SemanticDb, path: &Path) -> Option<(Module, Vec<A
424433
let jar: &mut SemanticJar = db.jar_mut();
425434
let modules = &mut jar.module_resolver;
426435

427-
modules.by_file.retain(|_, id| {
436+
modules.by_file.retain(|_, module| {
428437
if modules
429438
.modules
430-
.get(id)
439+
.get(module)
431440
.unwrap()
432441
.name
433442
.starts_with(&parent_name)
434443
{
435-
to_remove.push(*id);
444+
to_remove.push(*module);
436445
false
437446
} else {
438447
true
@@ -441,8 +450,8 @@ pub fn add_module(db: &mut dyn SemanticDb, path: &Path) -> Option<(Module, Vec<A
441450

442451
// TODO remove need for this vec
443452
let mut removed = Vec::with_capacity(to_remove.len());
444-
for id in &to_remove {
445-
removed.push(modules.remove_module_by_id(*id));
453+
for module in &to_remove {
454+
removed.push(modules.remove_module(*module));
446455
}
447456

448457
Some((module, removed))
@@ -455,10 +464,10 @@ pub struct ModuleResolver {
455464

456465
// Locking: Locking is done by acquiring a (write) lock on `by_name`. This is because `by_name` is the primary
457466
// lookup method. Acquiring locks in any other ordering can result in deadlocks.
458-
/// Resolves a module name to it's module id.
467+
/// Looks up a module by name
459468
by_name: FxDashMap<ModuleName, Module>,
460469

461-
/// All known modules, indexed by the module id.
470+
/// A map of all known modules to data about those modules
462471
modules: FxDashMap<Module, Arc<ModuleData>>,
463472

464473
/// Lookup from absolute path to module.
@@ -479,24 +488,26 @@ impl ModuleResolver {
479488
}
480489

481490
/// Remove a module from the inner cache
482-
pub(crate) fn remove_module(&mut self, file_id: FileId) {
491+
pub(crate) fn remove_module_by_file(&mut self, file_id: FileId) {
483492
// No locking is required because we're holding a mutable reference to `self`.
484-
let Some((_, id)) = self.by_file.remove(&file_id) else {
493+
let Some((_, module)) = self.by_file.remove(&file_id) else {
485494
return;
486495
};
487496

488-
self.remove_module_by_id(id);
497+
self.remove_module(module);
489498
}
490499

491-
fn remove_module_by_id(&mut self, id: Module) -> Arc<ModuleData> {
492-
let (_, module) = self.modules.remove(&id).unwrap();
500+
fn remove_module(&mut self, module: Module) -> Arc<ModuleData> {
501+
let (_, module_data) = self.modules.remove(&module).unwrap();
493502

494-
self.by_name.remove(&module.name).unwrap();
503+
self.by_name.remove(&module_data.name).unwrap();
495504

496-
// It's possible that multiple paths map to the same id. Search all other paths referencing the same module id.
497-
self.by_file.retain(|_, current_id| *current_id != id);
505+
// It's possible that multiple paths map to the same module.
506+
// Search all other paths referencing the same module.
507+
self.by_file
508+
.retain(|_, current_module| *current_module != module);
498509

499-
module
510+
module_data
500511
}
501512
}
502513

crates/red_knot/src/program/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl Program {
4242

4343
let (source, semantic, lint) = self.jars_mut();
4444
for change in aggregated_changes.iter() {
45-
semantic.module_resolver.remove_module(change.id);
45+
semantic.module_resolver.remove_module_by_file(change.id);
4646
semantic.symbol_tables.remove(&change.id);
4747
source.sources.remove(&change.id);
4848
source.parsed.remove(&change.id);

0 commit comments

Comments
 (0)