aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-10 20:35:45 +0000
committerGitHub <[email protected]>2020-03-10 20:35:45 +0000
commit0714a065d578e8b22b0451bfc64378c875fe858f (patch)
tree75665c712625782d88e03447fcd10245c903d6f8
parente5df8c402847d5bedb8ebcb621aac46dbe215cdd (diff)
parentadc7b8ea2d0ff1dafecaa697638825463f4b8891 (diff)
Merge #3552
3552: Fix completion with a partially unknown type r=matklad a=flodiebold To test whether the receiver type matches for the impl, we unify the given self type (in this case `HashSet<{unknown}>`) with the self type of the impl (`HashSet<?0>`), but if the given self type contains Unknowns, they won't be unified with the variables in those places. So we got a receiver type that was different from the expected one, and concluded the impl doesn't match. The fix is slightly hacky; if after the unification, our variables are still there, we make them fall back to Unknown. This does make some sense though, since we don't want to 'leak' the variables. Fixes #3547. Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs28
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs31
2 files changed, 56 insertions, 3 deletions
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index b7e8855fb..7f5e1469e 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -516,9 +516,31 @@ pub(crate) fn inherent_impl_substs(
516 let self_ty_with_vars = 516 let self_ty_with_vars =
517 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; 517 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars };
518 let substs = super::infer::unify(&self_ty_with_vars, self_ty); 518 let substs = super::infer::unify(&self_ty_with_vars, self_ty);
519 // we only want the substs for the vars we added, not the ones from self_ty 519 // We only want the substs for the vars we added, not the ones from self_ty.
520 let result = substs.map(|s| s.suffix(vars.len())); 520 // Also, if any of the vars we added are still in there, we replace them by
521 result 521 // Unknown. I think this can only really happen if self_ty contained
522 // Unknown, and in that case we want the result to contain Unknown in those
523 // places again.
524 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars))
525}
526
527/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
528/// num_vars_to_keep) by `Ty::Unknown`.
529fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs {
530 s.fold_binders(
531 &mut |ty, binders| {
532 if let Ty::Bound(idx) = &ty {
533 if *idx >= binders as u32 {
534 Ty::Unknown
535 } else {
536 ty
537 }
538 } else {
539 ty
540 }
541 },
542 num_vars_to_keep,
543 )
522} 544}
523 545
524fn transform_receiver_ty( 546fn transform_receiver_ty(
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index f275305e2..d8f6f0d9d 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -718,4 +718,35 @@ mod tests {
718 "### 718 "###
719 ); 719 );
720 } 720 }
721
722 #[test]
723 fn test_method_completion_3547() {
724 assert_debug_snapshot!(
725 do_ref_completion(
726 r"
727 struct HashSet<T> {}
728 impl<T> HashSet<T> {
729 pub fn the_method(&self) {}
730 }
731 fn foo() {
732 let s: HashSet<_>;
733 s.<|>
734 }
735 ",
736 ),
737 @r###"
738 [
739 CompletionItem {
740 label: "the_method()",
741 source_range: [201; 201),
742 delete: [201; 201),
743 insert: "the_method()$0",
744 kind: Method,
745 lookup: "the_method",
746 detail: "pub fn the_method(&self)",
747 },
748 ]
749 "###
750 );
751 }
721} 752}