Remove unnecessary StorageDead

This commit is contained in:
hkalbasi 2023-06-03 17:24:10 +03:30
parent aab7589c40
commit f44fc271d4
4 changed files with 238 additions and 301 deletions

View file

@ -9,10 +9,7 @@ use chalk_ir::{
};
use hir_def::{
data::adt::VariantData,
hir::{
Array, BinaryOp, BindingAnnotation, BindingId, CaptureBy, Expr, ExprId, Pat, PatId,
Statement, UnaryOp,
},
hir::{Array, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, UnaryOp},
lang_item::LangItem,
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
DefWithBodyId, FieldId, HasModule, VariantId,
@ -28,9 +25,9 @@ use crate::{
mir::{BorrowKind, MirSpan, ProjectionElem},
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
utils::{self, generics, pattern_matching_dereference_count, Generics},
Adjust, Adjustment, Binders, ChalkTraitId, ClosureId, ConstValue, DynTy, FnPointer, FnSig,
Interner, Substitution, Ty, TyExt,
utils::{self, generics, Generics},
Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, ConstValue, DynTy,
FnPointer, FnSig, Interner, Substitution, Ty, TyExt,
};
use super::{Expectation, InferenceContext};
@ -488,13 +485,7 @@ impl InferenceContext<'_> {
if let Some(initializer) = initializer {
self.walk_expr(*initializer);
if let Some(place) = self.place_of_expr(*initializer) {
let ty = self.expr_ty(*initializer);
self.consume_with_pat(
place,
ty,
BindingAnnotation::Unannotated,
*pat,
);
self.consume_with_pat(place, *pat);
}
}
}
@ -799,41 +790,37 @@ impl InferenceContext<'_> {
}
}
fn consume_with_pat(
&mut self,
mut place: HirPlace,
mut ty: Ty,
mut bm: BindingAnnotation,
pat: PatId,
) {
fn consume_with_pat(&mut self, mut place: HirPlace, pat: PatId) {
let cnt = self.result.pat_adjustments.get(&pat).map(|x| x.len()).unwrap_or_default();
place.projections = place
.projections
.iter()
.cloned()
.chain((0..cnt).map(|_| ProjectionElem::Deref))
.collect::<Vec<_>>()
.into();
match &self.body[pat] {
Pat::Missing | Pat::Wild => (),
Pat::Tuple { args, ellipsis } => {
pattern_matching_dereference(&mut ty, &mut bm, &mut place);
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
let subst = match ty.kind(Interner) {
TyKind::Tuple(_, s) => s,
let field_count = match self.result[pat].kind(Interner) {
TyKind::Tuple(_, s) => s.len(Interner),
_ => return,
};
let fields = subst.iter(Interner).map(|x| x.assert_ty_ref(Interner)).enumerate();
let fields = 0..field_count;
let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev()));
for (arg, (i, ty)) in it {
for (arg, i) in it {
let mut p = place.clone();
p.projections.push(ProjectionElem::TupleOrClosureField(i));
self.consume_with_pat(p, ty.clone(), bm, *arg);
self.consume_with_pat(p, *arg);
}
}
Pat::Or(pats) => {
for pat in pats.iter() {
self.consume_with_pat(place.clone(), ty.clone(), bm, *pat);
self.consume_with_pat(place.clone(), *pat);
}
}
Pat::Record { args, .. } => {
pattern_matching_dereference(&mut ty, &mut bm, &mut place);
let subst = match ty.kind(Interner) {
TyKind::Adt(_, s) => s,
_ => return,
};
let Some(variant) = self.result.variant_resolution_for_pat(pat) else {
return;
};
@ -843,7 +830,6 @@ impl InferenceContext<'_> {
}
VariantId::StructId(s) => {
let vd = &*self.db.struct_data(s).variant_data;
let field_types = self.db.field_types(variant);
for field_pat in args.iter() {
let arg = field_pat.pat;
let Some(local_id) = vd.field(&field_pat.name) else {
@ -854,12 +840,7 @@ impl InferenceContext<'_> {
parent: variant.into(),
local_id,
}));
self.consume_with_pat(
p,
field_types[local_id].clone().substitute(Interner, subst),
bm,
arg,
);
self.consume_with_pat(p, arg);
}
}
}
@ -870,26 +851,20 @@ impl InferenceContext<'_> {
| Pat::Path(_)
| Pat::Lit(_) => self.consume_place(place, pat.into()),
Pat::Bind { id, subpat: _ } => {
let mode = self.body.bindings[*id].mode;
if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
bm = mode;
}
let capture_kind = match bm {
BindingAnnotation::Unannotated | BindingAnnotation::Mutable => {
let mode = self.result.binding_modes[*id];
let capture_kind = match mode {
BindingMode::Move => {
self.consume_place(place, pat.into());
return;
}
BindingAnnotation::Ref => BorrowKind::Shared,
BindingAnnotation::RefMut => BorrowKind::Mut { allow_two_phase_borrow: false },
BindingMode::Ref(Mutability::Not) => BorrowKind::Shared,
BindingMode::Ref(Mutability::Mut) => {
BorrowKind::Mut { allow_two_phase_borrow: false }
}
};
self.add_capture(place, CaptureKind::ByRef(capture_kind), pat.into());
}
Pat::TupleStruct { path: _, args, ellipsis } => {
pattern_matching_dereference(&mut ty, &mut bm, &mut place);
let subst = match ty.kind(Interner) {
TyKind::Adt(_, s) => s,
_ => return,
};
let Some(variant) = self.result.variant_resolution_for_pat(pat) else {
return;
};
@ -903,29 +878,20 @@ impl InferenceContext<'_> {
let fields = vd.fields().iter();
let it =
al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev()));
let field_types = self.db.field_types(variant);
for (arg, (i, _)) in it {
let mut p = place.clone();
p.projections.push(ProjectionElem::Field(FieldId {
parent: variant.into(),
local_id: i,
}));
self.consume_with_pat(
p,
field_types[i].clone().substitute(Interner, subst),
bm,
*arg,
);
self.consume_with_pat(p, *arg);
}
}
}
}
Pat::Ref { pat, mutability: _ } => {
if let Some((inner, _, _)) = ty.as_reference() {
ty = inner.clone();
place.projections.push(ProjectionElem::Deref);
self.consume_with_pat(place, ty, bm, *pat)
}
place.projections.push(ProjectionElem::Deref);
self.consume_with_pat(place, *pat)
}
Pat::Box { .. } => (), // not supported
}
@ -1054,12 +1020,3 @@ fn apply_adjusts_to_place(mut r: HirPlace, adjustments: &[Adjustment]) -> Option
}
Some(r)
}
fn pattern_matching_dereference(
cond_ty: &mut Ty,
binding_mode: &mut BindingAnnotation,
cond_place: &mut HirPlace,
) {
let cnt = pattern_matching_dereference_count(cond_ty, binding_mode);
cond_place.projections.extend((0..cnt).map(|_| ProjectionElem::Deref));
}

View file

@ -478,9 +478,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
current,
None,
cond_place,
self.expr_ty_after_adjustments(*expr),
*pat,
BindingAnnotation::Unannotated,
)?;
self.write_bytes_to_place(
then_target,
@ -598,16 +596,13 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
let cond_ty = self.expr_ty_after_adjustments(*expr);
let mut end = None;
for MatchArm { pat, guard, expr } in arms.iter() {
let (then, mut otherwise) = self.pattern_match(
current,
None,
cond_place.clone(),
cond_ty.clone(),
*pat,
BindingAnnotation::Unannotated,
)?;
let then = if let &Some(guard) = guard {
let next = self.new_basic_block();
@ -1477,9 +1472,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
span: MirSpan,
) -> Result<()> {
self.drop_scopes.last_mut().unwrap().locals.push(l);
// FIXME: this storage dead is not neccessary, but since drop scope handling is broken, we need
// it to avoid falso positives in mutability errors
self.push_statement(current, StatementKind::StorageDead(l).with_span(span));
self.push_statement(current, StatementKind::StorageLive(l).with_span(span));
Ok(())
}
@ -1508,14 +1500,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
current = c;
(current, else_block) = self.pattern_match(
current,
None,
init_place,
self.expr_ty_after_adjustments(*expr_id),
*pat,
BindingAnnotation::Unannotated,
)?;
(current, else_block) =
self.pattern_match(current, None, init_place, *pat)?;
match (else_block, else_branch) {
(None, _) => (),
(Some(else_block), None) => {
@ -1595,14 +1581,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
continue;
}
}
let r = self.pattern_match(
current,
None,
local.into(),
self.result.locals[local].ty.clone(),
param,
BindingAnnotation::Unannotated,
)?;
let r = self.pattern_match(current, None, local.into(), param)?;
if let Some(b) = r.1 {
self.set_terminator(b, TerminatorKind::Unreachable, param.into());
}

View file

@ -2,7 +2,7 @@
use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
use crate::utils::pattern_matching_dereference_count;
use crate::BindingMode;
use super::*;
@ -18,6 +18,26 @@ pub(super) enum AdtPatternShape<'a> {
Unit,
}
/// We need to do pattern matching in two phases: One to check if the pattern matches, and one to fill the bindings
/// of patterns. This is necessary to prevent double moves and similar problems. For example:
/// ```ignore
/// struct X;
/// match (X, 3) {
/// (b, 2) | (b, 3) => {},
/// _ => {}
/// }
/// ```
/// If we do everything in one pass, we will move `X` to the first `b`, then we see that the second field of tuple
/// doesn't match and we should move the `X` to the second `b` (which here is the same thing, but doesn't need to be) and
/// it might even doesn't match the second pattern and we may want to not move `X` at all.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MatchingMode {
/// Check that if this pattern matches
Check,
/// Assume that this pattern matches, fill bindings
Bind,
}
impl MirLowerCtx<'_> {
/// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if
/// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which
@ -29,20 +49,50 @@ impl MirLowerCtx<'_> {
/// wouldn't be `None` as well. Note that this function will add jumps to the beginning of the `current_else` block,
/// so it should be an empty block.
pub(super) fn pattern_match(
&mut self,
current: BasicBlockId,
current_else: Option<BasicBlockId>,
cond_place: Place,
pattern: PatId,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let (current, current_else) = self.pattern_match_inner(
current,
current_else,
cond_place.clone(),
pattern,
MatchingMode::Check,
)?;
let (current, current_else) = self.pattern_match_inner(
current,
current_else,
cond_place,
pattern,
MatchingMode::Bind,
)?;
Ok((current, current_else))
}
fn pattern_match_inner(
&mut self,
mut current: BasicBlockId,
mut current_else: Option<BasicBlockId>,
mut cond_place: Place,
mut cond_ty: Ty,
pattern: PatId,
mut binding_mode: BindingAnnotation,
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
cond_place.projection = cond_place
.projection
.iter()
.cloned()
.chain((0..cnt).map(|_| ProjectionElem::Deref))
.collect::<Vec<_>>()
.into();
Ok(match &self.body.pats[pattern] {
Pat::Missing => return Err(MirLowerError::IncompletePattern),
Pat::Wild => (current, current_else),
Pat::Tuple { args, ellipsis } => {
pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place);
let subst = match cond_ty.kind(Interner) {
let subst = match self.infer[pattern].kind(Interner) {
TyKind::Tuple(_, s) => s,
_ => {
return Err(MirLowerError::TypeError(
@ -55,25 +105,31 @@ impl MirLowerCtx<'_> {
current_else,
args,
*ellipsis,
subst.iter(Interner).enumerate().map(|(i, x)| {
(PlaceElem::TupleOrClosureField(i), x.assert_ty_ref(Interner).clone())
}),
&cond_place,
binding_mode,
(0..subst.len(Interner)).map(|i| PlaceElem::TupleOrClosureField(i)),
&(&mut cond_place),
mode,
)?
}
Pat::Or(pats) => {
let then_target = self.new_basic_block();
let mut finished = false;
for pat in &**pats {
let (next, next_else) = self.pattern_match(
let (mut next, next_else) = self.pattern_match_inner(
current,
None,
cond_place.clone(),
cond_ty.clone(),
(&mut cond_place).clone(),
*pat,
binding_mode,
MatchingMode::Check,
)?;
if mode == MatchingMode::Bind {
(next, _) = self.pattern_match_inner(
next,
None,
(&mut cond_place).clone(),
*pat,
MatchingMode::Bind,
)?;
}
self.set_goto(next, then_target, pattern.into());
match next_else {
Some(t) => {
@ -86,8 +142,12 @@ impl MirLowerCtx<'_> {
}
}
if !finished {
let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
self.set_goto(current, ce, pattern.into());
if mode == MatchingMode::Bind {
self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
} else {
let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
self.set_goto(current, ce, pattern.into());
}
}
(then_target, current_else)
}
@ -96,19 +156,19 @@ impl MirLowerCtx<'_> {
not_supported!("unresolved variant for record");
};
self.pattern_matching_variant(
cond_ty,
binding_mode,
cond_place,
variant,
current,
pattern.into(),
current_else,
AdtPatternShape::Record { args: &*args },
mode,
)?
}
Pat::Range { start, end } => {
let mut add_check = |l: &LiteralOrConst, binop| -> Result<()> {
let lv = self.lower_literal_or_const_to_operand(cond_ty.clone(), l)?;
let lv =
self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?;
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
let next = self.new_basic_block();
let discr: Place =
@ -116,7 +176,11 @@ impl MirLowerCtx<'_> {
self.push_assignment(
current,
discr.clone(),
Rvalue::CheckedBinaryOp(binop, lv, Operand::Copy(cond_place.clone())),
Rvalue::CheckedBinaryOp(
binop,
lv,
Operand::Copy((&mut cond_place).clone()),
),
pattern.into(),
);
let discr = Operand::Copy(discr);
@ -131,24 +195,25 @@ impl MirLowerCtx<'_> {
current = next;
Ok(())
};
if let Some(start) = start {
add_check(start, BinOp::Le)?;
}
if let Some(end) = end {
add_check(end, BinOp::Ge)?;
if mode == MatchingMode::Check {
if let Some(start) = start {
add_check(start, BinOp::Le)?;
}
if let Some(end) = end {
add_check(end, BinOp::Ge)?;
}
}
(current, current_else)
}
Pat::Slice { prefix, slice, suffix } => {
pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place);
if let TyKind::Slice(_) = cond_ty.kind(Interner) {
if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) {
let pattern_len = prefix.len() + suffix.len();
let place_len: Place =
self.temp(TyBuilder::usize(), current, pattern.into())?.into();
self.push_assignment(
current,
place_len.clone(),
Rvalue::Len(cond_place.clone()),
Rvalue::Len((&mut cond_place).clone()),
pattern.into(),
);
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
@ -193,63 +258,49 @@ impl MirLowerCtx<'_> {
current = next;
}
for (i, &pat) in prefix.iter().enumerate() {
let next_place = cond_place.project(ProjectionElem::ConstantIndex {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
offset: i as u64,
from_end: false,
});
let cond_ty = self.infer[pat].clone();
(current, current_else) = self.pattern_match(
current,
current_else,
next_place,
cond_ty,
pat,
binding_mode,
)?;
(current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
if let Some(slice) = slice {
if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
let next_place = cond_place.project(ProjectionElem::Subslice {
from: prefix.len() as u64,
to: suffix.len() as u64,
});
(current, current_else) = self.pattern_match_binding(
id,
&mut binding_mode,
next_place,
(*slice).into(),
current,
current_else,
)?;
if mode == MatchingMode::Bind {
if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
let next_place = (&mut cond_place).project(ProjectionElem::Subslice {
from: prefix.len() as u64,
to: suffix.len() as u64,
});
(current, current_else) = self.pattern_match_binding(
id,
next_place,
(*slice).into(),
current,
current_else,
)?;
}
}
}
for (i, &pat) in suffix.iter().enumerate() {
let next_place = cond_place.project(ProjectionElem::ConstantIndex {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
offset: i as u64,
from_end: true,
});
let cond_ty = self.infer[pat].clone();
(current, current_else) = self.pattern_match(
current,
current_else,
next_place,
cond_ty,
pat,
binding_mode,
)?;
(current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
(current, current_else)
}
Pat::Path(p) => match self.infer.variant_resolution_for_pat(pattern) {
Some(variant) => self.pattern_matching_variant(
cond_ty,
binding_mode,
cond_place,
variant,
current,
pattern.into(),
current_else,
AdtPatternShape::Unit,
mode,
)?,
None => {
let unresolved_name = || MirLowerError::unresolved_path(self.db, p);
@ -270,9 +321,17 @@ impl MirLowerCtx<'_> {
}
not_supported!("path in pattern position that is not const or variant")
};
let tmp: Place = self.temp(cond_ty.clone(), current, pattern.into())?.into();
let tmp: Place =
self.temp(self.infer[pattern].clone(), current, pattern.into())?.into();
let span = pattern.into();
self.lower_const(c.into(), current, tmp.clone(), subst, span, cond_ty.clone())?;
self.lower_const(
c.into(),
current,
tmp.clone(),
subst,
span,
self.infer[pattern].clone(),
)?;
let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into();
self.push_assignment(
current,
@ -299,61 +358,58 @@ impl MirLowerCtx<'_> {
},
Pat::Lit(l) => match &self.body.exprs[*l] {
Expr::Literal(l) => {
let c = self.lower_literal_to_operand(cond_ty, l)?;
self.pattern_match_const(current_else, current, c, cond_place, pattern)?
let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?;
if mode == MatchingMode::Check {
self.pattern_match_const(current_else, current, c, cond_place, pattern)?
} else {
(current, current_else)
}
}
_ => not_supported!("expression path literal"),
},
Pat::Bind { id, subpat } => {
if let Some(subpat) = subpat {
(current, current_else) = self.pattern_match(
(current, current_else) = self.pattern_match_inner(
current,
current_else,
cond_place.clone(),
cond_ty,
(&mut cond_place).clone(),
*subpat,
binding_mode,
mode,
)?
}
self.pattern_match_binding(
*id,
&mut binding_mode,
cond_place,
pattern.into(),
current,
current_else,
)?
if mode == MatchingMode::Bind {
self.pattern_match_binding(
*id,
cond_place,
pattern.into(),
current,
current_else,
)?
} else {
(current, current_else)
}
}
Pat::TupleStruct { path: _, args, ellipsis } => {
let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else {
not_supported!("unresolved variant");
};
self.pattern_matching_variant(
cond_ty,
binding_mode,
cond_place,
variant,
current,
pattern.into(),
current_else,
AdtPatternShape::Tuple { args, ellipsis: *ellipsis },
mode,
)?
}
Pat::Ref { pat, mutability: _ } => {
if let Some((ty, _, _)) = cond_ty.as_reference() {
cond_ty = ty.clone();
self.pattern_match(
current,
current_else,
cond_place.project(ProjectionElem::Deref),
cond_ty,
*pat,
binding_mode,
)?
} else {
return Err(MirLowerError::TypeError("& pattern for non reference"));
}
}
Pat::Ref { pat, mutability: _ } => self.pattern_match_inner(
current,
current_else,
cond_place.project(ProjectionElem::Deref),
*pat,
mode,
)?,
Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"),
})
@ -362,27 +418,21 @@ impl MirLowerCtx<'_> {
fn pattern_match_binding(
&mut self,
id: BindingId,
binding_mode: &mut BindingAnnotation,
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.body.bindings[id].mode;
if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
*binding_mode = mode;
}
let mode = self.infer.binding_modes[id];
self.push_storage_live(id, current)?;
self.push_assignment(
current,
target_place.into(),
match *binding_mode {
BindingAnnotation::Unannotated | BindingAnnotation::Mutable => {
Operand::Copy(cond_place).into()
}
BindingAnnotation::Ref => Rvalue::Ref(BorrowKind::Shared, cond_place),
BindingAnnotation::RefMut => {
match mode {
BindingMode::Move => Operand::Copy(cond_place).into(),
BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place),
BindingMode::Ref(Mutability::Mut) => {
Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, cond_place)
}
},
@ -420,52 +470,48 @@ impl MirLowerCtx<'_> {
Ok((then_target, Some(else_target)))
}
pub(super) fn pattern_matching_variant(
fn pattern_matching_variant(
&mut self,
mut cond_ty: Ty,
mut binding_mode: BindingAnnotation,
mut cond_place: Place,
cond_place: Place,
variant: VariantId,
current: BasicBlockId,
mut current: BasicBlockId,
span: MirSpan,
current_else: Option<BasicBlockId>,
mut current_else: Option<BasicBlockId>,
shape: AdtPatternShape<'_>,
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place);
let subst = match cond_ty.kind(Interner) {
TyKind::Adt(_, s) => s,
_ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")),
};
Ok(match variant {
VariantId::EnumVariantId(v) => {
let e = self.const_eval_discriminant(v)? as u128;
let tmp = self.discr_temp_place(current);
self.push_assignment(
current,
tmp.clone(),
Rvalue::Discriminant(cond_place.clone()),
span,
);
let next = self.new_basic_block();
let else_target = current_else.unwrap_or_else(|| self.new_basic_block());
self.set_terminator(
current,
TerminatorKind::SwitchInt {
discr: Operand::Copy(tmp),
targets: SwitchTargets::static_if(e, next, else_target),
},
span,
);
if mode == MatchingMode::Check {
let e = self.const_eval_discriminant(v)? as u128;
let tmp = self.discr_temp_place(current);
self.push_assignment(
current,
tmp.clone(),
Rvalue::Discriminant(cond_place.clone()),
span,
);
let next = self.new_basic_block();
let else_target = current_else.get_or_insert_with(|| self.new_basic_block());
self.set_terminator(
current,
TerminatorKind::SwitchInt {
discr: Operand::Copy(tmp),
targets: SwitchTargets::static_if(e, next, *else_target),
},
span,
);
current = next;
}
let enum_data = self.db.enum_data(v.parent);
self.pattern_matching_variant_fields(
shape,
&enum_data.variants[v.local_id].variant_data,
variant,
subst,
next,
Some(else_target),
current,
current_else,
&cond_place,
binding_mode,
mode,
)?
}
VariantId::StructId(s) => {
@ -474,11 +520,10 @@ impl MirLowerCtx<'_> {
shape,
&struct_data.variant_data,
variant,
subst,
current,
current_else,
&cond_place,
binding_mode,
mode,
)?
}
VariantId::UnionId(_) => {
@ -492,13 +537,11 @@ impl MirLowerCtx<'_> {
shape: AdtPatternShape<'_>,
variant_data: &VariantData,
v: VariantId,
subst: &Substitution,
current: BasicBlockId,
current_else: Option<BasicBlockId>,
cond_place: &Place,
binding_mode: BindingAnnotation,
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let fields_type = self.db.field_types(v);
Ok(match shape {
AdtPatternShape::Record { args } => {
let it = args
@ -509,25 +552,16 @@ impl MirLowerCtx<'_> {
Ok((
PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }),
x.pat,
fields_type[field_id].clone().substitute(Interner, subst),
))
})
.collect::<Result<Vec<_>>>()?;
self.pattern_match_adt(
current,
current_else,
it.into_iter(),
cond_place,
binding_mode,
)?
self.pattern_match_adt(current, current_else, it.into_iter(), cond_place, mode)?
}
AdtPatternShape::Tuple { args, ellipsis } => {
let fields = variant_data.fields().iter().map(|(x, _)| {
(
PlaceElem::Field(FieldId { parent: v.into(), local_id: x }),
fields_type[x].clone().substitute(Interner, subst),
)
});
let fields = variant_data
.fields()
.iter()
.map(|(x, _)| PlaceElem::Field(FieldId { parent: v.into(), local_id: x }));
self.pattern_match_tuple_like(
current,
current_else,
@ -535,7 +569,7 @@ impl MirLowerCtx<'_> {
ellipsis,
fields,
cond_place,
binding_mode,
mode,
)?
}
AdtPatternShape::Unit => (current, current_else),
@ -546,14 +580,14 @@ impl MirLowerCtx<'_> {
&mut self,
mut current: BasicBlockId,
mut current_else: Option<BasicBlockId>,
args: impl Iterator<Item = (PlaceElem, PatId, Ty)>,
args: impl Iterator<Item = (PlaceElem, PatId)>,
cond_place: &Place,
binding_mode: BindingAnnotation,
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
for (proj, arg, ty) in args {
for (proj, arg) in args {
let cond_place = cond_place.project(proj);
(current, current_else) =
self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?;
self.pattern_match_inner(current, current_else, cond_place, arg, mode)?;
}
Ok((current, current_else))
}
@ -564,31 +598,16 @@ impl MirLowerCtx<'_> {
current_else: Option<BasicBlockId>,
args: &[PatId],
ellipsis: Option<usize>,
fields: impl DoubleEndedIterator<Item = (PlaceElem, Ty)> + Clone,
fields: impl DoubleEndedIterator<Item = PlaceElem> + Clone,
cond_place: &Place,
binding_mode: BindingAnnotation,
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
let it = al
.iter()
.zip(fields.clone())
.chain(ar.iter().rev().zip(fields.rev()))
.map(|(x, y)| (y.0, *x, y.1));
self.pattern_match_adt(current, current_else, it, cond_place, binding_mode)
.map(|(x, y)| (y, *x));
self.pattern_match_adt(current, current_else, it, cond_place, mode)
}
}
fn pattern_matching_dereference(
cond_ty: &mut Ty,
binding_mode: &mut BindingAnnotation,
cond_place: &mut Place,
) {
let cnt = pattern_matching_dereference_count(cond_ty, binding_mode);
cond_place.projection = cond_place
.projection
.iter()
.cloned()
.chain((0..cnt).map(|_| ProjectionElem::Deref))
.collect::<Vec<_>>()
.into();
}

View file

@ -7,7 +7,7 @@ use base_db::CrateId;
use chalk_ir::{
cast::Cast,
fold::{FallibleTypeFolder, Shift},
BoundVar, DebruijnIndex, Mutability,
BoundVar, DebruijnIndex,
};
use either::Either;
use hir_def::{
@ -16,7 +16,6 @@ use hir_def::{
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
},
hir::BindingAnnotation,
lang_item::LangItem,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
@ -35,7 +34,7 @@ use crate::{
layout::{Layout, TagEncoding},
mir::pad16,
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
Ty, TyExt, WhereClause,
Ty, WhereClause,
};
pub(crate) fn fn_traits(
@ -395,23 +394,6 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
}
}
pub(crate) fn pattern_matching_dereference_count(
cond_ty: &mut Ty,
binding_mode: &mut BindingAnnotation,
) -> usize {
let mut r = 0;
while let Some((ty, _, mu)) = cond_ty.as_reference() {
if mu == Mutability::Mut && *binding_mode != BindingAnnotation::Ref {
*binding_mode = BindingAnnotation::RefMut;
} else {
*binding_mode = BindingAnnotation::Ref;
}
*cond_ty = ty.clone();
r += 1;
}
r
}
pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
pub(crate) db: &'a dyn HirDatabase,
}