@@ -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} ;
3636use crate :: suppression:: check_suppressions;
3737use crate :: symbol:: { Boundness , Symbol } ;
3838use 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`.
284285fn 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.
308306pub ( 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