[ty] don't allow first-party code to shadow stdlib types module (#19128)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / mkdocs (push) Waiting to run
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run

This commit is contained in:
Carl Meyer 2025-07-04 03:36:26 -07:00 committed by GitHub
parent 25bdb67d9a
commit 7712c2fd15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 28 additions and 10 deletions

View file

@ -535,14 +535,23 @@ struct ModuleNameIngredient<'db> {
pub(super) name: ModuleName,
}
/// Returns `true` if the module name refers to a standard library module which can't be shadowed
/// by a first-party module.
///
/// This includes "builtin" modules, which can never be shadowed at runtime either, as well as the
/// `types` module, which tends to be imported early in Python startup, so can't be consistently
/// shadowed, and is important to type checking.
fn is_non_shadowable(minor_version: u8, module_name: &str) -> bool {
module_name == "types" || ruff_python_stdlib::sys::is_builtin_module(minor_version, module_name)
}
/// Given a module name and a list of search paths in which to lookup modules,
/// attempt to resolve the module name
fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<ResolvedName> {
let program = Program::get(db);
let python_version = program.python_version(db);
let resolver_state = ResolverContext::new(db, python_version);
let is_builtin_module =
ruff_python_stdlib::sys::is_builtin_module(python_version.minor, name.as_str());
let is_non_shadowable = is_non_shadowable(python_version.minor, name.as_str());
let name = RelaxedModuleName::new(name);
let stub_name = name.to_stub_package();
@ -553,7 +562,8 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<ResolvedName> {
// the module name always resolves to the stdlib module,
// even if there's a module of the same name in the first-party root
// (which would normally result in the stdlib module being overridden).
if is_builtin_module && !search_path.is_standard_library() {
// TODO: offer a diagnostic if there is a first-party module of the same name
if is_non_shadowable && !search_path.is_standard_library() {
continue;
}