[red-knot] Rename *_ty functions (#15617)

## Summary

General rules:

* Change the `_ty` suffix of all functions to `_type`.
* `_type_and_qualifiers` suffixes seem too long, so we ignore the
existence of qualifiers and still speak of "types"
* Functions only have a `_type` suffix if they return either `Type`,
`Option<Type>`, or `TypeAndQualifiers`

Free functions:

* `binding_ty` => `binding_type`
* `declaration_ty` => `declaration_type`
* `definition_expression_ty` => `definition_expression_type`

Methods:

* `CallDunderResult::return_ty` => `return_type`
* `NotCallableError::return_ty` => `return_type`
* `NotCallableError::called_ty` => `called_type`
* `TypeAndQualifiers::inner_ty` => `inner_type`
* `TypeAliasType::value_ty` => `value_type`
* `TypeInference::expression_ty` => `expression_type`
* `TypeInference::try_expression_ty` => `try_expression_type`
* `TypeInference::binding_ty` => `binding_type`
* `TypeInference::declaration_ty` => `declaration_type` 
* `TypeInferenceBuilder::expression_ty` => `expression_type`
* `TypeInferenceBuilder::file_expression_ty` => `file_expression_type`
* `TypeInferenceBuilder::module_ty_from_name` => `module_type_from_name`
* `ClassBase::try_from_ty` => `try_from_type`
* `Parameter::annotated_ty` => `annotated_type`
* `Parameter::default_ty` => `default_type`
* `CallOutcome::return_ty` => `return_type`
* `CallOutcome::return_ty_result` => `return_type_result`
* `CallBinding::from_return_ty` => `from_return_type`
* `CallBinding::set_return_ty` => `set_return_type`
* `CallBinding::return_ty` => `return_type`
* `CallBinding::parameter_tys` => `parameter_types`
* `CallBinding::one_parameter_ty` => `one_parameter_type`
* `CallBinding::two_parameter_tys` => `two_parameter_types`
* `Unpacker::tuple_ty_elements` => `tuple_type_elements`
* `StringPartsCollector::ty` => `string_type`

Traits

* `HasTy` => `HasType`
* `HasTy::ty` => `inferred_type`

Test functions:

* `assert_public_ty` => `assert_public_type`
* `assert_scope_ty` => `assert_scope_type`

closes #15569

## Test Plan

—
This commit is contained in:
David Peter 2025-01-22 09:06:56 +01:00 committed by GitHub
parent 6fe404a40f
commit 792f9e357e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 334 additions and 328 deletions

View file

@ -1,6 +1,6 @@
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use red_knot_project::{ProjectDatabase, ProjectMetadata}; use red_knot_project::{ProjectDatabase, ProjectMetadata};
use red_knot_python_semantic::{HasTy, SemanticModel}; use red_knot_python_semantic::{HasType, SemanticModel};
use ruff_db::files::{system_path_to_file, File}; use ruff_db::files::{system_path_to_file, File};
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
use ruff_db::system::{SystemPath, SystemPathBuf, TestSystem}; use ruff_db::system::{SystemPath, SystemPathBuf, TestSystem};
@ -197,10 +197,10 @@ impl SourceOrderVisitor<'_> for PullTypesVisitor<'_> {
fn visit_stmt(&mut self, stmt: &Stmt) { fn visit_stmt(&mut self, stmt: &Stmt) {
match stmt { match stmt {
Stmt::FunctionDef(function) => { Stmt::FunctionDef(function) => {
let _ty = function.ty(&self.model); let _ty = function.inferred_type(&self.model);
} }
Stmt::ClassDef(class) => { Stmt::ClassDef(class) => {
let _ty = class.ty(&self.model); let _ty = class.inferred_type(&self.model);
} }
Stmt::Assign(assign) => { Stmt::Assign(assign) => {
for target in &assign.targets { for target in &assign.targets {
@ -243,25 +243,25 @@ impl SourceOrderVisitor<'_> for PullTypesVisitor<'_> {
} }
fn visit_expr(&mut self, expr: &Expr) { fn visit_expr(&mut self, expr: &Expr) {
let _ty = expr.ty(&self.model); let _ty = expr.inferred_type(&self.model);
source_order::walk_expr(self, expr); source_order::walk_expr(self, expr);
} }
fn visit_parameter(&mut self, parameter: &Parameter) { fn visit_parameter(&mut self, parameter: &Parameter) {
let _ty = parameter.ty(&self.model); let _ty = parameter.inferred_type(&self.model);
source_order::walk_parameter(self, parameter); source_order::walk_parameter(self, parameter);
} }
fn visit_parameter_with_default(&mut self, parameter_with_default: &ParameterWithDefault) { fn visit_parameter_with_default(&mut self, parameter_with_default: &ParameterWithDefault) {
let _ty = parameter_with_default.ty(&self.model); let _ty = parameter_with_default.inferred_type(&self.model);
source_order::walk_parameter_with_default(self, parameter_with_default); source_order::walk_parameter_with_default(self, parameter_with_default);
} }
fn visit_alias(&mut self, alias: &Alias) { fn visit_alias(&mut self, alias: &Alias) {
let _ty = alias.ty(&self.model); let _ty = alias.inferred_type(&self.model);
source_order::walk_alias(self, alias); source_order::walk_alias(self, alias);
} }

View file

@ -10,7 +10,7 @@ pub use module_resolver::{resolve_module, system_module_search_paths, KnownModul
pub use program::{Program, ProgramSettings, SearchPathSettings, SitePackages}; pub use program::{Program, ProgramSettings, SearchPathSettings, SitePackages};
pub use python_platform::PythonPlatform; pub use python_platform::PythonPlatform;
pub use python_version::PythonVersion; pub use python_version::PythonVersion;
pub use semantic_model::{HasTy, SemanticModel}; pub use semantic_model::{HasType, SemanticModel};
pub mod ast_node_ref; pub mod ast_node_ref;
mod db; mod db;

View file

@ -603,8 +603,8 @@ impl<'db> SemanticIndexBuilder<'db> {
let definition = self.add_definition(symbol, parameter); let definition = self.add_definition(symbol, parameter);
// Insert a mapping from the inner Parameter node to the same definition. // Insert a mapping from the inner Parameter node to the same definition. This
// This ensures that calling `HasTy::ty` on the inner parameter returns // ensures that calling `HasType::inferred_type` on the inner parameter returns
// a valid type (and doesn't panic) // a valid type (and doesn't panic)
let existing_definition = self let existing_definition = self
.definitions_by_node .definitions_by_node

View file

@ -8,7 +8,7 @@ use crate::module_name::ModuleName;
use crate::module_resolver::{resolve_module, Module}; use crate::module_resolver::{resolve_module, Module};
use crate::semantic_index::ast_ids::HasScopedExpressionId; use crate::semantic_index::ast_ids::HasScopedExpressionId;
use crate::semantic_index::semantic_index; use crate::semantic_index::semantic_index;
use crate::types::{binding_ty, infer_scope_types, Type}; use crate::types::{binding_type, infer_scope_types, Type};
use crate::Db; use crate::Db;
pub struct SemanticModel<'db> { pub struct SemanticModel<'db> {
@ -40,117 +40,117 @@ impl<'db> SemanticModel<'db> {
} }
} }
pub trait HasTy { pub trait HasType {
/// Returns the inferred type of `self`. /// Returns the inferred type of `self`.
/// ///
/// ## Panics /// ## Panics
/// May panic if `self` is from another file than `model`. /// May panic if `self` is from another file than `model`.
fn ty<'db>(&self, model: &SemanticModel<'db>) -> Type<'db>; fn inferred_type<'db>(&self, model: &SemanticModel<'db>) -> Type<'db>;
} }
impl HasTy for ast::ExprRef<'_> { impl HasType for ast::ExprRef<'_> {
fn ty<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> { fn inferred_type<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> {
let index = semantic_index(model.db, model.file); let index = semantic_index(model.db, model.file);
let file_scope = index.expression_scope_id(*self); let file_scope = index.expression_scope_id(*self);
let scope = file_scope.to_scope_id(model.db, model.file); let scope = file_scope.to_scope_id(model.db, model.file);
let expression_id = self.scoped_expression_id(model.db, scope); let expression_id = self.scoped_expression_id(model.db, scope);
infer_scope_types(model.db, scope).expression_ty(expression_id) infer_scope_types(model.db, scope).expression_type(expression_id)
} }
} }
macro_rules! impl_expression_has_ty { macro_rules! impl_expression_has_type {
($ty: ty) => { ($ty: ty) => {
impl HasTy for $ty { impl HasType for $ty {
#[inline] #[inline]
fn ty<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> { fn inferred_type<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> {
let expression_ref = ExprRef::from(self); let expression_ref = ExprRef::from(self);
expression_ref.ty(model) expression_ref.inferred_type(model)
} }
} }
}; };
} }
impl_expression_has_ty!(ast::ExprBoolOp); impl_expression_has_type!(ast::ExprBoolOp);
impl_expression_has_ty!(ast::ExprNamed); impl_expression_has_type!(ast::ExprNamed);
impl_expression_has_ty!(ast::ExprBinOp); impl_expression_has_type!(ast::ExprBinOp);
impl_expression_has_ty!(ast::ExprUnaryOp); impl_expression_has_type!(ast::ExprUnaryOp);
impl_expression_has_ty!(ast::ExprLambda); impl_expression_has_type!(ast::ExprLambda);
impl_expression_has_ty!(ast::ExprIf); impl_expression_has_type!(ast::ExprIf);
impl_expression_has_ty!(ast::ExprDict); impl_expression_has_type!(ast::ExprDict);
impl_expression_has_ty!(ast::ExprSet); impl_expression_has_type!(ast::ExprSet);
impl_expression_has_ty!(ast::ExprListComp); impl_expression_has_type!(ast::ExprListComp);
impl_expression_has_ty!(ast::ExprSetComp); impl_expression_has_type!(ast::ExprSetComp);
impl_expression_has_ty!(ast::ExprDictComp); impl_expression_has_type!(ast::ExprDictComp);
impl_expression_has_ty!(ast::ExprGenerator); impl_expression_has_type!(ast::ExprGenerator);
impl_expression_has_ty!(ast::ExprAwait); impl_expression_has_type!(ast::ExprAwait);
impl_expression_has_ty!(ast::ExprYield); impl_expression_has_type!(ast::ExprYield);
impl_expression_has_ty!(ast::ExprYieldFrom); impl_expression_has_type!(ast::ExprYieldFrom);
impl_expression_has_ty!(ast::ExprCompare); impl_expression_has_type!(ast::ExprCompare);
impl_expression_has_ty!(ast::ExprCall); impl_expression_has_type!(ast::ExprCall);
impl_expression_has_ty!(ast::ExprFString); impl_expression_has_type!(ast::ExprFString);
impl_expression_has_ty!(ast::ExprStringLiteral); impl_expression_has_type!(ast::ExprStringLiteral);
impl_expression_has_ty!(ast::ExprBytesLiteral); impl_expression_has_type!(ast::ExprBytesLiteral);
impl_expression_has_ty!(ast::ExprNumberLiteral); impl_expression_has_type!(ast::ExprNumberLiteral);
impl_expression_has_ty!(ast::ExprBooleanLiteral); impl_expression_has_type!(ast::ExprBooleanLiteral);
impl_expression_has_ty!(ast::ExprNoneLiteral); impl_expression_has_type!(ast::ExprNoneLiteral);
impl_expression_has_ty!(ast::ExprEllipsisLiteral); impl_expression_has_type!(ast::ExprEllipsisLiteral);
impl_expression_has_ty!(ast::ExprAttribute); impl_expression_has_type!(ast::ExprAttribute);
impl_expression_has_ty!(ast::ExprSubscript); impl_expression_has_type!(ast::ExprSubscript);
impl_expression_has_ty!(ast::ExprStarred); impl_expression_has_type!(ast::ExprStarred);
impl_expression_has_ty!(ast::ExprName); impl_expression_has_type!(ast::ExprName);
impl_expression_has_ty!(ast::ExprList); impl_expression_has_type!(ast::ExprList);
impl_expression_has_ty!(ast::ExprTuple); impl_expression_has_type!(ast::ExprTuple);
impl_expression_has_ty!(ast::ExprSlice); impl_expression_has_type!(ast::ExprSlice);
impl_expression_has_ty!(ast::ExprIpyEscapeCommand); impl_expression_has_type!(ast::ExprIpyEscapeCommand);
impl HasTy for ast::Expr { impl HasType for ast::Expr {
fn ty<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> { fn inferred_type<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> {
match self { match self {
Expr::BoolOp(inner) => inner.ty(model), Expr::BoolOp(inner) => inner.inferred_type(model),
Expr::Named(inner) => inner.ty(model), Expr::Named(inner) => inner.inferred_type(model),
Expr::BinOp(inner) => inner.ty(model), Expr::BinOp(inner) => inner.inferred_type(model),
Expr::UnaryOp(inner) => inner.ty(model), Expr::UnaryOp(inner) => inner.inferred_type(model),
Expr::Lambda(inner) => inner.ty(model), Expr::Lambda(inner) => inner.inferred_type(model),
Expr::If(inner) => inner.ty(model), Expr::If(inner) => inner.inferred_type(model),
Expr::Dict(inner) => inner.ty(model), Expr::Dict(inner) => inner.inferred_type(model),
Expr::Set(inner) => inner.ty(model), Expr::Set(inner) => inner.inferred_type(model),
Expr::ListComp(inner) => inner.ty(model), Expr::ListComp(inner) => inner.inferred_type(model),
Expr::SetComp(inner) => inner.ty(model), Expr::SetComp(inner) => inner.inferred_type(model),
Expr::DictComp(inner) => inner.ty(model), Expr::DictComp(inner) => inner.inferred_type(model),
Expr::Generator(inner) => inner.ty(model), Expr::Generator(inner) => inner.inferred_type(model),
Expr::Await(inner) => inner.ty(model), Expr::Await(inner) => inner.inferred_type(model),
Expr::Yield(inner) => inner.ty(model), Expr::Yield(inner) => inner.inferred_type(model),
Expr::YieldFrom(inner) => inner.ty(model), Expr::YieldFrom(inner) => inner.inferred_type(model),
Expr::Compare(inner) => inner.ty(model), Expr::Compare(inner) => inner.inferred_type(model),
Expr::Call(inner) => inner.ty(model), Expr::Call(inner) => inner.inferred_type(model),
Expr::FString(inner) => inner.ty(model), Expr::FString(inner) => inner.inferred_type(model),
Expr::StringLiteral(inner) => inner.ty(model), Expr::StringLiteral(inner) => inner.inferred_type(model),
Expr::BytesLiteral(inner) => inner.ty(model), Expr::BytesLiteral(inner) => inner.inferred_type(model),
Expr::NumberLiteral(inner) => inner.ty(model), Expr::NumberLiteral(inner) => inner.inferred_type(model),
Expr::BooleanLiteral(inner) => inner.ty(model), Expr::BooleanLiteral(inner) => inner.inferred_type(model),
Expr::NoneLiteral(inner) => inner.ty(model), Expr::NoneLiteral(inner) => inner.inferred_type(model),
Expr::EllipsisLiteral(inner) => inner.ty(model), Expr::EllipsisLiteral(inner) => inner.inferred_type(model),
Expr::Attribute(inner) => inner.ty(model), Expr::Attribute(inner) => inner.inferred_type(model),
Expr::Subscript(inner) => inner.ty(model), Expr::Subscript(inner) => inner.inferred_type(model),
Expr::Starred(inner) => inner.ty(model), Expr::Starred(inner) => inner.inferred_type(model),
Expr::Name(inner) => inner.ty(model), Expr::Name(inner) => inner.inferred_type(model),
Expr::List(inner) => inner.ty(model), Expr::List(inner) => inner.inferred_type(model),
Expr::Tuple(inner) => inner.ty(model), Expr::Tuple(inner) => inner.inferred_type(model),
Expr::Slice(inner) => inner.ty(model), Expr::Slice(inner) => inner.inferred_type(model),
Expr::IpyEscapeCommand(inner) => inner.ty(model), Expr::IpyEscapeCommand(inner) => inner.inferred_type(model),
} }
} }
} }
macro_rules! impl_binding_has_ty { macro_rules! impl_binding_has_ty {
($ty: ty) => { ($ty: ty) => {
impl HasTy for $ty { impl HasType for $ty {
#[inline] #[inline]
fn ty<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> { fn inferred_type<'db>(&self, model: &SemanticModel<'db>) -> Type<'db> {
let index = semantic_index(model.db, model.file); let index = semantic_index(model.db, model.file);
let binding = index.definition(self); let binding = index.definition(self);
binding_ty(model.db, binding) binding_type(model.db, binding)
} }
} }
}; };
@ -168,10 +168,10 @@ mod tests {
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
use crate::db::tests::TestDbBuilder; use crate::db::tests::TestDbBuilder;
use crate::{HasTy, SemanticModel}; use crate::{HasType, SemanticModel};
#[test] #[test]
fn function_ty() -> anyhow::Result<()> { fn function_type() -> anyhow::Result<()> {
let db = TestDbBuilder::new() let db = TestDbBuilder::new()
.with_file("/src/foo.py", "def test(): pass") .with_file("/src/foo.py", "def test(): pass")
.build()?; .build()?;
@ -182,7 +182,7 @@ mod tests {
let function = ast.suite()[0].as_function_def_stmt().unwrap(); let function = ast.suite()[0].as_function_def_stmt().unwrap();
let model = SemanticModel::new(&db, foo); let model = SemanticModel::new(&db, foo);
let ty = function.ty(&model); let ty = function.inferred_type(&model);
assert!(ty.is_function_literal()); assert!(ty.is_function_literal());
@ -190,7 +190,7 @@ mod tests {
} }
#[test] #[test]
fn class_ty() -> anyhow::Result<()> { fn class_type() -> anyhow::Result<()> {
let db = TestDbBuilder::new() let db = TestDbBuilder::new()
.with_file("/src/foo.py", "class Test: pass") .with_file("/src/foo.py", "class Test: pass")
.build()?; .build()?;
@ -201,7 +201,7 @@ mod tests {
let class = ast.suite()[0].as_class_def_stmt().unwrap(); let class = ast.suite()[0].as_class_def_stmt().unwrap();
let model = SemanticModel::new(&db, foo); let model = SemanticModel::new(&db, foo);
let ty = class.ty(&model); let ty = class.inferred_type(&model);
assert!(ty.is_class_literal()); assert!(ty.is_class_literal());
@ -209,7 +209,7 @@ mod tests {
} }
#[test] #[test]
fn alias_ty() -> anyhow::Result<()> { fn alias_type() -> anyhow::Result<()> {
let db = TestDbBuilder::new() let db = TestDbBuilder::new()
.with_file("/src/foo.py", "class Test: pass") .with_file("/src/foo.py", "class Test: pass")
.with_file("/src/bar.py", "from foo import Test") .with_file("/src/bar.py", "from foo import Test")
@ -222,7 +222,7 @@ mod tests {
let import = ast.suite()[0].as_import_from_stmt().unwrap(); let import = ast.suite()[0].as_import_from_stmt().unwrap();
let alias = &import.names[0]; let alias = &import.names[0];
let model = SemanticModel::new(&db, bar); let model = SemanticModel::new(&db, bar);
let ty = alias.ty(&model); let ty = alias.inferred_type(&model);
assert!(ty.is_class_literal()); assert!(ty.is_class_literal());

View file

@ -129,7 +129,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
Err((declared_ty, _)) => { Err((declared_ty, _)) => {
// Intentionally ignore conflicting declared types; that's not our problem, // Intentionally ignore conflicting declared types; that's not our problem,
// it's the problem of the module we are importing from. // it's the problem of the module we are importing from.
declared_ty.inner_ty().into() declared_ty.inner_type().into()
} }
} }
@ -243,15 +243,15 @@ pub(crate) fn global_symbol<'db>(db: &'db dyn Db, file: File, name: &str) -> Sym
} }
/// Infer the type of a binding. /// Infer the type of a binding.
pub(crate) fn binding_ty<'db>(db: &'db dyn Db, definition: Definition<'db>) -> Type<'db> { pub(crate) fn binding_type<'db>(db: &'db dyn Db, definition: Definition<'db>) -> Type<'db> {
let inference = infer_definition_types(db, definition); let inference = infer_definition_types(db, definition);
inference.binding_ty(definition) inference.binding_type(definition)
} }
/// Infer the type of a declaration. /// Infer the type of a declaration.
fn declaration_ty<'db>(db: &'db dyn Db, definition: Definition<'db>) -> TypeAndQualifiers<'db> { fn declaration_type<'db>(db: &'db dyn Db, definition: Definition<'db>) -> TypeAndQualifiers<'db> {
let inference = infer_definition_types(db, definition); let inference = infer_definition_types(db, definition);
inference.declaration_ty(definition) inference.declaration_type(definition)
} }
/// Infer the type of a (possibly deferred) sub-expression of a [`Definition`]. /// Infer the type of a (possibly deferred) sub-expression of a [`Definition`].
@ -260,7 +260,7 @@ fn declaration_ty<'db>(db: &'db dyn Db, definition: Definition<'db>) -> TypeAndQ
/// ///
/// ## Panics /// ## Panics
/// If the given expression is not a sub-expression of the given [`Definition`]. /// If the given expression is not a sub-expression of the given [`Definition`].
fn definition_expression_ty<'db>( fn definition_expression_type<'db>(
db: &'db dyn Db, db: &'db dyn Db,
definition: Definition<'db>, definition: Definition<'db>,
expression: &ast::Expr, expression: &ast::Expr,
@ -273,14 +273,14 @@ fn definition_expression_ty<'db>(
if scope == definition.scope(db) { if scope == definition.scope(db) {
// expression is in the definition scope // expression is in the definition scope
let inference = infer_definition_types(db, definition); let inference = infer_definition_types(db, definition);
if let Some(ty) = inference.try_expression_ty(expr_id) { if let Some(ty) = inference.try_expression_type(expr_id) {
ty ty
} else { } else {
infer_deferred_types(db, definition).expression_ty(expr_id) infer_deferred_types(db, definition).expression_type(expr_id)
} }
} else { } else {
// expression is in a type-params sub-scope // expression is in a type-params sub-scope
infer_scope_types(db, scope).expression_ty(expr_id) infer_scope_types(db, scope).expression_type(expr_id)
} }
} }
@ -323,7 +323,7 @@ fn symbol_from_bindings<'db>(
.filter_map(|constraint| narrowing_constraint(db, constraint, binding)) .filter_map(|constraint| narrowing_constraint(db, constraint, binding))
.peekable(); .peekable();
let binding_ty = binding_ty(db, binding); let binding_ty = binding_type(db, binding);
if constraint_tys.peek().is_some() { if constraint_tys.peek().is_some() {
let intersection_ty = constraint_tys let intersection_ty = constraint_tys
.fold( .fold(
@ -432,7 +432,7 @@ fn symbol_from_declarations<'db>(
if static_visibility.is_always_false() { if static_visibility.is_always_false() {
None None
} else { } else {
Some(declaration_ty(db, declaration)) Some(declaration_type(db, declaration))
} }
}, },
); );
@ -440,12 +440,12 @@ fn symbol_from_declarations<'db>(
if let Some(first) = types.next() { if let Some(first) = types.next() {
let mut conflicting: Vec<Type<'db>> = vec![]; let mut conflicting: Vec<Type<'db>> = vec![];
let declared_ty = if let Some(second) = types.next() { let declared_ty = if let Some(second) = types.next() {
let ty_first = first.inner_ty(); let ty_first = first.inner_type();
let mut qualifiers = first.qualifiers(); let mut qualifiers = first.qualifiers();
let mut builder = UnionBuilder::new(db).add(ty_first); let mut builder = UnionBuilder::new(db).add(ty_first);
for other in std::iter::once(second).chain(types) { for other in std::iter::once(second).chain(types) {
let other_ty = other.inner_ty(); let other_ty = other.inner_type();
if !ty_first.is_equivalent_to(db, other_ty) { if !ty_first.is_equivalent_to(db, other_ty) {
conflicting.push(other_ty); conflicting.push(other_ty);
} }
@ -466,13 +466,13 @@ fn symbol_from_declarations<'db>(
}; };
Ok(SymbolAndQualifiers( Ok(SymbolAndQualifiers(
Symbol::Type(declared_ty.inner_ty(), boundness), Symbol::Type(declared_ty.inner_type(), boundness),
declared_ty.qualifiers(), declared_ty.qualifiers(),
)) ))
} else { } else {
Err(( Err((
declared_ty, declared_ty,
std::iter::once(first.inner_ty()) std::iter::once(first.inner_type())
.chain(conflicting) .chain(conflicting)
.collect(), .collect(),
)) ))
@ -1787,7 +1787,7 @@ impl<'db> Type<'db> {
if let Some(Type::BooleanLiteral(bool_val)) = bool_method if let Some(Type::BooleanLiteral(bool_val)) = bool_method
.call(db, &CallArguments::positional([*instance_ty])) .call(db, &CallArguments::positional([*instance_ty]))
.return_ty(db) .return_type(db)
{ {
bool_val.into() bool_val.into()
} else { } else {
@ -1864,7 +1864,7 @@ impl<'db> Type<'db> {
CallDunderResult::MethodNotAvailable => return None, CallDunderResult::MethodNotAvailable => return None,
CallDunderResult::CallOutcome(outcome) | CallDunderResult::PossiblyUnbound(outcome) => { CallDunderResult::CallOutcome(outcome) | CallDunderResult::PossiblyUnbound(outcome) => {
outcome.return_ty(db)? outcome.return_type(db)?
} }
}; };
@ -1879,11 +1879,11 @@ impl<'db> Type<'db> {
let mut binding = bind_call(db, arguments, function_type.signature(db), Some(self)); let mut binding = bind_call(db, arguments, function_type.signature(db), Some(self));
match function_type.known(db) { match function_type.known(db) {
Some(KnownFunction::RevealType) => { Some(KnownFunction::RevealType) => {
let revealed_ty = binding.one_parameter_ty().unwrap_or(Type::unknown()); let revealed_ty = binding.one_parameter_type().unwrap_or(Type::unknown());
CallOutcome::revealed(binding, revealed_ty) CallOutcome::revealed(binding, revealed_ty)
} }
Some(KnownFunction::StaticAssert) => { Some(KnownFunction::StaticAssert) => {
if let Some((parameter_ty, message)) = binding.two_parameter_tys() { if let Some((parameter_ty, message)) = binding.two_parameter_types() {
let truthiness = parameter_ty.bool(db); let truthiness = parameter_ty.bool(db);
if truthiness.is_always_true() { if truthiness.is_always_true() {
@ -1914,64 +1914,64 @@ impl<'db> Type<'db> {
} }
Some(KnownFunction::IsEquivalentTo) => { Some(KnownFunction::IsEquivalentTo) => {
let (ty_a, ty_b) = binding let (ty_a, ty_b) = binding
.two_parameter_tys() .two_parameter_types()
.unwrap_or((Type::unknown(), Type::unknown())); .unwrap_or((Type::unknown(), Type::unknown()));
binding binding
.set_return_ty(Type::BooleanLiteral(ty_a.is_equivalent_to(db, ty_b))); .set_return_type(Type::BooleanLiteral(ty_a.is_equivalent_to(db, ty_b)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsSubtypeOf) => { Some(KnownFunction::IsSubtypeOf) => {
let (ty_a, ty_b) = binding let (ty_a, ty_b) = binding
.two_parameter_tys() .two_parameter_types()
.unwrap_or((Type::unknown(), Type::unknown())); .unwrap_or((Type::unknown(), Type::unknown()));
binding.set_return_ty(Type::BooleanLiteral(ty_a.is_subtype_of(db, ty_b))); binding.set_return_type(Type::BooleanLiteral(ty_a.is_subtype_of(db, ty_b)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsAssignableTo) => { Some(KnownFunction::IsAssignableTo) => {
let (ty_a, ty_b) = binding let (ty_a, ty_b) = binding
.two_parameter_tys() .two_parameter_types()
.unwrap_or((Type::unknown(), Type::unknown())); .unwrap_or((Type::unknown(), Type::unknown()));
binding binding
.set_return_ty(Type::BooleanLiteral(ty_a.is_assignable_to(db, ty_b))); .set_return_type(Type::BooleanLiteral(ty_a.is_assignable_to(db, ty_b)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsDisjointFrom) => { Some(KnownFunction::IsDisjointFrom) => {
let (ty_a, ty_b) = binding let (ty_a, ty_b) = binding
.two_parameter_tys() .two_parameter_types()
.unwrap_or((Type::unknown(), Type::unknown())); .unwrap_or((Type::unknown(), Type::unknown()));
binding binding
.set_return_ty(Type::BooleanLiteral(ty_a.is_disjoint_from(db, ty_b))); .set_return_type(Type::BooleanLiteral(ty_a.is_disjoint_from(db, ty_b)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsGradualEquivalentTo) => { Some(KnownFunction::IsGradualEquivalentTo) => {
let (ty_a, ty_b) = binding let (ty_a, ty_b) = binding
.two_parameter_tys() .two_parameter_types()
.unwrap_or((Type::unknown(), Type::unknown())); .unwrap_or((Type::unknown(), Type::unknown()));
binding.set_return_ty(Type::BooleanLiteral( binding.set_return_type(Type::BooleanLiteral(
ty_a.is_gradual_equivalent_to(db, ty_b), ty_a.is_gradual_equivalent_to(db, ty_b),
)); ));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsFullyStatic) => { Some(KnownFunction::IsFullyStatic) => {
let ty = binding.one_parameter_ty().unwrap_or(Type::unknown()); let ty = binding.one_parameter_type().unwrap_or(Type::unknown());
binding.set_return_ty(Type::BooleanLiteral(ty.is_fully_static(db))); binding.set_return_type(Type::BooleanLiteral(ty.is_fully_static(db)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsSingleton) => { Some(KnownFunction::IsSingleton) => {
let ty = binding.one_parameter_ty().unwrap_or(Type::unknown()); let ty = binding.one_parameter_type().unwrap_or(Type::unknown());
binding.set_return_ty(Type::BooleanLiteral(ty.is_singleton(db))); binding.set_return_type(Type::BooleanLiteral(ty.is_singleton(db)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::IsSingleValued) => { Some(KnownFunction::IsSingleValued) => {
let ty = binding.one_parameter_ty().unwrap_or(Type::unknown()); let ty = binding.one_parameter_type().unwrap_or(Type::unknown());
binding.set_return_ty(Type::BooleanLiteral(ty.is_single_valued(db))); binding.set_return_type(Type::BooleanLiteral(ty.is_single_valued(db)));
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::Len) => { Some(KnownFunction::Len) => {
if let Some(first_arg) = binding.one_parameter_ty() { if let Some(first_arg) = binding.one_parameter_type() {
if let Some(len_ty) = first_arg.len(db) { if let Some(len_ty) = first_arg.len(db) {
binding.set_return_ty(len_ty); binding.set_return_type(len_ty);
} }
}; };
@ -1979,15 +1979,15 @@ impl<'db> Type<'db> {
} }
Some(KnownFunction::Repr) => { Some(KnownFunction::Repr) => {
if let Some(first_arg) = binding.one_parameter_ty() { if let Some(first_arg) = binding.one_parameter_type() {
binding.set_return_ty(first_arg.repr(db)); binding.set_return_type(first_arg.repr(db));
}; };
CallOutcome::callable(binding) CallOutcome::callable(binding)
} }
Some(KnownFunction::AssertType) => { Some(KnownFunction::AssertType) => {
let Some((_, asserted_ty)) = binding.two_parameter_tys() else { let Some((_, asserted_ty)) = binding.two_parameter_types() else {
return CallOutcome::callable(binding); return CallOutcome::callable(binding);
}; };
@ -1997,12 +1997,12 @@ impl<'db> Type<'db> {
Some(KnownFunction::Cast) => { Some(KnownFunction::Cast) => {
// TODO: Use `.two_parameter_tys()` exclusively // TODO: Use `.two_parameter_tys()` exclusively
// when overloads are supported. // when overloads are supported.
if binding.two_parameter_tys().is_none() { if binding.two_parameter_types().is_none() {
return CallOutcome::callable(binding); return CallOutcome::callable(binding);
}; };
if let Some(casted_ty) = arguments.first_argument() { if let Some(casted_ty) = arguments.first_argument() {
binding.set_return_ty(casted_ty); binding.set_return_type(casted_ty);
}; };
CallOutcome::callable(binding) CallOutcome::callable(binding)
@ -2015,7 +2015,7 @@ impl<'db> Type<'db> {
// TODO annotated return type on `__new__` or metaclass `__call__` // TODO annotated return type on `__new__` or metaclass `__call__`
// TODO check call vs signatures of `__new__` and/or `__init__` // TODO check call vs signatures of `__new__` and/or `__init__`
Type::ClassLiteral(ClassLiteralType { class }) => { Type::ClassLiteral(ClassLiteralType { class }) => {
CallOutcome::callable(CallBinding::from_return_ty(match class.known(db) { CallOutcome::callable(CallBinding::from_return_type(match class.known(db) {
// If the class is the builtin-bool class (for example `bool(1)`), we try to // If the class is the builtin-bool class (for example `bool(1)`), we try to
// return the specific truthiness value of the input arg, `Literal[True]` for // return the specific truthiness value of the input arg, `Literal[True]` for
// the example above. // the example above.
@ -2061,7 +2061,7 @@ impl<'db> Type<'db> {
} }
// Dynamic types are callable, and the return type is the same dynamic type // Dynamic types are callable, and the return type is the same dynamic type
Type::Dynamic(_) => CallOutcome::callable(CallBinding::from_return_ty(self)), Type::Dynamic(_) => CallOutcome::callable(CallBinding::from_return_type(self)),
Type::Union(union) => CallOutcome::union( Type::Union(union) => CallOutcome::union(
self, self,
@ -2071,7 +2071,7 @@ impl<'db> Type<'db> {
.map(|elem| elem.call(db, arguments)), .map(|elem| elem.call(db, arguments)),
), ),
Type::Intersection(_) => CallOutcome::callable(CallBinding::from_return_ty( Type::Intersection(_) => CallOutcome::callable(CallBinding::from_return_type(
todo_type!("Type::Intersection.call()"), todo_type!("Type::Intersection.call()"),
)), )),
@ -2117,7 +2117,7 @@ impl<'db> Type<'db> {
match dunder_iter_result { match dunder_iter_result {
CallDunderResult::CallOutcome(ref call_outcome) CallDunderResult::CallOutcome(ref call_outcome)
| CallDunderResult::PossiblyUnbound(ref call_outcome) => { | CallDunderResult::PossiblyUnbound(ref call_outcome) => {
let Some(iterator_ty) = call_outcome.return_ty(db) else { let Some(iterator_ty) = call_outcome.return_type(db) else {
return IterationOutcome::NotIterable { return IterationOutcome::NotIterable {
not_iterable_ty: self, not_iterable_ty: self,
}; };
@ -2125,7 +2125,7 @@ impl<'db> Type<'db> {
return if let Some(element_ty) = iterator_ty return if let Some(element_ty) = iterator_ty
.call_dunder(db, "__next__", &CallArguments::positional([iterator_ty])) .call_dunder(db, "__next__", &CallArguments::positional([iterator_ty]))
.return_ty(db) .return_type(db)
{ {
if matches!(dunder_iter_result, CallDunderResult::PossiblyUnbound(..)) { if matches!(dunder_iter_result, CallDunderResult::PossiblyUnbound(..)) {
IterationOutcome::PossiblyUnboundDunderIter { IterationOutcome::PossiblyUnboundDunderIter {
@ -2156,7 +2156,7 @@ impl<'db> Type<'db> {
"__getitem__", "__getitem__",
&CallArguments::positional([self, KnownClass::Int.to_instance(db)]), &CallArguments::positional([self, KnownClass::Int.to_instance(db)]),
) )
.return_ty(db) .return_type(db)
{ {
IterationOutcome::Iterable { element_ty } IterationOutcome::Iterable { element_ty }
} else { } else {
@ -2262,7 +2262,9 @@ impl<'db> Type<'db> {
Type::Dynamic(_) => Ok(*self), Type::Dynamic(_) => Ok(*self),
// TODO map this to a new `Type::TypeVar` variant // TODO map this to a new `Type::TypeVar` variant
Type::KnownInstance(KnownInstanceType::TypeVar(_)) => Ok(*self), Type::KnownInstance(KnownInstanceType::TypeVar(_)) => Ok(*self),
Type::KnownInstance(KnownInstanceType::TypeAliasType(alias)) => Ok(alias.value_ty(db)), Type::KnownInstance(KnownInstanceType::TypeAliasType(alias)) => {
Ok(alias.value_type(db))
}
Type::KnownInstance(KnownInstanceType::Never | KnownInstanceType::NoReturn) => { Type::KnownInstance(KnownInstanceType::Never | KnownInstanceType::NoReturn) => {
Ok(Type::Never) Ok(Type::Never)
} }
@ -2358,7 +2360,8 @@ impl<'db> Type<'db> {
ClassBase::Dynamic(_) => *self, ClassBase::Dynamic(_) => *self,
ClassBase::Class(class) => SubclassOfType::from( ClassBase::Class(class) => SubclassOfType::from(
db, db,
ClassBase::try_from_ty(db, class.metaclass(db)).unwrap_or(ClassBase::unknown()), ClassBase::try_from_type(db, class.metaclass(db))
.unwrap_or(ClassBase::unknown()),
), ),
}, },
@ -2367,7 +2370,7 @@ impl<'db> Type<'db> {
// TODO intersections // TODO intersections
Type::Intersection(_) => SubclassOfType::from( Type::Intersection(_) => SubclassOfType::from(
db, db,
ClassBase::try_from_ty(db, todo_type!("Intersection meta-type")) ClassBase::try_from_type(db, todo_type!("Intersection meta-type"))
.expect("Type::Todo should be a valid ClassBase"), .expect("Type::Todo should be a valid ClassBase"),
), ),
Type::AlwaysTruthy | Type::AlwaysFalsy => KnownClass::Type.to_instance(db), Type::AlwaysTruthy | Type::AlwaysFalsy => KnownClass::Type.to_instance(db),
@ -2491,7 +2494,7 @@ impl<'db> TypeAndQualifiers<'db> {
} }
/// Forget about type qualifiers and only return the inner type. /// Forget about type qualifiers and only return the inner type.
pub(crate) fn inner_ty(&self) -> Type<'db> { pub(crate) fn inner_type(&self) -> Type<'db> {
self.inner self.inner
} }
@ -3778,7 +3781,7 @@ impl<'db> Class<'db> {
class_stmt class_stmt
.bases() .bases()
.iter() .iter()
.map(|base_node| definition_expression_ty(db, class_definition, base_node)) .map(|base_node| definition_expression_type(db, class_definition, base_node))
.collect() .collect()
} }
@ -3807,7 +3810,7 @@ impl<'db> Class<'db> {
.decorator_list .decorator_list
.iter() .iter()
.map(|decorator_node| { .map(|decorator_node| {
definition_expression_ty(db, class_definition, &decorator_node.expression) definition_expression_type(db, class_definition, &decorator_node.expression)
}) })
.collect() .collect()
} }
@ -3866,7 +3869,7 @@ impl<'db> Class<'db> {
.find_keyword("metaclass")? .find_keyword("metaclass")?
.value; .value;
let class_definition = semantic_index(db, self.file(db)).definition(class_stmt); let class_definition = semantic_index(db, self.file(db)).definition(class_stmt);
let metaclass_ty = definition_expression_ty(db, class_definition, metaclass_node); let metaclass_ty = definition_expression_type(db, class_definition, metaclass_node);
Some(metaclass_ty) Some(metaclass_ty)
} }
@ -3926,7 +3929,7 @@ impl<'db> Class<'db> {
let return_ty = outcomes let return_ty = outcomes
.iter() .iter()
.fold(None, |acc, outcome| { .fold(None, |acc, outcome| {
let ty = outcome.return_ty(db); let ty = outcome.return_type(db);
match (acc, ty) { match (acc, ty) {
(acc, None) => { (acc, None) => {
@ -3957,7 +3960,7 @@ impl<'db> Class<'db> {
CallOutcome::Callable { binding } CallOutcome::Callable { binding }
| CallOutcome::RevealType { binding, .. } | CallOutcome::RevealType { binding, .. }
| CallOutcome::StaticAssertionError { binding, .. } | CallOutcome::StaticAssertionError { binding, .. }
| CallOutcome::AssertType { binding, .. } => Ok(binding.return_ty()), | CallOutcome::AssertType { binding, .. } => Ok(binding.return_type()),
}; };
return return_ty_result.map(|ty| ty.to_meta_type(db)); return return_ty_result.map(|ty| ty.to_meta_type(db));
@ -4110,7 +4113,7 @@ impl<'db> Class<'db> {
} }
Err((declared_ty, _conflicting_declarations)) => { Err((declared_ty, _conflicting_declarations)) => {
// Ignore conflicting declarations // Ignore conflicting declarations
SymbolAndQualifiers(declared_ty.inner_ty().into(), declared_ty.qualifiers()) SymbolAndQualifiers(declared_ty.inner_type().into(), declared_ty.qualifiers())
} }
} }
} else { } else {
@ -4176,13 +4179,13 @@ pub struct TypeAliasType<'db> {
#[salsa::tracked] #[salsa::tracked]
impl<'db> TypeAliasType<'db> { impl<'db> TypeAliasType<'db> {
#[salsa::tracked] #[salsa::tracked]
pub fn value_ty(self, db: &'db dyn Db) -> Type<'db> { pub fn value_type(self, db: &'db dyn Db) -> Type<'db> {
let scope = self.rhs_scope(db); let scope = self.rhs_scope(db);
let type_alias_stmt_node = scope.node(db).expect_type_alias(); let type_alias_stmt_node = scope.node(db).expect_type_alias();
let definition = semantic_index(db, scope.file(db)).definition(type_alias_stmt_node); let definition = semantic_index(db, scope.file(db)).definition(type_alias_stmt_node);
definition_expression_ty(db, definition, &type_alias_stmt_node.value) definition_expression_type(db, definition, &type_alias_stmt_node.value)
} }
} }

View file

@ -89,13 +89,13 @@ impl<'db> CallOutcome<'db> {
} }
/// Get the return type of the call, or `None` if not callable. /// Get the return type of the call, or `None` if not callable.
pub(super) fn return_ty(&self, db: &'db dyn Db) -> Option<Type<'db>> { pub(super) fn return_type(&self, db: &'db dyn Db) -> Option<Type<'db>> {
match self { match self {
Self::Callable { binding } => Some(binding.return_ty()), Self::Callable { binding } => Some(binding.return_type()),
Self::RevealType { Self::RevealType {
binding, binding,
revealed_ty: _, revealed_ty: _,
} => Some(binding.return_ty()), } => Some(binding.return_type()),
Self::NotCallable { not_callable_ty: _ } => None, Self::NotCallable { not_callable_ty: _ } => None,
Self::Union { Self::Union {
outcomes, outcomes,
@ -105,7 +105,7 @@ impl<'db> CallOutcome<'db> {
// If all outcomes are NotCallable, we return None; if some outcomes are callable // If all outcomes are NotCallable, we return None; if some outcomes are callable
// and some are not, we return a union including Unknown. // and some are not, we return a union including Unknown.
.fold(None, |acc, outcome| { .fold(None, |acc, outcome| {
let ty = outcome.return_ty(db); let ty = outcome.return_type(db);
match (acc, ty) { match (acc, ty) {
(None, None) => None, (None, None) => None,
(None, Some(ty)) => Some(UnionBuilder::new(db).add(ty)), (None, Some(ty)) => Some(UnionBuilder::new(db).add(ty)),
@ -113,12 +113,12 @@ impl<'db> CallOutcome<'db> {
} }
}) })
.map(UnionBuilder::build), .map(UnionBuilder::build),
Self::PossiblyUnboundDunderCall { call_outcome, .. } => call_outcome.return_ty(db), Self::PossiblyUnboundDunderCall { call_outcome, .. } => call_outcome.return_type(db),
Self::StaticAssertionError { .. } => Some(Type::none(db)), Self::StaticAssertionError { .. } => Some(Type::none(db)),
Self::AssertType { Self::AssertType {
binding, binding,
asserted_ty: _, asserted_ty: _,
} => Some(binding.return_ty()), } => Some(binding.return_type()),
} }
} }
@ -128,7 +128,7 @@ impl<'db> CallOutcome<'db> {
context: &InferContext<'db>, context: &InferContext<'db>,
node: ast::AnyNodeRef, node: ast::AnyNodeRef,
) -> Type<'db> { ) -> Type<'db> {
match self.return_ty_result(context, node) { match self.return_type_result(context, node) {
Ok(return_ty) => return_ty, Ok(return_ty) => return_ty,
Err(NotCallableError::Type { Err(NotCallableError::Type {
not_callable_ty, not_callable_ty,
@ -194,7 +194,7 @@ impl<'db> CallOutcome<'db> {
} }
/// Get the return type of the call as a result. /// Get the return type of the call as a result.
pub(super) fn return_ty_result( pub(super) fn return_type_result(
&self, &self,
context: &InferContext<'db>, context: &InferContext<'db>,
node: ast::AnyNodeRef, node: ast::AnyNodeRef,
@ -205,7 +205,7 @@ impl<'db> CallOutcome<'db> {
match self { match self {
Self::Callable { binding } => { Self::Callable { binding } => {
binding.report_diagnostics(context, node); binding.report_diagnostics(context, node);
Ok(binding.return_ty()) Ok(binding.return_type())
} }
Self::RevealType { Self::RevealType {
binding, binding,
@ -218,7 +218,7 @@ impl<'db> CallOutcome<'db> {
Severity::Info, Severity::Info,
format_args!("Revealed type is `{}`", revealed_ty.display(context.db())), format_args!("Revealed type is `{}`", revealed_ty.display(context.db())),
); );
Ok(binding.return_ty()) Ok(binding.return_type())
} }
Self::NotCallable { not_callable_ty } => Err(NotCallableError::Type { Self::NotCallable { not_callable_ty } => Err(NotCallableError::Type {
not_callable_ty: *not_callable_ty, not_callable_ty: *not_callable_ty,
@ -230,7 +230,7 @@ impl<'db> CallOutcome<'db> {
} => Err(NotCallableError::PossiblyUnboundDunderCall { } => Err(NotCallableError::PossiblyUnboundDunderCall {
callable_ty: *called_ty, callable_ty: *called_ty,
return_ty: call_outcome return_ty: call_outcome
.return_ty(context.db()) .return_type(context.db())
.unwrap_or(Type::unknown()), .unwrap_or(Type::unknown()),
}), }),
Self::Union { Self::Union {
@ -251,7 +251,7 @@ impl<'db> CallOutcome<'db> {
revealed_ty: _, revealed_ty: _,
} => { } => {
if revealed { if revealed {
binding.return_ty() binding.return_type()
} else { } else {
revealed = true; revealed = true;
outcome.unwrap_with_diagnostic(context, node) outcome.unwrap_with_diagnostic(context, node)
@ -329,8 +329,8 @@ impl<'db> CallOutcome<'db> {
binding, binding,
asserted_ty, asserted_ty,
} => { } => {
let [actual_ty, _asserted] = binding.parameter_tys() else { let [actual_ty, _asserted] = binding.parameter_types() else {
return Ok(binding.return_ty()); return Ok(binding.return_type());
}; };
if !actual_ty.is_gradual_equivalent_to(context.db(), *asserted_ty) { if !actual_ty.is_gradual_equivalent_to(context.db(), *asserted_ty) {
@ -345,7 +345,7 @@ impl<'db> CallOutcome<'db> {
); );
} }
Ok(binding.return_ty()) Ok(binding.return_type())
} }
} }
} }
@ -358,9 +358,9 @@ pub(super) enum CallDunderResult<'db> {
} }
impl<'db> CallDunderResult<'db> { impl<'db> CallDunderResult<'db> {
pub(super) fn return_ty(&self, db: &'db dyn Db) -> Option<Type<'db>> { pub(super) fn return_type(&self, db: &'db dyn Db) -> Option<Type<'db>> {
match self { match self {
Self::CallOutcome(outcome) => outcome.return_ty(db), Self::CallOutcome(outcome) => outcome.return_type(db),
Self::PossiblyUnbound { .. } => None, Self::PossiblyUnbound { .. } => None,
Self::MethodNotAvailable => None, Self::MethodNotAvailable => None,
} }
@ -394,7 +394,7 @@ pub(super) enum NotCallableError<'db> {
impl<'db> NotCallableError<'db> { impl<'db> NotCallableError<'db> {
/// The return type that should be used when a call is not callable. /// The return type that should be used when a call is not callable.
pub(super) fn return_ty(&self) -> Type<'db> { pub(super) fn return_type(&self) -> Type<'db> {
match self { match self {
Self::Type { return_ty, .. } => *return_ty, Self::Type { return_ty, .. } => *return_ty,
Self::UnionElement { return_ty, .. } => *return_ty, Self::UnionElement { return_ty, .. } => *return_ty,
@ -407,7 +407,7 @@ impl<'db> NotCallableError<'db> {
/// ///
/// For unions, returns the union type itself, which may contain a mix of callable and /// For unions, returns the union type itself, which may contain a mix of callable and
/// non-callable types. /// non-callable types.
pub(super) fn called_ty(&self) -> Type<'db> { pub(super) fn called_type(&self) -> Type<'db> {
match self { match self {
Self::Type { Self::Type {
not_callable_ty, .. not_callable_ty, ..

View file

@ -73,7 +73,7 @@ pub(crate) fn bind_call<'db>(
continue; continue;
} }
}; };
if let Some(expected_ty) = parameter.annotated_ty() { if let Some(expected_ty) = parameter.annotated_type() {
if !argument_ty.is_assignable_to(db, expected_ty) { if !argument_ty.is_assignable_to(db, expected_ty) {
errors.push(CallBindingError::InvalidArgumentType { errors.push(CallBindingError::InvalidArgumentType {
parameter: ParameterContext::new(parameter, index, positional), parameter: ParameterContext::new(parameter, index, positional),
@ -109,7 +109,8 @@ pub(crate) fn bind_call<'db>(
for (index, bound_ty) in parameter_tys.iter().enumerate() { for (index, bound_ty) in parameter_tys.iter().enumerate() {
if bound_ty.is_none() { if bound_ty.is_none() {
let param = &parameters[index]; let param = &parameters[index];
if param.is_variadic() || param.is_keyword_variadic() || param.default_ty().is_some() { if param.is_variadic() || param.is_keyword_variadic() || param.default_type().is_some()
{
// variadic/keywords and defaulted arguments are not required // variadic/keywords and defaulted arguments are not required
continue; continue;
} }
@ -151,7 +152,7 @@ pub(crate) struct CallBinding<'db> {
impl<'db> CallBinding<'db> { impl<'db> CallBinding<'db> {
// TODO remove this constructor and construct always from `bind_call` // TODO remove this constructor and construct always from `bind_call`
pub(crate) fn from_return_ty(return_ty: Type<'db>) -> Self { pub(crate) fn from_return_type(return_ty: Type<'db>) -> Self {
Self { Self {
callable_ty: None, callable_ty: None,
return_ty, return_ty,
@ -160,27 +161,27 @@ impl<'db> CallBinding<'db> {
} }
} }
pub(crate) fn set_return_ty(&mut self, return_ty: Type<'db>) { pub(crate) fn set_return_type(&mut self, return_ty: Type<'db>) {
self.return_ty = return_ty; self.return_ty = return_ty;
} }
pub(crate) fn return_ty(&self) -> Type<'db> { pub(crate) fn return_type(&self) -> Type<'db> {
self.return_ty self.return_ty
} }
pub(crate) fn parameter_tys(&self) -> &[Type<'db>] { pub(crate) fn parameter_types(&self) -> &[Type<'db>] {
&self.parameter_tys &self.parameter_tys
} }
pub(crate) fn one_parameter_ty(&self) -> Option<Type<'db>> { pub(crate) fn one_parameter_type(&self) -> Option<Type<'db>> {
match self.parameter_tys() { match self.parameter_types() {
[ty] => Some(*ty), [ty] => Some(*ty),
_ => None, _ => None,
} }
} }
pub(crate) fn two_parameter_tys(&self) -> Option<(Type<'db>, Type<'db>)> { pub(crate) fn two_parameter_types(&self) -> Option<(Type<'db>, Type<'db>)> {
match self.parameter_tys() { match self.parameter_types() {
[first, second] => Some((*first, *second)), [first, second] => Some((*first, *second)),
_ => None, _ => None,
} }

View file

@ -62,7 +62,7 @@ impl<'db> ClassBase<'db> {
/// Attempt to resolve `ty` into a `ClassBase`. /// Attempt to resolve `ty` into a `ClassBase`.
/// ///
/// Return `None` if `ty` is not an acceptable type for a class base. /// Return `None` if `ty` is not an acceptable type for a class base.
pub(super) fn try_from_ty(db: &'db dyn Db, ty: Type<'db>) -> Option<Self> { pub(super) fn try_from_type(db: &'db dyn Db, ty: Type<'db>) -> Option<Self> {
match ty { match ty {
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)), Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
Type::ClassLiteral(ClassLiteralType { class }) => Some(Self::Class(class)), Type::ClassLiteral(ClassLiteralType { class }) => Some(Self::Class(class)),
@ -112,40 +112,40 @@ impl<'db> ClassBase<'db> {
KnownInstanceType::Any => Some(Self::any()), KnownInstanceType::Any => Some(Self::any()),
// TODO: Classes inheriting from `typing.Type` et al. also have `Generic` in their MRO // TODO: Classes inheriting from `typing.Type` et al. also have `Generic` in their MRO
KnownInstanceType::Dict => { KnownInstanceType::Dict => {
Self::try_from_ty(db, KnownClass::Dict.to_class_literal(db)) Self::try_from_type(db, KnownClass::Dict.to_class_literal(db))
} }
KnownInstanceType::List => { KnownInstanceType::List => {
Self::try_from_ty(db, KnownClass::List.to_class_literal(db)) Self::try_from_type(db, KnownClass::List.to_class_literal(db))
} }
KnownInstanceType::Type => { KnownInstanceType::Type => {
Self::try_from_ty(db, KnownClass::Type.to_class_literal(db)) Self::try_from_type(db, KnownClass::Type.to_class_literal(db))
} }
KnownInstanceType::Tuple => { KnownInstanceType::Tuple => {
Self::try_from_ty(db, KnownClass::Tuple.to_class_literal(db)) Self::try_from_type(db, KnownClass::Tuple.to_class_literal(db))
} }
KnownInstanceType::Set => { KnownInstanceType::Set => {
Self::try_from_ty(db, KnownClass::Set.to_class_literal(db)) Self::try_from_type(db, KnownClass::Set.to_class_literal(db))
} }
KnownInstanceType::FrozenSet => { KnownInstanceType::FrozenSet => {
Self::try_from_ty(db, KnownClass::FrozenSet.to_class_literal(db)) Self::try_from_type(db, KnownClass::FrozenSet.to_class_literal(db))
} }
KnownInstanceType::ChainMap => { KnownInstanceType::ChainMap => {
Self::try_from_ty(db, KnownClass::ChainMap.to_class_literal(db)) Self::try_from_type(db, KnownClass::ChainMap.to_class_literal(db))
} }
KnownInstanceType::Counter => { KnownInstanceType::Counter => {
Self::try_from_ty(db, KnownClass::Counter.to_class_literal(db)) Self::try_from_type(db, KnownClass::Counter.to_class_literal(db))
} }
KnownInstanceType::DefaultDict => { KnownInstanceType::DefaultDict => {
Self::try_from_ty(db, KnownClass::DefaultDict.to_class_literal(db)) Self::try_from_type(db, KnownClass::DefaultDict.to_class_literal(db))
} }
KnownInstanceType::Deque => { KnownInstanceType::Deque => {
Self::try_from_ty(db, KnownClass::Deque.to_class_literal(db)) Self::try_from_type(db, KnownClass::Deque.to_class_literal(db))
} }
KnownInstanceType::OrderedDict => { KnownInstanceType::OrderedDict => {
Self::try_from_ty(db, KnownClass::OrderedDict.to_class_literal(db)) Self::try_from_type(db, KnownClass::OrderedDict.to_class_literal(db))
} }
KnownInstanceType::Callable => { KnownInstanceType::Callable => {
Self::try_from_ty(db, todo_type!("Support for Callable as a base class")) Self::try_from_type(db, todo_type!("Support for Callable as a base class"))
} }
}, },
} }

View file

@ -8,7 +8,7 @@ use ruff_db::{
use ruff_python_ast::AnyNodeRef; use ruff_python_ast::AnyNodeRef;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use super::{binding_ty, KnownFunction, TypeCheckDiagnostic, TypeCheckDiagnostics}; use super::{binding_type, KnownFunction, TypeCheckDiagnostic, TypeCheckDiagnostics};
use crate::semantic_index::semantic_index; use crate::semantic_index::semantic_index;
use crate::semantic_index::symbol::ScopeId; use crate::semantic_index::symbol::ScopeId;
@ -144,7 +144,7 @@ impl<'db> InferContext<'db> {
.ancestor_scopes(scope_id) .ancestor_scopes(scope_id)
.filter_map(|(_, scope)| scope.node().as_function()) .filter_map(|(_, scope)| scope.node().as_function())
.filter_map(|function| { .filter_map(|function| {
binding_ty(self.db, index.definition(function)).into_function_literal() binding_type(self.db, index.definition(function)).into_function_literal()
}); });
// Iterate over all functions and test if any is decorated with `@no_type_check`. // Iterate over all functions and test if any is decorated with `@no_type_check`.

View file

@ -3,7 +3,7 @@
//! //!
//! Scope-level inference is for when we are actually checking a file, and need to check types for //! Scope-level inference is for when we are actually checking a file, and need to check types for
//! everything in that file's scopes, or give a linter access to types of arbitrary expressions //! everything in that file's scopes, or give a linter access to types of arbitrary expressions
//! (via the [`HasTy`](crate::semantic_model::HasTy) trait). //! (via the [`HasType`](crate::semantic_model::HasType) trait).
//! //!
//! Definition-level inference allows us to look up the types of symbols in other scopes (e.g. for //! Definition-level inference allows us to look up the types of symbols in other scopes (e.g. for
//! imports) with the minimum inference necessary, so that if we're looking up one symbol from a //! imports) with the minimum inference necessary, so that if we're looking up one symbol from a
@ -269,21 +269,21 @@ impl<'db> TypeInference<'db> {
} }
#[track_caller] #[track_caller]
pub(crate) fn expression_ty(&self, expression: ScopedExpressionId) -> Type<'db> { pub(crate) fn expression_type(&self, expression: ScopedExpressionId) -> Type<'db> {
self.expressions[&expression] self.expressions[&expression]
} }
pub(crate) fn try_expression_ty(&self, expression: ScopedExpressionId) -> Option<Type<'db>> { pub(crate) fn try_expression_type(&self, expression: ScopedExpressionId) -> Option<Type<'db>> {
self.expressions.get(&expression).copied() self.expressions.get(&expression).copied()
} }
#[track_caller] #[track_caller]
pub(crate) fn binding_ty(&self, definition: Definition<'db>) -> Type<'db> { pub(crate) fn binding_type(&self, definition: Definition<'db>) -> Type<'db> {
self.bindings[&definition] self.bindings[&definition]
} }
#[track_caller] #[track_caller]
pub(crate) fn declaration_ty(&self, definition: Definition<'db>) -> TypeAndQualifiers<'db> { pub(crate) fn declaration_type(&self, definition: Definition<'db>) -> TypeAndQualifiers<'db> {
self.declarations[&definition] self.declarations[&definition]
} }
@ -460,9 +460,9 @@ impl<'db> TypeInferenceBuilder<'db> {
/// If the expression is not within this region, or if no type has yet been inferred for /// If the expression is not within this region, or if no type has yet been inferred for
/// this node. /// this node.
#[track_caller] #[track_caller]
fn expression_ty(&self, expr: &ast::Expr) -> Type<'db> { fn expression_type(&self, expr: &ast::Expr) -> Type<'db> {
self.types self.types
.expression_ty(expr.scoped_expression_id(self.db(), self.scope())) .expression_type(expr.scoped_expression_id(self.db(), self.scope()))
} }
/// Get the type of an expression from any scope in the same file. /// Get the type of an expression from any scope in the same file.
@ -477,13 +477,15 @@ impl<'db> TypeInferenceBuilder<'db> {
/// ///
/// Can cause query cycles if the expression is from a different scope and type inference is /// Can cause query cycles if the expression is from a different scope and type inference is
/// already in progress for that scope (further up the stack). /// already in progress for that scope (further up the stack).
fn file_expression_ty(&self, expression: &ast::Expr) -> Type<'db> { fn file_expression_type(&self, expression: &ast::Expr) -> Type<'db> {
let file_scope = self.index.expression_scope_id(expression); let file_scope = self.index.expression_scope_id(expression);
let expr_scope = file_scope.to_scope_id(self.db(), self.file()); let expr_scope = file_scope.to_scope_id(self.db(), self.file());
let expr_id = expression.scoped_expression_id(self.db(), expr_scope); let expr_id = expression.scoped_expression_id(self.db(), expr_scope);
match self.region { match self.region {
InferenceRegion::Scope(scope) if scope == expr_scope => self.expression_ty(expression), InferenceRegion::Scope(scope) if scope == expr_scope => {
_ => infer_scope_types(self.db(), expr_scope).expression_ty(expr_id), self.expression_type(expression)
}
_ => infer_scope_types(self.db(), expr_scope).expression_type(expr_id),
} }
} }
@ -565,7 +567,7 @@ impl<'db> TypeInferenceBuilder<'db> {
.filter_map(|(definition, ty)| { .filter_map(|(definition, ty)| {
// Filter out class literals that result from imports // Filter out class literals that result from imports
if let DefinitionKind::Class(class) = definition.kind(self.db()) { if let DefinitionKind::Class(class) = definition.kind(self.db()) {
ty.inner_ty() ty.inner_type()
.into_class_literal() .into_class_literal()
.map(|ty| (ty.class, class.node())) .map(|ty| (ty.class, class.node()))
} else { } else {
@ -873,7 +875,7 @@ impl<'db> TypeInferenceBuilder<'db> {
conflicting.display(self.db()) conflicting.display(self.db())
), ),
); );
ty.inner_ty() ty.inner_type()
}); });
if !bound_ty.is_assignable_to(self.db(), declared_ty) { if !bound_ty.is_assignable_to(self.db(), declared_ty) {
report_invalid_assignment(&self.context, node, declared_ty, bound_ty); report_invalid_assignment(&self.context, node, declared_ty, bound_ty);
@ -897,7 +899,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let inferred_ty = symbol_from_bindings(self.db(), prior_bindings) let inferred_ty = symbol_from_bindings(self.db(), prior_bindings)
.ignore_possibly_unbound() .ignore_possibly_unbound()
.unwrap_or(Type::Never); .unwrap_or(Type::Never);
let ty = if inferred_ty.is_assignable_to(self.db(), ty.inner_ty()) { let ty = if inferred_ty.is_assignable_to(self.db(), ty.inner_type()) {
ty ty
} else { } else {
self.context.report_lint( self.context.report_lint(
@ -905,7 +907,7 @@ impl<'db> TypeInferenceBuilder<'db> {
node, node,
format_args!( format_args!(
"Cannot declare type `{}` for inferred type `{}`", "Cannot declare type `{}` for inferred type `{}`",
ty.inner_ty().display(self.db()), ty.inner_type().display(self.db()),
inferred_ty.display(self.db()) inferred_ty.display(self.db())
), ),
); );
@ -929,17 +931,17 @@ impl<'db> TypeInferenceBuilder<'db> {
declared_ty, declared_ty,
inferred_ty, inferred_ty,
} => { } => {
if inferred_ty.is_assignable_to(self.db(), declared_ty.inner_ty()) { if inferred_ty.is_assignable_to(self.db(), declared_ty.inner_type()) {
(declared_ty, inferred_ty) (declared_ty, inferred_ty)
} else { } else {
report_invalid_assignment( report_invalid_assignment(
&self.context, &self.context,
node, node,
declared_ty.inner_ty(), declared_ty.inner_type(),
inferred_ty, inferred_ty,
); );
// if the assignment is invalid, fall back to assuming the annotation is correct // if the assignment is invalid, fall back to assuming the annotation is correct
(declared_ty, declared_ty.inner_ty()) (declared_ty, declared_ty.inner_type())
} }
} }
}; };
@ -1229,9 +1231,9 @@ impl<'db> TypeInferenceBuilder<'db> {
} = parameter_with_default; } = parameter_with_default;
let default_ty = default let default_ty = default
.as_ref() .as_ref()
.map(|default| self.file_expression_ty(default)); .map(|default| self.file_expression_type(default));
if let Some(annotation) = parameter.annotation.as_ref() { if let Some(annotation) = parameter.annotation.as_ref() {
let declared_ty = self.file_expression_ty(annotation); let declared_ty = self.file_expression_type(annotation);
let declared_and_inferred_ty = if let Some(default_ty) = default_ty { let declared_and_inferred_ty = if let Some(default_ty) = default_ty {
if default_ty.is_assignable_to(self.db(), declared_ty) { if default_ty.is_assignable_to(self.db(), declared_ty) {
DeclaredAndInferredType::MightBeDifferent { DeclaredAndInferredType::MightBeDifferent {
@ -1283,7 +1285,7 @@ impl<'db> TypeInferenceBuilder<'db> {
definition: Definition<'db>, definition: Definition<'db>,
) { ) {
if let Some(annotation) = parameter.annotation.as_ref() { if let Some(annotation) = parameter.annotation.as_ref() {
let _annotated_ty = self.file_expression_ty(annotation); let _annotated_ty = self.file_expression_type(annotation);
// TODO `tuple[annotated_ty, ...]` // TODO `tuple[annotated_ty, ...]`
let ty = KnownClass::Tuple.to_instance(self.db()); let ty = KnownClass::Tuple.to_instance(self.db());
self.add_declaration_with_binding( self.add_declaration_with_binding(
@ -1312,7 +1314,7 @@ impl<'db> TypeInferenceBuilder<'db> {
definition: Definition<'db>, definition: Definition<'db>,
) { ) {
if let Some(annotation) = parameter.annotation.as_ref() { if let Some(annotation) = parameter.annotation.as_ref() {
let _annotated_ty = self.file_expression_ty(annotation); let _annotated_ty = self.file_expression_type(annotation);
// TODO `dict[str, annotated_ty]` // TODO `dict[str, annotated_ty]`
let ty = KnownClass::Dict.to_instance(self.db()); let ty = KnownClass::Dict.to_instance(self.db());
self.add_declaration_with_binding( self.add_declaration_with_binding(
@ -1531,7 +1533,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let target_ty = self.infer_context_expression( let target_ty = self.infer_context_expression(
&with_item.context_expr, &with_item.context_expr,
self.expression_ty(&with_item.context_expr), self.expression_type(&with_item.context_expr),
is_async, is_async,
); );
@ -1602,7 +1604,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let target_ty = enter_ty let target_ty = enter_ty
.call(self.db(), &CallArguments::positional([context_expression_ty])) .call(self.db(), &CallArguments::positional([context_expression_ty]))
.return_ty_result(&self.context, context_expression.into()) .return_type_result(&self.context, context_expression.into())
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
self.context.report_lint( self.context.report_lint(
&INVALID_CONTEXT_MANAGER, &INVALID_CONTEXT_MANAGER,
@ -1611,7 +1613,7 @@ impl<'db> TypeInferenceBuilder<'db> {
Object of type `{context_expression}` cannot be used with `with` because the method `__enter__` of type `{enter_ty}` is not callable", context_expression = context_expression_ty.display(self.db()), enter_ty = enter_ty.display(self.db()) Object of type `{context_expression}` cannot be used with `with` because the method `__enter__` of type `{enter_ty}` is not callable", context_expression = context_expression_ty.display(self.db()), enter_ty = enter_ty.display(self.db())
), ),
); );
err.return_ty() err.return_type()
}); });
match exit { match exit {
@ -1649,7 +1651,7 @@ impl<'db> TypeInferenceBuilder<'db> {
Type::none(self.db()), Type::none(self.db()),
]), ]),
) )
.return_ty_result(&self.context, context_expression.into()) .return_type_result(&self.context, context_expression.into())
.is_err() .is_err()
{ {
self.context.report_lint( self.context.report_lint(
@ -2081,7 +2083,7 @@ impl<'db> TypeInferenceBuilder<'db> {
); );
// Handle various singletons. // Handle various singletons.
if let Type::Instance(InstanceType { class }) = declared_ty.inner_ty() { if let Type::Instance(InstanceType { class }) = declared_ty.inner_type() {
if class.is_known(self.db(), KnownClass::SpecialForm) { if class.is_known(self.db(), KnownClass::SpecialForm) {
if let Some(name_expr) = target.as_name_expr() { if let Some(name_expr) = target.as_name_expr() {
if let Some(known_instance) = KnownInstanceType::try_from_file_and_name( if let Some(known_instance) = KnownInstanceType::try_from_file_and_name(
@ -2098,7 +2100,7 @@ impl<'db> TypeInferenceBuilder<'db> {
if let Some(value) = value.as_deref() { if let Some(value) = value.as_deref() {
let inferred_ty = self.infer_expression(value); let inferred_ty = self.infer_expression(value);
let inferred_ty = if self.in_stub() && value.is_ellipsis_literal_expr() { let inferred_ty = if self.in_stub() && value.is_ellipsis_literal_expr() {
declared_ty.inner_ty() declared_ty.inner_type()
} else { } else {
inferred_ty inferred_ty
}; };
@ -2150,7 +2152,7 @@ impl<'db> TypeInferenceBuilder<'db> {
&CallArguments::positional([target_type, value_type]), &CallArguments::positional([target_type, value_type]),
); );
let augmented_return_ty = match call let augmented_return_ty = match call
.return_ty_result(&self.context, AnyNodeRef::StmtAugAssign(assignment)) .return_type_result(&self.context, AnyNodeRef::StmtAugAssign(assignment))
{ {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
@ -2163,7 +2165,7 @@ impl<'db> TypeInferenceBuilder<'db> {
value_type.display(self.db()) value_type.display(self.db())
), ),
); );
e.return_ty() e.return_type()
} }
}; };
@ -2338,7 +2340,7 @@ impl<'db> TypeInferenceBuilder<'db> {
}; };
// Resolve the module being imported. // Resolve the module being imported.
let Some(full_module_ty) = self.module_ty_from_name(&full_module_name) else { let Some(full_module_ty) = self.module_type_from_name(&full_module_name) else {
report_unresolved_module(&self.context, alias, 0, Some(name)); report_unresolved_module(&self.context, alias, 0, Some(name));
self.add_unknown_declaration_with_binding(alias.into(), definition); self.add_unknown_declaration_with_binding(alias.into(), definition);
return; return;
@ -2354,7 +2356,7 @@ impl<'db> TypeInferenceBuilder<'db> {
// parent package of that module. // parent package of that module.
let topmost_parent_name = let topmost_parent_name =
ModuleName::new(full_module_name.components().next().unwrap()).unwrap(); ModuleName::new(full_module_name.components().next().unwrap()).unwrap();
let Some(topmost_parent_ty) = self.module_ty_from_name(&topmost_parent_name) else { let Some(topmost_parent_ty) = self.module_type_from_name(&topmost_parent_name) else {
self.add_unknown_declaration_with_binding(alias.into(), definition); self.add_unknown_declaration_with_binding(alias.into(), definition);
return; return;
}; };
@ -2522,7 +2524,7 @@ impl<'db> TypeInferenceBuilder<'db> {
} }
}; };
let Some(module_ty) = self.module_ty_from_name(&module_name) else { let Some(module_ty) = self.module_type_from_name(&module_name) else {
report_unresolved_module(&self.context, import_from, *level, module); report_unresolved_module(&self.context, import_from, *level, module);
self.add_unknown_declaration_with_binding(alias.into(), definition); self.add_unknown_declaration_with_binding(alias.into(), definition);
return; return;
@ -2571,7 +2573,7 @@ impl<'db> TypeInferenceBuilder<'db> {
if let Some(submodule_name) = ModuleName::new(name) { if let Some(submodule_name) = ModuleName::new(name) {
let mut full_submodule_name = module_name.clone(); let mut full_submodule_name = module_name.clone();
full_submodule_name.extend(&submodule_name); full_submodule_name.extend(&submodule_name);
if let Some(submodule_ty) = self.module_ty_from_name(&full_submodule_name) { if let Some(submodule_ty) = self.module_type_from_name(&full_submodule_name) {
self.add_declaration_with_binding( self.add_declaration_with_binding(
alias.into(), alias.into(),
definition, definition,
@ -2600,7 +2602,7 @@ impl<'db> TypeInferenceBuilder<'db> {
} }
} }
fn module_ty_from_name(&self, module_name: &ModuleName) -> Option<Type<'db>> { fn module_type_from_name(&self, module_name: &ModuleName) -> Option<Type<'db>> {
resolve_module(self.db(), module_name) resolve_module(self.db(), module_name)
.map(|module| Type::module_literal(self.db(), self.file(), module)) .map(|module| Type::module_literal(self.db(), self.file(), module))
} }
@ -2679,7 +2681,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let standalone_expression = self.index.expression(expression); let standalone_expression = self.index.expression(expression);
let types = infer_expression_types(self.db(), standalone_expression); let types = infer_expression_types(self.db(), standalone_expression);
self.extend(types); self.extend(types);
self.expression_ty(expression) self.expression_type(expression)
} }
fn infer_expression_impl(&mut self, expression: &ast::Expr) -> Type<'db> { fn infer_expression_impl(&mut self, expression: &ast::Expr) -> Type<'db> {
@ -2828,7 +2830,7 @@ impl<'db> TypeInferenceBuilder<'db> {
} }
} }
} }
collector.ty(self.db()) collector.string_type(self.db())
} }
fn infer_ellipsis_literal_expression( fn infer_ellipsis_literal_expression(
@ -3061,10 +3063,10 @@ impl<'db> TypeInferenceBuilder<'db> {
.parent_scope_id(self.scope().file_scope_id(self.db())) .parent_scope_id(self.scope().file_scope_id(self.db()))
.expect("A comprehension should never be the top-level scope") .expect("A comprehension should never be the top-level scope")
.to_scope_id(self.db(), self.file()); .to_scope_id(self.db(), self.file());
result.expression_ty(iterable.scoped_expression_id(self.db(), lookup_scope)) result.expression_type(iterable.scoped_expression_id(self.db(), lookup_scope))
} else { } else {
self.extend(result); self.extend(result);
result.expression_ty(iterable.scoped_expression_id(self.db(), self.scope())) result.expression_type(iterable.scoped_expression_id(self.db(), self.scope()))
}; };
let target_ty = if is_async { let target_ty = if is_async {
@ -3089,7 +3091,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let definition = self.index.definition(named); let definition = self.index.definition(named);
let result = infer_definition_types(self.db(), definition); let result = infer_definition_types(self.db(), definition);
self.extend(result); self.extend(result);
result.binding_ty(definition) result.binding_type(definition)
} else { } else {
// For syntactically invalid targets, we still need to run type inference: // For syntactically invalid targets, we still need to run type inference:
self.infer_expression(&named.target); self.infer_expression(&named.target);
@ -3500,7 +3502,7 @@ impl<'db> TypeInferenceBuilder<'db> {
unary_dunder_method, unary_dunder_method,
&CallArguments::positional([operand_type]), &CallArguments::positional([operand_type]),
) { ) {
match call.return_ty_result(&self.context, AnyNodeRef::ExprUnaryOp(unary)) { match call.return_type_result(&self.context, AnyNodeRef::ExprUnaryOp(unary)) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
self.context.report_lint( self.context.report_lint(
@ -3511,7 +3513,7 @@ impl<'db> TypeInferenceBuilder<'db> {
operand_type.display(self.db()), operand_type.display(self.db()),
), ),
); );
e.return_ty() e.return_type()
} }
} }
} else { } else {
@ -3760,7 +3762,7 @@ impl<'db> TypeInferenceBuilder<'db> {
reflected_dunder, reflected_dunder,
&CallArguments::positional([right_ty, left_ty]), &CallArguments::positional([right_ty, left_ty]),
) )
.return_ty(self.db()) .return_type(self.db())
.or_else(|| { .or_else(|| {
left_ty left_ty
.call_dunder( .call_dunder(
@ -3768,7 +3770,7 @@ impl<'db> TypeInferenceBuilder<'db> {
op.dunder(), op.dunder(),
&CallArguments::positional([left_ty, right_ty]), &CallArguments::positional([left_ty, right_ty]),
) )
.return_ty(self.db()) .return_type(self.db())
}); });
} }
} }
@ -3778,7 +3780,7 @@ impl<'db> TypeInferenceBuilder<'db> {
{ {
class_member class_member
.call(self.db(), &CallArguments::positional([left_ty, right_ty])) .call(self.db(), &CallArguments::positional([left_ty, right_ty]))
.return_ty(self.db()) .return_type(self.db())
} else { } else {
None None
}; };
@ -3792,7 +3794,7 @@ impl<'db> TypeInferenceBuilder<'db> {
{ {
class_member class_member
.call(self.db(), &CallArguments::positional([right_ty, left_ty])) .call(self.db(), &CallArguments::positional([right_ty, left_ty]))
.return_ty(self.db()) .return_type(self.db())
} else { } else {
None None
} }
@ -3893,8 +3895,8 @@ impl<'db> TypeInferenceBuilder<'db> {
.tuple_windows::<(_, _)>() .tuple_windows::<(_, _)>()
.zip(ops) .zip(ops)
.map(|((left, right), op)| { .map(|((left, right), op)| {
let left_ty = self.expression_ty(left); let left_ty = self.expression_type(left);
let right_ty = self.expression_ty(right); let right_ty = self.expression_type(right);
self.infer_binary_type_comparison(left_ty, *op, right_ty) self.infer_binary_type_comparison(left_ty, *op, right_ty)
.unwrap_or_else(|error| { .unwrap_or_else(|error| {
@ -4573,18 +4575,18 @@ impl<'db> TypeInferenceBuilder<'db> {
return dunder_getitem_method return dunder_getitem_method
.call(self.db(), &CallArguments::positional([value_ty, slice_ty])) .call(self.db(), &CallArguments::positional([value_ty, slice_ty]))
.return_ty_result(&self.context, value_node.into()) .return_type_result(&self.context, value_node.into())
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
self.context.report_lint( self.context.report_lint(
&CALL_NON_CALLABLE, &CALL_NON_CALLABLE,
value_node.into(), value_node.into(),
format_args!( format_args!(
"Method `__getitem__` of type `{}` is not callable on object of type `{}`", "Method `__getitem__` of type `{}` is not callable on object of type `{}`",
err.called_ty().display(self.db()), err.called_type().display(self.db()),
value_ty.display(self.db()), value_ty.display(self.db()),
), ),
); );
err.return_ty() err.return_type()
}); });
} }
} }
@ -4618,18 +4620,18 @@ impl<'db> TypeInferenceBuilder<'db> {
return ty return ty
.call(self.db(), &CallArguments::positional([value_ty, slice_ty])) .call(self.db(), &CallArguments::positional([value_ty, slice_ty]))
.return_ty_result(&self.context, value_node.into()) .return_type_result(&self.context, value_node.into())
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
self.context.report_lint( self.context.report_lint(
&CALL_NON_CALLABLE, &CALL_NON_CALLABLE,
value_node.into(), value_node.into(),
format_args!( format_args!(
"Method `__class_getitem__` of type `{}` is not callable on object of type `{}`", "Method `__class_getitem__` of type `{}` is not callable on object of type `{}`",
err.called_ty().display(self.db()), err.called_type().display(self.db()),
value_ty.display(self.db()), value_ty.display(self.db()),
), ),
); );
err.return_ty() err.return_type()
}); });
} }
} }
@ -4837,7 +4839,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let inner_annotation_ty = let inner_annotation_ty =
self.infer_annotation_expression_impl(inner_annotation); self.infer_annotation_expression_impl(inner_annotation);
self.store_expression_type(slice, inner_annotation_ty.inner_ty()); self.store_expression_type(slice, inner_annotation_ty.inner_type());
inner_annotation_ty inner_annotation_ty
} else { } else {
self.infer_type_expression(slice); self.infer_type_expression(slice);
@ -4892,7 +4894,7 @@ impl<'db> TypeInferenceBuilder<'db> {
type_expr => self.infer_type_expression_no_store(type_expr).into(), type_expr => self.infer_type_expression_no_store(type_expr).into(),
}; };
self.store_expression_type(annotation, annotation_ty.inner_ty()); self.store_expression_type(annotation, annotation_ty.inner_type());
annotation_ty annotation_ty
} }
@ -5831,7 +5833,7 @@ impl StringPartsCollector {
self.expression = true; self.expression = true;
} }
fn ty(self, db: &dyn Db) -> Type { fn string_type(self, db: &dyn Db) -> Type {
if self.expression { if self.expression {
KnownClass::Str.to_instance(db) KnownClass::Str.to_instance(db)
} else if let Some(concatenated) = self.concatenated { } else if let Some(concatenated) = self.concatenated {
@ -5867,7 +5869,7 @@ fn perform_rich_comparison<'db>(
db, db,
&CallArguments::positional([Type::Instance(left), Type::Instance(right)]), &CallArguments::positional([Type::Instance(left), Type::Instance(right)]),
) )
.return_ty(db), .return_type(db),
_ => None, _ => None,
} }
}; };
@ -5914,7 +5916,7 @@ fn perform_membership_test_comparison<'db>(
db, db,
&CallArguments::positional([Type::Instance(right), Type::Instance(left)]), &CallArguments::positional([Type::Instance(right), Type::Instance(left)]),
) )
.return_ty(db) .return_type(db)
} }
_ => { _ => {
// iteration-based membership test // iteration-based membership test
@ -5951,7 +5953,7 @@ mod tests {
use crate::semantic_index::symbol::FileScopeId; use crate::semantic_index::symbol::FileScopeId;
use crate::semantic_index::{global_scope, semantic_index, symbol_table, use_def_map}; use crate::semantic_index::{global_scope, semantic_index, symbol_table, use_def_map};
use crate::types::check_types; use crate::types::check_types;
use crate::{HasTy, SemanticModel}; use crate::{HasType, SemanticModel};
use ruff_db::files::{system_path_to_file, File}; use ruff_db::files::{system_path_to_file, File};
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
use ruff_db::system::DbWithTestSystem; use ruff_db::system::DbWithTestSystem;
@ -5960,7 +5962,7 @@ mod tests {
use super::*; use super::*;
#[track_caller] #[track_caller]
fn assert_public_ty(db: &TestDb, file_name: &str, symbol_name: &str, expected: &str) { fn assert_public_type(db: &TestDb, file_name: &str, symbol_name: &str, expected: &str) {
let file = system_path_to_file(db, file_name).expect("file to exist"); let file = system_path_to_file(db, file_name).expect("file to exist");
let ty = global_symbol(db, file, symbol_name).expect_type(); let ty = global_symbol(db, file, symbol_name).expect_type();
@ -5996,7 +5998,7 @@ mod tests {
} }
#[track_caller] #[track_caller]
fn assert_scope_ty( fn assert_scope_type(
db: &TestDb, db: &TestDb,
file_name: &str, file_name: &str,
scopes: &[&str], scopes: &[&str],
@ -6062,11 +6064,11 @@ mod tests {
); );
db.write_dedented("src/a.py", &content)?; db.write_dedented("src/a.py", &content)?;
assert_public_ty(&db, "src/a.py", "v", "bool"); assert_public_type(&db, "src/a.py", "v", "bool");
assert_public_ty(&db, "src/a.py", "w", "bool"); assert_public_type(&db, "src/a.py", "w", "bool");
assert_public_ty(&db, "src/a.py", "x", "bool"); assert_public_type(&db, "src/a.py", "x", "bool");
assert_public_ty(&db, "src/a.py", "z", "Literal[True]"); assert_public_type(&db, "src/a.py", "z", "Literal[True]");
assert_public_ty(&db, "src/a.py", "u", "Literal[True]"); assert_public_type(&db, "src/a.py", "u", "Literal[True]");
Ok(()) Ok(())
} }
@ -6091,9 +6093,9 @@ mod tests {
), ),
)?; )?;
assert_public_ty(&db, "src/a.py", "w", r#"Literal["hellohello"]"#); assert_public_type(&db, "src/a.py", "w", r#"Literal["hellohello"]"#);
assert_public_ty(&db, "src/a.py", "x", r#"Literal["goodbyegoodbyegoodbye"]"#); assert_public_type(&db, "src/a.py", "x", r#"Literal["goodbyegoodbyegoodbye"]"#);
assert_public_ty( assert_public_type(
&db, &db,
"src/a.py", "src/a.py",
"y", "y",
@ -6102,9 +6104,9 @@ mod tests {
"a".repeat(TypeInferenceBuilder::MAX_STRING_LITERAL_SIZE) "a".repeat(TypeInferenceBuilder::MAX_STRING_LITERAL_SIZE)
), ),
); );
assert_public_ty(&db, "src/a.py", "z", "LiteralString"); assert_public_type(&db, "src/a.py", "z", "LiteralString");
assert_public_ty(&db, "src/a.py", "a", r#"Literal[""]"#); assert_public_type(&db, "src/a.py", "a", r#"Literal[""]"#);
assert_public_ty(&db, "src/a.py", "b", r#"Literal[""]"#); assert_public_type(&db, "src/a.py", "b", r#"Literal[""]"#);
Ok(()) Ok(())
} }
@ -6124,11 +6126,11 @@ mod tests {
); );
db.write_dedented("src/a.py", &content)?; db.write_dedented("src/a.py", &content)?;
assert_public_ty(&db, "src/a.py", "v", "LiteralString"); assert_public_type(&db, "src/a.py", "v", "LiteralString");
assert_public_ty(&db, "src/a.py", "w", "LiteralString"); assert_public_type(&db, "src/a.py", "w", "LiteralString");
assert_public_ty(&db, "src/a.py", "x", "LiteralString"); assert_public_type(&db, "src/a.py", "x", "LiteralString");
assert_public_ty(&db, "src/a.py", "z", r#"Literal[""]"#); assert_public_type(&db, "src/a.py", "z", r#"Literal[""]"#);
assert_public_ty(&db, "src/a.py", "u", r#"Literal[""]"#); assert_public_type(&db, "src/a.py", "u", r#"Literal[""]"#);
Ok(()) Ok(())
} }
@ -6145,8 +6147,8 @@ mod tests {
); );
db.write_dedented("src/a.py", &content)?; db.write_dedented("src/a.py", &content)?;
assert_public_ty(&db, "src/a.py", "w", "LiteralString"); assert_public_type(&db, "src/a.py", "w", "LiteralString");
assert_public_ty(&db, "src/a.py", "x", "LiteralString"); assert_public_type(&db, "src/a.py", "x", "LiteralString");
Ok(()) Ok(())
} }
@ -6165,10 +6167,10 @@ mod tests {
); );
db.write_dedented("src/a.py", &content)?; db.write_dedented("src/a.py", &content)?;
assert_public_ty(&db, "src/a.py", "v", "LiteralString"); assert_public_type(&db, "src/a.py", "v", "LiteralString");
assert_public_ty(&db, "src/a.py", "w", "LiteralString"); assert_public_type(&db, "src/a.py", "w", "LiteralString");
assert_public_ty(&db, "src/a.py", "x", "LiteralString"); assert_public_type(&db, "src/a.py", "x", "LiteralString");
assert_public_ty(&db, "src/a.py", "z", "LiteralString"); assert_public_type(&db, "src/a.py", "z", "LiteralString");
Ok(()) Ok(())
} }
@ -6217,7 +6219,7 @@ mod tests {
let statement = parsed.suite().first().unwrap().as_assign_stmt().unwrap(); let statement = parsed.suite().first().unwrap().as_assign_stmt().unwrap();
let model = SemanticModel::new(&db, a); let model = SemanticModel::new(&db, a);
let literal_ty = statement.value.ty(&model); let literal_ty = statement.value.inferred_type(&model);
assert_eq!(format!("{}", literal_ty.display(&db)), "Literal[10]"); assert_eq!(format!("{}", literal_ty.display(&db)), "Literal[10]");
@ -6230,7 +6232,7 @@ mod tests {
db.write_file("/src/a.py", "c = chr")?; db.write_file("/src/a.py", "c = chr")?;
assert_public_ty(&db, "/src/a.py", "c", "Literal[chr]"); assert_public_type(&db, "/src/a.py", "c", "Literal[chr]");
Ok(()) Ok(())
} }
@ -6247,7 +6249,7 @@ mod tests {
.with_file("/typeshed/stdlib/VERSIONS", "builtins: 3.8-") .with_file("/typeshed/stdlib/VERSIONS", "builtins: 3.8-")
.build()?; .build()?;
assert_public_ty(&db, "/src/a.py", "c", "Literal[copyright]"); assert_public_type(&db, "/src/a.py", "c", "Literal[copyright]");
Ok(()) Ok(())
} }
@ -6261,7 +6263,7 @@ mod tests {
.with_file("/typeshed/stdlib/VERSIONS", "builtins: 3.8-") .with_file("/typeshed/stdlib/VERSIONS", "builtins: 3.8-")
.build()?; .build()?;
assert_public_ty(&db, "/src/a.py", "x", "Unknown"); assert_public_type(&db, "/src/a.py", "x", "Unknown");
Ok(()) Ok(())
} }
@ -6270,7 +6272,7 @@ mod tests {
fn str_builtin() -> anyhow::Result<()> { fn str_builtin() -> anyhow::Result<()> {
let mut db = setup_db(); let mut db = setup_db();
db.write_file("/src/a.py", "x = str")?; db.write_file("/src/a.py", "x = str")?;
assert_public_ty(&db, "/src/a.py", "x", "Literal[str]"); assert_public_type(&db, "/src/a.py", "x", "Literal[str]");
Ok(()) Ok(())
} }
@ -6303,7 +6305,7 @@ mod tests {
foo = get_foo() foo = get_foo()
", ",
)?; )?;
assert_public_ty(&db, "/src/stub.pyi", "foo", "Foo"); assert_public_type(&db, "/src/stub.pyi", "foo", "Foo");
Ok(()) Ok(())
} }
@ -6323,7 +6325,7 @@ mod tests {
foo = get_foo() foo = get_foo()
", ",
)?; )?;
assert_public_ty(&db, "/src/source.py", "foo", "Unknown"); assert_public_type(&db, "/src/source.py", "foo", "Unknown");
Ok(()) Ok(())
} }
@ -6342,7 +6344,7 @@ mod tests {
foo = get_foo() foo = get_foo()
", ",
)?; )?;
assert_public_ty(&db, "/src/source_with_future.py", "foo", "Foo"); assert_public_type(&db, "/src/source_with_future.py", "foo", "Foo");
Ok(()) Ok(())
} }
@ -6375,8 +6377,8 @@ mod tests {
", ",
)?; )?;
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "x", "int"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "x", "int");
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "y", "IntIterable"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "y", "IntIterable");
Ok(()) Ok(())
} }
@ -6404,14 +6406,14 @@ mod tests {
", ",
)?; )?;
assert_scope_ty( assert_scope_type(
&db, &db,
"src/a.py", "src/a.py",
&["foo", "<listcomp>", "<listcomp>"], &["foo", "<listcomp>", "<listcomp>"],
"x", "x",
"int", "int",
); );
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "y", "int"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "y", "int");
Ok(()) Ok(())
} }
@ -6446,14 +6448,14 @@ mod tests {
", ",
)?; )?;
assert_scope_ty( assert_scope_type(
&db, &db,
"src/a.py", "src/a.py",
&["foo", "<listcomp>", "<listcomp>"], &["foo", "<listcomp>", "<listcomp>"],
"x", "x",
"int", "int",
); );
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "y", "IntIterable"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "y", "IntIterable");
Ok(()) Ok(())
} }
@ -6468,7 +6470,7 @@ mod tests {
assert!(x.is_unbound()); assert!(x.is_unbound());
// Iterating over an unbound iterable yields `Unknown`: // Iterating over an unbound iterable yields `Unknown`:
assert_scope_ty(&db, "src/a.py", &["<listcomp>"], "z", "Unknown"); assert_scope_type(&db, "src/a.py", &["<listcomp>"], "z", "Unknown");
assert_file_diagnostics(&db, "src/a.py", &["Name `x` used when not defined"]); assert_file_diagnostics(&db, "src/a.py", &["Name `x` used when not defined"]);
@ -6495,8 +6497,8 @@ mod tests {
", ",
)?; )?;
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "x", "int"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "x", "int");
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "z", "Unknown"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "z", "Unknown");
assert_file_diagnostics(&db, "src/a.py", &["Object of type `int` is not iterable"]); assert_file_diagnostics(&db, "src/a.py", &["Object of type `int` is not iterable"]);
Ok(()) Ok(())
@ -6522,7 +6524,7 @@ mod tests {
", ",
)?; )?;
assert_scope_ty(&db, "src/a.py", &["foo", "<dictcomp>"], "x", "int"); assert_scope_type(&db, "src/a.py", &["foo", "<dictcomp>"], "x", "int");
assert_file_diagnostics(&db, "src/a.py", &[]); assert_file_diagnostics(&db, "src/a.py", &[]);
Ok(()) Ok(())
@ -6548,7 +6550,7 @@ mod tests {
", ",
)?; )?;
assert_scope_ty(&db, "src/a.py", &["foo", "<dictcomp>"], "x", "int"); assert_scope_type(&db, "src/a.py", &["foo", "<dictcomp>"], "x", "int");
assert_file_diagnostics(&db, "src/a.py", &[]); assert_file_diagnostics(&db, "src/a.py", &[]);
Ok(()) Ok(())
@ -6577,7 +6579,7 @@ mod tests {
// We'll emit a diagnostic separately for invalid syntax, // We'll emit a diagnostic separately for invalid syntax,
// but it's reasonably clear here what they *meant* to write, // but it's reasonably clear here what they *meant* to write,
// so we'll still infer the correct type: // so we'll still infer the correct type:
assert_scope_ty(&db, "src/a.py", &["foo", "<listcomp>"], "z", "int"); assert_scope_type(&db, "src/a.py", &["foo", "<listcomp>"], "z", "int");
Ok(()) Ok(())
} }
@ -6614,7 +6616,7 @@ mod tests {
fn comprehension_with_missing_for() -> anyhow::Result<()> { fn comprehension_with_missing_for() -> anyhow::Result<()> {
let mut db = setup_db(); let mut db = setup_db();
db.write_dedented("src/a.py", "[z for z in]")?; db.write_dedented("src/a.py", "[z for z in]")?;
assert_scope_ty(&db, "src/a.py", &["<listcomp>"], "z", "Unknown"); assert_scope_type(&db, "src/a.py", &["<listcomp>"], "z", "Unknown");
Ok(()) Ok(())
} }
@ -6622,7 +6624,7 @@ mod tests {
fn comprehension_with_missing_in_keyword_and_missing_iter() -> anyhow::Result<()> { fn comprehension_with_missing_in_keyword_and_missing_iter() -> anyhow::Result<()> {
let mut db = setup_db(); let mut db = setup_db();
db.write_dedented("src/a.py", "[z for z]")?; db.write_dedented("src/a.py", "[z for z]")?;
assert_scope_ty(&db, "src/a.py", &["<listcomp>"], "z", "Unknown"); assert_scope_type(&db, "src/a.py", &["<listcomp>"], "z", "Unknown");
Ok(()) Ok(())
} }
@ -6648,7 +6650,7 @@ mod tests {
// We currently return `Todo` for all async comprehensions, // We currently return `Todo` for all async comprehensions,
// including comprehensions that have invalid syntax // including comprehensions that have invalid syntax
assert_scope_ty( assert_scope_type(
&db, &db,
"src/a.py", "src/a.py",
&["foo", "<listcomp>"], &["foo", "<listcomp>"],
@ -6682,7 +6684,7 @@ mod tests {
)?; )?;
// TODO async iterables/iterators! --Alex // TODO async iterables/iterators! --Alex
assert_scope_ty( assert_scope_type(
&db, &db,
"src/a.py", "src/a.py",
&["foo", "<listcomp>"], &["foo", "<listcomp>"],

View file

@ -76,7 +76,7 @@ impl<'db> Mro<'db> {
// This *could* theoretically be handled by the final branch below, // This *could* theoretically be handled by the final branch below,
// but it's a common case (i.e., worth optimizing for), // but it's a common case (i.e., worth optimizing for),
// and the `c3_merge` function requires lots of allocations. // and the `c3_merge` function requires lots of allocations.
[single_base] => ClassBase::try_from_ty(db, *single_base).map_or_else( [single_base] => ClassBase::try_from_type(db, *single_base).map_or_else(
|| Err(MroErrorKind::InvalidBases(Box::from([(0, *single_base)]))), || Err(MroErrorKind::InvalidBases(Box::from([(0, *single_base)]))),
|single_base| { |single_base| {
Ok(std::iter::once(ClassBase::Class(class)) Ok(std::iter::once(ClassBase::Class(class))
@ -95,7 +95,7 @@ impl<'db> Mro<'db> {
let mut invalid_bases = vec![]; let mut invalid_bases = vec![];
for (i, base) in multiple_bases.iter().enumerate() { for (i, base) in multiple_bases.iter().enumerate() {
match ClassBase::try_from_ty(db, *base) { match ClassBase::try_from_type(db, *base) {
Some(valid_base) => valid_bases.push(valid_base), Some(valid_base) => valid_bases.push(valid_base),
None => invalid_bases.push((i, *base)), None => invalid_bases.push((i, *base)),
} }

View file

@ -322,9 +322,9 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
for (op, (left, right)) in std::iter::zip(&**ops, comparator_tuples) { for (op, (left, right)) in std::iter::zip(&**ops, comparator_tuples) {
let lhs_ty = last_rhs_ty.unwrap_or_else(|| { let lhs_ty = last_rhs_ty.unwrap_or_else(|| {
inference.expression_ty(left.scoped_expression_id(self.db, scope)) inference.expression_type(left.scoped_expression_id(self.db, scope))
}); });
let rhs_ty = inference.expression_ty(right.scoped_expression_id(self.db, scope)); let rhs_ty = inference.expression_type(right.scoped_expression_id(self.db, scope));
last_rhs_ty = Some(rhs_ty); last_rhs_ty = Some(rhs_ty);
match left { match left {
@ -393,7 +393,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
} }
let callable_ty = let callable_ty =
inference.expression_ty(callable.scoped_expression_id(self.db, scope)); inference.expression_type(callable.scoped_expression_id(self.db, scope));
if callable_ty if callable_ty
.into_class_literal() .into_class_literal()
@ -422,7 +422,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
let inference = infer_expression_types(self.db, expression); let inference = infer_expression_types(self.db, expression);
let callable_ty = let callable_ty =
inference.expression_ty(expr_call.func.scoped_expression_id(self.db, scope)); inference.expression_type(expr_call.func.scoped_expression_id(self.db, scope));
// TODO: add support for PEP 604 union types on the right hand side of `isinstance` // TODO: add support for PEP 604 union types on the right hand side of `isinstance`
// and `issubclass`, for example `isinstance(x, str | (int | float))`. // and `issubclass`, for example `isinstance(x, str | (int | float))`.
@ -441,7 +441,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
let symbol = self.symbols().symbol_id_by_name(id).unwrap(); let symbol = self.symbols().symbol_id_by_name(id).unwrap();
let class_info_ty = let class_info_ty =
inference.expression_ty(class_info.scoped_expression_id(self.db, scope)); inference.expression_type(class_info.scoped_expression_id(self.db, scope));
function function
.generate_constraint(self.db, class_info_ty) .generate_constraint(self.db, class_info_ty)
@ -500,7 +500,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
let scope = self.scope(); let scope = self.scope();
let inference = infer_expression_types(self.db, cls); let inference = infer_expression_types(self.db, cls);
let ty = inference let ty = inference
.expression_ty(cls.node_ref(self.db).scoped_expression_id(self.db, scope)) .expression_type(cls.node_ref(self.db).scoped_expression_id(self.db, scope))
.to_instance(self.db); .to_instance(self.db);
let mut constraints = NarrowingConstraints::default(); let mut constraints = NarrowingConstraints::default();
constraints.insert(symbol, ty); constraints.insert(symbol, ty);
@ -524,7 +524,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
// filter our arms with statically known truthiness // filter our arms with statically known truthiness
.filter(|expr| { .filter(|expr| {
inference inference
.expression_ty(expr.scoped_expression_id(self.db, scope)) .expression_type(expr.scoped_expression_id(self.db, scope))
.bool(self.db) .bool(self.db)
!= match expr_bool_op.op { != match expr_bool_op.op {
BoolOp::And => Truthiness::AlwaysTrue, BoolOp::And => Truthiness::AlwaysTrue,

View file

@ -1,4 +1,4 @@
use super::{definition_expression_ty, Type}; use super::{definition_expression_type, Type};
use crate::Db; use crate::Db;
use crate::{semantic_index::definition::Definition, types::todo_type}; use crate::{semantic_index::definition::Definition, types::todo_type};
use ruff_python_ast::{self as ast, name::Name}; use ruff_python_ast::{self as ast, name::Name};
@ -39,7 +39,7 @@ impl<'db> Signature<'db> {
if function_node.is_async { if function_node.is_async {
todo_type!("generic types.CoroutineType") todo_type!("generic types.CoroutineType")
} else { } else {
definition_expression_ty(db, definition, returns.as_ref()) definition_expression_type(db, definition, returns.as_ref())
} }
}); });
@ -97,7 +97,7 @@ impl<'db> Parameters<'db> {
parameter_with_default parameter_with_default
.default .default
.as_deref() .as_deref()
.map(|default| definition_expression_ty(db, definition, default)) .map(|default| definition_expression_type(db, definition, default))
}; };
let positional_only = posonlyargs.iter().map(|arg| { let positional_only = posonlyargs.iter().map(|arg| {
Parameter::from_node_and_kind( Parameter::from_node_and_kind(
@ -245,7 +245,7 @@ impl<'db> Parameter<'db> {
annotated_ty: parameter annotated_ty: parameter
.annotation .annotation
.as_deref() .as_deref()
.map(|annotation| definition_expression_ty(db, definition, annotation)), .map(|annotation| definition_expression_type(db, definition, annotation)),
kind, kind,
} }
} }
@ -276,7 +276,7 @@ impl<'db> Parameter<'db> {
} }
/// Annotated type of the parameter, if annotated. /// Annotated type of the parameter, if annotated.
pub(crate) fn annotated_ty(&self) -> Option<Type<'db>> { pub(crate) fn annotated_type(&self) -> Option<Type<'db>> {
self.annotated_ty self.annotated_ty
} }
@ -295,7 +295,7 @@ impl<'db> Parameter<'db> {
} }
/// Default-value type of the parameter, if any. /// Default-value type of the parameter, if any.
pub(crate) fn default_ty(&self) -> Option<Type<'db>> { pub(crate) fn default_type(&self) -> Option<Type<'db>> {
match self.kind { match self.kind {
ParameterKind::PositionalOnly { default_ty } => default_ty, ParameterKind::PositionalOnly { default_ty } => default_ty,
ParameterKind::PositionalOrKeyword { default_ty } => default_ty, ParameterKind::PositionalOrKeyword { default_ty } => default_ty,

View file

@ -43,7 +43,7 @@ impl<'db> Unpacker<'db> {
); );
let mut value_ty = infer_expression_types(self.db(), value.expression()) let mut value_ty = infer_expression_types(self.db(), value.expression())
.expression_ty(value.scoped_expression_id(self.db(), self.scope)); .expression_type(value.scoped_expression_id(self.db(), self.scope));
if value.is_assign() if value.is_assign()
&& self.context.in_stub() && self.context.in_stub()

View file

@ -294,8 +294,8 @@ impl<'db> VisibilityConstraints<'db> {
ConstraintNode::Expression(test_expr) => { ConstraintNode::Expression(test_expr) => {
let inference = infer_expression_types(db, test_expr); let inference = infer_expression_types(db, test_expr);
let scope = test_expr.scope(db); let scope = test_expr.scope(db);
let ty = let ty = inference
inference.expression_ty(test_expr.node_ref(db).scoped_expression_id(db, scope)); .expression_type(test_expr.node_ref(db).scoped_expression_id(db, scope));
ty.bool(db).negate_if(!constraint.is_positive) ty.bool(db).negate_if(!constraint.is_positive)
} }
@ -304,7 +304,7 @@ impl<'db> VisibilityConstraints<'db> {
let subject_expression = inner.subject(db); let subject_expression = inner.subject(db);
let inference = infer_expression_types(db, *subject_expression); let inference = infer_expression_types(db, *subject_expression);
let scope = subject_expression.scope(db); let scope = subject_expression.scope(db);
let subject_ty = inference.expression_ty( let subject_ty = inference.expression_type(
subject_expression subject_expression
.node_ref(db) .node_ref(db)
.scoped_expression_id(db, scope), .scoped_expression_id(db, scope),
@ -312,8 +312,8 @@ impl<'db> VisibilityConstraints<'db> {
let inference = infer_expression_types(db, *value); let inference = infer_expression_types(db, *value);
let scope = value.scope(db); let scope = value.scope(db);
let value_ty = let value_ty = inference
inference.expression_ty(value.node_ref(db).scoped_expression_id(db, scope)); .expression_type(value.node_ref(db).scoped_expression_id(db, scope));
if subject_ty.is_single_valued(db) { if subject_ty.is_single_valued(db) {
let truthiness = let truthiness =