[ty] Fix a panic when sorting diagnostics without a source location (#29780)

This commit is contained in:
Micha Reiser authored and GitHub committed 2026-10-28 02:35:34 +00:00
1 parent b6a2ae6a70
commit 2ffdaee262
2 files changed
+42 -25

No files matched your search

+25 -25
View File
@@ -573,49 +573,49 @@ struct RenderingSortKey<'a> {
}
impl Ord for RenderingSortKey<'_> {
// We sort diagnostics in a way that keeps them in source order
// and grouped by file. After that, we fall back to severity
// Group diagnostics by file and sort them in source order.
// For diagnostics at the same location, fall back to severity
// (with fatal messages sorting before info messages) and then
// finally the diagnostic ID and concise message.
// Diagnostics without a file come first. Whole-file diagnostics sort at offset zero.
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if let (Some(span1), Some(span2)) = (
self.diagnostic.primary_span(),
other.diagnostic.primary_span(),
) {
let file1 = span1.file();
let file2 = span2.file();
if file1 != file2 {
let order = file1.path(&self.db).cmp(file2.path(&self.db));
let left = self.diagnostic;
let right = other.diagnostic;
let left_span = left.primary_span_ref();
let right_span = right.primary_span_ref();
let location = if let (Some(left_span), Some(right_span)) = (left_span, right_span) {
let left_file = left_span.file();
let right_file = right_span.file();
if left_file != right_file {
let order = left_file.path(&self.db).cmp(right_file.path(&self.db));
if order.is_ne() {
return order;
}
}
if let (Some(range1), Some(range2)) = (span1.range(), span2.range()) {
let order = range1.start().cmp(&range2.start());
if order.is_ne() {
return order;
}
}
let left_start = left_span.range().unwrap_or_default().start();
let right_start = right_span.range().unwrap_or_default().start();
left_start.cmp(&right_start)
} else {
left_span.is_some().cmp(&right_span.is_some())
};
if location.is_ne() {
return location;
}
// Reverse so that, e.g., Fatal sorts before Info.
let order = self
.diagnostic
.severity()
.cmp(&other.diagnostic.severity())
.reverse();
let order = left.severity().cmp(&right.severity()).reverse();
if order.is_ne() {
return order;
}
let order = self.diagnostic.id().cmp(&other.diagnostic.id());
let order = left.id().cmp(&right.id());
if order.is_ne() {
return order;
}
self.diagnostic
.concise_message()
left.concise_message()
.to_str()
.cmp(&other.diagnostic.concise_message().to_str())
.cmp(&right.concise_message().to_str())
}
}
+17
View File
@@ -2433,6 +2433,23 @@ watermelon
);
}
#[test]
fn diagnostic_order_with_missing_locations() {
let mut env = TestEnvironment::new();
env.add("fruits", FRUITS);
let fileless = Diagnostic::new(DiagnosticId::Io, Severity::Hint, "Missing directory");
let mut whole_file =
Diagnostic::new(DiagnosticId::Io, Severity::Warning, "Check this file");
whole_file.annotate(Annotation::primary(env.path("fruits")));
let at_zero = env.err().primary("fruits", "1:0", "1:0", "").build();
let at_one = env.err().primary("fruits", "1:1", "1:1", "").build();
let mut diagnostics = [&at_one, &whole_file, &at_zero, &fileless];
diagnostics.sort_by_key(|diagnostic| diagnostic.rendering_sort_key(&env.db));
assert_eq!(diagnostics, [&fileless, &at_zero, &whole_file, &at_one]);
}
#[test]
fn diagnostics_with_equal_locations_sort_by_concise_message() {
let mut env = TestEnvironment::new();