mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-01 12:25:45 +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>");
|
||||
}
|
||||
|
||||
#[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.
|
||||
// We should refactor this by converting to using a builder
|
||||
// to set different modes. ---AG
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use crate::types::call::{CallArguments, MatchedArgument};
|
|||
use crate::types::signatures::Signature;
|
||||
use crate::types::{
|
||||
ClassBase, ClassLiteral, DynamicType, KnownClass, KnownInstanceType, Type,
|
||||
class::CodeGeneratorKind,
|
||||
TypeVarBoundOrConstraints, class::CodeGeneratorKind,
|
||||
};
|
||||
use crate::{Db, HasType, NameKind, SemanticModel};
|
||||
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::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::BooleanLiteral(_)
|
||||
| Type::StringLiteral(_)
|
||||
|
|
@ -194,7 +217,6 @@ impl<'db> AllMembers<'db> {
|
|||
| Type::ProtocolInstance(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::KnownInstance(_)
|
||||
| Type::TypeVar(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::TypeIs(_) => match ty.to_meta_type(db) {
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue