Skip to content

Commit 96b5a35

Browse files
committed
Address review feedback
1 parent feb96fb commit 96b5a35

2 files changed

Lines changed: 52 additions & 42 deletions

File tree

crates/red_knot_python_semantic/src/stdlib.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::module_resolver::{resolve_module, KnownModule};
22
use crate::semantic_index::global_scope;
33
use crate::semantic_index::symbol::ScopeId;
44
use crate::symbol::Symbol;
5-
use crate::types::{imported_symbol, module_type_symbol};
5+
use crate::types::imported_symbol;
66
use crate::Db;
77

88
/// Lookup the type of `symbol` in a given known module
@@ -14,21 +14,10 @@ pub(crate) fn known_module_symbol<'db>(
1414
symbol: &str,
1515
) -> Symbol<'db> {
1616
resolve_module(db, &known_module.name())
17-
.map(|module| {
18-
imported_symbol(db, &module, symbol)
19-
.or_fall_back_to(db, || module_type_symbol(db, symbol))
20-
})
17+
.map(|module| imported_symbol(db, &module, symbol))
2118
.unwrap_or(Symbol::Unbound)
2219
}
2320

24-
/// Lookup the type of `symbol` in the builtins namespace.
25-
///
26-
/// Returns `Symbol::Unbound` if the `builtins` module isn't available for some reason.
27-
#[inline]
28-
pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> {
29-
known_module_symbol(db, KnownModule::Builtins, symbol)
30-
}
31-
3221
/// Lookup the type of `symbol` in the `typing` module namespace.
3322
///
3423
/// Returns `Symbol::Unbound` if the `typing` module isn't available for some reason.

crates/red_knot_python_semantic/src/types.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::semantic_index::{
3232
use_def_map, BindingWithConstraints, BindingWithConstraintsIterator, DeclarationWithConstraint,
3333
DeclarationsIterator,
3434
};
35-
use crate::stdlib::{builtins_symbol, known_module_symbol, typing_extensions_symbol};
35+
use crate::stdlib::{known_module_symbol, typing_extensions_symbol};
3636
use crate::suppression::check_suppressions;
3737
use crate::symbol::{Boundness, Symbol};
3838
use crate::types::call::{
@@ -280,12 +280,13 @@ pub(crate) fn module_type_symbol<'db>(db: &'db dyn Db, name: &str) -> Symbol<'db
280280
}
281281
}
282282

283-
/// Infer the public type of a symbol (its type as seen from outside its scope).
283+
/// Infer the public type of a symbol (its type as seen from outside its scope) in the given
284+
/// `scope`.
284285
fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db> {
285286
symbol_impl(db, scope, name, RequiresExplicitReExport::No)
286287
}
287288

288-
/// Infers the public type of a symbol as seen from the same file.
289+
/// Infers the public type of a module-global symbol as seen from within the same file.
289290
///
290291
/// If it's not defined explicitly in the global scope, it will look it up in `types.ModuleType`
291292
/// with a few very special exceptions.
@@ -302,11 +303,52 @@ pub(crate) fn global_symbol<'db>(db: &'db dyn Db, file: File, name: &str) -> Sym
302303
}
303304

304305
/// Infers the public type of an imported symbol.
305-
///
306-
/// Unlike [`global_symbol`], this does not fall back to looking up the symbol in
307-
/// `types.ModuleType`. The fallback logic needs to be handled by the caller.
308306
pub(crate) fn imported_symbol<'db>(db: &'db dyn Db, module: &Module, name: &str) -> Symbol<'db> {
309-
let file = module.file();
307+
// If it's not found in the global scope, check if it's present as an instance on
308+
// `types.ModuleType` or `builtins.object`.
309+
//
310+
// We do a more limited version of this in `global_symbol`, but there are two crucial
311+
// differences here:
312+
// - If a member is looked up as an attribute, `__init__` is also available on the module, but
313+
// it isn't available as a global from inside the module
314+
// - If a member is looked up as an attribute, members on `builtins.object` are also available
315+
// (because `types.ModuleType` inherits from `object`); these attributes are also not
316+
// available as globals from inside the module.
317+
//
318+
// The same way as in `global_symbol`, however, we need to be careful to ignore
319+
// `__getattr__`. Typeshed has a fake `__getattr__` on `types.ModuleType` to help out with
320+
// dynamic imports; we shouldn't use it for `ModuleLiteral` types where we know exactly which
321+
// module we're dealing with.
322+
external_symbol_impl(db, module.file(), name).or_fall_back_to(db, || {
323+
if name == "__getattr__" {
324+
Symbol::Unbound
325+
} else {
326+
KnownClass::ModuleType.to_instance(db).member(db, name)
327+
}
328+
})
329+
}
330+
331+
/// Lookup the type of `symbol` in the builtins namespace.
332+
///
333+
/// Returns `Symbol::Unbound` if the `builtins` module isn't available for some reason.
334+
///
335+
/// Note that this function is only intended for use in the context of the builtins *namespace*
336+
/// and should not be used when a symbol is being explicitly imported from the `builtins` module
337+
/// (e.g. `from builtins import int`).
338+
pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> {
339+
resolve_module(db, &KnownModule::Builtins.name())
340+
.map(|module| {
341+
external_symbol_impl(db, module.file(), symbol).or_fall_back_to(db, || {
342+
// We're looking up in the builtins namespace and not the module, so we should
343+
// do the normal lookup in `types.ModuleType` and not the special one as in
344+
// `imported_symbol`.
345+
module_type_symbol(db, symbol)
346+
})
347+
})
348+
.unwrap_or(Symbol::Unbound)
349+
}
350+
351+
fn external_symbol_impl<'db>(db: &'db dyn Db, file: File, name: &str) -> Symbol<'db> {
310352
symbol_impl(
311353
db,
312354
global_scope(db, file),
@@ -3866,28 +3908,7 @@ impl<'db> ModuleLiteralType<'db> {
38663908
}
38673909
}
38683910

3869-
// If it's not found in the global scope, check if it's present as an instance
3870-
// on `types.ModuleType` or `builtins.object`.
3871-
//
3872-
// We do a more limited version of this in `module_type_symbol`,
3873-
// but there are two crucial differences here:
3874-
// - If a member is looked up as an attribute, `__init__` is also available
3875-
// on the module, but it isn't available as a global from inside the module
3876-
// - If a member is looked up as an attribute, members on `builtins.object`
3877-
// are also available (because `types.ModuleType` inherits from `object`);
3878-
// these attributes are also not available as globals from inside the module.
3879-
//
3880-
// The same way as in `global_symbol_ty`, however, we need to be careful to
3881-
// ignore `__getattr__`. Typeshed has a fake `__getattr__` on `types.ModuleType`
3882-
// to help out with dynamic imports; we shouldn't use it for `ModuleLiteral` types
3883-
// where we know exactly which module we're dealing with.
3884-
imported_symbol(db, &self.module(db), name).or_fall_back_to(db, || {
3885-
if name == "__getattr__" {
3886-
Symbol::Unbound
3887-
} else {
3888-
KnownClass::ModuleType.to_instance(db).member(db, name)
3889-
}
3890-
})
3911+
imported_symbol(db, &self.module(db), name)
38913912
}
38923913
}
38933914

0 commit comments

Comments
 (0)