Unnamed repository; edit this file 'description' to name the repository.
Store binding mode for each instance independently
hkalbasi 2023-10-23
parent 7c11399 · commit 8b82ea4
-rw-r--r--crates/hir-ty/src/consteval/tests.rs14
-rw-r--r--crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir-ty/src/infer.rs14
-rw-r--r--crates/hir-ty/src/infer/closure.rs6
-rw-r--r--crates/hir-ty/src/infer/pat.rs2
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs5
-rw-r--r--crates/hir/src/source_analyzer.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs15
8 files changed, 53 insertions, 9 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 7ad3659a4f..b395e7f4a8 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1159,6 +1159,20 @@ fn pattern_matching_slice() {
"#,
33213,
);
+ check_number(
+ r#"
+ //- minicore: slice, index, coerce_unsized, copy
+ const fn f(mut slice: &[u32]) -> usize {
+ slice = match slice {
+ [0, rest @ ..] | rest => rest,
+ };
+ slice.len()
+ }
+ const GOAL: usize = f(&[]) + f(&[10]) + f(&[0, 100])
+ + f(&[1000, 1000, 1000]) + f(&[0, 57, 34, 46, 10000, 10000]);
+ "#,
+ 10,
+ );
}
#[test]
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index f8cdeaa5e3..2e04bbfee8 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -147,7 +147,7 @@ impl<'a> PatCtxt<'a> {
}
hir_def::hir::Pat::Bind { id, subpat, .. } => {
- let bm = self.infer.binding_modes[id];
+ let bm = self.infer.binding_modes[pat];
ty = &self.infer[id];
let name = &self.body.bindings[id].name;
match (bm, ty.kind(Interner)) {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 78d3c667a1..3d5ed1f93c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -420,7 +420,19 @@ pub struct InferenceResult {
standard_types: InternedStandardTypes,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
- pub binding_modes: ArenaMap<BindingId, BindingMode>,
+ /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings.
+ ///
+ /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an
+ /// or pattern can have multiple binding modes. For example:
+ /// ```
+ /// fn foo(mut slice: &[u32]) -> usize {
+ /// slice = match slice {
+ /// [0, rest @ ..] | rest => rest,
+ /// };
+ /// }
+ /// ```
+ /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
+ pub binding_modes: ArenaMap<PatId, BindingMode>,
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
// FIXME: remove this field
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 13d6b5643a..0805e20447 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -679,7 +679,7 @@ impl InferenceContext<'_> {
| Pat::Range { .. } => {
update_result(CaptureKind::ByRef(BorrowKind::Shared));
}
- Pat::Bind { id, .. } => match self.result.binding_modes[*id] {
+ Pat::Bind { id, .. } => match self.result.binding_modes[p] {
crate::BindingMode::Move => {
if self.is_ty_copy(self.result.type_of_binding[*id].clone()) {
update_result(CaptureKind::ByRef(BorrowKind::Shared));
@@ -838,8 +838,8 @@ impl InferenceContext<'_> {
| Pat::ConstBlock(_)
| Pat::Path(_)
| Pat::Lit(_) => self.consume_place(place, pat.into()),
- Pat::Bind { id, subpat: _ } => {
- let mode = self.result.binding_modes[*id];
+ Pat::Bind { id: _, subpat: _ } => {
+ let mode = self.result.binding_modes[pat];
let capture_kind = match mode {
BindingMode::Move => {
self.consume_place(place, pat.into());
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 4e28ec0602..7ff12e5b7f 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -421,7 +421,7 @@ impl InferenceContext<'_> {
} else {
BindingMode::convert(mode)
};
- self.result.binding_modes.insert(binding, mode);
+ self.result.binding_modes.insert(pat, mode);
let inner_ty = match subpat {
Some(subpat) => self.infer_pat(subpat, &expected, default_bm),
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 270f75ad96..1120bb1c11 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -284,6 +284,7 @@ impl MirLowerCtx<'_> {
);
(current, current_else) = self.pattern_match_binding(
id,
+ *slice,
next_place,
(*slice).into(),
current,
@@ -395,6 +396,7 @@ impl MirLowerCtx<'_> {
if mode == MatchingMode::Bind {
self.pattern_match_binding(
*id,
+ pattern,
cond_place,
pattern.into(),
current,
@@ -431,13 +433,14 @@ impl MirLowerCtx<'_> {
fn pattern_match_binding(
&mut self,
id: BindingId,
+ pat: PatId,
cond_place: Place,
span: MirSpan,
current: BasicBlockId,
current_else: Option<BasicBlockId>,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let target_place = self.binding_local(id)?;
- let mode = self.infer.binding_modes[id];
+ let mode = self.infer.binding_modes[pat];
self.push_storage_live(id, current)?;
self.push_assignment(
current,
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8d8ba48ad9..55c2f8324c 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -236,9 +236,9 @@ impl SourceAnalyzer {
_db: &dyn HirDatabase,
pat: &ast::IdentPat,
) -> Option<BindingMode> {
- let binding_id = self.binding_id_of_pat(pat)?;
+ let id = self.pat_id(&pat.clone().into())?;
let infer = self.infer.as_ref()?;
- infer.binding_modes.get(binding_id).map(|bm| match bm {
+ infer.binding_modes.get(id).map(|bm| match bm {
hir_ty::BindingMode::Move => BindingMode::Move,
hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
diff --git a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 20175b3fd5..886aefeb57 100644
--- a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -175,4 +175,19 @@ fn main() {
"#,
);
}
+
+ #[test]
+ fn regression_15787() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, slice, copy
+fn foo(mut slice: &[u32]) -> usize {
+ slice = match slice {
+ [0, rest @ ..] | rest => rest,
+ };
+ slice.len()
+}
+"#,
+ );
+ }
}