Store binding mode for each instance independently

This commit is contained in:
hkalbasi 2023-10-22 23:34:27 +03:30
parent 7c11399b6b
commit 8b82ea4f51
8 changed files with 53 additions and 9 deletions

View File

@ -1159,6 +1159,20 @@ const fn f(x: &[usize]) -> usize {
"#,
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]

View File

@ -147,7 +147,7 @@ fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat {
}
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)) {

View File

@ -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

View File

@ -679,7 +679,7 @@ fn walk_pat_inner(
| 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 @@ fn consume_with_pat(&mut self, mut place: HirPlace, pat: PatId) {
| 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());

View File

@ -421,7 +421,7 @@ fn infer_bind_pat(
} 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),

View File

@ -284,6 +284,7 @@ fn pattern_match_inner(
);
(current, current_else) = self.pattern_match_binding(
id,
*slice,
next_place,
(*slice).into(),
current,
@ -395,6 +396,7 @@ fn pattern_match_inner(
if mode == MatchingMode::Bind {
self.pattern_match_binding(
*id,
pattern,
cond_place,
pattern.into(),
current,
@ -431,13 +433,14 @@ fn pattern_match_inner(
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,

View File

@ -236,9 +236,9 @@ pub(crate) fn binding_mode_of_pat(
_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) => {

View File

@ -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()
}
"#,
);
}
}