Compare commits
2 Commits
ag/auto-im
...
dcreager/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9964f4eee6 | ||
|
|
46c936cc72 |
@@ -1438,7 +1438,7 @@ impl<'db> CallableBinding<'db> {
|
||||
// TODO: For an unannotated `self` / `cls` parameter, the type should be
|
||||
// `typing.Self` / `type[typing.Self]`
|
||||
let current_parameter_type = overload.signature.parameters()[*parameter_index]
|
||||
.annotated_type()
|
||||
.annotated_type(db)
|
||||
.unwrap_or(Type::unknown());
|
||||
if let Some(first_parameter_type) = first_parameter_type {
|
||||
if !first_parameter_type.is_equivalent_to(db, current_parameter_type) {
|
||||
@@ -1483,7 +1483,7 @@ impl<'db> CallableBinding<'db> {
|
||||
// TODO: For an unannotated `self` / `cls` parameter, the type should be
|
||||
// `typing.Self` / `type[typing.Self]`
|
||||
let parameter_type = overload.signature.parameters()[*parameter_index]
|
||||
.annotated_type()
|
||||
.annotated_type(db)
|
||||
.unwrap_or(Type::unknown());
|
||||
current_parameter_types.push(parameter_type);
|
||||
}
|
||||
@@ -2056,7 +2056,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||
{
|
||||
for parameter_index in &self.argument_matches[argument_index].parameters {
|
||||
let parameter = ¶meters[*parameter_index];
|
||||
let Some(expected_type) = parameter.annotated_type() else {
|
||||
let Some(expected_type) = parameter.annotated_type(self.db) else {
|
||||
continue;
|
||||
};
|
||||
if let Err(error) = builder.infer(expected_type, argument_type) {
|
||||
@@ -2087,7 +2087,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||
) {
|
||||
let parameters = self.signature.parameters();
|
||||
let parameter = ¶meters[parameter_index];
|
||||
if let Some(mut expected_ty) = parameter.annotated_type() {
|
||||
if let Some(mut expected_ty) = parameter.annotated_type(self.db) {
|
||||
if let Some(specialization) = self.specialization {
|
||||
argument_type = argument_type.apply_specialization(self.db, specialization);
|
||||
expected_ty = expected_ty.apply_specialization(self.db, specialization);
|
||||
|
||||
@@ -1852,7 +1852,9 @@ impl<'db> ClassLiteral<'db> {
|
||||
overload.signature.parameters().get_positional(2)
|
||||
{
|
||||
value_types = value_types.add(
|
||||
value_param.annotated_type().unwrap_or_else(Type::unknown),
|
||||
value_param
|
||||
.annotated_type(db)
|
||||
.unwrap_or_else(Type::unknown),
|
||||
);
|
||||
} else if overload.signature.parameters().is_gradual() {
|
||||
value_types = value_types.add(Type::unknown());
|
||||
|
||||
@@ -753,18 +753,19 @@ impl Display for DisplayParameter<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
if let Some(name) = self.param.display_name() {
|
||||
f.write_str(&name)?;
|
||||
if let Some(annotated_type) = self.param.annotated_type() {
|
||||
if let Some(annotated_type) = self.param.annotated_type(self.db) {
|
||||
// TODO: display starred annotation
|
||||
write!(f, ": {}", annotated_type.display(self.db))?;
|
||||
}
|
||||
// Default value can only be specified if `name` is given.
|
||||
if let Some(default_ty) = self.param.default_type() {
|
||||
if self.param.annotated_type().is_some() {
|
||||
if self.param.annotated_type(self.db).is_some() {
|
||||
write!(f, " = {}", default_ty.display(self.db))?;
|
||||
} else {
|
||||
write!(f, "={}", default_ty.display(self.db))?;
|
||||
}
|
||||
}
|
||||
} else if let Some(ty) = self.param.annotated_type() {
|
||||
} else if let Some(ty) = self.param.annotated_type(self.db) {
|
||||
// This case is specifically for the `Callable` signature where name and default value
|
||||
// cannot be provided.
|
||||
ty.display(self.db).fmt(f)?;
|
||||
|
||||
@@ -133,7 +133,7 @@ impl<'db> GenericContext<'db> {
|
||||
// Find all of the legacy typevars mentioned in the function signature.
|
||||
let mut variables = FxOrderSet::default();
|
||||
for param in parameters {
|
||||
if let Some(ty) = param.annotated_type() {
|
||||
if let Some(ty) = param.annotated_type(db) {
|
||||
ty.find_legacy_typevars(db, &mut variables);
|
||||
}
|
||||
if let Some(ty) = param.default_type() {
|
||||
|
||||
@@ -18,6 +18,7 @@ use smallvec::{SmallVec, smallvec_inline};
|
||||
use super::{DynamicType, Type, TypeTransformer, TypeVarVariance, definition_expression_type};
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::types::generics::{GenericContext, walk_generic_context};
|
||||
use crate::types::tuple::TupleSpec;
|
||||
use crate::types::{KnownClass, TypeMapping, TypeRelation, TypeVarInstance, todo_type};
|
||||
use crate::{Db, FxOrderSet};
|
||||
use ruff_python_ast::{self as ast, name::Name};
|
||||
@@ -255,7 +256,7 @@ pub(super) fn walk_signature<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
// By default we usually don't visit the type of the default value,
|
||||
// as it isn't relevant to most things
|
||||
for parameter in &signature.parameters {
|
||||
if let Some(ty) = parameter.annotated_type() {
|
||||
if let Some(ty) = parameter.annotated_type(db) {
|
||||
visitor.visit_type(db, ty);
|
||||
}
|
||||
}
|
||||
@@ -431,7 +432,7 @@ impl<'db> Signature<'db> {
|
||||
typevars: &mut FxOrderSet<TypeVarInstance<'db>>,
|
||||
) {
|
||||
for param in &self.parameters {
|
||||
if let Some(ty) = param.annotated_type() {
|
||||
if let Some(ty) = param.annotated_type(db) {
|
||||
ty.find_legacy_typevars(db, typevars);
|
||||
}
|
||||
if let Some(ty) = param.default_type() {
|
||||
@@ -502,10 +503,12 @@ impl<'db> Signature<'db> {
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: self_name,
|
||||
default_type: self_default,
|
||||
..
|
||||
},
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: other_name,
|
||||
default_type: other_default,
|
||||
..
|
||||
},
|
||||
) if self_default.is_some() == other_default.is_some()
|
||||
&& self_name == other_name => {}
|
||||
@@ -516,10 +519,12 @@ impl<'db> Signature<'db> {
|
||||
ParameterKind::KeywordOnly {
|
||||
name: self_name,
|
||||
default_type: self_default,
|
||||
..
|
||||
},
|
||||
ParameterKind::KeywordOnly {
|
||||
name: other_name,
|
||||
default_type: other_default,
|
||||
..
|
||||
},
|
||||
) if self_default.is_some() == other_default.is_some()
|
||||
&& self_name == other_name => {}
|
||||
@@ -530,8 +535,8 @@ impl<'db> Signature<'db> {
|
||||
}
|
||||
|
||||
if !check_types(
|
||||
self_parameter.annotated_type(),
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(db),
|
||||
other_parameter.annotated_type(db),
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -624,14 +629,15 @@ impl<'db> Signature<'db> {
|
||||
// A gradual parameter list is a supertype of the "bottom" parameter list (*args: object,
|
||||
// **kwargs: object).
|
||||
if other.parameters.is_gradual()
|
||||
&& self
|
||||
.parameters
|
||||
.variadic()
|
||||
.is_some_and(|(_, param)| param.annotated_type().is_some_and(|ty| ty.is_object(db)))
|
||||
&& self.parameters.variadic().is_some_and(|(_, param)| {
|
||||
param.annotated_type(db).is_some_and(|ty| ty.is_object(db))
|
||||
})
|
||||
&& self
|
||||
.parameters
|
||||
.keyword_variadic()
|
||||
.is_some_and(|(_, param)| param.annotated_type().is_some_and(|ty| ty.is_object(db)))
|
||||
.is_some_and(|(_, param)| {
|
||||
param.annotated_type(db).is_some_and(|ty| ty.is_object(db))
|
||||
})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -696,14 +702,17 @@ impl<'db> Signature<'db> {
|
||||
match (self_parameter.kind(), other_parameter.kind()) {
|
||||
(
|
||||
ParameterKind::PositionalOnly {
|
||||
annotated_type: self_annotated,
|
||||
default_type: self_default,
|
||||
..
|
||||
}
|
||||
| ParameterKind::PositionalOrKeyword {
|
||||
annotated_type: self_annotated,
|
||||
default_type: self_default,
|
||||
..
|
||||
},
|
||||
ParameterKind::PositionalOnly {
|
||||
annotated_type: other_annotated,
|
||||
default_type: other_default,
|
||||
..
|
||||
},
|
||||
@@ -711,10 +720,7 @@ impl<'db> Signature<'db> {
|
||||
if self_default.is_none() && other_default.is_some() {
|
||||
return false;
|
||||
}
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(),
|
||||
) {
|
||||
if !check_types(*other_annotated, *self_annotated) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -722,11 +728,15 @@ impl<'db> Signature<'db> {
|
||||
(
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: self_name,
|
||||
annotated_type: self_annotated,
|
||||
default_type: self_default,
|
||||
..
|
||||
},
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: other_name,
|
||||
annotated_type: other_annotated,
|
||||
default_type: other_default,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
if self_name != other_name {
|
||||
@@ -736,23 +746,24 @@ impl<'db> Signature<'db> {
|
||||
if self_default.is_none() && other_default.is_some() {
|
||||
return false;
|
||||
}
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(),
|
||||
) {
|
||||
if !check_types(*other_annotated, *self_annotated) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
ParameterKind::Variadic { .. },
|
||||
ParameterKind::PositionalOnly { .. }
|
||||
| ParameterKind::PositionalOrKeyword { .. },
|
||||
ParameterKind::PositionalOnly {
|
||||
annotated_type: other_annotated,
|
||||
..
|
||||
}
|
||||
| ParameterKind::PositionalOrKeyword {
|
||||
annotated_type: other_annotated,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(),
|
||||
) {
|
||||
let self_annotated = self_parameter.annotated_type(db);
|
||||
if !check_types(*other_annotated, self_annotated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -789,10 +800,8 @@ impl<'db> Signature<'db> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(),
|
||||
) {
|
||||
if !check_types(other_parameter.annotated_type(db), self_annotated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
parameters.next_other();
|
||||
@@ -801,8 +810,8 @@ impl<'db> Signature<'db> {
|
||||
|
||||
(ParameterKind::Variadic { .. }, ParameterKind::Variadic { .. }) => {
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(),
|
||||
other_parameter.annotated_type(db),
|
||||
self_parameter.annotated_type(db),
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -845,8 +854,8 @@ impl<'db> Signature<'db> {
|
||||
| ParameterKind::PositionalOrKeyword { name, .. } => {
|
||||
self_keywords.insert(name.clone(), self_parameter);
|
||||
}
|
||||
ParameterKind::KeywordVariadic { .. } => {
|
||||
self_keyword_variadic = Some(self_parameter.annotated_type());
|
||||
ParameterKind::KeywordVariadic { annotated_type, .. } => {
|
||||
self_keyword_variadic = Some(*annotated_type);
|
||||
}
|
||||
ParameterKind::PositionalOnly { .. } => {
|
||||
// These are the unmatched positional-only parameters in `self` from the
|
||||
@@ -863,29 +872,32 @@ impl<'db> Signature<'db> {
|
||||
match other_parameter.kind() {
|
||||
ParameterKind::KeywordOnly {
|
||||
name: other_name,
|
||||
annotated_type: other_annotated,
|
||||
default_type: other_default,
|
||||
..
|
||||
}
|
||||
| ParameterKind::PositionalOrKeyword {
|
||||
name: other_name,
|
||||
annotated_type: other_annotated,
|
||||
default_type: other_default,
|
||||
..
|
||||
} => {
|
||||
if let Some(self_parameter) = self_keywords.remove(other_name) {
|
||||
match self_parameter.kind() {
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
annotated_type: self_annotated,
|
||||
default_type: self_default,
|
||||
..
|
||||
}
|
||||
| ParameterKind::KeywordOnly {
|
||||
annotated_type: self_annotated,
|
||||
default_type: self_default,
|
||||
..
|
||||
} => {
|
||||
if self_default.is_none() && other_default.is_some() {
|
||||
return false;
|
||||
}
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_parameter.annotated_type(),
|
||||
) {
|
||||
if !check_types(*other_annotated, *self_annotated) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -894,23 +906,23 @@ impl<'db> Signature<'db> {
|
||||
),
|
||||
}
|
||||
} else if let Some(self_keyword_variadic_type) = self_keyword_variadic {
|
||||
if !check_types(
|
||||
other_parameter.annotated_type(),
|
||||
self_keyword_variadic_type,
|
||||
) {
|
||||
if !check_types(*other_annotated, self_keyword_variadic_type) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ParameterKind::KeywordVariadic { .. } => {
|
||||
ParameterKind::KeywordVariadic {
|
||||
annotated_type: other_annotated,
|
||||
..
|
||||
} => {
|
||||
let Some(self_keyword_variadic_type) = self_keyword_variadic else {
|
||||
// For a `self <: other` relationship, if `other` has a keyword variadic
|
||||
// parameter, `self` must also have a keyword variadic parameter.
|
||||
return false;
|
||||
};
|
||||
if !check_types(other_parameter.annotated_type(), self_keyword_variadic_type) {
|
||||
if !check_types(*other_annotated, self_keyword_variadic_type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -991,11 +1003,18 @@ impl<'db> Parameters<'db> {
|
||||
pub(crate) fn new(parameters: impl IntoIterator<Item = Parameter<'db>>) -> Self {
|
||||
let value: Vec<Parameter<'db>> = parameters.into_iter().collect();
|
||||
let is_gradual = value.len() == 2
|
||||
&& value
|
||||
.iter()
|
||||
.any(|p| p.is_variadic() && p.annotated_type().is_none_or(|ty| ty.is_dynamic()))
|
||||
&& value.iter().any(|p| {
|
||||
p.is_keyword_variadic() && p.annotated_type().is_none_or(|ty| ty.is_dynamic())
|
||||
&& value.iter().any(|p| match p.kind() {
|
||||
ParameterKind::Variadic { annotated_type, .. } => annotated_type
|
||||
.as_ref()
|
||||
.and_then(|tuple| tuple.to_homogeneous().copied())
|
||||
.is_none_or(|ty| ty.is_dynamic()),
|
||||
_ => false,
|
||||
})
|
||||
&& value.iter().any(|p| match p.kind() {
|
||||
ParameterKind::KeywordVariadic { annotated_type, .. } => {
|
||||
annotated_type.is_none_or(|ty| ty.is_dynamic())
|
||||
}
|
||||
_ => false,
|
||||
});
|
||||
Self { value, is_gradual }
|
||||
}
|
||||
@@ -1101,63 +1120,53 @@ impl<'db> Parameters<'db> {
|
||||
range: _,
|
||||
node_index: _,
|
||||
} = parameters;
|
||||
let annotated_type = |param: &ast::Parameter| {
|
||||
param
|
||||
.annotation()
|
||||
.map(|annotation| definition_expression_type(db, definition, annotation))
|
||||
};
|
||||
let default_type = |param: &ast::ParameterWithDefault| {
|
||||
param
|
||||
.default()
|
||||
.map(|default| definition_expression_type(db, definition, default))
|
||||
};
|
||||
let positional_only = posonlyargs.iter().map(|arg| {
|
||||
Parameter::from_node_and_kind(
|
||||
db,
|
||||
definition,
|
||||
&arg.parameter,
|
||||
ParameterKind::PositionalOnly {
|
||||
name: Some(arg.parameter.name.id.clone()),
|
||||
default_type: default_type(arg),
|
||||
},
|
||||
)
|
||||
let positional_only = posonlyargs.iter().map(|arg| Parameter {
|
||||
kind: ParameterKind::PositionalOnly {
|
||||
name: Some(arg.parameter.name.id.clone()),
|
||||
annotated_type: annotated_type(&arg.parameter),
|
||||
default_type: default_type(arg),
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
});
|
||||
let positional_or_keyword = args.iter().map(|arg| {
|
||||
Parameter::from_node_and_kind(
|
||||
db,
|
||||
definition,
|
||||
&arg.parameter,
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: arg.parameter.name.id.clone(),
|
||||
default_type: default_type(arg),
|
||||
},
|
||||
)
|
||||
let positional_or_keyword = args.iter().map(|arg| Parameter {
|
||||
kind: ParameterKind::PositionalOrKeyword {
|
||||
name: arg.parameter.name.id.clone(),
|
||||
annotated_type: annotated_type(&arg.parameter),
|
||||
default_type: default_type(arg),
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
});
|
||||
let variadic = vararg.as_ref().map(|arg| {
|
||||
Parameter::from_node_and_kind(
|
||||
db,
|
||||
definition,
|
||||
arg,
|
||||
ParameterKind::Variadic {
|
||||
name: arg.name.id.clone(),
|
||||
},
|
||||
)
|
||||
let variadic = vararg.as_ref().map(|arg| Parameter {
|
||||
kind: ParameterKind::Variadic {
|
||||
name: arg.name.id.clone(),
|
||||
annotated_type: annotated_type(arg).map(TupleSpec::homogeneous),
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
});
|
||||
let keyword_only = kwonlyargs.iter().map(|arg| {
|
||||
Parameter::from_node_and_kind(
|
||||
db,
|
||||
definition,
|
||||
&arg.parameter,
|
||||
ParameterKind::KeywordOnly {
|
||||
name: arg.parameter.name.id.clone(),
|
||||
default_type: default_type(arg),
|
||||
},
|
||||
)
|
||||
let keyword_only = kwonlyargs.iter().map(|arg| Parameter {
|
||||
kind: ParameterKind::KeywordOnly {
|
||||
name: arg.parameter.name.id.clone(),
|
||||
annotated_type: annotated_type(&arg.parameter),
|
||||
default_type: default_type(arg),
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
});
|
||||
let keywords = kwarg.as_ref().map(|arg| {
|
||||
Parameter::from_node_and_kind(
|
||||
db,
|
||||
definition,
|
||||
arg,
|
||||
ParameterKind::KeywordVariadic {
|
||||
name: arg.name.id.clone(),
|
||||
},
|
||||
)
|
||||
let keywords = kwarg.as_ref().map(|arg| Parameter {
|
||||
kind: ParameterKind::KeywordVariadic {
|
||||
name: arg.name.id.clone(),
|
||||
annotated_type: annotated_type(arg),
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
});
|
||||
Self::new(
|
||||
positional_only
|
||||
@@ -1261,9 +1270,6 @@ impl<'db> std::ops::Index<usize> for Parameters<'db> {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct Parameter<'db> {
|
||||
/// Annotated type of the parameter.
|
||||
annotated_type: Option<Type<'db>>,
|
||||
|
||||
kind: ParameterKind<'db>,
|
||||
pub(crate) form: ParameterForm,
|
||||
}
|
||||
@@ -1271,9 +1277,9 @@ pub(crate) struct Parameter<'db> {
|
||||
impl<'db> Parameter<'db> {
|
||||
pub(crate) fn positional_only(name: Option<Name>) -> Self {
|
||||
Self {
|
||||
annotated_type: None,
|
||||
kind: ParameterKind::PositionalOnly {
|
||||
name,
|
||||
annotated_type: None,
|
||||
default_type: None,
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
@@ -1282,9 +1288,9 @@ impl<'db> Parameter<'db> {
|
||||
|
||||
pub(crate) fn positional_or_keyword(name: Name) -> Self {
|
||||
Self {
|
||||
annotated_type: None,
|
||||
kind: ParameterKind::PositionalOrKeyword {
|
||||
name,
|
||||
annotated_type: None,
|
||||
default_type: None,
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
@@ -1293,17 +1299,19 @@ impl<'db> Parameter<'db> {
|
||||
|
||||
pub(crate) fn variadic(name: Name) -> Self {
|
||||
Self {
|
||||
annotated_type: None,
|
||||
kind: ParameterKind::Variadic { name },
|
||||
kind: ParameterKind::Variadic {
|
||||
name,
|
||||
annotated_type: None,
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn keyword_only(name: Name) -> Self {
|
||||
Self {
|
||||
annotated_type: None,
|
||||
kind: ParameterKind::KeywordOnly {
|
||||
name,
|
||||
annotated_type: None,
|
||||
default_type: None,
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
@@ -1312,14 +1320,26 @@ impl<'db> Parameter<'db> {
|
||||
|
||||
pub(crate) fn keyword_variadic(name: Name) -> Self {
|
||||
Self {
|
||||
annotated_type: None,
|
||||
kind: ParameterKind::KeywordVariadic { name },
|
||||
kind: ParameterKind::KeywordVariadic {
|
||||
name,
|
||||
annotated_type: None,
|
||||
},
|
||||
form: ParameterForm::Value,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_annotated_type(mut self, annotated_type: Type<'db>) -> Self {
|
||||
self.annotated_type = Some(annotated_type);
|
||||
pub(crate) fn with_annotated_type(mut self, annotated: Type<'db>) -> Self {
|
||||
match &mut self.kind {
|
||||
ParameterKind::PositionalOnly { annotated_type, .. }
|
||||
| ParameterKind::PositionalOrKeyword { annotated_type, .. }
|
||||
| ParameterKind::KeywordOnly { annotated_type, .. }
|
||||
| ParameterKind::KeywordVariadic { annotated_type, .. } => {
|
||||
*annotated_type = Some(annotated);
|
||||
}
|
||||
ParameterKind::Variadic { annotated_type, .. } => {
|
||||
*annotated_type = Some(TupleSpec::homogeneous(annotated));
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@@ -1342,21 +1362,13 @@ impl<'db> Parameter<'db> {
|
||||
|
||||
fn materialize(&self, db: &'db dyn Db, variance: TypeVarVariance) -> Self {
|
||||
Self {
|
||||
annotated_type: Some(
|
||||
self.annotated_type
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, variance),
|
||||
),
|
||||
kind: self.kind.clone(),
|
||||
kind: self.kind.materialize(db, variance),
|
||||
form: self.form,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self {
|
||||
Self {
|
||||
annotated_type: self
|
||||
.annotated_type
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
kind: self.kind.apply_type_mapping(db, type_mapping),
|
||||
form: self.form,
|
||||
}
|
||||
@@ -1371,69 +1383,81 @@ impl<'db> Parameter<'db> {
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
let Parameter {
|
||||
annotated_type,
|
||||
kind,
|
||||
form,
|
||||
} = self;
|
||||
let Parameter { kind, form } = self;
|
||||
|
||||
// Ensure unions and intersections are ordered in the annotated type (if there is one).
|
||||
// Ensure that a parameter without an annotation is treated equivalently to a parameter
|
||||
// with a dynamic type as its annotation. (We must use `Any` here as all dynamic types
|
||||
// normalize to `Any`.)
|
||||
let annotated_type = annotated_type
|
||||
.map(|ty| ty.normalized_impl(db, visitor))
|
||||
.unwrap_or_else(Type::any);
|
||||
|
||||
// Ensure that parameter names are stripped from positional-only, variadic and keyword-variadic parameters.
|
||||
// Ensure that we only record whether a parameter *has* a default
|
||||
// (strip the precise *type* of the default from the parameter, replacing it with `Never`).
|
||||
let kind = match kind {
|
||||
ParameterKind::PositionalOnly {
|
||||
name: _,
|
||||
annotated_type,
|
||||
default_type,
|
||||
} => ParameterKind::PositionalOnly {
|
||||
name: None,
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.map(|ty| ty.normalized_impl(db, visitor))
|
||||
.unwrap_or_else(Type::any),
|
||||
),
|
||||
default_type: default_type.map(|_| Type::Never),
|
||||
},
|
||||
ParameterKind::PositionalOrKeyword { name, default_type } => {
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: name.clone(),
|
||||
default_type: default_type.map(|_| Type::Never),
|
||||
}
|
||||
}
|
||||
ParameterKind::KeywordOnly { name, default_type } => ParameterKind::KeywordOnly {
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name,
|
||||
annotated_type,
|
||||
default_type,
|
||||
} => ParameterKind::PositionalOrKeyword {
|
||||
name: name.clone(),
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.map(|ty| ty.normalized_impl(db, visitor))
|
||||
.unwrap_or_else(Type::any),
|
||||
),
|
||||
default_type: default_type.map(|_| Type::Never),
|
||||
},
|
||||
ParameterKind::Variadic { name: _ } => ParameterKind::Variadic {
|
||||
name: Name::new_static("args"),
|
||||
ParameterKind::KeywordOnly {
|
||||
name,
|
||||
annotated_type,
|
||||
default_type,
|
||||
} => ParameterKind::KeywordOnly {
|
||||
name: name.clone(),
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.map(|ty| ty.normalized_impl(db, visitor))
|
||||
.unwrap_or_else(Type::any),
|
||||
),
|
||||
default_type: default_type.map(|_| Type::Never),
|
||||
},
|
||||
ParameterKind::KeywordVariadic { name: _ } => ParameterKind::KeywordVariadic {
|
||||
ParameterKind::Variadic {
|
||||
name: _,
|
||||
annotated_type,
|
||||
} => ParameterKind::Variadic {
|
||||
name: Name::new_static("args"),
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.as_ref()
|
||||
.map(|tuple| tuple.normalized_impl(db, visitor))
|
||||
.unwrap_or_else(|| TupleSpec::homogeneous(Type::any())),
|
||||
),
|
||||
},
|
||||
ParameterKind::KeywordVariadic {
|
||||
name: _,
|
||||
annotated_type,
|
||||
} => ParameterKind::KeywordVariadic {
|
||||
name: Name::new_static("kwargs"),
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.map(|ty| ty.normalized_impl(db, visitor))
|
||||
.unwrap_or_else(Type::any),
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
Self {
|
||||
annotated_type: Some(annotated_type),
|
||||
kind,
|
||||
form: *form,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_node_and_kind(
|
||||
db: &'db dyn Db,
|
||||
definition: Definition<'db>,
|
||||
parameter: &ast::Parameter,
|
||||
kind: ParameterKind<'db>,
|
||||
) -> Self {
|
||||
Self {
|
||||
annotated_type: parameter
|
||||
.annotation()
|
||||
.map(|annotation| definition_expression_type(db, definition, annotation)),
|
||||
kind,
|
||||
form: ParameterForm::Value,
|
||||
}
|
||||
Self { kind, form: *form }
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a keyword-only parameter.
|
||||
@@ -1478,8 +1502,16 @@ impl<'db> Parameter<'db> {
|
||||
}
|
||||
|
||||
/// Annotated type of the parameter, if annotated.
|
||||
pub(crate) fn annotated_type(&self) -> Option<Type<'db>> {
|
||||
self.annotated_type
|
||||
pub(crate) fn annotated_type(&self, db: &'db dyn Db) -> Option<Type<'db>> {
|
||||
match &self.kind {
|
||||
ParameterKind::PositionalOnly { annotated_type, .. }
|
||||
| ParameterKind::PositionalOrKeyword { annotated_type, .. }
|
||||
| ParameterKind::KeywordOnly { annotated_type, .. }
|
||||
| ParameterKind::KeywordVariadic { annotated_type, .. } => *annotated_type,
|
||||
ParameterKind::Variadic { annotated_type, .. } => annotated_type
|
||||
.as_ref()
|
||||
.map(|tuple| tuple.homogeneous_element_type(db)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Kind of the parameter.
|
||||
@@ -1492,9 +1524,9 @@ impl<'db> Parameter<'db> {
|
||||
match &self.kind {
|
||||
ParameterKind::PositionalOnly { name, .. } => name.as_ref(),
|
||||
ParameterKind::PositionalOrKeyword { name, .. } => Some(name),
|
||||
ParameterKind::Variadic { name } => Some(name),
|
||||
ParameterKind::Variadic { name, .. } => Some(name),
|
||||
ParameterKind::KeywordOnly { name, .. } => Some(name),
|
||||
ParameterKind::KeywordVariadic { name } => Some(name),
|
||||
ParameterKind::KeywordVariadic { name, .. } => Some(name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1527,6 +1559,7 @@ pub(crate) enum ParameterKind<'db> {
|
||||
/// It is possible for signatures to be defined in ways that leave positional-only parameters
|
||||
/// nameless (e.g. via `Callable` annotations).
|
||||
name: Option<Name>,
|
||||
annotated_type: Option<Type<'db>>,
|
||||
default_type: Option<Type<'db>>,
|
||||
},
|
||||
|
||||
@@ -1534,6 +1567,7 @@ pub(crate) enum ParameterKind<'db> {
|
||||
PositionalOrKeyword {
|
||||
/// Parameter name.
|
||||
name: Name,
|
||||
annotated_type: Option<Type<'db>>,
|
||||
default_type: Option<Type<'db>>,
|
||||
},
|
||||
|
||||
@@ -1541,12 +1575,14 @@ pub(crate) enum ParameterKind<'db> {
|
||||
Variadic {
|
||||
/// Parameter name.
|
||||
name: Name,
|
||||
annotated_type: Option<TupleSpec<'db>>,
|
||||
},
|
||||
|
||||
/// Keyword-only parameter, e.g. `def f(*, x): ...`
|
||||
KeywordOnly {
|
||||
/// Parameter name.
|
||||
name: Name,
|
||||
annotated_type: Option<Type<'db>>,
|
||||
default_type: Option<Type<'db>>,
|
||||
},
|
||||
|
||||
@@ -1554,31 +1590,137 @@ pub(crate) enum ParameterKind<'db> {
|
||||
KeywordVariadic {
|
||||
/// Parameter name.
|
||||
name: Name,
|
||||
annotated_type: Option<Type<'db>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'db> ParameterKind<'db> {
|
||||
fn materialize(&self, db: &'db dyn Db, variance: TypeVarVariance) -> Self {
|
||||
match self {
|
||||
Self::PositionalOnly {
|
||||
annotated_type,
|
||||
default_type,
|
||||
name,
|
||||
} => Self::PositionalOnly {
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, variance),
|
||||
),
|
||||
default_type: *default_type,
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::PositionalOrKeyword {
|
||||
annotated_type,
|
||||
default_type,
|
||||
name,
|
||||
} => Self::PositionalOrKeyword {
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, variance),
|
||||
),
|
||||
default_type: *default_type,
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::KeywordOnly {
|
||||
annotated_type,
|
||||
default_type,
|
||||
name,
|
||||
} => Self::KeywordOnly {
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, variance),
|
||||
),
|
||||
default_type: *default_type,
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::Variadic {
|
||||
annotated_type,
|
||||
name,
|
||||
} => Self::Variadic {
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.as_ref()
|
||||
.map(|tuple| tuple.materialize(db, variance))
|
||||
.unwrap_or_else(|| TupleSpec::homogeneous(Type::unknown())),
|
||||
),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::KeywordVariadic {
|
||||
annotated_type,
|
||||
name,
|
||||
} => Self::KeywordVariadic {
|
||||
annotated_type: Some(
|
||||
annotated_type
|
||||
.unwrap_or(Type::unknown())
|
||||
.materialize(db, variance),
|
||||
),
|
||||
name: name.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self {
|
||||
match self {
|
||||
Self::PositionalOnly { default_type, name } => Self::PositionalOnly {
|
||||
Self::PositionalOnly {
|
||||
annotated_type,
|
||||
default_type,
|
||||
name,
|
||||
} => Self::PositionalOnly {
|
||||
annotated_type: annotated_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
default_type: default_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::PositionalOrKeyword { default_type, name } => Self::PositionalOrKeyword {
|
||||
Self::PositionalOrKeyword {
|
||||
annotated_type,
|
||||
default_type,
|
||||
name,
|
||||
} => Self::PositionalOrKeyword {
|
||||
annotated_type: annotated_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
default_type: default_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::KeywordOnly { default_type, name } => Self::KeywordOnly {
|
||||
Self::KeywordOnly {
|
||||
annotated_type,
|
||||
default_type,
|
||||
name,
|
||||
} => Self::KeywordOnly {
|
||||
annotated_type: annotated_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
default_type: default_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::Variadic { .. } | Self::KeywordVariadic { .. } => self.clone(),
|
||||
Self::Variadic {
|
||||
annotated_type,
|
||||
name,
|
||||
} => Self::Variadic {
|
||||
annotated_type: annotated_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::KeywordVariadic {
|
||||
annotated_type,
|
||||
name,
|
||||
} => Self::KeywordVariadic {
|
||||
annotated_type: annotated_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1702,8 +1844,12 @@ mod tests {
|
||||
|
||||
let [
|
||||
Parameter {
|
||||
annotated_type,
|
||||
kind: ParameterKind::PositionalOrKeyword { name, .. },
|
||||
kind:
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name,
|
||||
annotated_type,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
] = &sig.parameters.value[..]
|
||||
@@ -1740,8 +1886,12 @@ mod tests {
|
||||
|
||||
let [
|
||||
Parameter {
|
||||
annotated_type,
|
||||
kind: ParameterKind::PositionalOrKeyword { name, .. },
|
||||
kind:
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name,
|
||||
annotated_type,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
] = &sig.parameters.value[..]
|
||||
@@ -1778,13 +1928,21 @@ mod tests {
|
||||
|
||||
let [
|
||||
Parameter {
|
||||
annotated_type: a_annotated_ty,
|
||||
kind: ParameterKind::PositionalOrKeyword { name: a_name, .. },
|
||||
kind:
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: a_name,
|
||||
annotated_type: a_annotated_ty,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
Parameter {
|
||||
annotated_type: b_annotated_ty,
|
||||
kind: ParameterKind::PositionalOrKeyword { name: b_name, .. },
|
||||
kind:
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: b_name,
|
||||
annotated_type: b_annotated_ty,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
] = &sig.parameters.value[..]
|
||||
@@ -1826,13 +1984,21 @@ mod tests {
|
||||
|
||||
let [
|
||||
Parameter {
|
||||
annotated_type: a_annotated_ty,
|
||||
kind: ParameterKind::PositionalOrKeyword { name: a_name, .. },
|
||||
kind:
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: a_name,
|
||||
annotated_type: a_annotated_ty,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
Parameter {
|
||||
annotated_type: b_annotated_ty,
|
||||
kind: ParameterKind::PositionalOrKeyword { name: b_name, .. },
|
||||
kind:
|
||||
ParameterKind::PositionalOrKeyword {
|
||||
name: b_name,
|
||||
annotated_type: b_annotated_ty,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
] = &sig.parameters.value[..]
|
||||
|
||||
@@ -300,7 +300,7 @@ pub(crate) type TupleSpec<'db> = Tuple<Type<'db>>;
|
||||
///
|
||||
/// Our tuple representation can hold instances of any Rust type. For tuples containing Python
|
||||
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub struct FixedLengthTuple<T>(Vec<T>);
|
||||
|
||||
impl<T> FixedLengthTuple<T> {
|
||||
@@ -517,7 +517,7 @@ impl<'db> PySlice<'db> for FixedLengthTuple<Type<'db>> {
|
||||
///
|
||||
/// Our tuple representation can hold instances of any Rust type. For tuples containing Python
|
||||
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub struct VariableLengthTuple<T> {
|
||||
pub(crate) prefix: Vec<T>,
|
||||
pub(crate) variable: T,
|
||||
@@ -959,7 +959,7 @@ impl<'db> PyIndex<'db> for &VariableLengthTuple<Type<'db>> {
|
||||
///
|
||||
/// Our tuple representation can hold instances of any Rust type. For tuples containing Python
|
||||
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub enum Tuple<T> {
|
||||
Fixed(FixedLengthTuple<T>),
|
||||
Variable(VariableLengthTuple<T>),
|
||||
@@ -986,6 +986,15 @@ impl<T> Tuple<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_homogeneous(&self) -> Option<&T> {
|
||||
match self {
|
||||
Tuple::Variable(tuple) if tuple.prefix.is_empty() && tuple.suffix.is_empty() => {
|
||||
Some(&tuple.variable)
|
||||
}
|
||||
Tuple::Variable(_) | Tuple::Fixed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of all of the element types of this tuple. Does not deduplicate the
|
||||
/// elements, and does not distinguish between fixed- and variable-length elements.
|
||||
pub(crate) fn all_elements(&self) -> impl Iterator<Item = &T> + '_ {
|
||||
|
||||
Reference in New Issue
Block a user