diff options
Diffstat (limited to 'crates/ra_ssr/src/matching.rs')
-rw-r--r-- | crates/ra_ssr/src/matching.rs | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs index f3cc60c29..4862622bd 100644 --- a/crates/ra_ssr/src/matching.rs +++ b/crates/ra_ssr/src/matching.rs | |||
@@ -189,10 +189,17 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
189 | } | 189 | } |
190 | return Ok(()); | 190 | return Ok(()); |
191 | } | 191 | } |
192 | // Non-placeholders. | 192 | // We allow a UFCS call to match a method call, provided they resolve to the same function. |
193 | if let Some(pattern_function) = self.rule.pattern.ufcs_function_calls.get(pattern) { | ||
194 | if let (Some(pattern), Some(code)) = | ||
195 | (ast::CallExpr::cast(pattern.clone()), ast::MethodCallExpr::cast(code.clone())) | ||
196 | { | ||
197 | return self.attempt_match_ufcs(phase, &pattern, &code, *pattern_function); | ||
198 | } | ||
199 | } | ||
193 | if pattern.kind() != code.kind() { | 200 | if pattern.kind() != code.kind() { |
194 | fail_match!( | 201 | fail_match!( |
195 | "Pattern had a `{}` ({:?}), code had `{}` ({:?})", | 202 | "Pattern had `{}` ({:?}), code had `{}` ({:?})", |
196 | pattern.text(), | 203 | pattern.text(), |
197 | pattern.kind(), | 204 | pattern.kind(), |
198 | code.text(), | 205 | code.text(), |
@@ -514,6 +521,37 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
514 | Ok(()) | 521 | Ok(()) |
515 | } | 522 | } |
516 | 523 | ||
524 | fn attempt_match_ufcs( | ||
525 | &self, | ||
526 | phase: &mut Phase, | ||
527 | pattern: &ast::CallExpr, | ||
528 | code: &ast::MethodCallExpr, | ||
529 | pattern_function: hir::Function, | ||
530 | ) -> Result<(), MatchFailed> { | ||
531 | use ast::ArgListOwner; | ||
532 | let code_resolved_function = self | ||
533 | .sema | ||
534 | .resolve_method_call(code) | ||
535 | .ok_or_else(|| match_error!("Failed to resolve method call"))?; | ||
536 | if pattern_function != code_resolved_function { | ||
537 | fail_match!("Method call resolved to a different function"); | ||
538 | } | ||
539 | // Check arguments. | ||
540 | let mut pattern_args = pattern | ||
541 | .arg_list() | ||
542 | .ok_or_else(|| match_error!("Pattern function call has no args"))? | ||
543 | .args(); | ||
544 | self.attempt_match_opt(phase, pattern_args.next(), code.expr())?; | ||
545 | let mut code_args = | ||
546 | code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args(); | ||
547 | loop { | ||
548 | match (pattern_args.next(), code_args.next()) { | ||
549 | (None, None) => return Ok(()), | ||
550 | (p, c) => self.attempt_match_opt(phase, p, c)?, | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | |||
517 | fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> { | 555 | fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> { |
518 | only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident)) | 556 | only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident)) |
519 | } | 557 | } |