[red-knot] Rename and rework the CoreStdlibModule enum (#15071)

This commit is contained in:
Alex Waygood 2024-12-19 20:59:00 +00:00 committed by GitHub
parent a06099dffe
commit bcec5e615b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 214 additions and 138 deletions

View file

@ -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};

View file

@ -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;

View file

@ -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<KnownModule> {
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<KnownModule>,
}
#[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<Self> {
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)
}
}

View file

@ -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)
)
}
}

View file

@ -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<ScopeId<'_>> {
fn core_module_scope(db: &dyn Db, core_module: KnownModule) -> Option<ScopeId<'_>> {
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<Scope
///
/// Can return `None` if a custom typeshed is used that is missing `builtins.pyi`.
pub(crate) fn builtins_module_scope(db: &dyn Db) -> Option<ScopeId<'_>> {
core_module_scope(db, CoreStdlibModule::Builtins)
core_module_scope(db, KnownModule::Builtins)
}

View file

@ -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<Self> {
pub fn try_from_file_and_name(db: &dyn Db, file: File, class_name: &str) -> Option<Self> {
// 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<Self> {
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<Self> {
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"))]

View file

@ -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);
}
}