diff --git a/crates/red_knot_python_semantic/src/lib.rs b/crates/red_knot_python_semantic/src/lib.rs index 6f975eea01..324d2756b8 100644 --- a/crates/red_knot_python_semantic/src/lib.rs +++ b/crates/red_knot_python_semantic/src/lib.rs @@ -5,7 +5,7 @@ use rustc_hash::FxHasher; use crate::lint::{LintRegistry, LintRegistryBuilder}; pub use db::Db; pub use module_name::ModuleName; -pub use module_resolver::{resolve_module, system_module_search_paths, Module}; +pub use module_resolver::{resolve_module, system_module_search_paths, KnownModule, Module}; pub use program::{Program, ProgramSettings, SearchPathSettings, SitePackages}; pub use python_version::PythonVersion; pub use semantic_model::{HasTy, SemanticModel}; diff --git a/crates/red_knot_python_semantic/src/module_resolver/mod.rs b/crates/red_knot_python_semantic/src/module_resolver/mod.rs index c17925606f..53b68c7c8c 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/mod.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/mod.rs @@ -1,6 +1,6 @@ use std::iter::FusedIterator; -pub use module::Module; +pub use module::{KnownModule, Module}; pub use resolver::resolve_module; pub(crate) use resolver::{file_to_module, SearchPaths}; use ruff_db::system::SystemPath; diff --git a/crates/red_knot_python_semantic/src/module_resolver/module.rs b/crates/red_knot_python_semantic/src/module_resolver/module.rs index 1891d3085d..140153674d 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/module.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/module.rs @@ -19,12 +19,14 @@ impl Module { search_path: SearchPath, file: File, ) -> Self { + let known = KnownModule::try_from_search_path_and_name(&search_path, &name); Self { inner: Arc::new(ModuleInner { name, kind, search_path, file, + known, }), } } @@ -39,6 +41,16 @@ impl Module { self.inner.file } + /// Is this a module that we special-case somehow? If so, which one? + pub fn known(&self) -> Option { + self.inner.known + } + + /// Does this module represent the given known module? + pub fn is_known(&self, known_module: KnownModule) -> bool { + self.known() == Some(known_module) + } + /// The search path from which the module was resolved. pub(crate) fn search_path(&self) -> &SearchPath { &self.inner.search_path @@ -67,6 +79,7 @@ struct ModuleInner { kind: ModuleKind, search_path: SearchPath, file: File, + known: Option, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -83,3 +96,62 @@ impl ModuleKind { matches!(self, ModuleKind::Package) } } + +/// Enumeration of various core stdlib modules in which important types are located +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum KnownModule { + Builtins, + Types, + Typeshed, + TypingExtensions, + Typing, + Sys, + #[allow(dead_code)] + Abc, // currently only used in tests + Collections, +} + +impl KnownModule { + pub const fn as_str(self) -> &'static str { + match self { + Self::Builtins => "builtins", + Self::Types => "types", + Self::Typing => "typing", + Self::Typeshed => "_typeshed", + Self::TypingExtensions => "typing_extensions", + Self::Sys => "sys", + Self::Abc => "abc", + Self::Collections => "collections", + } + } + + pub fn name(self) -> ModuleName { + let self_as_str = self.as_str(); + ModuleName::new_static(self_as_str) + .unwrap_or_else(|| panic!("{self_as_str} should be a valid module name!")) + } + + pub(crate) fn try_from_search_path_and_name( + search_path: &SearchPath, + name: &ModuleName, + ) -> Option { + if !search_path.is_standard_library() { + return None; + } + match name.as_str() { + "builtins" => Some(Self::Builtins), + "types" => Some(Self::Types), + "typing" => Some(Self::Typing), + "_typeshed" => Some(Self::Typeshed), + "typing_extensions" => Some(Self::TypingExtensions), + "sys" => Some(Self::Sys), + "abc" => Some(Self::Abc), + "collections" => Some(Self::Collections), + _ => None, + } + } + + pub const fn is_typing(self) -> bool { + matches!(self, Self::Typing) + } +} diff --git a/crates/red_knot_python_semantic/src/semantic_index/definition.rs b/crates/red_knot_python_semantic/src/semantic_index/definition.rs index a7b80a225d..6b9d57ca07 100644 --- a/crates/red_knot_python_semantic/src/semantic_index/definition.rs +++ b/crates/red_knot_python_semantic/src/semantic_index/definition.rs @@ -8,7 +8,7 @@ use crate::module_resolver::file_to_module; use crate::node_key::NodeKey; use crate::semantic_index::symbol::{FileScopeId, ScopeId, ScopedSymbolId}; use crate::unpack::Unpack; -use crate::Db; +use crate::{Db, KnownModule}; /// A definition of a symbol. /// @@ -63,17 +63,16 @@ impl<'db> Definition<'db> { } pub(crate) fn is_builtin_definition(self, db: &'db dyn Db) -> bool { - file_to_module(db, self.file(db)).is_some_and(|module| { - module.search_path().is_standard_library() && matches!(&**module.name(), "builtins") - }) + file_to_module(db, self.file(db)) + .is_some_and(|module| module.is_known(KnownModule::Builtins)) } /// Return true if this symbol was defined in the `typing` or `typing_extensions` modules pub(crate) fn is_typing_definition(self, db: &'db dyn Db) -> bool { - file_to_module(db, self.file(db)).is_some_and(|module| { - module.search_path().is_standard_library() - && matches!(&**module.name(), "typing" | "typing_extensions") - }) + matches!( + file_to_module(db, self.file(db)).and_then(|module| module.known()), + Some(KnownModule::Typing | KnownModule::TypingExtensions) + ) } } diff --git a/crates/red_knot_python_semantic/src/stdlib.rs b/crates/red_knot_python_semantic/src/stdlib.rs index 2ab2fa2331..d5e200aa08 100644 --- a/crates/red_knot_python_semantic/src/stdlib.rs +++ b/crates/red_knot_python_semantic/src/stdlib.rs @@ -1,55 +1,19 @@ -use crate::module_name::ModuleName; -use crate::module_resolver::resolve_module; +use crate::module_resolver::{resolve_module, KnownModule}; use crate::semantic_index::global_scope; use crate::semantic_index::symbol::ScopeId; use crate::symbol::Symbol; use crate::types::global_symbol; use crate::Db; -/// Enumeration of various core stdlib modules, for which we have dedicated Salsa queries. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum CoreStdlibModule { - Builtins, - Types, - Typeshed, - TypingExtensions, - Typing, - Sys, - #[allow(dead_code)] - Abc, // currently only used in tests - Collections, -} - -impl CoreStdlibModule { - pub(crate) const fn as_str(self) -> &'static str { - match self { - Self::Builtins => "builtins", - Self::Types => "types", - Self::Typing => "typing", - Self::Typeshed => "_typeshed", - Self::TypingExtensions => "typing_extensions", - Self::Sys => "sys", - Self::Abc => "abc", - Self::Collections => "collections", - } - } - - pub(crate) fn name(self) -> ModuleName { - let self_as_str = self.as_str(); - ModuleName::new_static(self_as_str) - .unwrap_or_else(|| panic!("{self_as_str} should be a valid module name!")) - } -} - -/// Lookup the type of `symbol` in a given core module +/// Lookup the type of `symbol` in a given known module /// -/// Returns `Symbol::Unbound` if the given core module cannot be resolved for some reason -pub(crate) fn core_module_symbol<'db>( +/// Returns `Symbol::Unbound` if the given known module cannot be resolved for some reason +pub(crate) fn known_module_symbol<'db>( db: &'db dyn Db, - core_module: CoreStdlibModule, + known_module: KnownModule, symbol: &str, ) -> Symbol<'db> { - resolve_module(db, &core_module.name()) + resolve_module(db, &known_module.name()) .map(|module| global_symbol(db, module.file(), symbol)) .unwrap_or(Symbol::Unbound) } @@ -59,7 +23,7 @@ pub(crate) fn core_module_symbol<'db>( /// Returns `Symbol::Unbound` if the `builtins` module isn't available for some reason. #[inline] pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> { - core_module_symbol(db, CoreStdlibModule::Builtins, symbol) + known_module_symbol(db, KnownModule::Builtins, symbol) } /// Lookup the type of `symbol` in the `typing` module namespace. @@ -68,7 +32,7 @@ pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> #[inline] #[cfg(test)] pub(crate) fn typing_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> { - core_module_symbol(db, CoreStdlibModule::Typing, symbol) + known_module_symbol(db, KnownModule::Typing, symbol) } /// Lookup the type of `symbol` in the `typing_extensions` module namespace. @@ -76,13 +40,13 @@ pub(crate) fn typing_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> { /// Returns `Symbol::Unbound` if the `typing_extensions` module isn't available for some reason. #[inline] pub(crate) fn typing_extensions_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> { - core_module_symbol(db, CoreStdlibModule::TypingExtensions, symbol) + known_module_symbol(db, KnownModule::TypingExtensions, symbol) } /// Get the scope of a core stdlib module. /// /// Can return `None` if a custom typeshed is used that is missing the core module in question. -fn core_module_scope(db: &dyn Db, core_module: CoreStdlibModule) -> Option> { +fn core_module_scope(db: &dyn Db, core_module: KnownModule) -> Option> { resolve_module(db, &core_module.name()).map(|module| global_scope(db, module.file())) } @@ -90,5 +54,5 @@ fn core_module_scope(db: &dyn Db, core_module: CoreStdlibModule) -> Option Option> { - core_module_scope(db, CoreStdlibModule::Builtins) + core_module_scope(db, KnownModule::Builtins) } diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 8c7a84d489..a58e7ebd39 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -17,7 +17,7 @@ pub(crate) use self::infer::{ }; pub(crate) use self::signatures::Signature; use crate::module_name::ModuleName; -use crate::module_resolver::{file_to_module, resolve_module}; +use crate::module_resolver::{file_to_module, resolve_module, KnownModule}; use crate::semantic_index::ast_ids::HasScopedExpressionId; use crate::semantic_index::definition::Definition; use crate::semantic_index::symbol::{self as symbol, ScopeId, ScopedSymbolId}; @@ -25,9 +25,7 @@ use crate::semantic_index::{ global_scope, imported_modules, semantic_index, symbol_table, use_def_map, BindingWithConstraints, BindingWithConstraintsIterator, DeclarationsIterator, }; -use crate::stdlib::{ - builtins_symbol, core_module_symbol, typing_extensions_symbol, CoreStdlibModule, -}; +use crate::stdlib::{builtins_symbol, known_module_symbol, typing_extensions_symbol}; use crate::symbol::{Boundness, Symbol}; use crate::types::call::{CallDunderResult, CallOutcome}; use crate::types::class_base::ClassBase; @@ -129,7 +127,8 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db> // We don't need to check for `typing_extensions` here, because `typing_extensions.TYPE_CHECKING` // is just a re-export of `typing.TYPE_CHECKING`. if name == "TYPE_CHECKING" - && file_to_module(db, scope.file(db)).is_some_and(|module| module.name() == "typing") + && file_to_module(db, scope.file(db)) + .is_some_and(|module| module.is_known(KnownModule::Typing)) { return Symbol::Type(Type::BooleanLiteral(true), Boundness::Bound); } @@ -2178,7 +2177,7 @@ impl InvalidTypeExpression { /// /// Feel free to expand this enum if you ever find yourself using the same class in multiple /// places. -/// Note: good candidates are any classes in `[crate::stdlib::CoreStdlibModule]` +/// Note: good candidates are any classes in `[crate::module_resolver::module::KnownModule]` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum KnownClass { // To figure out where an stdlib symbol is defined, you can go into `crates/red_knot_vendored` @@ -2269,7 +2268,7 @@ impl<'db> KnownClass { } pub fn to_class_literal(self, db: &'db dyn Db) -> Type<'db> { - core_module_symbol(db, self.canonical_module(db), self.as_str()) + known_module_symbol(db, self.canonical_module(db), self.as_str()) .ignore_possibly_unbound() .unwrap_or(Type::Unknown) } @@ -2282,7 +2281,7 @@ impl<'db> KnownClass { } /// Return the module in which we should look up the definition for this class - pub(crate) fn canonical_module(self, db: &'db dyn Db) -> CoreStdlibModule { + pub(crate) fn canonical_module(self, db: &'db dyn Db) -> KnownModule { match self { Self::Bool | Self::Object @@ -2298,12 +2297,12 @@ impl<'db> KnownClass { | Self::Dict | Self::BaseException | Self::BaseExceptionGroup - | Self::Slice => CoreStdlibModule::Builtins, - Self::VersionInfo => CoreStdlibModule::Sys, - Self::GenericAlias | Self::ModuleType | Self::FunctionType => CoreStdlibModule::Types, - Self::NoneType => CoreStdlibModule::Typeshed, + | Self::Slice => KnownModule::Builtins, + Self::VersionInfo => KnownModule::Sys, + Self::GenericAlias | Self::ModuleType | Self::FunctionType => KnownModule::Types, + Self::NoneType => KnownModule::Typeshed, Self::SpecialForm | Self::TypeVar | Self::TypeAliasType | Self::StdlibAlias => { - CoreStdlibModule::Typing + KnownModule::Typing } Self::NoDefaultType => { let python_version = Program::get(db).python_version(db); @@ -2312,16 +2311,16 @@ impl<'db> KnownClass { // singleton, but not for `typing._NoDefaultType`. So we need to switch // to `typing._NoDefaultType` for newer versions: if python_version >= PythonVersion::PY313 { - CoreStdlibModule::Typing + KnownModule::Typing } else { - CoreStdlibModule::TypingExtensions + KnownModule::TypingExtensions } } Self::ChainMap | Self::Counter | Self::DefaultDict | Self::Deque - | Self::OrderedDict => CoreStdlibModule::Collections, + | Self::OrderedDict => KnownModule::Collections, } } @@ -2361,7 +2360,7 @@ impl<'db> KnownClass { } } - pub fn try_from_file(db: &dyn Db, file: File, class_name: &str) -> Option { + pub fn try_from_file_and_name(db: &dyn Db, file: File, class_name: &str) -> Option { // Note: if this becomes hard to maintain (as rust can't ensure at compile time that all // variants of `Self` are covered), we might use a macro (in-house or dependency) // See: https://stackoverflow.com/q/39070244 @@ -2398,15 +2397,13 @@ impl<'db> KnownClass { _ => return None, }; - let module = file_to_module(db, file)?; - candidate.check_module(db, &module).then_some(candidate) + candidate + .check_module(db, file_to_module(db, file)?.known()?) + .then_some(candidate) } - /// Return `true` if the module of `self` matches `module_name` - fn check_module(self, db: &'db dyn Db, module: &Module) -> bool { - if !module.search_path().is_standard_library() { - return false; - } + /// Return `true` if the module of `self` matches `module` + fn check_module(self, db: &'db dyn Db, module: KnownModule) -> bool { match self { Self::Bool | Self::Object @@ -2432,10 +2429,10 @@ impl<'db> KnownClass { | Self::VersionInfo | Self::BaseException | Self::BaseExceptionGroup - | Self::FunctionType => module.name() == self.canonical_module(db).as_str(), - Self::NoneType => matches!(module.name().as_str(), "_typeshed" | "types"), + | Self::FunctionType => module == self.canonical_module(db), + Self::NoneType => matches!(module, KnownModule::Typeshed | KnownModule::Types), Self::SpecialForm | Self::TypeVar | Self::TypeAliasType | Self::NoDefaultType => { - matches!(module.name().as_str(), "typing" | "typing_extensions") + matches!(module, KnownModule::Typing | KnownModule::TypingExtensions) } } } @@ -2669,43 +2666,88 @@ impl<'db> KnownInstanceType<'db> { self.class().to_instance(db) } - pub fn try_from_module_and_symbol(module: &Module, instance_name: &str) -> Option { - if !module.search_path().is_standard_library() { - return None; - } - match (module.name().as_str(), instance_name) { - ("typing", "Any") => Some(Self::Any), - ("typing", "ClassVar") => Some(Self::ClassVar), - ("typing", "Deque") => Some(Self::Deque), - ("typing", "List") => Some(Self::List), - ("typing", "Dict") => Some(Self::Dict), - ("typing", "DefaultDict") => Some(Self::DefaultDict), - ("typing", "Set") => Some(Self::Set), - ("typing", "FrozenSet") => Some(Self::FrozenSet), - ("typing", "Counter") => Some(Self::Counter), - ("typing", "ChainMap") => Some(Self::ChainMap), - ("typing", "OrderedDict") => Some(Self::OrderedDict), - ("typing", "Optional") => Some(Self::Optional), - ("typing", "Union") => Some(Self::Union), - ("typing", "NoReturn") => Some(Self::NoReturn), - ("typing", "Tuple") => Some(Self::Tuple), - ("typing", "Type") => Some(Self::Type), - ("typing", "Callable") => Some(Self::Callable), - ("typing" | "typing_extensions", "Annotated") => Some(Self::Annotated), - ("typing" | "typing_extensions", "Literal") => Some(Self::Literal), - ("typing" | "typing_extensions", "LiteralString") => Some(Self::LiteralString), - ("typing" | "typing_extensions", "Never") => Some(Self::Never), - ("typing" | "typing_extensions", "Self") => Some(Self::TypingSelf), - ("typing" | "typing_extensions", "Final") => Some(Self::Final), - ("typing" | "typing_extensions", "Concatenate") => Some(Self::Concatenate), - ("typing" | "typing_extensions", "Unpack") => Some(Self::Unpack), - ("typing" | "typing_extensions", "Required") => Some(Self::Required), - ("typing" | "typing_extensions", "NotRequired") => Some(Self::NotRequired), - ("typing" | "typing_extensions", "TypeAlias") => Some(Self::TypeAlias), - ("typing" | "typing_extensions", "TypeGuard") => Some(Self::TypeGuard), - ("typing" | "typing_extensions", "TypeIs") => Some(Self::TypeIs), - ("typing" | "typing_extensions", "ReadOnly") => Some(Self::ReadOnly), - _ => None, + pub fn try_from_file_and_name(db: &'db dyn Db, file: File, symbol_name: &str) -> Option { + let candidate = match symbol_name { + "Any" => Self::Any, + "ClassVar" => Self::ClassVar, + "Deque" => Self::Deque, + "List" => Self::List, + "Dict" => Self::Dict, + "DefaultDict" => Self::DefaultDict, + "Set" => Self::Set, + "FrozenSet" => Self::FrozenSet, + "Counter" => Self::Counter, + "ChainMap" => Self::ChainMap, + "OrderedDict" => Self::OrderedDict, + "Optional" => Self::Optional, + "Union" => Self::Union, + "NoReturn" => Self::NoReturn, + "Tuple" => Self::Tuple, + "Type" => Self::Type, + "Callable" => Self::Callable, + "Annotated" => Self::Annotated, + "Literal" => Self::Literal, + "Never" => Self::Never, + "Self" => Self::TypingSelf, + "Final" => Self::Final, + "Unpack" => Self::Unpack, + "Required" => Self::Required, + "TypeAlias" => Self::TypeAlias, + "TypeGuard" => Self::TypeGuard, + "TypeIs" => Self::TypeIs, + "ReadOnly" => Self::ReadOnly, + "Concatenate" => Self::Concatenate, + "NotRequired" => Self::NotRequired, + "LiteralString" => Self::LiteralString, + _ => return None, + }; + + candidate + .check_module(file_to_module(db, file)?.known()?) + .then_some(candidate) + } + + /// Return `true` if `module` is a module from which this `KnownInstance` variant can validly originate. + /// + /// Most variants can only exist in one module, which is the same as `self.class().canonical_module()`. + /// Some variants could validly be defined in either `typing` or `typing_extensions`, however. + pub fn check_module(self, module: KnownModule) -> bool { + match self { + Self::Any + | Self::ClassVar + | Self::Deque + | Self::List + | Self::Dict + | Self::DefaultDict + | Self::Set + | Self::FrozenSet + | Self::Counter + | Self::ChainMap + | Self::OrderedDict + | Self::Optional + | Self::Union + | Self::NoReturn + | Self::Tuple + | Self::Type + | Self::Callable => module.is_typing(), + Self::Annotated + | Self::Literal + | Self::LiteralString + | Self::Never + | Self::TypingSelf + | Self::Final + | Self::Concatenate + | Self::Unpack + | Self::Required + | Self::NotRequired + | Self::TypeAlias + | Self::TypeGuard + | Self::TypeIs + | Self::ReadOnly + | Self::TypeAliasType(_) + | Self::TypeVar(_) => { + matches!(module, KnownModule::Typing | KnownModule::TypingExtensions) + } } } @@ -2941,7 +2983,7 @@ impl KnownFunction { } } - fn from_definition<'db>( + fn try_from_definition_and_name<'db>( db: &'db dyn Db, definition: Definition<'db>, name: &str, @@ -3614,7 +3656,7 @@ pub(crate) mod tests { SubclassOfUnknown, SubclassOfBuiltinClass(&'static str), SubclassOfAbcClass(&'static str), - StdlibModule(CoreStdlibModule), + StdlibModule(KnownModule), SliceLiteral(i32, i32, i32), AlwaysTruthy, AlwaysFalsy, @@ -3634,11 +3676,11 @@ pub(crate) mod tests { Ty::LiteralString => Type::LiteralString, Ty::BytesLiteral(s) => Type::bytes_literal(db, s.as_bytes()), Ty::BuiltinInstance(s) => builtins_symbol(db, s).expect_type().to_instance(db), - Ty::AbcInstance(s) => core_module_symbol(db, CoreStdlibModule::Abc, s) + Ty::AbcInstance(s) => known_module_symbol(db, KnownModule::Abc, s) .expect_type() .to_instance(db), Ty::AbcClassLiteral(s) => { - core_module_symbol(db, CoreStdlibModule::Abc, s).expect_type() + known_module_symbol(db, KnownModule::Abc, s).expect_type() } Ty::TypingInstance(s) => typing_symbol(db, s).expect_type().to_instance(db), Ty::TypingLiteral => Type::KnownInstance(KnownInstanceType::Literal), @@ -3670,7 +3712,7 @@ pub(crate) mod tests { .class, ), Ty::SubclassOfAbcClass(s) => Type::subclass_of( - core_module_symbol(db, CoreStdlibModule::Abc, s) + known_module_symbol(db, KnownModule::Abc, s) .expect_type() .expect_class_literal() .class, @@ -3820,7 +3862,7 @@ pub(crate) mod tests { #[test_case(Ty::Tuple(vec![Ty::BuiltinInstance("int")]), Ty::BuiltinInstance("tuple"))] #[test_case(Ty::BuiltinClassLiteral("str"), Ty::BuiltinInstance("type"))] #[test_case( - Ty::StdlibModule(CoreStdlibModule::Typing), + Ty::StdlibModule(KnownModule::Typing), Ty::KnownClassInstance(KnownClass::ModuleType) )] #[test_case(Ty::SliceLiteral(1, 2, 3), Ty::BuiltinInstance("slice"))] diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 0fbecd188d..bd3208f916 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -1036,7 +1036,8 @@ impl<'db> TypeInferenceBuilder<'db> { } } - let function_kind = KnownFunction::from_definition(self.db(), definition, name); + let function_kind = + KnownFunction::try_from_definition_and_name(self.db(), definition, name); let body_scope = self .index @@ -1251,7 +1252,7 @@ impl<'db> TypeInferenceBuilder<'db> { .node_scope(NodeWithScopeRef::Class(class_node)) .to_scope_id(self.db(), self.file()); - let maybe_known_class = KnownClass::try_from_file(self.db(), self.file(), name); + let maybe_known_class = KnownClass::try_from_file_and_name(self.db(), self.file(), name); let class = Class::new(self.db(), &name.id, body_scope, maybe_known_class); let class_ty = Type::class_literal(class); @@ -1849,9 +1850,8 @@ impl<'db> TypeInferenceBuilder<'db> { TargetKind::Name => value_ty, }; - if let Some(known_instance) = file_to_module(self.db(), definition.file(self.db())) - .as_ref() - .and_then(|module| KnownInstanceType::try_from_module_and_symbol(module, &name.id)) + if let Some(known_instance) = + KnownInstanceType::try_from_file_and_name(self.db(), self.file(), &name.id) { target_ty = Type::KnownInstance(known_instance); } @@ -1901,12 +1901,11 @@ impl<'db> TypeInferenceBuilder<'db> { if let Type::Instance(InstanceType { class }) = annotation_ty { if class.is_known(self.db(), KnownClass::SpecialForm) { if let Some(name_expr) = target.as_name_expr() { - if let Some(known_instance) = file_to_module(self.db(), self.file()) - .as_ref() - .and_then(|module| { - KnownInstanceType::try_from_module_and_symbol(module, &name_expr.id) - }) - { + if let Some(known_instance) = KnownInstanceType::try_from_file_and_name( + self.db(), + self.file(), + &name_expr.id, + ) { annotation_ty = Type::KnownInstance(known_instance); } }