mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:14:52 +00:00
[ty] guard against recursion in determining completion kind (#20354)
## Summary Fixes https://github.com/astral-sh/ty/issues/1158 ## Test Plan Added test.
This commit is contained in:
parent
5bf6977ded
commit
c4cd5c00fd
2 changed files with 46 additions and 9 deletions
|
@ -11,7 +11,7 @@ use crate::semantic_index::definition::Definition;
|
|||
use crate::semantic_index::scope::FileScopeId;
|
||||
use crate::semantic_index::semantic_index;
|
||||
use crate::types::ide_support::all_declarations_and_bindings;
|
||||
use crate::types::{Type, binding_type, infer_scope_types};
|
||||
use crate::types::{CycleDetector, Type, binding_type, infer_scope_types};
|
||||
|
||||
pub struct SemanticModel<'db> {
|
||||
db: &'db dyn Db,
|
||||
|
@ -319,7 +319,11 @@ impl<'db> Completion<'db> {
|
|||
/// 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>) -> Option<CompletionKind> {
|
||||
fn imp<'db>(
|
||||
db: &'db dyn Db,
|
||||
ty: Type<'db>,
|
||||
visitor: &CompletionKindVisitor<'db>,
|
||||
) -> Option<CompletionKind> {
|
||||
Some(match ty {
|
||||
Type::FunctionLiteral(_)
|
||||
| Type::DataclassDecorator(_)
|
||||
|
@ -346,23 +350,33 @@ impl<'db> Completion<'db> {
|
|||
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))?,
|
||||
Type::Intersection(intersection) => {
|
||||
intersection.iter_positive(db).find_map(|ty| imp(db, ty))?
|
||||
}
|
||||
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) => imp(db, alias.value_type(db))?,
|
||||
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)))
|
||||
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:
|
||||
|
@ -372,7 +386,7 @@ impl<'db> Completion<'db> {
|
|||
/// `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)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum CompletionKind {
|
||||
Text,
|
||||
Method,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue