From a860a720baa508aa28d44f4d277814a086d6bd9d Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 20 Mar 2023 22:48:26 +0800 Subject: [PATCH 1/3] Fix issue when there are multiple candidates for edit_distance_with_substrings --- compiler/rustc_span/src/edit_distance.rs | 24 ++++++++++++++++++++---- tests/ui/suggestions/issue-109291.rs | 4 ++++ tests/ui/suggestions/issue-109291.stderr | 12 ++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 tests/ui/suggestions/issue-109291.rs create mode 100644 tests/ui/suggestions/issue-109291.stderr diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 89f0386e3e9..40d36578350 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -174,10 +174,10 @@ pub fn find_best_match_for_name( fn find_best_match_for_name_impl( use_substring_score: bool, candidates: &[Symbol], - lookup: Symbol, + lookup_symbol: Symbol, dist: Option, ) -> Option { - let lookup = lookup.as_str(); + let lookup = lookup_symbol.as_str(); let lookup_uppercase = lookup.to_uppercase(); // Priority of matches: @@ -190,6 +190,7 @@ fn find_best_match_for_name_impl( let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); let mut best = None; + let mut next_candidates = vec![]; for c in candidates { match if use_substring_score { edit_distance_with_substrings(lookup, c.as_str(), dist) @@ -198,12 +199,27 @@ fn find_best_match_for_name_impl( } { Some(0) => return Some(*c), Some(d) => { - dist = d - 1; - best = Some(*c); + if use_substring_score { + dist = d; + next_candidates.push(*c); + best = Some(*c); + } else { + dist = d - 1; + best = Some(*c); + } } None => {} } } + + if next_candidates.len() > 1 { + best = find_best_match_for_name_impl( + false, + &next_candidates, + lookup_symbol, + Some(lookup.len()), + ); + } if best.is_some() { return best; } diff --git a/tests/ui/suggestions/issue-109291.rs b/tests/ui/suggestions/issue-109291.rs new file mode 100644 index 00000000000..1947b16a32e --- /dev/null +++ b/tests/ui/suggestions/issue-109291.rs @@ -0,0 +1,4 @@ +fn main() { + println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capture()); + //~^ ERROR no function or associated item name +} diff --git a/tests/ui/suggestions/issue-109291.stderr b/tests/ui/suggestions/issue-109291.stderr new file mode 100644 index 00000000000..4ef5948d9bf --- /dev/null +++ b/tests/ui/suggestions/issue-109291.stderr @@ -0,0 +1,12 @@ +error[E0599]: no function or associated item named `forced_capture` found for struct `Backtrace` in the current scope + --> $DIR/issue-109291.rs:2:65 + | +LL | println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capture()); + | ^^^^^^^^^^^^^^ + | | + | function or associated item not found in `Backtrace` + | help: there is an associated function with a similar name: `force_capture` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. From 7b4f436a30f00c8b8bf533b92592385cba2ea5f1 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 26 Mar 2023 12:03:25 +0800 Subject: [PATCH 2/3] add comments and cleanup --- compiler/rustc_span/src/edit_distance.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 40d36578350..19c4aae97ef 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -190,6 +190,7 @@ fn find_best_match_for_name_impl( let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); let mut best = None; + // store the candidates with the same distance, only for `use_substring_score` current. let mut next_candidates = vec![]; for c in candidates { match if use_substring_score { @@ -200,19 +201,25 @@ fn find_best_match_for_name_impl( Some(0) => return Some(*c), Some(d) => { if use_substring_score { - dist = d; + if d < dist { + dist = d; + next_candidates.clear(); + } else { + // `d == dist` here, we need to store the candidates with the same distance + // so we won't decrease the distance in the next loop. + } next_candidates.push(*c); - best = Some(*c); } else { dist = d - 1; - best = Some(*c); } + best = Some(*c); } None => {} } } if next_candidates.len() > 1 { + debug_assert!(use_substring_score); best = find_best_match_for_name_impl( false, &next_candidates, From 4fc3c6b07a5aff0bb3da87496daf825b128d6e08 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 6 Apr 2023 06:51:49 +0800 Subject: [PATCH 3/3] add comment --- compiler/rustc_span/src/edit_distance.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 19c4aae97ef..9fe9e3a7a5f 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -218,6 +218,9 @@ fn find_best_match_for_name_impl( } } + // We have a tie among several candidates, try to select the best among them ignoring substrings. + // For example, the candidates list `force_capture`, `capture`, and user inputed `forced_capture`, + // we select `force_capture` with a extra round of edit distance calculation. if next_candidates.len() > 1 { debug_assert!(use_substring_score); best = find_best_match_for_name_impl(