Skip to content

Commit 9564773

Browse files
committed
Improve pattern matching MIR lowering
1 parent 051dae2 commit 9564773

File tree

9 files changed

+590
-395
lines changed

9 files changed

+590
-395
lines changed

crates/hir-def/src/body/lower.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,9 +1030,16 @@ impl ExprCollector<'_> {
10301030
.collect(),
10311031
}
10321032
}
1033-
ast::Pat::LiteralPat(lit) => {
1033+
ast::Pat::LiteralPat(lit) => 'b: {
10341034
if let Some(ast_lit) = lit.literal() {
1035-
let expr = Expr::Literal(ast_lit.kind().into());
1035+
let mut hir_lit: Literal = ast_lit.kind().into();
1036+
if lit.minus_token().is_some() {
1037+
let Some(h) = hir_lit.negate() else {
1038+
break 'b Pat::Missing;
1039+
};
1040+
hir_lit = h;
1041+
}
1042+
let expr = Expr::Literal(hir_lit);
10361043
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
10371044
let expr_id = self.alloc_expr(expr, expr_ptr);
10381045
Pat::Lit(expr_id)
@@ -1144,11 +1151,11 @@ impl From<ast::LiteralKind> for Literal {
11441151
FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
11451152
builtin,
11461153
)
1147-
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) {
1148-
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
1149-
} else {
1150-
let builtin = lit.suffix().and_then(BuiltinUint::from_suffix);
1154+
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) {
11511155
Literal::Uint(lit.value().unwrap_or(0), builtin)
1156+
} else {
1157+
let builtin = lit.suffix().and_then(BuiltinInt::from_suffix);
1158+
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
11521159
}
11531160
}
11541161
LiteralKind::FloatNumber(lit) => {

crates/hir-def/src/expr.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ pub enum Literal {
9292
Float(FloatTypeWrapper, Option<BuiltinFloat>),
9393
}
9494

95+
impl Literal {
96+
pub fn negate(self) -> Option<Self> {
97+
if let Literal::Int(i, k) = self {
98+
Some(Literal::Int(-i, k))
99+
} else {
100+
None
101+
}
102+
}
103+
}
104+
95105
#[derive(Debug, Clone, Eq, PartialEq)]
96106
pub enum Expr {
97107
/// This is produced if the syntax tree does not have a required expression piece.

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

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,36 @@ fn path_pattern_matching() {
685685
);
686686
}
687687

688+
#[test]
689+
fn pattern_matching_literal() {
690+
check_number(
691+
r#"
692+
const fn f(x: i32) -> i32 {
693+
match x {
694+
-1 => 1,
695+
1 => 10,
696+
_ => 100,
697+
}
698+
}
699+
const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5);
700+
"#,
701+
211
702+
);
703+
check_number(
704+
r#"
705+
const fn f(x: &str) -> u8 {
706+
match x {
707+
"foo" => 1,
708+
"bar" => 10,
709+
_ => 100,
710+
}
711+
}
712+
const GOAL: u8 = f("foo") + f("bar");
713+
"#,
714+
11
715+
);
716+
}
717+
688718
#[test]
689719
fn pattern_matching_ergonomics() {
690720
check_number(
@@ -698,6 +728,16 @@ fn pattern_matching_ergonomics() {
698728
"#,
699729
5,
700730
);
731+
check_number(
732+
r#"
733+
const GOAL: u8 = {
734+
let a = &(2, 3);
735+
let &(x, y) = a;
736+
x + y
737+
};
738+
"#,
739+
5,
740+
);
701741
}
702742

703743
#[test]
@@ -781,6 +821,33 @@ fn function_param_patterns() {
781821
);
782822
}
783823

824+
#[test]
825+
fn match_guards() {
826+
check_number(
827+
r#"
828+
//- minicore: option, eq
829+
impl<T: PartialEq> PartialEq for Option<T> {
830+
fn eq(&self, other: &Rhs) -> bool {
831+
match (self, other) {
832+
(Some(x), Some(y)) => x == y,
833+
(None, None) => true,
834+
_ => false,
835+
}
836+
}
837+
}
838+
fn f(x: Option<i32>) -> i32 {
839+
match x {
840+
y if y == Some(42) => 42000,
841+
Some(y) => y,
842+
None => 10
843+
}
844+
}
845+
const GOAL: i32 = f(Some(42)) + f(Some(2)) + f(None);
846+
"#,
847+
42012,
848+
);
849+
}
850+
784851
#[test]
785852
fn options() {
786853
check_number(
@@ -983,6 +1050,51 @@ fn function_pointer() {
9831050
);
9841051
}
9851052

1053+
#[test]
1054+
fn enum_variant_as_function() {
1055+
check_number(
1056+
r#"
1057+
//- minicore: option
1058+
const GOAL: u8 = {
1059+
let f = Some;
1060+
f(3).unwrap_or(2)
1061+
};
1062+
"#,
1063+
3,
1064+
);
1065+
check_number(
1066+
r#"
1067+
//- minicore: option
1068+
const GOAL: u8 = {
1069+
let f: fn(u8) -> Option<u8> = Some;
1070+
f(3).unwrap_or(2)
1071+
};
1072+
"#,
1073+
3,
1074+
);
1075+
check_number(
1076+
r#"
1077+
//- minicore: coerce_unsized, index, slice
1078+
enum Foo {
1079+
Add2(u8),
1080+
Mult3(u8),
1081+
}
1082+
use Foo::*;
1083+
const fn f(x: Foo) -> u8 {
1084+
match x {
1085+
Add2(x) => x + 2,
1086+
Mult3(x) => x * 3,
1087+
}
1088+
}
1089+
const GOAL: u8 = {
1090+
let x = [Add2, Mult3];
1091+
f(x[0](1)) + f(x[1](5))
1092+
};
1093+
"#,
1094+
18,
1095+
);
1096+
}
1097+
9861098
#[test]
9871099
fn function_traits() {
9881100
check_number(

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ impl Evaluator<'_> {
423423
args: impl Iterator<Item = Vec<u8>>,
424424
subst: Substitution,
425425
) -> Result<Vec<u8>> {
426+
dbg!(body.dbg(self.db));
426427
if let Some(x) = self.stack_depth_limit.checked_sub(1) {
427428
self.stack_depth_limit = x;
428429
} else {
@@ -581,7 +582,14 @@ impl Evaluator<'_> {
581582
let mut ty = self.operand_ty(lhs, locals)?;
582583
while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
583584
ty = z.clone();
584-
let size = self.size_of_sized(&ty, locals, "operand of binary op")?;
585+
let size = if ty.kind(Interner) == &TyKind::Str {
586+
let ns = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]);
587+
lc = &lc[..self.ptr_size()];
588+
rc = &rc[..self.ptr_size()];
589+
ns
590+
} else {
591+
self.size_of_sized(&ty, locals, "operand of binary op")?
592+
};
585593
lc = self.read_memory(Address::from_bytes(lc)?, size)?;
586594
rc = self.read_memory(Address::from_bytes(rc)?, size)?;
587595
}

0 commit comments

Comments
 (0)