mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] Move CompletionKind
to ty_ide
I think this is a better home for it. This way, `ty_ide` more clearly owns how the "kind" of a completion is computed. In particular, it is computed differently for things where we know its type versus unimported symbols.
This commit is contained in:
parent
6c3c963f8a
commit
0a2325c5fe
6 changed files with 143 additions and 155 deletions
|
@ -5,13 +5,121 @@ use ruff_db::parsed::{ParsedModuleRef, parsed_module};
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_parser::{Token, TokenAt, TokenKind};
|
use ruff_python_parser::{Token, TokenAt, TokenKind};
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
use ty_python_semantic::{Completion, NameKind, SemanticModel};
|
use ty_python_semantic::{
|
||||||
|
Completion as SemanticCompletion, ModuleName, NameKind, SemanticModel,
|
||||||
|
types::{CycleDetector, Type},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::docstring::Docstring;
|
use crate::docstring::Docstring;
|
||||||
use crate::find_node::covering_node;
|
use crate::find_node::covering_node;
|
||||||
use crate::goto::DefinitionsOrTargets;
|
use crate::goto::DefinitionsOrTargets;
|
||||||
use crate::{Db, all_symbols};
|
use crate::{Db, all_symbols};
|
||||||
|
|
||||||
|
impl<'db> Completion<'db> {
|
||||||
|
/// Returns the "kind" of this completion.
|
||||||
|
///
|
||||||
|
/// This is meant to be a very general classification of this completion.
|
||||||
|
/// Typically, this is communicated from the LSP server to a client, and
|
||||||
|
/// the client uses this information to help improve the UX (perhaps by
|
||||||
|
/// assigning an icon of some kind to the completion).
|
||||||
|
pub fn kind(&self, db: &'db dyn Db) -> Option<CompletionKind> {
|
||||||
|
type CompletionKindVisitor<'db> =
|
||||||
|
CycleDetector<CompletionKind, Type<'db>, Option<CompletionKind>>;
|
||||||
|
|
||||||
|
fn imp<'db>(
|
||||||
|
db: &'db dyn Db,
|
||||||
|
ty: Type<'db>,
|
||||||
|
visitor: &CompletionKindVisitor<'db>,
|
||||||
|
) -> Option<CompletionKind> {
|
||||||
|
Some(match ty {
|
||||||
|
Type::FunctionLiteral(_)
|
||||||
|
| Type::DataclassDecorator(_)
|
||||||
|
| Type::WrapperDescriptor(_)
|
||||||
|
| Type::DataclassTransformer(_)
|
||||||
|
| Type::Callable(_) => CompletionKind::Function,
|
||||||
|
Type::BoundMethod(_) | Type::KnownBoundMethod(_) => CompletionKind::Method,
|
||||||
|
Type::ModuleLiteral(_) => CompletionKind::Module,
|
||||||
|
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
|
||||||
|
CompletionKind::Class
|
||||||
|
}
|
||||||
|
// This is a little weird for "struct." I'm mostly interpreting
|
||||||
|
// "struct" here as a more general "object." ---AG
|
||||||
|
Type::NominalInstance(_)
|
||||||
|
| Type::PropertyInstance(_)
|
||||||
|
| Type::BoundSuper(_)
|
||||||
|
| Type::TypedDict(_) => CompletionKind::Struct,
|
||||||
|
Type::IntLiteral(_)
|
||||||
|
| Type::BooleanLiteral(_)
|
||||||
|
| Type::TypeIs(_)
|
||||||
|
| Type::StringLiteral(_)
|
||||||
|
| Type::LiteralString
|
||||||
|
| Type::BytesLiteral(_) => CompletionKind::Value,
|
||||||
|
Type::EnumLiteral(_) => CompletionKind::Enum,
|
||||||
|
Type::ProtocolInstance(_) => CompletionKind::Interface,
|
||||||
|
Type::NonInferableTypeVar(_) | Type::TypeVar(_) => CompletionKind::TypeParameter,
|
||||||
|
Type::Union(union) => union
|
||||||
|
.elements(db)
|
||||||
|
.iter()
|
||||||
|
.find_map(|&ty| imp(db, ty, visitor))?,
|
||||||
|
Type::Intersection(intersection) => intersection
|
||||||
|
.iter_positive(db)
|
||||||
|
.find_map(|ty| imp(db, ty, visitor))?,
|
||||||
|
Type::Dynamic(_)
|
||||||
|
| Type::Never
|
||||||
|
| Type::SpecialForm(_)
|
||||||
|
| Type::KnownInstance(_)
|
||||||
|
| Type::AlwaysTruthy
|
||||||
|
| Type::AlwaysFalsy => return None,
|
||||||
|
Type::TypeAlias(alias) => {
|
||||||
|
visitor.visit(ty, || imp(db, alias.value_type(db), visitor))?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
self.kind.or_else(|| {
|
||||||
|
self.ty
|
||||||
|
.and_then(|ty| imp(db, ty, &CompletionKindVisitor::default()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The "kind" of a completion.
|
||||||
|
///
|
||||||
|
/// This is taken directly from the LSP completion specification:
|
||||||
|
/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind>
|
||||||
|
///
|
||||||
|
/// The idea here is that [`Completion::kind`] defines the mapping to this from
|
||||||
|
/// `Type` (and possibly other information), which might be interesting and
|
||||||
|
/// contentious. Then the outer edges map this to the LSP types, which is
|
||||||
|
/// expected to be mundane and boring.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum CompletionKind {
|
||||||
|
Text,
|
||||||
|
Method,
|
||||||
|
Function,
|
||||||
|
Constructor,
|
||||||
|
Field,
|
||||||
|
Variable,
|
||||||
|
Class,
|
||||||
|
Interface,
|
||||||
|
Module,
|
||||||
|
Property,
|
||||||
|
Unit,
|
||||||
|
Value,
|
||||||
|
Enum,
|
||||||
|
Keyword,
|
||||||
|
Snippet,
|
||||||
|
Color,
|
||||||
|
File,
|
||||||
|
Reference,
|
||||||
|
Folder,
|
||||||
|
EnumMember,
|
||||||
|
Constant,
|
||||||
|
Struct,
|
||||||
|
Event,
|
||||||
|
Operator,
|
||||||
|
TypeParameter,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct CompletionSettings {
|
pub struct CompletionSettings {
|
||||||
pub auto_import: bool,
|
pub auto_import: bool,
|
||||||
|
|
|
@ -26,7 +26,7 @@ mod symbols;
|
||||||
mod workspace_symbols;
|
mod workspace_symbols;
|
||||||
|
|
||||||
pub use all_symbols::{AllSymbolInfo, all_symbols};
|
pub use all_symbols::{AllSymbolInfo, all_symbols};
|
||||||
pub use completion::{CompletionSettings, completion};
|
pub use completion::{Completion, CompletionKind, CompletionSettings, completion};
|
||||||
pub use doc_highlights::document_highlights;
|
pub use doc_highlights::document_highlights;
|
||||||
pub use document_symbols::document_symbols;
|
pub use document_symbols::document_symbols;
|
||||||
pub use goto::{goto_declaration, goto_definition, goto_type_definition};
|
pub use goto::{goto_declaration, goto_definition, goto_type_definition};
|
||||||
|
|
|
@ -13,7 +13,8 @@ use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor};
|
||||||
use ruff_python_ast::{Expr, Stmt};
|
use ruff_python_ast::{Expr, Stmt};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
use ty_project::Db;
|
use ty_project::Db;
|
||||||
use ty_python_semantic::CompletionKind;
|
|
||||||
|
use crate::completion::CompletionKind;
|
||||||
|
|
||||||
/// A compiled query pattern used for searching symbols.
|
/// A compiled query pattern used for searching symbols.
|
||||||
///
|
///
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub use program::{
|
||||||
pub use python_platform::PythonPlatform;
|
pub use python_platform::PythonPlatform;
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
pub use semantic_model::{
|
pub use semantic_model::{
|
||||||
Completion, CompletionKind, HasDefinition, HasType, NameKind, SemanticModel,
|
Completion, HasDefinition, HasType, MemberDefinition, NameKind, SemanticModel,
|
||||||
};
|
};
|
||||||
pub use site_packages::{PythonEnvironment, SitePackagesPaths, SysPrefixPathOrigin};
|
pub use site_packages::{PythonEnvironment, SitePackagesPaths, SysPrefixPathOrigin};
|
||||||
pub use types::DisplaySettings;
|
pub use types::DisplaySettings;
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::semantic_index::definition::Definition;
|
||||||
use crate::semantic_index::scope::FileScopeId;
|
use crate::semantic_index::scope::FileScopeId;
|
||||||
use crate::semantic_index::semantic_index;
|
use crate::semantic_index::semantic_index;
|
||||||
use crate::types::ide_support::all_declarations_and_bindings;
|
use crate::types::ide_support::all_declarations_and_bindings;
|
||||||
use crate::types::{CycleDetector, Type, binding_type, infer_scope_types};
|
use crate::types::{Type, binding_type, infer_scope_types};
|
||||||
|
|
||||||
pub struct SemanticModel<'db> {
|
pub struct SemanticModel<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
|
@ -51,7 +51,6 @@ impl<'db> SemanticModel<'db> {
|
||||||
Completion {
|
Completion {
|
||||||
name: Name::new(module.name(self.db).as_str()),
|
name: Name::new(module.name(self.db).as_str()),
|
||||||
ty: Some(ty),
|
ty: Some(ty),
|
||||||
kind: None,
|
|
||||||
builtin,
|
builtin,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -166,7 +165,6 @@ impl<'db> SemanticModel<'db> {
|
||||||
completions.push(Completion {
|
completions.push(Completion {
|
||||||
name,
|
name,
|
||||||
ty: Some(ty),
|
ty: Some(ty),
|
||||||
kind: None,
|
|
||||||
builtin,
|
builtin,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -187,7 +185,6 @@ impl<'db> SemanticModel<'db> {
|
||||||
completions.push(Completion {
|
completions.push(Completion {
|
||||||
name: Name::new(base),
|
name: Name::new(base),
|
||||||
ty: Some(ty),
|
ty: Some(ty),
|
||||||
kind: None,
|
|
||||||
builtin,
|
builtin,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -202,7 +199,6 @@ impl<'db> SemanticModel<'db> {
|
||||||
.map(|member| Completion {
|
.map(|member| Completion {
|
||||||
name: member.name,
|
name: member.name,
|
||||||
ty: Some(member.ty),
|
ty: Some(member.ty),
|
||||||
kind: None,
|
|
||||||
builtin: false,
|
builtin: false,
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -239,7 +235,6 @@ impl<'db> SemanticModel<'db> {
|
||||||
.map(|memberdef| Completion {
|
.map(|memberdef| Completion {
|
||||||
name: memberdef.member.name,
|
name: memberdef.member.name,
|
||||||
ty: Some(memberdef.member.ty),
|
ty: Some(memberdef.member.ty),
|
||||||
kind: None,
|
|
||||||
builtin: false,
|
builtin: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -296,15 +291,6 @@ pub struct Completion<'db> {
|
||||||
/// an unimported symbol. In that case, computing the
|
/// an unimported symbol. In that case, computing the
|
||||||
/// type of all such symbols could be quite expensive.
|
/// type of all such symbols could be quite expensive.
|
||||||
pub ty: Option<Type<'db>>,
|
pub ty: Option<Type<'db>>,
|
||||||
/// The "kind" of this completion.
|
|
||||||
///
|
|
||||||
/// When this is set, it takes priority over any kind
|
|
||||||
/// inferred from `ty`.
|
|
||||||
///
|
|
||||||
/// Usually this is set when `ty` is `None`, since it
|
|
||||||
/// may be cheaper to compute at scale. (e.g., For
|
|
||||||
/// unimported symbol completions.)
|
|
||||||
pub kind: Option<CompletionKind>,
|
|
||||||
/// Whether this suggestion came from builtins or not.
|
/// Whether this suggestion came from builtins or not.
|
||||||
///
|
///
|
||||||
/// At time of writing (2025-06-26), this information
|
/// At time of writing (2025-06-26), this information
|
||||||
|
@ -314,110 +300,6 @@ pub struct Completion<'db> {
|
||||||
pub builtin: bool,
|
pub builtin: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Completion<'db> {
|
|
||||||
/// Returns the "kind" of this completion.
|
|
||||||
///
|
|
||||||
/// This is meant to be a very general classification of this completion.
|
|
||||||
/// Typically, this is communicated from the LSP server to a client, and
|
|
||||||
/// the client uses this information to help improve the UX (perhaps by
|
|
||||||
/// assigning an icon of some kind to the completion).
|
|
||||||
pub fn kind(&self, db: &'db dyn Db) -> Option<CompletionKind> {
|
|
||||||
fn imp<'db>(
|
|
||||||
db: &'db dyn Db,
|
|
||||||
ty: Type<'db>,
|
|
||||||
visitor: &CompletionKindVisitor<'db>,
|
|
||||||
) -> Option<CompletionKind> {
|
|
||||||
Some(match ty {
|
|
||||||
Type::FunctionLiteral(_)
|
|
||||||
| Type::DataclassDecorator(_)
|
|
||||||
| Type::WrapperDescriptor(_)
|
|
||||||
| Type::DataclassTransformer(_)
|
|
||||||
| Type::Callable(_) => CompletionKind::Function,
|
|
||||||
Type::BoundMethod(_) | Type::KnownBoundMethod(_) => CompletionKind::Method,
|
|
||||||
Type::ModuleLiteral(_) => CompletionKind::Module,
|
|
||||||
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
|
|
||||||
CompletionKind::Class
|
|
||||||
}
|
|
||||||
// This is a little weird for "struct." I'm mostly interpreting
|
|
||||||
// "struct" here as a more general "object." ---AG
|
|
||||||
Type::NominalInstance(_)
|
|
||||||
| Type::PropertyInstance(_)
|
|
||||||
| Type::BoundSuper(_)
|
|
||||||
| Type::TypedDict(_) => CompletionKind::Struct,
|
|
||||||
Type::IntLiteral(_)
|
|
||||||
| Type::BooleanLiteral(_)
|
|
||||||
| Type::TypeIs(_)
|
|
||||||
| Type::StringLiteral(_)
|
|
||||||
| Type::LiteralString
|
|
||||||
| Type::BytesLiteral(_) => CompletionKind::Value,
|
|
||||||
Type::EnumLiteral(_) => CompletionKind::Enum,
|
|
||||||
Type::ProtocolInstance(_) => CompletionKind::Interface,
|
|
||||||
Type::NonInferableTypeVar(_) | Type::TypeVar(_) => CompletionKind::TypeParameter,
|
|
||||||
Type::Union(union) => union
|
|
||||||
.elements(db)
|
|
||||||
.iter()
|
|
||||||
.find_map(|&ty| imp(db, ty, visitor))?,
|
|
||||||
Type::Intersection(intersection) => intersection
|
|
||||||
.iter_positive(db)
|
|
||||||
.find_map(|ty| imp(db, ty, visitor))?,
|
|
||||||
Type::Dynamic(_)
|
|
||||||
| Type::Never
|
|
||||||
| Type::SpecialForm(_)
|
|
||||||
| Type::KnownInstance(_)
|
|
||||||
| Type::AlwaysTruthy
|
|
||||||
| Type::AlwaysFalsy => return None,
|
|
||||||
Type::TypeAlias(alias) => {
|
|
||||||
visitor.visit(ty, || imp(db, alias.value_type(db), visitor))?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
self.kind.or_else(|| {
|
|
||||||
self.ty
|
|
||||||
.and_then(|ty| imp(db, ty, &CompletionKindVisitor::default()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CompletionKindVisitor<'db> = CycleDetector<CompletionKind, Type<'db>, Option<CompletionKind>>;
|
|
||||||
|
|
||||||
/// The "kind" of a completion.
|
|
||||||
///
|
|
||||||
/// This is taken directly from the LSP completion specification:
|
|
||||||
/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind>
|
|
||||||
///
|
|
||||||
/// The idea here is that `Completion::kind` defines the mapping to this from
|
|
||||||
/// `Type` (and possibly other information), which might be interesting and
|
|
||||||
/// contentious. Then the outer edges map this to the LSP types, which is
|
|
||||||
/// expected to be mundane and boring.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
||||||
pub enum CompletionKind {
|
|
||||||
Text,
|
|
||||||
Method,
|
|
||||||
Function,
|
|
||||||
Constructor,
|
|
||||||
Field,
|
|
||||||
Variable,
|
|
||||||
Class,
|
|
||||||
Interface,
|
|
||||||
Module,
|
|
||||||
Property,
|
|
||||||
Unit,
|
|
||||||
Value,
|
|
||||||
Enum,
|
|
||||||
Keyword,
|
|
||||||
Snippet,
|
|
||||||
Color,
|
|
||||||
File,
|
|
||||||
Reference,
|
|
||||||
Folder,
|
|
||||||
EnumMember,
|
|
||||||
Constant,
|
|
||||||
Struct,
|
|
||||||
Event,
|
|
||||||
Operator,
|
|
||||||
TypeParameter,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait HasType {
|
pub trait HasType {
|
||||||
/// Returns the inferred type of `self`.
|
/// Returns the inferred type of `self`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -425,14 +425,11 @@ impl Workspace {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|completion| Completion {
|
.map(|completion| Completion {
|
||||||
kind: completion.kind(&self.db).map(CompletionKind::from),
|
kind: completion.kind(&self.db).map(CompletionKind::from),
|
||||||
name: completion.inner.name.into(),
|
name: completion.name.into(),
|
||||||
documentation: completion
|
documentation: completion
|
||||||
.documentation
|
.documentation
|
||||||
.map(|documentation| documentation.render_plaintext()),
|
.map(|documentation| documentation.render_plaintext()),
|
||||||
detail: completion
|
detail: completion.ty.map(|ty| ty.display(&self.db).to_string()),
|
||||||
.inner
|
|
||||||
.ty
|
|
||||||
.map(|ty| ty.display(&self.db).to_string()),
|
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
@ -956,34 +953,34 @@ pub enum CompletionKind {
|
||||||
TypeParameter,
|
TypeParameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ty_python_semantic::CompletionKind> for CompletionKind {
|
impl From<ty_ide::CompletionKind> for CompletionKind {
|
||||||
fn from(value: ty_python_semantic::CompletionKind) -> Self {
|
fn from(value: ty_ide::CompletionKind) -> Self {
|
||||||
match value {
|
match value {
|
||||||
ty_python_semantic::CompletionKind::Text => Self::Text,
|
ty_ide::CompletionKind::Text => Self::Text,
|
||||||
ty_python_semantic::CompletionKind::Method => Self::Method,
|
ty_ide::CompletionKind::Method => Self::Method,
|
||||||
ty_python_semantic::CompletionKind::Function => Self::Function,
|
ty_ide::CompletionKind::Function => Self::Function,
|
||||||
ty_python_semantic::CompletionKind::Constructor => Self::Constructor,
|
ty_ide::CompletionKind::Constructor => Self::Constructor,
|
||||||
ty_python_semantic::CompletionKind::Field => Self::Field,
|
ty_ide::CompletionKind::Field => Self::Field,
|
||||||
ty_python_semantic::CompletionKind::Variable => Self::Variable,
|
ty_ide::CompletionKind::Variable => Self::Variable,
|
||||||
ty_python_semantic::CompletionKind::Class => Self::Class,
|
ty_ide::CompletionKind::Class => Self::Class,
|
||||||
ty_python_semantic::CompletionKind::Interface => Self::Interface,
|
ty_ide::CompletionKind::Interface => Self::Interface,
|
||||||
ty_python_semantic::CompletionKind::Module => Self::Module,
|
ty_ide::CompletionKind::Module => Self::Module,
|
||||||
ty_python_semantic::CompletionKind::Property => Self::Property,
|
ty_ide::CompletionKind::Property => Self::Property,
|
||||||
ty_python_semantic::CompletionKind::Unit => Self::Unit,
|
ty_ide::CompletionKind::Unit => Self::Unit,
|
||||||
ty_python_semantic::CompletionKind::Value => Self::Value,
|
ty_ide::CompletionKind::Value => Self::Value,
|
||||||
ty_python_semantic::CompletionKind::Enum => Self::Enum,
|
ty_ide::CompletionKind::Enum => Self::Enum,
|
||||||
ty_python_semantic::CompletionKind::Keyword => Self::Keyword,
|
ty_ide::CompletionKind::Keyword => Self::Keyword,
|
||||||
ty_python_semantic::CompletionKind::Snippet => Self::Snippet,
|
ty_ide::CompletionKind::Snippet => Self::Snippet,
|
||||||
ty_python_semantic::CompletionKind::Color => Self::Color,
|
ty_ide::CompletionKind::Color => Self::Color,
|
||||||
ty_python_semantic::CompletionKind::File => Self::File,
|
ty_ide::CompletionKind::File => Self::File,
|
||||||
ty_python_semantic::CompletionKind::Reference => Self::Reference,
|
ty_ide::CompletionKind::Reference => Self::Reference,
|
||||||
ty_python_semantic::CompletionKind::Folder => Self::Folder,
|
ty_ide::CompletionKind::Folder => Self::Folder,
|
||||||
ty_python_semantic::CompletionKind::EnumMember => Self::EnumMember,
|
ty_ide::CompletionKind::EnumMember => Self::EnumMember,
|
||||||
ty_python_semantic::CompletionKind::Constant => Self::Constant,
|
ty_ide::CompletionKind::Constant => Self::Constant,
|
||||||
ty_python_semantic::CompletionKind::Struct => Self::Struct,
|
ty_ide::CompletionKind::Struct => Self::Struct,
|
||||||
ty_python_semantic::CompletionKind::Event => Self::Event,
|
ty_ide::CompletionKind::Event => Self::Event,
|
||||||
ty_python_semantic::CompletionKind::Operator => Self::Operator,
|
ty_ide::CompletionKind::Operator => Self::Operator,
|
||||||
ty_python_semantic::CompletionKind::TypeParameter => Self::TypeParameter,
|
ty_ide::CompletionKind::TypeParameter => Self::TypeParameter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue