Skip to content

Commit c0a0664

Browse files
committed
Support "or patterns" MIR lowering
1 parent 61ad6a9 commit c0a0664

File tree

2 files changed

+122
-15
lines changed

2 files changed

+122
-15
lines changed

crates/hir-ty/src/consteval/tests.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,11 +559,11 @@ fn function_param_patterns() {
559559
check_number(
560560
r#"
561561
const fn f(c @ (a, b): &(u8, u8)) -> u8 {
562-
*a + *b + (*c).1
562+
*a + *b + c.0 + (*c).1
563563
}
564564
const GOAL: u8 = f(&(2, 3));
565565
"#,
566-
8,
566+
10,
567567
);
568568
check_number(
569569
r#"
@@ -641,6 +641,44 @@ fn options() {
641641
);
642642
}
643643

644+
#[test]
645+
fn or_pattern() {
646+
check_number(
647+
r#"
648+
const GOAL: u8 = {
649+
let (a | a) = 2;
650+
a
651+
};
652+
"#,
653+
2,
654+
);
655+
check_number(
656+
r#"
657+
//- minicore: option
658+
const fn f(x: Option<i32>) -> i32 {
659+
let (Some(a) | Some(a)) = x else { return 2; };
660+
a
661+
}
662+
const GOAL: i32 = f(Some(10)) + f(None);
663+
"#,
664+
12,
665+
);
666+
check_number(
667+
r#"
668+
//- minicore: option
669+
const fn f(x: Option<i32>, y: Option<i32>) -> i32 {
670+
match (x, y) {
671+
(Some(x), Some(y)) => x * y,
672+
(Some(a), _) | (_, Some(a)) => a,
673+
_ => 10,
674+
}
675+
}
676+
const GOAL: i32 = f(Some(10), Some(20)) + f(Some(30), None) + f(None, Some(40)) + f(None, None);
677+
"#,
678+
280,
679+
);
680+
}
681+
644682
#[test]
645683
fn array_and_index() {
646684
check_number(

crates/hir-ty/src/mir/lower.rs

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,7 @@ impl MirLowerCtx<'_> {
155155
if let Some(p) = self.lower_expr_as_place(expr_id) {
156156
return Ok((p, prev_block));
157157
}
158-
let mut ty = self.expr_ty(expr_id);
159-
if let Some(x) = self.infer.expr_adjustments.get(&expr_id) {
160-
if let Some(x) = x.last() {
161-
ty = x.target.clone();
162-
}
163-
}
158+
let ty = self.expr_ty_after_adjustments(expr_id);
164159
let place = self.temp(ty)?;
165160
Ok((place.into(), self.lower_expr_to_place(expr_id, place.into(), prev_block)?))
166161
}
@@ -323,7 +318,7 @@ impl MirLowerCtx<'_> {
323318
current,
324319
None,
325320
cond_place,
326-
self.expr_ty(*expr),
321+
self.expr_ty_after_adjustments(*expr),
327322
*pat,
328323
BindingAnnotation::Unannotated,
329324
)?;
@@ -339,7 +334,53 @@ impl MirLowerCtx<'_> {
339334
self.lower_block_to_place(None, statements, current, *tail, place)
340335
}
341336
Expr::Block { id: _, statements, tail, label } => {
342-
self.lower_block_to_place(*label, statements, current, *tail, place)
337+
if label.is_some() {
338+
not_supported!("block with label");
339+
}
340+
for statement in statements.iter() {
341+
match statement {
342+
hir_def::expr::Statement::Let {
343+
pat,
344+
initializer,
345+
else_branch,
346+
type_ref: _,
347+
} => match initializer {
348+
Some(expr_id) => {
349+
let else_block;
350+
let init_place;
351+
(init_place, current) =
352+
self.lower_expr_to_some_place(*expr_id, current)?;
353+
(current, else_block) = self.pattern_match(
354+
current,
355+
None,
356+
init_place,
357+
self.expr_ty_after_adjustments(*expr_id),
358+
*pat,
359+
BindingAnnotation::Unannotated,
360+
)?;
361+
match (else_block, else_branch) {
362+
(None, _) => (),
363+
(Some(else_block), None) => {
364+
self.set_terminator(else_block, Terminator::Unreachable);
365+
}
366+
(Some(else_block), Some(else_branch)) => {
367+
let (_, b) = self
368+
.lower_expr_to_some_place(*else_branch, else_block)?;
369+
self.set_terminator(b, Terminator::Unreachable);
370+
}
371+
}
372+
}
373+
None => continue,
374+
},
375+
hir_def::expr::Statement::Expr { expr, has_semi: _ } => {
376+
(_, current) = self.lower_expr_to_some_place(*expr, current)?;
377+
}
378+
}
379+
}
380+
match tail {
381+
Some(tail) => self.lower_expr_to_place(*tail, place, current),
382+
None => Ok(current),
383+
}
343384
}
344385
Expr::Loop { body, label } => self.lower_loop(current, *label, |this, begin, _| {
345386
let (_, block) = this.lower_expr_to_some_place(*body, begin)?;
@@ -364,7 +405,7 @@ impl MirLowerCtx<'_> {
364405
}
365406
Expr::For { .. } => not_supported!("for loop"),
366407
Expr::Call { callee, args, .. } => {
367-
let callee_ty = self.expr_ty(*callee);
408+
let callee_ty = self.expr_ty_after_adjustments(*callee);
368409
match &callee_ty.data(Interner).kind {
369410
chalk_ir::TyKind::FnDef(..) => {
370411
let func = Operand::from_bytes(vec![], callee_ty.clone());
@@ -414,7 +455,7 @@ impl MirLowerCtx<'_> {
414455
}
415456
Expr::Match { expr, arms } => {
416457
let (cond_place, mut current) = self.lower_expr_to_some_place(*expr, current)?;
417-
let cond_ty = self.expr_ty(*expr);
458+
let cond_ty = self.expr_ty_after_adjustments(*expr);
418459
let end = self.new_basic_block();
419460
for MatchArm { pat, guard, expr } in arms.iter() {
420461
if guard.is_some() {
@@ -524,7 +565,7 @@ impl MirLowerCtx<'_> {
524565
}
525566
Expr::Field { expr, name } => {
526567
let (mut current_place, current) = self.lower_expr_to_some_place(*expr, current)?;
527-
if let TyKind::Tuple(..) = self.expr_ty(*expr).kind(Interner) {
568+
if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) {
528569
let index = name
529570
.as_tuple_index()
530571
.ok_or(MirLowerError::TypeError("named field on tuple"))?;
@@ -623,7 +664,7 @@ impl MirLowerCtx<'_> {
623664
Expr::Index { base, index } => {
624665
let mut p_base;
625666
(p_base, current) = self.lower_expr_to_some_place(*base, current)?;
626-
let l_index = self.temp(self.expr_ty(*index))?;
667+
let l_index = self.temp(self.expr_ty_after_adjustments(*index))?;
627668
current = self.lower_expr_to_place(*index, l_index.into(), current)?;
628669
p_base.projection.push(ProjectionElem::Index(l_index));
629670
self.push_assignment(current, place, Operand::Copy(p_base).into());
@@ -878,6 +919,16 @@ impl MirLowerCtx<'_> {
878919
self.infer[e].clone()
879920
}
880921

922+
fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty {
923+
let mut ty = None;
924+
if let Some(x) = self.infer.expr_adjustments.get(&e) {
925+
if let Some(x) = x.last() {
926+
ty = Some(x.target.clone());
927+
}
928+
}
929+
ty.unwrap_or_else(|| self.expr_ty(e))
930+
}
931+
881932
fn push_assignment(&mut self, block: BasicBlockId, place: Place, rvalue: Rvalue) {
882933
self.result.basic_blocks[block].statements.push(Statement::Assign(place, rvalue));
883934
}
@@ -928,7 +979,25 @@ impl MirLowerCtx<'_> {
928979
binding_mode,
929980
)?
930981
}
931-
Pat::Or(_) => not_supported!("or pattern"),
982+
Pat::Or(pats) => {
983+
let then_target = self.new_basic_block();
984+
let mut finished = false;
985+
for pat in &**pats {
986+
let (next, next_else) =
987+
self.pattern_match(current, None, cond_place.clone(), cond_ty.clone(), *pat, binding_mode)?;
988+
self.set_goto(next, then_target);
989+
match next_else {
990+
Some(t) => {
991+
current = t;
992+
}
993+
None => {
994+
finished = true;
995+
break;
996+
}
997+
}
998+
}
999+
(then_target, (!finished).then_some(current))
1000+
}
9321001
Pat::Record { .. } => not_supported!("record pattern"),
9331002
Pat::Range { .. } => not_supported!("range pattern"),
9341003
Pat::Slice { .. } => not_supported!("slice pattern"),

0 commit comments

Comments
 (0)