@@ -20,8 +20,9 @@ pub fn parse_with_recovery<'i>(
2020 input. parse_collecting_errors ( )
2121}
2222
23- // Most general errors first, most specific last (for deduplication, we prefer
24- // being able to give a more specific error message to the user)
23+ // Most general errors first, most specific last (when removing redundant
24+ // errors, we prefer being able to give a more specific error message to the
25+ // user)
2526#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
2627pub enum ParsingError {
2728 // lowest priority
@@ -54,7 +55,7 @@ pub enum ParsingError {
5455 InvalidQuantityUncertainty ( usize ) ,
5556 InvalidQuantityMagnitude ( usize ) ,
5657 InvalidQuantitySymbol ( usize ) ,
57- // highest priority when deduplicating
58+ // highest priority
5859 UnclosedInterpolation ( usize ) ,
5960}
6061
@@ -94,11 +95,11 @@ impl ParsingError {
9495 }
9596}
9697
97- /// Deduplicate errors, preferring more specific errors over generic ones at the same offset.
98+ /// Remove redundant errors, keeping only the most specific error at each offset.
9899/// When multiple errors occur at the same offset, keep only the most specific one.
99100/// Since ParsingError derives Ord with general errors first and specific errors last,
100101/// we use > to prefer the higher Ord value (more specific) errors.
101- fn deduplicate_errors ( errors : Vec < ParsingError > ) -> Vec < ParsingError > {
102+ fn remove_redundant_errors ( errors : Vec < ParsingError > ) -> Vec < ParsingError > {
102103 let mut deduped = Vec :: new ( ) ;
103104
104105 for error in errors {
@@ -109,11 +110,11 @@ fn deduplicate_errors(errors: Vec<ParsingError>) -> Vec<ParsingError> {
109110 . iter ( )
110111 . position ( |e : & ParsingError | e. offset ( ) == error_offset)
111112 {
112- // Keep the more specific error (higher Ord value, since specific errors come last)
113+ // Keep the more specific error
113114 if error > deduped[ existing_idx] {
114115 deduped[ existing_idx] = error;
115116 }
116- // Otherwise, keep the existing more specific error
117+ // Otherwise, keep the existing error
117118 } else {
118119 // No error at this offset yet, add it
119120 deduped. push ( error) ;
@@ -318,13 +319,12 @@ impl<'i> Parser<'i> {
318319 let document = Document { header, body } ;
319320 let errors = std:: mem:: take ( & mut self . problems ) ;
320321
321- // Deduplicate errors, preferring more specific errors over generic
322- // ones at the same offset
323- let errors = deduplicate_errors ( errors) ;
324-
325322 if errors. is_empty ( ) {
326323 Ok ( document)
327324 } else {
325+ // Remove redundant errors, keeping only the most specific error
326+ // at each offset
327+ let errors = remove_redundant_errors ( errors) ;
328328 Err ( errors)
329329 }
330330 }
@@ -4829,7 +4829,47 @@ broken_proc2 : -> B
48294829 }
48304830
48314831 #[ test]
4832- fn test_error_deduplication_unclosed_interpolation ( ) {
4832+ fn test_redundant_error_removal_needed ( ) {
4833+ use std:: path:: Path ;
4834+
4835+ // Create a malformed procedure that could generate multiple errors at the same offset
4836+ let content = r#"
4837+ % technique v1
4838+
4839+ broken :
4840+ This is not a valid signature line
4841+
4842+ 1. Step one
4843+ "# ;
4844+
4845+ let result = parse_with_recovery ( Path :: new ( "test.tq" ) , content) ;
4846+
4847+ // Check that we get an error about the invalid signature
4848+ match result {
4849+ Err ( errors) => {
4850+ // Debug: print what errors we actually get
4851+ eprintln ! ( "Errors: {:?}" , errors) ;
4852+
4853+ // Verify no redundant errors at the same offset
4854+ let mut offsets = errors
4855+ . iter ( )
4856+ . map ( |e| e. offset ( ) )
4857+ . collect :: < Vec < _ > > ( ) ;
4858+ offsets. sort ( ) ;
4859+ let original_len = offsets. len ( ) ;
4860+ offsets. dedup ( ) ;
4861+ assert_eq ! (
4862+ offsets. len( ) ,
4863+ original_len,
4864+ "Found redundant errors at same offset"
4865+ ) ;
4866+ }
4867+ Ok ( _) => panic ! ( "Expected errors for malformed content" ) ,
4868+ }
4869+ }
4870+
4871+ #[ test]
4872+ fn test_redundant_error_removal_unclosed_interpolation ( ) {
48334873 let mut input = Parser :: new ( ) ;
48344874
48354875 // Test that UnclosedInterpolation error takes precedence over generic
0 commit comments