diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-10 20:35:45 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-10 20:35:45 +0000 |
commit | 0714a065d578e8b22b0451bfc64378c875fe858f (patch) | |
tree | 75665c712625782d88e03447fcd10245c903d6f8 /crates/ra_hir_ty | |
parent | e5df8c402847d5bedb8ebcb621aac46dbe215cdd (diff) | |
parent | adc7b8ea2d0ff1dafecaa697638825463f4b8891 (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]>
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 28 |
1 files changed, 25 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`. | ||
529 | fn 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 | ||
524 | fn transform_receiver_ty( | 546 | fn transform_receiver_ty( |