mirror of https://github.com/astral-sh/ruff
Update mdtests
This commit is contained in:
parent
178f48fc0b
commit
0b19caedec
|
|
@ -253,4 +253,23 @@ reveal_type(D().instance_method)
|
|||
reveal_type(D.class_method)
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```py
|
||||
from ty_extensions import generic_context
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
U = TypeVar("U")
|
||||
|
||||
class C(Generic[T]):
|
||||
def method(self, u: int) -> int:
|
||||
return u
|
||||
|
||||
def generic_method(self, t: T, u: U) -> U:
|
||||
return u
|
||||
|
||||
reveal_type(generic_context(C.method)) # revealed: tuple[Self@method]
|
||||
```
|
||||
|
||||
[self attribute]: https://typing.python.org/en/latest/spec/generics.html#use-in-attribute-annotations
|
||||
|
|
|
|||
|
|
@ -69,9 +69,7 @@ reveal_type(bound_method(1)) # revealed: str
|
|||
When we call the function object itself, we need to pass the `instance` explicitly:
|
||||
|
||||
```py
|
||||
# error: [invalid-argument-type]
|
||||
# error: [missing-argument]
|
||||
C.f(1)
|
||||
C.f(1) # error: [missing-argument]
|
||||
|
||||
reveal_type(C.f(C(), 1)) # revealed: str
|
||||
```
|
||||
|
|
|
|||
|
|
@ -562,17 +562,17 @@ class C(Generic[T]):
|
|||
return u
|
||||
|
||||
reveal_type(generic_context(C)) # revealed: tuple[T@C]
|
||||
reveal_type(generic_context(C.method)) # revealed: None
|
||||
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U@generic_method]
|
||||
reveal_type(generic_context(C.method)) # revealed: tuple[Self@method]
|
||||
reveal_type(generic_context(C.generic_method)) # revealed: tuple[Self@generic_method, U@generic_method]
|
||||
reveal_type(generic_context(C[int])) # revealed: None
|
||||
reveal_type(generic_context(C[int].method)) # revealed: None
|
||||
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[U@generic_method]
|
||||
reveal_type(generic_context(C[int].method)) # revealed: tuple[Self@method]
|
||||
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[Self@generic_method, U@generic_method]
|
||||
|
||||
c: C[int] = C[int]()
|
||||
reveal_type(c.generic_method(1, "string")) # revealed: Literal["string"]
|
||||
reveal_type(generic_context(c)) # revealed: None
|
||||
reveal_type(generic_context(c.method)) # revealed: None
|
||||
reveal_type(generic_context(c.generic_method)) # revealed: tuple[U@generic_method]
|
||||
reveal_type(generic_context(c.method)) # revealed: tuple[Self@method]
|
||||
reveal_type(generic_context(c.generic_method)) # revealed: tuple[Self@generic_method, U@generic_method]
|
||||
```
|
||||
|
||||
## Specializations propagate
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ class C[T]:
|
|||
|
||||
def __init__[S](self, x: T, y: S) -> None: ...
|
||||
|
||||
# TODO: need to handle self in __init__ call.
|
||||
reveal_type(C(1, 1)) # revealed: C[int]
|
||||
reveal_type(C(1, "string")) # revealed: C[int]
|
||||
reveal_type(C(1, True)) # revealed: C[int]
|
||||
|
|
@ -511,16 +512,16 @@ class C[T]:
|
|||
def cannot_shadow_class_typevar[T](self, t: T): ...
|
||||
|
||||
reveal_type(generic_context(C)) # revealed: tuple[T@C]
|
||||
reveal_type(generic_context(C.method)) # revealed: None
|
||||
reveal_type(generic_context(C.method)) # revealed: tuple[Self@method]
|
||||
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U@generic_method]
|
||||
reveal_type(generic_context(C[int])) # revealed: None
|
||||
reveal_type(generic_context(C[int].method)) # revealed: None
|
||||
reveal_type(generic_context(C[int].method)) # revealed: tuple[Self@method]
|
||||
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[U@generic_method]
|
||||
|
||||
c: C[int] = C[int]()
|
||||
reveal_type(c.generic_method(1, "string")) # revealed: Literal["string"]
|
||||
reveal_type(generic_context(c)) # revealed: None
|
||||
reveal_type(generic_context(c.method)) # revealed: None
|
||||
reveal_type(generic_context(c.method)) # revealed: tuple[Self@method]
|
||||
reveal_type(generic_context(c.generic_method)) # revealed: tuple[U@generic_method]
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ from ty_extensions import generic_context
|
|||
legacy.m("string", None) # error: [invalid-argument-type]
|
||||
reveal_type(legacy.m) # revealed: bound method Legacy[int].m[S](x: int, y: S@m) -> S@m
|
||||
reveal_type(generic_context(Legacy)) # revealed: tuple[T@Legacy]
|
||||
reveal_type(generic_context(legacy.m)) # revealed: tuple[S@m]
|
||||
reveal_type(generic_context(legacy.m)) # revealed: tuple[Self@m, S@m]
|
||||
```
|
||||
|
||||
With PEP 695 syntax, it is clearer that the method uses a separate typevar:
|
||||
|
|
@ -165,6 +165,10 @@ class C[T]:
|
|||
return y
|
||||
|
||||
c: C[int] = C()
|
||||
reveal_type(c) # revealed: C[Unknown]
|
||||
# reveal_type(c) # revealed: C[Unknown]
|
||||
# TODO: Next line fails. The reason is the reveal type above
|
||||
# error: 13 [invalid-argument-type] "Argument to bound method `m` is incorrect: Expected `Self@m`, found `C[Unknown]`"
|
||||
reveal_type(c.m(1, "string")) # revealed: Literal["string"]
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -13,42 +13,41 @@
|
|||
use std::{collections::HashMap, slice::Iter};
|
||||
|
||||
use itertools::EitherOrBoth;
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use smallvec::{SmallVec, smallvec_inline};
|
||||
|
||||
use super::TypeVarVariance;
|
||||
use super::{
|
||||
DynamicType, Type, definition_expression_type, infer_definition_types, semantic_index,
|
||||
DynamicType, Type, TypeVarVariance, definition_expression_type, infer_definition_types,
|
||||
semantic_index,
|
||||
};
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::semantic_index::definition::{Definition, DefinitionKind};
|
||||
use crate::types::constraints::{ConstraintSet, Constraints, IteratorConstraintsExtension};
|
||||
use crate::types::function::FunctionType;
|
||||
use crate::types::generics::GenericContext;
|
||||
use crate::types::generics::walk_generic_context;
|
||||
use crate::types::generics::{GenericContext, walk_generic_context};
|
||||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, FindLegacyTypeVarsVisitor,
|
||||
HasRelationToVisitor, IsEquivalentVisitor, KnownClass, MaterializationKind, NormalizedVisitor,
|
||||
SpecialFormType, TypeMapping, TypeRelation, VarianceInferable, todo_type,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_python_ast::{self as ast, name::Name};
|
||||
|
||||
fn infer_method_type<'db>(
|
||||
db: &'db dyn Db,
|
||||
definition: Definition<'db>,
|
||||
) -> Option<FunctionType<'db>> {
|
||||
let scope_id = definition.scope(db);
|
||||
let file = scope_id.file(db);
|
||||
let class_scope_id = definition.scope(db);
|
||||
let file = class_scope_id.file(db);
|
||||
let index = semantic_index(db, file);
|
||||
let module = parsed_module(db, file).load(db);
|
||||
|
||||
let method_scope = index.scope(scope_id.file_scope_id(db));
|
||||
let method = method_scope.node().as_function(&module)?;
|
||||
let parent_scope_id = method_scope.parent()?;
|
||||
let parent_scope = index.scope(parent_scope_id);
|
||||
parent_scope.node().as_class(&module)?;
|
||||
let DefinitionKind::Function(func_def) = definition.kind(db) else {
|
||||
return None;
|
||||
};
|
||||
let class_scope = index.scope(class_scope_id.file_scope_id(db));
|
||||
class_scope.node().as_class(&module)?;
|
||||
|
||||
let method_definition = index.expect_single_definition(method);
|
||||
let method_definition = index.expect_single_definition(func_def.node(&module));
|
||||
let func_type = infer_definition_types(db, method_definition)
|
||||
.declaration_type(method_definition)
|
||||
.inner_type()
|
||||
|
|
@ -384,6 +383,7 @@ impl<'db> Signature<'db> {
|
|||
) -> Self {
|
||||
let parameters =
|
||||
Parameters::from_parameters(db, definition, function_node.parameters.as_ref());
|
||||
|
||||
let return_ty = function_node.returns.as_ref().map(|returns| {
|
||||
let plain_return_ty = definition_expression_type(db, definition, returns.as_ref())
|
||||
.apply_type_mapping(
|
||||
|
|
@ -1194,17 +1194,30 @@ impl<'db> Parameters<'db> {
|
|||
},
|
||||
)
|
||||
});
|
||||
|
||||
let method_type = infer_method_type(db, definition);
|
||||
let is_method = method_type.is_some();
|
||||
let is_classmethod = method_type.is_some_and(|f| f.is_classmethod(db));
|
||||
let is_staticmethod = method_type.is_some_and(|f| f.is_staticmethod(db));
|
||||
|
||||
let positional_or_keyword = args.iter().map(|arg| {
|
||||
// TODO(https://github.com/astral-sh/ty/issues/159): Also set the type for `cls` argument
|
||||
if !is_staticmethod
|
||||
// eprintln!(
|
||||
// "arg {}: pos: {:?}, is_static: {}, is_class: {}, anno: {:?}",
|
||||
// arg.name().id.as_str(),
|
||||
// parameters.index(arg.name().id()),
|
||||
// is_staticmethod,
|
||||
// is_classmethod,
|
||||
// arg.parameter.annotation()
|
||||
// );
|
||||
// dbg!(is_method);
|
||||
if is_method
|
||||
&& !is_staticmethod
|
||||
&& !is_classmethod
|
||||
&& arg.parameter.annotation().is_none()
|
||||
&& parameters.index(arg.name().id()) == Some(0)
|
||||
{
|
||||
eprintln!("arg {} is self", arg.name().id.as_str());
|
||||
let implicit_annotation = Type::SpecialForm(SpecialFormType::TypingSelf)
|
||||
.in_type_expression(db, definition.scope(db), Some(definition))
|
||||
.ok();
|
||||
|
|
@ -1218,6 +1231,7 @@ impl<'db> Parameters<'db> {
|
|||
form: ParameterForm::Value,
|
||||
}
|
||||
} else {
|
||||
eprintln!("arg {} is not self", arg.name().id.as_str());
|
||||
Parameter::from_node_and_kind(
|
||||
db,
|
||||
definition,
|
||||
|
|
|
|||
Loading…
Reference in New Issue