Compare commits
3 Commits
dhruv/para
...
dcreager/e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3782ccf028 | ||
|
|
5945ca6fce | ||
|
|
b5456c9395 |
@@ -420,17 +420,30 @@ the typevars of the enclosing generic class, and introduce new (distinct) typeva
|
||||
scope for the method.
|
||||
|
||||
```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: U) -> U:
|
||||
def method(self, u: int) -> int:
|
||||
return u
|
||||
|
||||
def generic_method(self, t: T, u: U) -> U:
|
||||
return u
|
||||
|
||||
reveal_type(generic_context(C)) # revealed: tuple[T]
|
||||
reveal_type(generic_context(C.method)) # revealed: None
|
||||
# TODO: revealed: tuple[U]
|
||||
reveal_type(generic_context(C.generic_method)) # revealed: tuple[T, U]
|
||||
reveal_type(generic_context(C[int])) # revealed: None
|
||||
reveal_type(generic_context(C[int].method)) # revealed: None
|
||||
# TODO: revealed: tuple[U]
|
||||
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[T, U]
|
||||
|
||||
c: C[int] = C[int]()
|
||||
reveal_type(c.method("string")) # revealed: Literal["string"]
|
||||
reveal_type(c.generic_method(1, "string")) # revealed: Literal["string"]
|
||||
```
|
||||
|
||||
## Specializations propagate
|
||||
|
||||
@@ -345,8 +345,13 @@ the typevars of the enclosing generic class, and introduce new (distinct) typeva
|
||||
scope for the method.
|
||||
|
||||
```py
|
||||
from ty_extensions import generic_context
|
||||
|
||||
class C[T]:
|
||||
def method[U](self, u: U) -> U:
|
||||
def method(self, u: int) -> int:
|
||||
return u
|
||||
|
||||
def generic_method[U](self, t: T, u: U) -> U:
|
||||
return u
|
||||
# error: [unresolved-reference]
|
||||
def cannot_use_outside_of_method(self, u: U): ...
|
||||
@@ -354,8 +359,15 @@ class C[T]:
|
||||
# TODO: error
|
||||
def cannot_shadow_class_typevar[T](self, t: T): ...
|
||||
|
||||
reveal_type(generic_context(C)) # revealed: tuple[T]
|
||||
reveal_type(generic_context(C.method)) # revealed: None
|
||||
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U]
|
||||
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]
|
||||
|
||||
c: C[int] = C[int]()
|
||||
reveal_type(c.method("string")) # revealed: Literal["string"]
|
||||
reveal_type(c.generic_method(1, "string")) # revealed: Literal["string"]
|
||||
```
|
||||
|
||||
## Specializations propagate
|
||||
|
||||
@@ -6867,6 +6867,10 @@ impl<'db> FunctionType<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn non_overloaded_signature(self, db: &'db dyn Db) -> Signature<'db> {
|
||||
self.internal_signature(db, self.inherited_generic_context(db))
|
||||
}
|
||||
|
||||
/// Typed internally-visible signature for this function.
|
||||
///
|
||||
/// This represents the annotations on the function itself, unmodified by decorators and
|
||||
|
||||
@@ -591,16 +591,28 @@ impl<'db> Bindings<'db> {
|
||||
// TODO: Handle generic functions, and unions/intersections of
|
||||
// generic types
|
||||
overload.set_return_type(match ty {
|
||||
Type::ClassLiteral(class) => match class.generic_context(db) {
|
||||
Some(generic_context) => TupleType::from_elements(
|
||||
Type::ClassLiteral(class) => (class.generic_context(db))
|
||||
.map(|generic_context| generic_context.as_tuple(db))
|
||||
.unwrap_or(Type::none(db)),
|
||||
|
||||
Type::FunctionLiteral(function) => {
|
||||
let union = UnionType::from_elements(
|
||||
db,
|
||||
generic_context
|
||||
.variables(db)
|
||||
function
|
||||
.signature(db)
|
||||
.overloads
|
||||
.iter()
|
||||
.map(|typevar| Type::TypeVar(*typevar)),
|
||||
),
|
||||
None => Type::none(db),
|
||||
},
|
||||
.filter_map(|signature| signature.generic_context)
|
||||
.map(|generic_context| {
|
||||
generic_context.as_tuple(db)
|
||||
}),
|
||||
);
|
||||
if union.is_never() {
|
||||
Type::none(db)
|
||||
} else {
|
||||
union
|
||||
}
|
||||
}
|
||||
|
||||
_ => Type::none(db),
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::types::class_base::ClassBase;
|
||||
use crate::types::instance::{NominalInstanceType, Protocol, ProtocolInstanceType};
|
||||
use crate::types::signatures::{Parameter, Parameters, Signature};
|
||||
use crate::types::{
|
||||
KnownInstanceType, Type, TypeMapping, TypeVarBoundOrConstraints, TypeVarInstance,
|
||||
KnownInstanceType, TupleType, Type, TypeMapping, TypeVarBoundOrConstraints, TypeVarInstance,
|
||||
TypeVarVariance, UnionType, declaration_type, todo_type,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
@@ -105,6 +105,15 @@ impl<'db> GenericContext<'db> {
|
||||
Some(Self::new(db, variables, GenericContextOrigin::Inherited))
|
||||
}
|
||||
|
||||
pub(crate) fn is_legacy(self, db: &'db dyn Db) -> bool {
|
||||
matches!(
|
||||
self.origin(db),
|
||||
GenericContextOrigin::LegacyBase(_)
|
||||
| GenericContextOrigin::Inherited
|
||||
| GenericContextOrigin::LegacyGenericFunction
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn len(self, db: &'db dyn Db) -> usize {
|
||||
self.variables(db).len()
|
||||
}
|
||||
@@ -171,6 +180,16 @@ impl<'db> GenericContext<'db> {
|
||||
self.specialize(db, types.into())
|
||||
}
|
||||
|
||||
/// Returns a tuple type of the typevars introduced by this generic context.
|
||||
pub(crate) fn as_tuple(self, db: &'db dyn Db) -> Type<'db> {
|
||||
TupleType::from_elements(
|
||||
db,
|
||||
self.variables(db)
|
||||
.iter()
|
||||
.map(|typevar| Type::TypeVar(*typevar)),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn is_subset_of(self, db: &'db dyn Db, other: GenericContext<'db>) -> bool {
|
||||
self.variables(db).is_subset(other.variables(db))
|
||||
}
|
||||
|
||||
@@ -355,6 +355,42 @@ pub(crate) fn enclosing_class_symbol<'db>(
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns in iterator of any generic context introduced by the given scope or any enclosing
|
||||
/// scope.
|
||||
pub(crate) fn enclosing_generic_contexts<'db>(
|
||||
db: &'db dyn Db,
|
||||
index: &SemanticIndex<'db>,
|
||||
scope: ScopeId,
|
||||
) -> impl Iterator<Item = GenericContext<'db>> {
|
||||
index
|
||||
.ancestor_scopes(scope.file_scope_id(db))
|
||||
.filter_map(|(_, ancestor_scope)| match ancestor_scope.node() {
|
||||
NodeWithScopeKind::Class(class) => {
|
||||
binding_type(db, index.expect_single_definition(class.node()))
|
||||
.into_class_literal()?
|
||||
.generic_context(db)
|
||||
}
|
||||
NodeWithScopeKind::Function(function) => {
|
||||
binding_type(db, index.expect_single_definition(function.node()))
|
||||
.into_function_literal()?
|
||||
.non_overloaded_signature(db)
|
||||
.generic_context
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the legacy typevars that have been bound in the given scope or any enclosing scope.
|
||||
pub(crate) fn bound_legacy_typevars<'db>(
|
||||
db: &'db dyn Db,
|
||||
index: &'db SemanticIndex<'db>,
|
||||
scope: ScopeId,
|
||||
) -> impl Iterator<Item = TypeVarInstance<'db>> {
|
||||
enclosing_generic_contexts(db, index, scope)
|
||||
.filter(|generic_context| generic_context.is_legacy(db))
|
||||
.flat_map(|generic_context| generic_context.variables(db).iter().copied())
|
||||
}
|
||||
|
||||
/// A region within which we can infer types.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum InferenceRegion<'db> {
|
||||
@@ -4233,7 +4269,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
}
|
||||
|
||||
fn infer_expression_impl(&mut self, expression: &ast::Expr) -> Type<'db> {
|
||||
let ty = match expression {
|
||||
let mut ty = match expression {
|
||||
ast::Expr::NoneLiteral(ast::ExprNoneLiteral { range: _ }) => Type::none(self.db()),
|
||||
ast::Expr::NumberLiteral(literal) => self.infer_number_literal_expression(literal),
|
||||
ast::Expr::BooleanLiteral(literal) => self.infer_boolean_literal_expression(literal),
|
||||
@@ -4274,6 +4310,12 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
}
|
||||
};
|
||||
|
||||
// If the expression resolves to a legacy typevar, we will have the TypeVarInstance that
|
||||
// was created when the typevar was created, which will not have an associated definition.
|
||||
// Walk the enclosing scopes, looking for the nearest generic context that binds the
|
||||
// typevar.
|
||||
if let Type::TypeVar(typevar) = f
|
||||
|
||||
self.store_expression_type(expression, ty);
|
||||
|
||||
ty
|
||||
|
||||
Reference in New Issue
Block a user