mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-18 17:40:37 +00:00
[ty] Format conflicting types as an enumeration (#18956)
## Summary Format conflicting declared types as ``` `str`, `int` and `bytes` ``` Thanks to @AlexWaygood for the initial draft. @dcreager, looking forward to your one-character follow-up PR.
This commit is contained in:
parent
c0beb3412f
commit
86fd9b634e
5 changed files with 90 additions and 83 deletions
|
@ -17,6 +17,7 @@ use crate::types::string_annotation::{
|
|||
};
|
||||
use crate::types::tuple::TupleType;
|
||||
use crate::types::{SpecialFormType, Type, protocol_class::ProtocolClassLiteral};
|
||||
use crate::util::diagnostics::format_enumeration;
|
||||
use crate::{Db, FxIndexMap, Module, ModuleName, Program, declare_lint};
|
||||
use itertools::Itertools;
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, SubDiagnostic};
|
||||
|
@ -2038,29 +2039,9 @@ impl<'db> IncompatibleBases<'db> {
|
|||
|
||||
/// List the problematic class bases in a human-readable format.
|
||||
fn describe_problematic_class_bases(&self, db: &dyn Db) -> String {
|
||||
let num_bases = self.len();
|
||||
debug_assert!(num_bases >= 2);
|
||||
let bad_base_names = self.0.values().map(|info| info.originating_base.name(db));
|
||||
|
||||
let mut bad_base_names = self.0.values().map(|info| info.originating_base.name(db));
|
||||
|
||||
let final_base = bad_base_names.next_back().unwrap();
|
||||
let penultimate_base = bad_base_names.next_back().unwrap();
|
||||
|
||||
let mut buffer = String::new();
|
||||
|
||||
for base_name in bad_base_names {
|
||||
buffer.push('`');
|
||||
buffer.push_str(base_name);
|
||||
buffer.push_str("`, ");
|
||||
}
|
||||
|
||||
buffer.push('`');
|
||||
buffer.push_str(penultimate_base);
|
||||
buffer.push_str("` and `");
|
||||
buffer.push_str(final_base);
|
||||
buffer.push('`');
|
||||
|
||||
buffer
|
||||
format_enumeration(bad_base_names)
|
||||
}
|
||||
|
||||
pub(super) fn len(&self) -> usize {
|
||||
|
|
|
@ -106,6 +106,7 @@ use crate::types::{
|
|||
todo_type,
|
||||
};
|
||||
use crate::unpack::{Unpack, UnpackPosition};
|
||||
use crate::util::diagnostics::format_enumeration;
|
||||
use crate::util::subscript::{PyIndex, PySlice};
|
||||
use crate::{Db, FxOrderSet, Program};
|
||||
|
||||
|
@ -1643,7 +1644,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
if let Some(builder) = self.context.report_lint(&CONFLICTING_DECLARATIONS, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Conflicting declared types for `{place}`: {}",
|
||||
conflicting.iter().map(|ty| ty.display(db)).join(", ")
|
||||
format_enumeration(conflicting.iter().map(|ty| ty.display(db)))
|
||||
));
|
||||
}
|
||||
ty.inner_type()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{Db, Program, PythonVersionWithSource};
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, SubDiagnostic};
|
||||
use std::fmt::Write;
|
||||
|
||||
/// Add a subdiagnostic to `diagnostic` that explains why a certain Python version was inferred.
|
||||
///
|
||||
|
@ -87,3 +88,27 @@ pub fn add_inferred_python_version_hint_to_diagnostic(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a list of elements as a human-readable enumeration.
|
||||
///
|
||||
/// Encloses every element in backticks (`1`, `2` and `3`).
|
||||
pub(crate) fn format_enumeration<I, IT, D>(elements: I) -> String
|
||||
where
|
||||
I: IntoIterator<IntoIter = IT>,
|
||||
IT: ExactSizeIterator<Item = D> + DoubleEndedIterator,
|
||||
D: std::fmt::Display,
|
||||
{
|
||||
let mut elements = elements.into_iter();
|
||||
debug_assert!(elements.len() >= 2);
|
||||
|
||||
let final_element = elements.next_back().unwrap();
|
||||
let penultimate_element = elements.next_back().unwrap();
|
||||
|
||||
let mut buffer = String::new();
|
||||
for element in elements {
|
||||
write!(&mut buffer, "`{element}`, ").ok();
|
||||
}
|
||||
write!(&mut buffer, "`{penultimate_element}` and `{final_element}`").ok();
|
||||
|
||||
buffer
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue