Fix missing terminator for slice pattern

This commit is contained in:
hkalbasi 2023-06-04 20:59:27 +03:30
parent 0408af6453
commit b4907a531f
2 changed files with 70 additions and 45 deletions

View file

@ -206,56 +206,60 @@ impl MirLowerCtx<'_> {
(current, current_else) (current, current_else)
} }
Pat::Slice { prefix, slice, suffix } => { Pat::Slice { prefix, slice, suffix } => {
if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) { if mode == MatchingMode::Check {
let pattern_len = prefix.len() + suffix.len(); // emit runtime length check for slice
let place_len: Place = if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) {
self.temp(TyBuilder::usize(), current, pattern.into())?.into(); let pattern_len = prefix.len() + suffix.len();
self.push_assignment( let place_len: Place =
current, self.temp(TyBuilder::usize(), current, pattern.into())?.into();
place_len.clone(),
Rvalue::Len((&mut cond_place).clone()),
pattern.into(),
);
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
let next = self.new_basic_block();
if slice.is_none() {
self.set_terminator(
current,
TerminatorKind::SwitchInt {
discr: Operand::Copy(place_len),
targets: SwitchTargets::static_if(
pattern_len as u128,
next,
else_target,
),
},
pattern.into(),
);
} else {
let c = Operand::from_concrete_const(
pattern_len.to_le_bytes().to_vec(),
MemoryMap::default(),
TyBuilder::usize(),
);
let discr: Place =
self.temp(TyBuilder::bool(), current, pattern.into())?.into();
self.push_assignment( self.push_assignment(
current, current,
discr.clone(), place_len.clone(),
Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)), Rvalue::Len((&mut cond_place).clone()),
pattern.into(),
);
let discr = Operand::Copy(discr);
self.set_terminator(
current,
TerminatorKind::SwitchInt {
discr,
targets: SwitchTargets::static_if(1, next, else_target),
},
pattern.into(), pattern.into(),
); );
let else_target =
*current_else.get_or_insert_with(|| self.new_basic_block());
let next = self.new_basic_block();
if slice.is_none() {
self.set_terminator(
current,
TerminatorKind::SwitchInt {
discr: Operand::Copy(place_len),
targets: SwitchTargets::static_if(
pattern_len as u128,
next,
else_target,
),
},
pattern.into(),
);
} else {
let c = Operand::from_concrete_const(
pattern_len.to_le_bytes().to_vec(),
MemoryMap::default(),
TyBuilder::usize(),
);
let discr: Place =
self.temp(TyBuilder::bool(), current, pattern.into())?.into();
self.push_assignment(
current,
discr.clone(),
Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)),
pattern.into(),
);
let discr = Operand::Copy(discr);
self.set_terminator(
current,
TerminatorKind::SwitchInt {
discr,
targets: SwitchTargets::static_if(1, next, else_target),
},
pattern.into(),
);
}
current = next;
} }
current = next;
} }
for (i, &pat) in prefix.iter().enumerate() { for (i, &pat) in prefix.iter().enumerate() {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {

View file

@ -993,6 +993,27 @@ fn f() {
); );
} }
#[test]
fn slice_pattern() {
check_diagnostics(
r#"
//- minicore: coerce_unsized, deref_mut, slice, copy
fn x(t: &[u8]) {
match t {
&[a, mut b] | &[a, _, mut b] => {
//^^^^^ 💡 weak: variable does not need to be mutable
a = 2;
//^^^^^ 💡 error: cannot mutate immutable variable `a`
}
_ => {}
}
}
"#,
);
}
#[test] #[test]
fn boxes() { fn boxes() {
check_diagnostics( check_diagnostics(