mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-01 04:18:05 +00:00
[ty] Provide completions on TypeVars (#20943)
## Summary closes https://github.com/astral-sh/ty/issues/1370 ## Test Plan New snapshot tests
This commit is contained in:
parent
c7e2bfd759
commit
6e7ff07065
2 changed files with 73 additions and 2 deletions
|
|
@ -3896,6 +3896,55 @@ print(t'''{Foo} and Foo.zqzq<CURSOR>
|
||||||
assert_snapshot!(test.completions_without_builtins(), @"<No completions found>");
|
assert_snapshot!(test.completions_without_builtins(), @"<No completions found>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn typevar_with_upper_bound() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
def f[T: str](msg: T):
|
||||||
|
msg.<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
test.assert_completions_include("upper");
|
||||||
|
test.assert_completions_include("capitalize");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn typevar_with_constraints() {
|
||||||
|
// Test TypeVar with constraints
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
class A:
|
||||||
|
only_on_a: int
|
||||||
|
on_a_and_b: str
|
||||||
|
|
||||||
|
class B:
|
||||||
|
only_on_b: float
|
||||||
|
on_a_and_b: str
|
||||||
|
|
||||||
|
T = TypeVar('T', A, B)
|
||||||
|
|
||||||
|
def f(x: T):
|
||||||
|
x.<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
test.assert_completions_include("on_a_and_b");
|
||||||
|
test.assert_completions_do_not_include("only_on_a");
|
||||||
|
test.assert_completions_do_not_include("only_on_b");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn typevar_without_bounds_or_constraints() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
def f[T](x: T):
|
||||||
|
x.<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
test.assert_completions_include("__repr__");
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: The methods below are getting somewhat ridiculous.
|
// NOTE: The methods below are getting somewhat ridiculous.
|
||||||
// We should refactor this by converting to using a builder
|
// We should refactor this by converting to using a builder
|
||||||
// to set different modes. ---AG
|
// to set different modes. ---AG
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::types::call::{CallArguments, MatchedArgument};
|
||||||
use crate::types::signatures::Signature;
|
use crate::types::signatures::Signature;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ClassBase, ClassLiteral, DynamicType, KnownClass, KnownInstanceType, Type,
|
ClassBase, ClassLiteral, DynamicType, KnownClass, KnownInstanceType, Type,
|
||||||
class::CodeGeneratorKind,
|
TypeVarBoundOrConstraints, class::CodeGeneratorKind,
|
||||||
};
|
};
|
||||||
use crate::{Db, HasType, NameKind, SemanticModel};
|
use crate::{Db, HasType, NameKind, SemanticModel};
|
||||||
use ruff_db::files::{File, FileRange};
|
use ruff_db::files::{File, FileRange};
|
||||||
|
|
@ -177,6 +177,29 @@ impl<'db> AllMembers<'db> {
|
||||||
|
|
||||||
Type::TypeAlias(alias) => self.extend_with_type(db, alias.value_type(db)),
|
Type::TypeAlias(alias) => self.extend_with_type(db, alias.value_type(db)),
|
||||||
|
|
||||||
|
Type::TypeVar(bound_typevar) => {
|
||||||
|
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||||
|
None => {
|
||||||
|
self.extend_with_type(db, Type::object());
|
||||||
|
}
|
||||||
|
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
||||||
|
self.extend_with_type(db, bound);
|
||||||
|
}
|
||||||
|
Some(TypeVarBoundOrConstraints::Constraints(constraints)) => {
|
||||||
|
self.members.extend(
|
||||||
|
constraints
|
||||||
|
.elements(db)
|
||||||
|
.iter()
|
||||||
|
.map(|ty| AllMembers::of(db, *ty).members)
|
||||||
|
.reduce(|acc, members| {
|
||||||
|
acc.intersection(&members).cloned().collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type::IntLiteral(_)
|
Type::IntLiteral(_)
|
||||||
| Type::BooleanLiteral(_)
|
| Type::BooleanLiteral(_)
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
|
|
@ -194,7 +217,6 @@ impl<'db> AllMembers<'db> {
|
||||||
| Type::ProtocolInstance(_)
|
| Type::ProtocolInstance(_)
|
||||||
| Type::SpecialForm(_)
|
| Type::SpecialForm(_)
|
||||||
| Type::KnownInstance(_)
|
| Type::KnownInstance(_)
|
||||||
| Type::TypeVar(_)
|
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeIs(_) => match ty.to_meta_type(db) {
|
| Type::TypeIs(_) => match ty.to_meta_type(db) {
|
||||||
Type::ClassLiteral(class_literal) => {
|
Type::ClassLiteral(class_literal) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue