mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:53 +00:00
[red-knot] Rename and rework the CoreStdlibModule
enum (#15071)
This commit is contained in:
parent
a06099dffe
commit
bcec5e615b
7 changed files with 214 additions and 138 deletions
|
@ -5,7 +5,7 @@ use rustc_hash::FxHasher;
|
||||||
use crate::lint::{LintRegistry, LintRegistryBuilder};
|
use crate::lint::{LintRegistry, LintRegistryBuilder};
|
||||||
pub use db::Db;
|
pub use db::Db;
|
||||||
pub use module_name::ModuleName;
|
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 program::{Program, ProgramSettings, SearchPathSettings, SitePackages};
|
||||||
pub use python_version::PythonVersion;
|
pub use python_version::PythonVersion;
|
||||||
pub use semantic_model::{HasTy, SemanticModel};
|
pub use semantic_model::{HasTy, SemanticModel};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
pub use module::Module;
|
pub use module::{KnownModule, Module};
|
||||||
pub use resolver::resolve_module;
|
pub use resolver::resolve_module;
|
||||||
pub(crate) use resolver::{file_to_module, SearchPaths};
|
pub(crate) use resolver::{file_to_module, SearchPaths};
|
||||||
use ruff_db::system::SystemPath;
|
use ruff_db::system::SystemPath;
|
||||||
|
|
|
@ -19,12 +19,14 @@ impl Module {
|
||||||
search_path: SearchPath,
|
search_path: SearchPath,
|
||||||
file: File,
|
file: File,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let known = KnownModule::try_from_search_path_and_name(&search_path, &name);
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(ModuleInner {
|
inner: Arc::new(ModuleInner {
|
||||||
name,
|
name,
|
||||||
kind,
|
kind,
|
||||||
search_path,
|
search_path,
|
||||||
file,
|
file,
|
||||||
|
known,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +41,16 @@ impl Module {
|
||||||
self.inner.file
|
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.
|
/// The search path from which the module was resolved.
|
||||||
pub(crate) fn search_path(&self) -> &SearchPath {
|
pub(crate) fn search_path(&self) -> &SearchPath {
|
||||||
&self.inner.search_path
|
&self.inner.search_path
|
||||||
|
@ -67,6 +79,7 @@ struct ModuleInner {
|
||||||
kind: ModuleKind,
|
kind: ModuleKind,
|
||||||
search_path: SearchPath,
|
search_path: SearchPath,
|
||||||
file: File,
|
file: File,
|
||||||
|
known: Option<KnownModule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
@ -83,3 +96,62 @@ impl ModuleKind {
|
||||||
matches!(self, ModuleKind::Package)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::module_resolver::file_to_module;
|
||||||
use crate::node_key::NodeKey;
|
use crate::node_key::NodeKey;
|
||||||
use crate::semantic_index::symbol::{FileScopeId, ScopeId, ScopedSymbolId};
|
use crate::semantic_index::symbol::{FileScopeId, ScopeId, ScopedSymbolId};
|
||||||
use crate::unpack::Unpack;
|
use crate::unpack::Unpack;
|
||||||
use crate::Db;
|
use crate::{Db, KnownModule};
|
||||||
|
|
||||||
/// A definition of a symbol.
|
/// 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 {
|
pub(crate) fn is_builtin_definition(self, db: &'db dyn Db) -> bool {
|
||||||
file_to_module(db, self.file(db)).is_some_and(|module| {
|
file_to_module(db, self.file(db))
|
||||||
module.search_path().is_standard_library() && matches!(&**module.name(), "builtins")
|
.is_some_and(|module| module.is_known(KnownModule::Builtins))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if this symbol was defined in the `typing` or `typing_extensions` modules
|
/// 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 {
|
pub(crate) fn is_typing_definition(self, db: &'db dyn Db) -> bool {
|
||||||
file_to_module(db, self.file(db)).is_some_and(|module| {
|
matches!(
|
||||||
module.search_path().is_standard_library()
|
file_to_module(db, self.file(db)).and_then(|module| module.known()),
|
||||||
&& matches!(&**module.name(), "typing" | "typing_extensions")
|
Some(KnownModule::Typing | KnownModule::TypingExtensions)
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,55 +1,19 @@
|
||||||
use crate::module_name::ModuleName;
|
use crate::module_resolver::{resolve_module, KnownModule};
|
||||||
use crate::module_resolver::resolve_module;
|
|
||||||
use crate::semantic_index::global_scope;
|
use crate::semantic_index::global_scope;
|
||||||
use crate::semantic_index::symbol::ScopeId;
|
use crate::semantic_index::symbol::ScopeId;
|
||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::types::global_symbol;
|
use crate::types::global_symbol;
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
|
||||||
/// Enumeration of various core stdlib modules, for which we have dedicated Salsa queries.
|
/// Lookup the type of `symbol` in a given known module
|
||||||
#[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
|
|
||||||
///
|
///
|
||||||
/// Returns `Symbol::Unbound` if the given core module cannot be resolved for some reason
|
/// Returns `Symbol::Unbound` if the given known module cannot be resolved for some reason
|
||||||
pub(crate) fn core_module_symbol<'db>(
|
pub(crate) fn known_module_symbol<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
core_module: CoreStdlibModule,
|
known_module: KnownModule,
|
||||||
symbol: &str,
|
symbol: &str,
|
||||||
) -> Symbol<'db> {
|
) -> Symbol<'db> {
|
||||||
resolve_module(db, &core_module.name())
|
resolve_module(db, &known_module.name())
|
||||||
.map(|module| global_symbol(db, module.file(), symbol))
|
.map(|module| global_symbol(db, module.file(), symbol))
|
||||||
.unwrap_or(Symbol::Unbound)
|
.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.
|
/// Returns `Symbol::Unbound` if the `builtins` module isn't available for some reason.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> {
|
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.
|
/// 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]
|
#[inline]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn typing_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> {
|
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.
|
/// 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.
|
/// Returns `Symbol::Unbound` if the `typing_extensions` module isn't available for some reason.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn typing_extensions_symbol<'db>(db: &'db dyn Db, symbol: &str) -> Symbol<'db> {
|
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.
|
/// 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.
|
/// 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()))
|
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`.
|
/// 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<'_>> {
|
pub(crate) fn builtins_module_scope(db: &dyn Db) -> Option<ScopeId<'_>> {
|
||||||
core_module_scope(db, CoreStdlibModule::Builtins)
|
core_module_scope(db, KnownModule::Builtins)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub(crate) use self::infer::{
|
||||||
};
|
};
|
||||||
pub(crate) use self::signatures::Signature;
|
pub(crate) use self::signatures::Signature;
|
||||||
use crate::module_name::ModuleName;
|
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::ast_ids::HasScopedExpressionId;
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::semantic_index::symbol::{self as symbol, ScopeId, ScopedSymbolId};
|
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,
|
global_scope, imported_modules, semantic_index, symbol_table, use_def_map,
|
||||||
BindingWithConstraints, BindingWithConstraintsIterator, DeclarationsIterator,
|
BindingWithConstraints, BindingWithConstraintsIterator, DeclarationsIterator,
|
||||||
};
|
};
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{builtins_symbol, known_module_symbol, typing_extensions_symbol};
|
||||||
builtins_symbol, core_module_symbol, typing_extensions_symbol, CoreStdlibModule,
|
|
||||||
};
|
|
||||||
use crate::symbol::{Boundness, Symbol};
|
use crate::symbol::{Boundness, Symbol};
|
||||||
use crate::types::call::{CallDunderResult, CallOutcome};
|
use crate::types::call::{CallDunderResult, CallOutcome};
|
||||||
use crate::types::class_base::ClassBase;
|
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`
|
// We don't need to check for `typing_extensions` here, because `typing_extensions.TYPE_CHECKING`
|
||||||
// is just a re-export of `typing.TYPE_CHECKING`.
|
// is just a re-export of `typing.TYPE_CHECKING`.
|
||||||
if name == "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);
|
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
|
/// Feel free to expand this enum if you ever find yourself using the same class in multiple
|
||||||
/// places.
|
/// 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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum KnownClass {
|
pub enum KnownClass {
|
||||||
// To figure out where an stdlib symbol is defined, you can go into `crates/red_knot_vendored`
|
// 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> {
|
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()
|
.ignore_possibly_unbound()
|
||||||
.unwrap_or(Type::Unknown)
|
.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
|
/// 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 {
|
match self {
|
||||||
Self::Bool
|
Self::Bool
|
||||||
| Self::Object
|
| Self::Object
|
||||||
|
@ -2298,12 +2297,12 @@ impl<'db> KnownClass {
|
||||||
| Self::Dict
|
| Self::Dict
|
||||||
| Self::BaseException
|
| Self::BaseException
|
||||||
| Self::BaseExceptionGroup
|
| Self::BaseExceptionGroup
|
||||||
| Self::Slice => CoreStdlibModule::Builtins,
|
| Self::Slice => KnownModule::Builtins,
|
||||||
Self::VersionInfo => CoreStdlibModule::Sys,
|
Self::VersionInfo => KnownModule::Sys,
|
||||||
Self::GenericAlias | Self::ModuleType | Self::FunctionType => CoreStdlibModule::Types,
|
Self::GenericAlias | Self::ModuleType | Self::FunctionType => KnownModule::Types,
|
||||||
Self::NoneType => CoreStdlibModule::Typeshed,
|
Self::NoneType => KnownModule::Typeshed,
|
||||||
Self::SpecialForm | Self::TypeVar | Self::TypeAliasType | Self::StdlibAlias => {
|
Self::SpecialForm | Self::TypeVar | Self::TypeAliasType | Self::StdlibAlias => {
|
||||||
CoreStdlibModule::Typing
|
KnownModule::Typing
|
||||||
}
|
}
|
||||||
Self::NoDefaultType => {
|
Self::NoDefaultType => {
|
||||||
let python_version = Program::get(db).python_version(db);
|
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
|
// singleton, but not for `typing._NoDefaultType`. So we need to switch
|
||||||
// to `typing._NoDefaultType` for newer versions:
|
// to `typing._NoDefaultType` for newer versions:
|
||||||
if python_version >= PythonVersion::PY313 {
|
if python_version >= PythonVersion::PY313 {
|
||||||
CoreStdlibModule::Typing
|
KnownModule::Typing
|
||||||
} else {
|
} else {
|
||||||
CoreStdlibModule::TypingExtensions
|
KnownModule::TypingExtensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::ChainMap
|
Self::ChainMap
|
||||||
| Self::Counter
|
| Self::Counter
|
||||||
| Self::DefaultDict
|
| Self::DefaultDict
|
||||||
| Self::Deque
|
| 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
|
// 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)
|
// variants of `Self` are covered), we might use a macro (in-house or dependency)
|
||||||
// See: https://stackoverflow.com/q/39070244
|
// See: https://stackoverflow.com/q/39070244
|
||||||
|
@ -2398,15 +2397,13 @@ impl<'db> KnownClass {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let module = file_to_module(db, file)?;
|
candidate
|
||||||
candidate.check_module(db, &module).then_some(candidate)
|
.check_module(db, file_to_module(db, file)?.known()?)
|
||||||
|
.then_some(candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the module of `self` matches `module_name`
|
/// Return `true` if the module of `self` matches `module`
|
||||||
fn check_module(self, db: &'db dyn Db, module: &Module) -> bool {
|
fn check_module(self, db: &'db dyn Db, module: KnownModule) -> bool {
|
||||||
if !module.search_path().is_standard_library() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
match self {
|
match self {
|
||||||
Self::Bool
|
Self::Bool
|
||||||
| Self::Object
|
| Self::Object
|
||||||
|
@ -2432,10 +2429,10 @@ impl<'db> KnownClass {
|
||||||
| Self::VersionInfo
|
| Self::VersionInfo
|
||||||
| Self::BaseException
|
| Self::BaseException
|
||||||
| Self::BaseExceptionGroup
|
| Self::BaseExceptionGroup
|
||||||
| Self::FunctionType => module.name() == self.canonical_module(db).as_str(),
|
| Self::FunctionType => module == self.canonical_module(db),
|
||||||
Self::NoneType => matches!(module.name().as_str(), "_typeshed" | "types"),
|
Self::NoneType => matches!(module, KnownModule::Typeshed | KnownModule::Types),
|
||||||
Self::SpecialForm | Self::TypeVar | Self::TypeAliasType | Self::NoDefaultType => {
|
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)
|
self.class().to_instance(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_from_module_and_symbol(module: &Module, instance_name: &str) -> Option<Self> {
|
pub fn try_from_file_and_name(db: &'db dyn Db, file: File, symbol_name: &str) -> Option<Self> {
|
||||||
if !module.search_path().is_standard_library() {
|
let candidate = match symbol_name {
|
||||||
return None;
|
"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)
|
||||||
}
|
}
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2941,7 +2983,7 @@ impl KnownFunction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_definition<'db>(
|
fn try_from_definition_and_name<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
definition: Definition<'db>,
|
definition: Definition<'db>,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -3614,7 +3656,7 @@ pub(crate) mod tests {
|
||||||
SubclassOfUnknown,
|
SubclassOfUnknown,
|
||||||
SubclassOfBuiltinClass(&'static str),
|
SubclassOfBuiltinClass(&'static str),
|
||||||
SubclassOfAbcClass(&'static str),
|
SubclassOfAbcClass(&'static str),
|
||||||
StdlibModule(CoreStdlibModule),
|
StdlibModule(KnownModule),
|
||||||
SliceLiteral(i32, i32, i32),
|
SliceLiteral(i32, i32, i32),
|
||||||
AlwaysTruthy,
|
AlwaysTruthy,
|
||||||
AlwaysFalsy,
|
AlwaysFalsy,
|
||||||
|
@ -3634,11 +3676,11 @@ pub(crate) mod tests {
|
||||||
Ty::LiteralString => Type::LiteralString,
|
Ty::LiteralString => Type::LiteralString,
|
||||||
Ty::BytesLiteral(s) => Type::bytes_literal(db, s.as_bytes()),
|
Ty::BytesLiteral(s) => Type::bytes_literal(db, s.as_bytes()),
|
||||||
Ty::BuiltinInstance(s) => builtins_symbol(db, s).expect_type().to_instance(db),
|
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()
|
.expect_type()
|
||||||
.to_instance(db),
|
.to_instance(db),
|
||||||
Ty::AbcClassLiteral(s) => {
|
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::TypingInstance(s) => typing_symbol(db, s).expect_type().to_instance(db),
|
||||||
Ty::TypingLiteral => Type::KnownInstance(KnownInstanceType::Literal),
|
Ty::TypingLiteral => Type::KnownInstance(KnownInstanceType::Literal),
|
||||||
|
@ -3670,7 +3712,7 @@ pub(crate) mod tests {
|
||||||
.class,
|
.class,
|
||||||
),
|
),
|
||||||
Ty::SubclassOfAbcClass(s) => Type::subclass_of(
|
Ty::SubclassOfAbcClass(s) => Type::subclass_of(
|
||||||
core_module_symbol(db, CoreStdlibModule::Abc, s)
|
known_module_symbol(db, KnownModule::Abc, s)
|
||||||
.expect_type()
|
.expect_type()
|
||||||
.expect_class_literal()
|
.expect_class_literal()
|
||||||
.class,
|
.class,
|
||||||
|
@ -3820,7 +3862,7 @@ pub(crate) mod tests {
|
||||||
#[test_case(Ty::Tuple(vec![Ty::BuiltinInstance("int")]), Ty::BuiltinInstance("tuple"))]
|
#[test_case(Ty::Tuple(vec![Ty::BuiltinInstance("int")]), Ty::BuiltinInstance("tuple"))]
|
||||||
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::BuiltinInstance("type"))]
|
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::BuiltinInstance("type"))]
|
||||||
#[test_case(
|
#[test_case(
|
||||||
Ty::StdlibModule(CoreStdlibModule::Typing),
|
Ty::StdlibModule(KnownModule::Typing),
|
||||||
Ty::KnownClassInstance(KnownClass::ModuleType)
|
Ty::KnownClassInstance(KnownClass::ModuleType)
|
||||||
)]
|
)]
|
||||||
#[test_case(Ty::SliceLiteral(1, 2, 3), Ty::BuiltinInstance("slice"))]
|
#[test_case(Ty::SliceLiteral(1, 2, 3), Ty::BuiltinInstance("slice"))]
|
||||||
|
|
|
@ -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
|
let body_scope = self
|
||||||
.index
|
.index
|
||||||
|
@ -1251,7 +1252,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
.node_scope(NodeWithScopeRef::Class(class_node))
|
.node_scope(NodeWithScopeRef::Class(class_node))
|
||||||
.to_scope_id(self.db(), self.file());
|
.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 = Class::new(self.db(), &name.id, body_scope, maybe_known_class);
|
||||||
let class_ty = Type::class_literal(class);
|
let class_ty = Type::class_literal(class);
|
||||||
|
@ -1849,9 +1850,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
TargetKind::Name => value_ty,
|
TargetKind::Name => value_ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(known_instance) = file_to_module(self.db(), definition.file(self.db()))
|
if let Some(known_instance) =
|
||||||
.as_ref()
|
KnownInstanceType::try_from_file_and_name(self.db(), self.file(), &name.id)
|
||||||
.and_then(|module| KnownInstanceType::try_from_module_and_symbol(module, &name.id))
|
|
||||||
{
|
{
|
||||||
target_ty = Type::KnownInstance(known_instance);
|
target_ty = Type::KnownInstance(known_instance);
|
||||||
}
|
}
|
||||||
|
@ -1901,12 +1901,11 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
if let Type::Instance(InstanceType { class }) = annotation_ty {
|
if let Type::Instance(InstanceType { class }) = annotation_ty {
|
||||||
if class.is_known(self.db(), KnownClass::SpecialForm) {
|
if class.is_known(self.db(), KnownClass::SpecialForm) {
|
||||||
if let Some(name_expr) = target.as_name_expr() {
|
if let Some(name_expr) = target.as_name_expr() {
|
||||||
if let Some(known_instance) = file_to_module(self.db(), self.file())
|
if let Some(known_instance) = KnownInstanceType::try_from_file_and_name(
|
||||||
.as_ref()
|
self.db(),
|
||||||
.and_then(|module| {
|
self.file(),
|
||||||
KnownInstanceType::try_from_module_and_symbol(module, &name_expr.id)
|
&name_expr.id,
|
||||||
})
|
) {
|
||||||
{
|
|
||||||
annotation_ty = Type::KnownInstance(known_instance);
|
annotation_ty = Type::KnownInstance(known_instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue