mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 05:44:56 +00:00
[ty] Improve disambiguation of class names in diagnostics (#20603)
This commit is contained in:
parent
81f43a1fc8
commit
3f640dacd4
6 changed files with 243 additions and 154 deletions
|
@ -43,8 +43,7 @@ import b
|
|||
df: a.DataFrame = b.DataFrame() # error: [invalid-assignment] "Object of type `b.DataFrame` is not assignable to `a.DataFrame`"
|
||||
|
||||
def _(dfs: list[b.DataFrame]):
|
||||
# TODO should be"Object of type `list[b.DataFrame]` is not assignable to `list[a.DataFrame]`
|
||||
# error: [invalid-assignment] "Object of type `list[DataFrame]` is not assignable to `list[DataFrame]`"
|
||||
# error: [invalid-assignment] "Object of type `list[b.DataFrame]` is not assignable to `list[a.DataFrame]`"
|
||||
dataframes: list[a.DataFrame] = dfs
|
||||
```
|
||||
|
||||
|
@ -228,3 +227,21 @@ from typing import TypedDict
|
|||
class Person(TypedDict):
|
||||
name: bytes
|
||||
```
|
||||
|
||||
## Tuple specializations
|
||||
|
||||
`module.py`:
|
||||
|
||||
```py
|
||||
class Model: ...
|
||||
```
|
||||
|
||||
```py
|
||||
class Model: ...
|
||||
|
||||
def get_models_tuple() -> tuple[Model]:
|
||||
from module import Model
|
||||
|
||||
# error: [invalid-return-type] "Return type does not match returned value: expected `tuple[mdtest_snippet.Model]`, found `tuple[module.Model]`"
|
||||
return (Model(),)
|
||||
```
|
||||
|
|
|
@ -339,7 +339,7 @@ class A: ...
|
|||
|
||||
def f(x: A):
|
||||
# TODO: no error
|
||||
# error: [invalid-assignment] "Object of type `A | A` is not assignable to `A`"
|
||||
# error: [invalid-assignment] "Object of type `mdtest_snippet.A | mdtest_snippet.A` is not assignable to `mdtest_snippet.A`"
|
||||
x = A()
|
||||
```
|
||||
|
||||
|
|
|
@ -7065,7 +7065,11 @@ impl<'db> KnownInstanceType<'db> {
|
|||
if let Some(specialization) = alias.specialization(self.db) {
|
||||
f.write_str(alias.name(self.db))?;
|
||||
specialization
|
||||
.display_short(self.db, TupleSpecialization::No)
|
||||
.display_short(
|
||||
self.db,
|
||||
TupleSpecialization::No,
|
||||
DisplaySettings::default(),
|
||||
)
|
||||
.fmt(f)
|
||||
} else {
|
||||
f.write_str("typing.TypeAliasType")
|
||||
|
|
|
@ -1986,7 +1986,7 @@ pub(super) fn report_invalid_assignment<'db>(
|
|||
target_ty,
|
||||
format_args!(
|
||||
"Object of type `{}` is not assignable to `{}`",
|
||||
source_ty.display_with(context.db(), settings),
|
||||
source_ty.display_with(context.db(), settings.clone()),
|
||||
target_ty.display_with(context.db(), settings)
|
||||
),
|
||||
);
|
||||
|
@ -2068,8 +2068,8 @@ pub(super) fn report_invalid_return_type(
|
|||
let mut diag = builder.into_diagnostic("Return type does not match returned value");
|
||||
diag.set_primary_message(format_args!(
|
||||
"expected `{expected_ty}`, found `{actual_ty}`",
|
||||
expected_ty = expected_ty.display_with(context.db(), settings),
|
||||
actual_ty = actual_ty.display_with(context.db(), settings),
|
||||
expected_ty = expected_ty.display_with(context.db(), settings.clone()),
|
||||
actual_ty = actual_ty.display_with(context.db(), settings.clone()),
|
||||
));
|
||||
diag.annotate(
|
||||
Annotation::secondary(return_type_span).message(format_args!(
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
//! Display implementations for types.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::rc::Rc;
|
||||
|
||||
use ruff_db::display::FormatterJoinExtension;
|
||||
use ruff_python_ast::str::{Quote, TripleQuotes};
|
||||
use ruff_python_literal::escape::AsciiEscape;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use crate::Db;
|
||||
use crate::module_resolver::file_to_module;
|
||||
|
@ -15,117 +19,149 @@ use crate::types::function::{FunctionType, OverloadLiteral};
|
|||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
||||
use crate::types::tuple::TupleSpec;
|
||||
use crate::types::visitor::TypeVisitor;
|
||||
use crate::types::{
|
||||
BoundTypeVarInstance, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
|
||||
MaterializationKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
|
||||
UnionType, WrapperDescriptorKind,
|
||||
MaterializationKind, Protocol, StringLiteralType, SubclassOfInner, Type, UnionType,
|
||||
WrapperDescriptorKind, visitor,
|
||||
};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
|
||||
/// Settings for displaying types and signatures
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct DisplaySettings {
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct DisplaySettings<'db> {
|
||||
/// Whether rendering can be multiline
|
||||
pub multiline: bool,
|
||||
/// Whether rendering will show qualified display (e.g., module.class)
|
||||
pub qualified: bool,
|
||||
/// Class names that should be displayed fully qualified
|
||||
/// (e.g., `module.ClassName` instead of just `ClassName`)
|
||||
pub qualified: Rc<FxHashSet<&'db str>>,
|
||||
}
|
||||
|
||||
impl DisplaySettings {
|
||||
impl<'db> DisplaySettings<'db> {
|
||||
#[must_use]
|
||||
pub fn multiline(self) -> Self {
|
||||
pub fn multiline(&self) -> Self {
|
||||
Self {
|
||||
multiline: true,
|
||||
..self
|
||||
..self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn singleline(self) -> Self {
|
||||
pub fn singleline(&self) -> Self {
|
||||
Self {
|
||||
multiline: false,
|
||||
..self
|
||||
..self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn qualified(self) -> Self {
|
||||
Self {
|
||||
qualified: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn from_possibly_ambiguous_type_pair<'db>(
|
||||
pub fn from_possibly_ambiguous_type_pair(
|
||||
db: &'db dyn Db,
|
||||
type_1: Type<'db>,
|
||||
type_2: Type<'db>,
|
||||
) -> Self {
|
||||
let result = Self::default();
|
||||
let collector = AmbiguousClassCollector::default();
|
||||
collector.visit_type(db, type_1);
|
||||
collector.visit_type(db, type_2);
|
||||
|
||||
let Some(class_1) = type_to_class_literal(db, type_1) else {
|
||||
return result;
|
||||
};
|
||||
|
||||
let Some(class_2) = type_to_class_literal(db, type_2) else {
|
||||
return result;
|
||||
};
|
||||
|
||||
if class_1 == class_2 {
|
||||
return result;
|
||||
}
|
||||
|
||||
if class_1.name(db) == class_2.name(db) {
|
||||
result.qualified()
|
||||
} else {
|
||||
result
|
||||
Self {
|
||||
qualified: Rc::new(
|
||||
collector
|
||||
.class_names
|
||||
.borrow()
|
||||
.iter()
|
||||
.filter_map(|(name, ambiguity)| ambiguity.is_ambiguous().then_some(*name))
|
||||
.collect(),
|
||||
),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: generalize this to a method that takes any two types, walks them recursively, and returns
|
||||
// a set of types with ambiguous names whose display should be qualified. Then we can use this in
|
||||
// any diagnostic that displays two types.
|
||||
fn type_to_class_literal<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<ClassLiteral<'db>> {
|
||||
#[derive(Debug, Default)]
|
||||
struct AmbiguousClassCollector<'db> {
|
||||
visited_types: RefCell<FxHashSet<Type<'db>>>,
|
||||
class_names: RefCell<FxHashMap<&'db str, AmbiguityState<'db>>>,
|
||||
}
|
||||
|
||||
impl<'db> AmbiguousClassCollector<'db> {
|
||||
fn record_class(&self, db: &'db dyn Db, class: ClassLiteral<'db>) {
|
||||
match self.class_names.borrow_mut().entry(class.name(db)) {
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(AmbiguityState::Unambiguous(class));
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
let value = entry.get_mut();
|
||||
if let AmbiguityState::Unambiguous(existing) = value
|
||||
&& *existing != class
|
||||
{
|
||||
*value = AmbiguityState::Ambiguous;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not a class can be unambiguously identified by its *unqualified* name
|
||||
/// given the other types that are present in the same context.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum AmbiguityState<'db> {
|
||||
/// The class can be displayed unambiguously using its unqualified name
|
||||
Unambiguous(ClassLiteral<'db>),
|
||||
/// The class must be displayed using its fully qualified name to avoid ambiguity.
|
||||
Ambiguous,
|
||||
}
|
||||
|
||||
impl AmbiguityState<'_> {
|
||||
const fn is_ambiguous(self) -> bool {
|
||||
matches!(self, AmbiguityState::Ambiguous)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> super::visitor::TypeVisitor<'db> for AmbiguousClassCollector<'db> {
|
||||
fn should_visit_lazy_type_attributes(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn visit_type(&self, db: &'db dyn Db, ty: Type<'db>) {
|
||||
match ty {
|
||||
Type::ClassLiteral(class) => Some(class),
|
||||
Type::NominalInstance(instance) => Some(instance.class_literal(db)),
|
||||
Type::EnumLiteral(enum_literal) => Some(enum_literal.enum_class(db)),
|
||||
Type::GenericAlias(alias) => Some(alias.origin(db)),
|
||||
Type::ProtocolInstance(ProtocolInstanceType {
|
||||
inner: Protocol::FromClass(class),
|
||||
..
|
||||
}) => type_to_class_literal(db, Type::from(class)),
|
||||
Type::TypedDict(typed_dict) => {
|
||||
type_to_class_literal(db, Type::from(typed_dict.defining_class()))
|
||||
Type::ClassLiteral(class) => self.record_class(db, class),
|
||||
Type::EnumLiteral(literal) => self.record_class(db, literal.enum_class(db)),
|
||||
Type::GenericAlias(alias) => self.record_class(db, alias.origin(db)),
|
||||
_ => {}
|
||||
}
|
||||
Type::SubclassOf(subclass_of) => {
|
||||
type_to_class_literal(db, Type::from(subclass_of.subclass_of().into_class()?))
|
||||
|
||||
if let visitor::TypeKind::NonAtomic(t) = visitor::TypeKind::from(ty) {
|
||||
if !self.visited_types.borrow_mut().insert(ty) {
|
||||
// If we have already seen this type, we can skip it.
|
||||
return;
|
||||
}
|
||||
visitor::walk_non_atomic_type(db, t, self);
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Type<'db> {
|
||||
pub fn display(&self, db: &'db dyn Db) -> DisplayType<'_> {
|
||||
pub fn display(self, db: &'db dyn Db) -> DisplayType<'db> {
|
||||
DisplayType {
|
||||
ty: self,
|
||||
settings: DisplaySettings::default(),
|
||||
db,
|
||||
}
|
||||
}
|
||||
pub fn display_with(&self, db: &'db dyn Db, settings: DisplaySettings) -> DisplayType<'_> {
|
||||
|
||||
pub fn display_with(self, db: &'db dyn Db, settings: DisplaySettings<'db>) -> DisplayType<'db> {
|
||||
DisplayType {
|
||||
ty: self,
|
||||
db,
|
||||
settings,
|
||||
}
|
||||
}
|
||||
|
||||
fn representation(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayRepresentation<'db> {
|
||||
DisplayRepresentation {
|
||||
db,
|
||||
|
@ -135,16 +171,15 @@ impl<'db> Type<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DisplayType<'db> {
|
||||
ty: &'db Type<'db>,
|
||||
ty: Type<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayType<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let representation = self.ty.representation(self.db, self.settings);
|
||||
let representation = self.ty.representation(self.db, self.settings.clone());
|
||||
match self.ty {
|
||||
Type::IntLiteral(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
|
@ -165,7 +200,7 @@ impl fmt::Debug for DisplayType<'_> {
|
|||
}
|
||||
|
||||
impl<'db> ClassLiteral<'db> {
|
||||
fn display_with(self, db: &'db dyn Db, settings: DisplaySettings) -> ClassDisplay<'db> {
|
||||
fn display_with(self, db: &'db dyn Db, settings: DisplaySettings<'db>) -> ClassDisplay<'db> {
|
||||
ClassDisplay {
|
||||
db,
|
||||
class: self,
|
||||
|
@ -177,7 +212,7 @@ impl<'db> ClassLiteral<'db> {
|
|||
struct ClassDisplay<'db> {
|
||||
db: &'db dyn Db,
|
||||
class: ClassLiteral<'db>,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl ClassDisplay<'_> {
|
||||
|
@ -224,7 +259,11 @@ impl ClassDisplay<'_> {
|
|||
|
||||
impl Display for ClassDisplay<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
if self.settings.qualified {
|
||||
if self
|
||||
.settings
|
||||
.qualified
|
||||
.contains(&**self.class.name(self.db))
|
||||
{
|
||||
for parent in self.class_parents() {
|
||||
f.write_str(&parent)?;
|
||||
f.write_char('.')?;
|
||||
|
@ -240,7 +279,7 @@ impl Display for ClassDisplay<'_> {
|
|||
struct DisplayRepresentation<'db> {
|
||||
ty: Type<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayRepresentation<'_> {
|
||||
|
@ -258,20 +297,20 @@ impl Display for DisplayRepresentation<'_> {
|
|||
.specialization(self.db)
|
||||
.tuple(self.db)
|
||||
.expect("Specialization::tuple() should always return `Some()` for `KnownClass::Tuple`")
|
||||
.display_with(self.db, self.settings)
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt(f),
|
||||
(ClassType::NonGeneric(class), _) => {
|
||||
class.display_with(self.db, self.settings).fmt(f)
|
||||
class.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
},
|
||||
(ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings).fmt(f),
|
||||
(ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings.clone()).fmt(f),
|
||||
}
|
||||
}
|
||||
Type::ProtocolInstance(protocol) => match protocol.inner {
|
||||
Protocol::FromClass(ClassType::NonGeneric(class)) => {
|
||||
class.display_with(self.db, self.settings).fmt(f)
|
||||
class.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
}
|
||||
Protocol::FromClass(ClassType::Generic(alias)) => {
|
||||
alias.display_with(self.db, self.settings).fmt(f)
|
||||
alias.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
}
|
||||
Protocol::Synthesized(synthetic) => {
|
||||
f.write_str("<Protocol with members ")?;
|
||||
|
@ -295,7 +334,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
Type::ClassLiteral(class) => write!(
|
||||
f,
|
||||
"<class '{}'>",
|
||||
class.display_with(self.db, self.settings)
|
||||
class.display_with(self.db, self.settings.clone())
|
||||
),
|
||||
Type::GenericAlias(generic) => write!(
|
||||
f,
|
||||
|
@ -304,7 +343,11 @@ impl Display for DisplayRepresentation<'_> {
|
|||
),
|
||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Class(ClassType::NonGeneric(class)) => {
|
||||
write!(f, "type[{}]", class.display_with(self.db, self.settings))
|
||||
write!(
|
||||
f,
|
||||
"type[{}]",
|
||||
class.display_with(self.db, self.settings.clone())
|
||||
)
|
||||
}
|
||||
SubclassOfInner::Class(ClassType::Generic(alias)) => {
|
||||
write!(
|
||||
|
@ -317,8 +360,12 @@ impl Display for DisplayRepresentation<'_> {
|
|||
},
|
||||
Type::SpecialForm(special_form) => special_form.fmt(f),
|
||||
Type::KnownInstance(known_instance) => known_instance.repr(self.db).fmt(f),
|
||||
Type::FunctionLiteral(function) => function.display_with(self.db, self.settings).fmt(f),
|
||||
Type::Callable(callable) => callable.display_with(self.db, self.settings).fmt(f),
|
||||
Type::FunctionLiteral(function) => {
|
||||
function.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
}
|
||||
Type::Callable(callable) => {
|
||||
callable.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
}
|
||||
Type::BoundMethod(bound_method) => {
|
||||
let function = bound_method.function(self.db);
|
||||
let self_ty = bound_method.self_instance(self.db);
|
||||
|
@ -329,7 +376,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
let type_parameters = DisplayOptionalGenericContext {
|
||||
generic_context: signature.generic_context.as_ref(),
|
||||
db: self.db,
|
||||
settings: self.settings,
|
||||
settings: self.settings.clone(),
|
||||
};
|
||||
|
||||
write!(
|
||||
|
@ -340,7 +387,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
type_parameters = type_parameters,
|
||||
signature = signature
|
||||
.bind_self(self.db, Some(typing_self_ty))
|
||||
.display_with(self.db, self.settings)
|
||||
.display_with(self.db, self.settings.clone())
|
||||
)
|
||||
}
|
||||
signatures => {
|
||||
|
@ -354,7 +401,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
join.entry(
|
||||
&signature
|
||||
.bind_self(self.db, Some(typing_self_ty))
|
||||
.display_with(self.db, self.settings),
|
||||
.display_with(self.db, self.settings.clone()),
|
||||
);
|
||||
}
|
||||
if !self.settings.multiline {
|
||||
|
@ -404,13 +451,15 @@ impl Display for DisplayRepresentation<'_> {
|
|||
Type::DataclassTransformer(_) => {
|
||||
f.write_str("<decorator produced by typing.dataclass_transform>")
|
||||
}
|
||||
Type::Union(union) => union.display_with(self.db, self.settings).fmt(f),
|
||||
Type::Intersection(intersection) => {
|
||||
intersection.display_with(self.db, self.settings).fmt(f)
|
||||
}
|
||||
Type::Union(union) => union.display_with(self.db, self.settings.clone()).fmt(f),
|
||||
Type::Intersection(intersection) => intersection
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt(f),
|
||||
Type::IntLiteral(n) => n.fmt(f),
|
||||
Type::BooleanLiteral(boolean) => f.write_str(if boolean { "True" } else { "False" }),
|
||||
Type::StringLiteral(string) => string.display_with(self.db, self.settings).fmt(f),
|
||||
Type::StringLiteral(string) => {
|
||||
string.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
}
|
||||
Type::LiteralString => f.write_str("LiteralString"),
|
||||
Type::BytesLiteral(bytes) => {
|
||||
let escape = AsciiEscape::with_preferred_quote(bytes.value(self.db), Quote::Double);
|
||||
|
@ -422,7 +471,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
"{enum_class}.{literal_name}",
|
||||
enum_class = enum_literal
|
||||
.enum_class(self.db)
|
||||
.display_with(self.db, self.settings),
|
||||
.display_with(self.db, self.settings.clone()),
|
||||
literal_name = enum_literal.name(self.db)
|
||||
),
|
||||
Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
|
||||
|
@ -458,7 +507,7 @@ impl Display for DisplayRepresentation<'_> {
|
|||
.defining_class()
|
||||
.class_literal(self.db)
|
||||
.0
|
||||
.display_with(self.db, self.settings)
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt(f),
|
||||
Type::TypeAlias(alias) => f.write_str(alias.name(self.db)),
|
||||
}
|
||||
|
@ -493,7 +542,7 @@ impl<'db> TupleSpec<'db> {
|
|||
pub(crate) fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayTuple<'db> {
|
||||
DisplayTuple {
|
||||
tuple: self,
|
||||
|
@ -506,7 +555,7 @@ impl<'db> TupleSpec<'db> {
|
|||
pub(crate) struct DisplayTuple<'db> {
|
||||
tuple: &'db TupleSpec<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayTuple<'_> {
|
||||
|
@ -580,7 +629,7 @@ impl<'db> OverloadLiteral<'db> {
|
|||
pub(crate) fn display_with(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayOverloadLiteral<'db> {
|
||||
DisplayOverloadLiteral {
|
||||
literal: self,
|
||||
|
@ -593,7 +642,7 @@ impl<'db> OverloadLiteral<'db> {
|
|||
pub(crate) struct DisplayOverloadLiteral<'db> {
|
||||
literal: OverloadLiteral<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayOverloadLiteral<'_> {
|
||||
|
@ -602,7 +651,7 @@ impl Display for DisplayOverloadLiteral<'_> {
|
|||
let type_parameters = DisplayOptionalGenericContext {
|
||||
generic_context: signature.generic_context.as_ref(),
|
||||
db: self.db,
|
||||
settings: self.settings,
|
||||
settings: self.settings.clone(),
|
||||
};
|
||||
|
||||
write!(
|
||||
|
@ -610,7 +659,7 @@ impl Display for DisplayOverloadLiteral<'_> {
|
|||
"def {name}{type_parameters}{signature}",
|
||||
name = self.literal.name(self.db),
|
||||
type_parameters = type_parameters,
|
||||
signature = signature.display_with(self.db, self.settings)
|
||||
signature = signature.display_with(self.db, self.settings.clone())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -619,7 +668,7 @@ impl<'db> FunctionType<'db> {
|
|||
pub(crate) fn display_with(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayFunctionType<'db> {
|
||||
DisplayFunctionType {
|
||||
ty: self,
|
||||
|
@ -632,7 +681,7 @@ impl<'db> FunctionType<'db> {
|
|||
pub(crate) struct DisplayFunctionType<'db> {
|
||||
ty: FunctionType<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayFunctionType<'_> {
|
||||
|
@ -644,7 +693,7 @@ impl Display for DisplayFunctionType<'_> {
|
|||
let type_parameters = DisplayOptionalGenericContext {
|
||||
generic_context: signature.generic_context.as_ref(),
|
||||
db: self.db,
|
||||
settings: self.settings,
|
||||
settings: self.settings.clone(),
|
||||
};
|
||||
|
||||
write!(
|
||||
|
@ -652,7 +701,7 @@ impl Display for DisplayFunctionType<'_> {
|
|||
"def {name}{type_parameters}{signature}",
|
||||
name = self.ty.name(self.db),
|
||||
type_parameters = type_parameters,
|
||||
signature = signature.display_with(self.db, self.settings)
|
||||
signature = signature.display_with(self.db, self.settings.clone())
|
||||
)
|
||||
}
|
||||
signatures => {
|
||||
|
@ -663,7 +712,7 @@ impl Display for DisplayFunctionType<'_> {
|
|||
let separator = if self.settings.multiline { "\n" } else { ", " };
|
||||
let mut join = f.join(separator);
|
||||
for signature in signatures {
|
||||
join.entry(&signature.display_with(self.db, self.settings));
|
||||
join.entry(&signature.display_with(self.db, self.settings.clone()));
|
||||
}
|
||||
if !self.settings.multiline {
|
||||
f.write_str("]")?;
|
||||
|
@ -678,7 +727,7 @@ impl<'db> GenericAlias<'db> {
|
|||
pub(crate) fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayGenericAlias<'db> {
|
||||
DisplayGenericAlias {
|
||||
origin: self.origin(db),
|
||||
|
@ -693,13 +742,13 @@ pub(crate) struct DisplayGenericAlias<'db> {
|
|||
origin: ClassLiteral<'db>,
|
||||
specialization: Specialization<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayGenericAlias<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
if let Some(tuple) = self.specialization.tuple(self.db) {
|
||||
tuple.display_with(self.db, self.settings).fmt(f)
|
||||
tuple.display_with(self.db, self.settings.clone()).fmt(f)
|
||||
} else {
|
||||
let prefix = match self.specialization.materialization_kind(self.db) {
|
||||
None => "",
|
||||
|
@ -714,10 +763,11 @@ impl Display for DisplayGenericAlias<'_> {
|
|||
f,
|
||||
"{prefix}{origin}{specialization}{suffix}",
|
||||
prefix = prefix,
|
||||
origin = self.origin.display_with(self.db, self.settings),
|
||||
origin = self.origin.display_with(self.db, self.settings.clone()),
|
||||
specialization = self.specialization.display_short(
|
||||
self.db,
|
||||
TupleSpecialization::from_class(self.db, self.origin)
|
||||
TupleSpecialization::from_class(self.db, self.origin),
|
||||
self.settings.clone()
|
||||
),
|
||||
suffix = suffix,
|
||||
)
|
||||
|
@ -732,7 +782,7 @@ impl<'db> GenericContext<'db> {
|
|||
pub fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayGenericContext<'db> {
|
||||
DisplayGenericContext {
|
||||
generic_context: self,
|
||||
|
@ -745,7 +795,7 @@ impl<'db> GenericContext<'db> {
|
|||
struct DisplayOptionalGenericContext<'db> {
|
||||
generic_context: Option<&'db GenericContext<'db>>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayOptionalGenericContext<'_> {
|
||||
|
@ -754,7 +804,7 @@ impl Display for DisplayOptionalGenericContext<'_> {
|
|||
DisplayGenericContext {
|
||||
generic_context,
|
||||
db: self.db,
|
||||
settings: self.settings,
|
||||
settings: self.settings.clone(),
|
||||
}
|
||||
.fmt(f)
|
||||
} else {
|
||||
|
@ -767,7 +817,7 @@ pub struct DisplayGenericContext<'db> {
|
|||
generic_context: &'db GenericContext<'db>,
|
||||
db: &'db dyn Db,
|
||||
#[expect(dead_code)]
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayGenericContext<'_> {
|
||||
|
@ -800,12 +850,13 @@ impl<'db> Specialization<'db> {
|
|||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
tuple_specialization: TupleSpecialization,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplaySpecialization<'db> {
|
||||
DisplaySpecialization {
|
||||
types: self.types(db),
|
||||
db,
|
||||
tuple_specialization,
|
||||
settings: DisplaySettings::default(),
|
||||
settings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -814,7 +865,7 @@ pub struct DisplaySpecialization<'db> {
|
|||
types: &'db [Type<'db>],
|
||||
db: &'db dyn Db,
|
||||
tuple_specialization: TupleSpecialization,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplaySpecialization<'_> {
|
||||
|
@ -824,7 +875,7 @@ impl Display for DisplaySpecialization<'_> {
|
|||
if idx > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
ty.display_with(self.db, self.settings).fmt(f)?;
|
||||
ty.display_with(self.db, self.settings.clone()).fmt(f)?;
|
||||
}
|
||||
if self.tuple_specialization.is_yes() {
|
||||
f.write_str(", ...")?;
|
||||
|
@ -861,7 +912,7 @@ impl<'db> CallableType<'db> {
|
|||
pub(crate) fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayCallableType<'db> {
|
||||
DisplayCallableType {
|
||||
signatures: self.signatures(db),
|
||||
|
@ -874,13 +925,15 @@ impl<'db> CallableType<'db> {
|
|||
pub(crate) struct DisplayCallableType<'db> {
|
||||
signatures: &'db CallableSignature<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayCallableType<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self.signatures.overloads.as_slice() {
|
||||
[signature] => signature.display_with(self.db, self.settings).fmt(f),
|
||||
[signature] => signature
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt(f),
|
||||
signatures => {
|
||||
// TODO: How to display overloads?
|
||||
if !self.settings.multiline {
|
||||
|
@ -889,7 +942,7 @@ impl Display for DisplayCallableType<'_> {
|
|||
let separator = if self.settings.multiline { "\n" } else { ", " };
|
||||
let mut join = f.join(separator);
|
||||
for signature in signatures {
|
||||
join.entry(&signature.display_with(self.db, self.settings));
|
||||
join.entry(&signature.display_with(self.db, self.settings.clone()));
|
||||
}
|
||||
join.finish()?;
|
||||
if !self.settings.multiline {
|
||||
|
@ -909,7 +962,7 @@ impl<'db> Signature<'db> {
|
|||
pub(crate) fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplaySignature<'db> {
|
||||
DisplaySignature {
|
||||
parameters: self.parameters(),
|
||||
|
@ -924,7 +977,7 @@ pub(crate) struct DisplaySignature<'db> {
|
|||
parameters: &'db Parameters<'db>,
|
||||
return_ty: Option<Type<'db>>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl DisplaySignature<'_> {
|
||||
|
@ -1128,7 +1181,7 @@ impl<'db> Parameter<'db> {
|
|||
fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayParameter<'db> {
|
||||
DisplayParameter {
|
||||
param: self,
|
||||
|
@ -1141,7 +1194,7 @@ impl<'db> Parameter<'db> {
|
|||
struct DisplayParameter<'db> {
|
||||
param: &'db Parameter<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayParameter<'_> {
|
||||
|
@ -1152,21 +1205,29 @@ impl Display for DisplayParameter<'_> {
|
|||
write!(
|
||||
f,
|
||||
": {}",
|
||||
annotated_type.display_with(self.db, self.settings)
|
||||
annotated_type.display_with(self.db, self.settings.clone())
|
||||
)?;
|
||||
}
|
||||
// Default value can only be specified if `name` is given.
|
||||
if let Some(default_ty) = self.param.default_type() {
|
||||
if self.param.annotated_type().is_some() {
|
||||
write!(f, " = {}", default_ty.display_with(self.db, self.settings))?;
|
||||
write!(
|
||||
f,
|
||||
" = {}",
|
||||
default_ty.display_with(self.db, self.settings.clone())
|
||||
)?;
|
||||
} else {
|
||||
write!(f, "={}", default_ty.display_with(self.db, self.settings))?;
|
||||
write!(
|
||||
f,
|
||||
"={}",
|
||||
default_ty.display_with(self.db, self.settings.clone())
|
||||
)?;
|
||||
}
|
||||
}
|
||||
} else if let Some(ty) = self.param.annotated_type() {
|
||||
// This case is specifically for the `Callable` signature where name and default value
|
||||
// cannot be provided.
|
||||
ty.display_with(self.db, self.settings).fmt(f)?;
|
||||
ty.display_with(self.db, self.settings.clone()).fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1176,7 +1237,7 @@ impl<'db> UnionType<'db> {
|
|||
fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayUnionType<'db> {
|
||||
DisplayUnionType {
|
||||
db,
|
||||
|
@ -1189,7 +1250,7 @@ impl<'db> UnionType<'db> {
|
|||
struct DisplayUnionType<'db> {
|
||||
ty: &'db UnionType<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayUnionType<'_> {
|
||||
|
@ -1249,7 +1310,7 @@ impl fmt::Debug for DisplayUnionType<'_> {
|
|||
struct DisplayLiteralGroup<'db> {
|
||||
literals: Vec<Type<'db>>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayLiteralGroup<'_> {
|
||||
|
@ -1270,7 +1331,7 @@ impl<'db> IntersectionType<'db> {
|
|||
fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayIntersectionType<'db> {
|
||||
DisplayIntersectionType {
|
||||
db,
|
||||
|
@ -1283,7 +1344,7 @@ impl<'db> IntersectionType<'db> {
|
|||
struct DisplayIntersectionType<'db> {
|
||||
ty: &'db IntersectionType<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayIntersectionType<'_> {
|
||||
|
@ -1323,7 +1384,7 @@ struct DisplayMaybeNegatedType<'db> {
|
|||
ty: Type<'db>,
|
||||
db: &'db dyn Db,
|
||||
negated: bool,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayMaybeNegatedType<'_> {
|
||||
|
@ -1334,7 +1395,7 @@ impl Display for DisplayMaybeNegatedType<'_> {
|
|||
DisplayMaybeParenthesizedType {
|
||||
ty: self.ty,
|
||||
db: self.db,
|
||||
settings: self.settings,
|
||||
settings: self.settings.clone(),
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
|
@ -1343,13 +1404,18 @@ impl Display for DisplayMaybeNegatedType<'_> {
|
|||
struct DisplayMaybeParenthesizedType<'db> {
|
||||
ty: Type<'db>,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayMaybeParenthesizedType<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let write_parentheses =
|
||||
|f: &mut Formatter<'_>| write!(f, "({})", self.ty.display_with(self.db, self.settings));
|
||||
let write_parentheses = |f: &mut Formatter<'_>| {
|
||||
write!(
|
||||
f,
|
||||
"({})",
|
||||
self.ty.display_with(self.db, self.settings.clone())
|
||||
)
|
||||
};
|
||||
match self.ty {
|
||||
Type::Callable(_)
|
||||
| Type::KnownBoundMethod(_)
|
||||
|
@ -1359,21 +1425,24 @@ impl Display for DisplayMaybeParenthesizedType<'_> {
|
|||
Type::Intersection(intersection) if !intersection.has_one_element(self.db) => {
|
||||
write_parentheses(f)
|
||||
}
|
||||
_ => self.ty.display_with(self.db, self.settings).fmt(f),
|
||||
_ => self.ty.display_with(self.db, self.settings.clone()).fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait TypeArrayDisplay<'db> {
|
||||
fn display_with(&self, db: &'db dyn Db, settings: DisplaySettings)
|
||||
-> DisplayTypeArray<'_, 'db>;
|
||||
fn display_with(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayTypeArray<'_, 'db>;
|
||||
}
|
||||
|
||||
impl<'db> TypeArrayDisplay<'db> for Box<[Type<'db>]> {
|
||||
fn display_with(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayTypeArray<'_, 'db> {
|
||||
DisplayTypeArray {
|
||||
types: self,
|
||||
|
@ -1387,7 +1456,7 @@ impl<'db> TypeArrayDisplay<'db> for Vec<Type<'db>> {
|
|||
fn display_with(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayTypeArray<'_, 'db> {
|
||||
DisplayTypeArray {
|
||||
types: self,
|
||||
|
@ -1401,7 +1470,7 @@ impl<'db> TypeArrayDisplay<'db> for [Type<'db>] {
|
|||
fn display_with(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayTypeArray<'_, 'db> {
|
||||
DisplayTypeArray {
|
||||
types: self,
|
||||
|
@ -1414,7 +1483,7 @@ impl<'db> TypeArrayDisplay<'db> for [Type<'db>] {
|
|||
pub(crate) struct DisplayTypeArray<'b, 'db> {
|
||||
types: &'b [Type<'db>],
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayTypeArray<'_, '_> {
|
||||
|
@ -1433,20 +1502,19 @@ impl<'db> StringLiteralType<'db> {
|
|||
fn display_with(
|
||||
&'db self,
|
||||
db: &'db dyn Db,
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
) -> DisplayStringLiteralType<'db> {
|
||||
display_quoted_string(self.value(db), settings)
|
||||
DisplayStringLiteralType {
|
||||
string: self.value(db),
|
||||
settings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn display_quoted_string(string: &str, settings: DisplaySettings) -> DisplayStringLiteralType<'_> {
|
||||
DisplayStringLiteralType { string, settings }
|
||||
}
|
||||
|
||||
struct DisplayStringLiteralType<'db> {
|
||||
string: &'db str,
|
||||
#[expect(dead_code)]
|
||||
settings: DisplaySettings,
|
||||
settings: DisplaySettings<'db>,
|
||||
}
|
||||
|
||||
impl Display for DisplayStringLiteralType<'_> {
|
||||
|
|
|
@ -107,7 +107,7 @@ pub(crate) trait TypeVisitor<'db> {
|
|||
|
||||
/// Enumeration of types that may contain other types, such as unions, intersections, and generics.
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
enum NonAtomicType<'db> {
|
||||
pub(super) enum NonAtomicType<'db> {
|
||||
Union(UnionType<'db>),
|
||||
Intersection(IntersectionType<'db>),
|
||||
FunctionLiteral(FunctionType<'db>),
|
||||
|
@ -128,7 +128,7 @@ enum NonAtomicType<'db> {
|
|||
TypeAlias(TypeAliasType<'db>),
|
||||
}
|
||||
|
||||
enum TypeKind<'db> {
|
||||
pub(super) enum TypeKind<'db> {
|
||||
Atomic,
|
||||
NonAtomic(NonAtomicType<'db>),
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ impl<'db> From<Type<'db>> for TypeKind<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
|
||||
pub(super) fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
non_atomic_type: NonAtomicType<'db>,
|
||||
visitor: &V,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue