From 41772466d53e4acdca30a8175cc9039275471fe6 Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Wed, 8 Oct 2025 14:57:33 -0400 Subject: [PATCH] [ty_test] Store CheckOutput references in SortedCheckOutputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update SortedCheckOutputs to store references to CheckOutput instead of owned values, matching the design of the previous SortedDiagnostics implementation. This avoids unnecessary cloning and makes the API more consistent. Changes: - SortedCheckOutputs now stores Vec<&CheckOutput> - new() takes IntoIterator - LineCheckOutputs.outputs is now &[&CheckOutput] - Implement Unmatched and UnmatchedWithColumn for &CheckOutput - Update match_line to take &[&CheckOutput] 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- crates/ty_test/src/check_output.rs | 23 +++++++++++++---------- crates/ty_test/src/matcher.rs | 29 ++++++++++++++++------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/crates/ty_test/src/check_output.rs b/crates/ty_test/src/check_output.rs index 84c1e0fc5e..4e5dddd227 100644 --- a/crates/ty_test/src/check_output.rs +++ b/crates/ty_test/src/check_output.rs @@ -39,18 +39,21 @@ impl CheckOutput { /// [`LineOutputRange`] has one entry for each contiguous slice of the outputs vector /// containing outputs which all start on the same line. #[derive(Debug)] -pub(crate) struct SortedCheckOutputs { - outputs: Vec, +pub(crate) struct SortedCheckOutputs<'a> { + outputs: Vec<&'a CheckOutput>, line_ranges: Vec, } -impl SortedCheckOutputs { - pub(crate) fn new(outputs: &[CheckOutput], line_index: &LineIndex) -> Self { +impl<'a> SortedCheckOutputs<'a> { + pub(crate) fn new( + outputs: impl IntoIterator, + line_index: &LineIndex, + ) -> Self { let mut outputs: Vec<_> = outputs - .iter() + .into_iter() .map(|output| OutputWithLine { line_number: output.line_number(line_index), - output: output.clone(), + output, }) .collect(); outputs.sort_unstable_by_key(|output_with_line| output_with_line.line_number); @@ -104,9 +107,9 @@ impl SortedCheckOutputs { } #[derive(Debug)] -struct OutputWithLine { +struct OutputWithLine<'a> { line_number: OneIndexed, - output: CheckOutput, + output: &'a CheckOutput, } /// Range delineating check outputs in [`SortedCheckOutputs`] that begin on a single line. @@ -118,7 +121,7 @@ struct LineOutputRange { /// Iterator to group sorted check outputs by line. pub(crate) struct LineCheckOutputsIterator<'a> { - outputs: &'a [CheckOutput], + outputs: &'a [&'a CheckOutput], inner: std::slice::Iter<'a, LineOutputRange>, } @@ -146,7 +149,7 @@ pub(crate) struct LineCheckOutputs<'a> { pub(crate) line_number: OneIndexed, /// Check outputs starting on this line. - pub(crate) outputs: &'a [CheckOutput], + pub(crate) outputs: &'a [&'a CheckOutput], } #[cfg(test)] diff --git a/crates/ty_test/src/matcher.rs b/crates/ty_test/src/matcher.rs index b00414a149..ae7619e3e1 100644 --- a/crates/ty_test/src/matcher.rs +++ b/crates/ty_test/src/matcher.rs @@ -13,8 +13,8 @@ use ruff_source_file::{LineIndex, OneIndexed}; use crate::assertion::{InlineFileAssertions, ParsedAssertion, UnparsedAssertion}; use crate::check_output::{CheckOutput, SortedCheckOutputs}; -use crate::hover::HoverOutput; use crate::db::Db; +use crate::hover::HoverOutput; #[derive(Debug, Default)] pub(super) struct FailuresByLine { @@ -171,7 +171,7 @@ fn maybe_add_undefined_reveal_clarification( } } -impl Unmatched for CheckOutput { +impl Unmatched for &CheckOutput { fn unmatched(&self) -> String { match self { CheckOutput::Diagnostic(diag) => diag.unmatched(), @@ -180,7 +180,7 @@ impl Unmatched for CheckOutput { } } -impl UnmatchedWithColumn for CheckOutput { +impl UnmatchedWithColumn for &CheckOutput { fn unmatched_with_column(&self, column: OneIndexed) -> String { match self { CheckOutput::Diagnostic(diag) => diag.unmatched_with_column(column), @@ -191,7 +191,11 @@ impl UnmatchedWithColumn for CheckOutput { impl Unmatched for &HoverOutput { fn unmatched(&self) -> String { - format!("{} hover result: {}", "unexpected:".red(), self.inferred_type) + format!( + "{} hover result: {}", + "unexpected:".red(), + self.inferred_type + ) } } @@ -267,14 +271,14 @@ impl Matcher { /// assertions. fn match_line<'a, 'b>( &self, - outputs: &'a [CheckOutput], + outputs: &'a [&'a CheckOutput], assertions: &'a [UnparsedAssertion<'b>], ) -> Result<(), Vec> where 'b: 'a, { let mut failures = vec![]; - let mut unmatched: Vec<&CheckOutput> = outputs.iter().collect(); + let mut unmatched = outputs.to_vec(); for assertion in assertions { match assertion.parse(&self.line_index, &self.source) { Ok(assertion) => { @@ -308,10 +312,11 @@ impl Matcher { .column }) .unwrap_or(OneIndexed::from_zero_indexed(0)), - CheckOutput::Hover(hover) => self - .line_index - .line_column(hover.offset, &self.source) - .column, + CheckOutput::Hover(hover) => { + self.line_index + .line_column(hover.offset, &self.source) + .column + } } } @@ -335,9 +340,7 @@ impl Matcher { let lint_name_matches = !error.rule.is_some_and(|rule| { !(diagnostic.id().is_lint_named(rule) || diagnostic.id().as_str() == rule) }); - let column_matches = error - .column - .is_none_or(|col| col == self.column(output)); + let column_matches = error.column.is_none_or(|col| col == self.column(output)); let message_matches = error.message_contains.is_none_or(|needle| { diagnostic.concise_message().to_string().contains(needle) });