handling comptime known match

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-17 19:01:01 +01:00
parent 95496116b0
commit 14cf5efaa5
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
4 changed files with 104 additions and 59 deletions

View file

@ -428,8 +428,10 @@ foo := @use("foo.hb")
main := fn(): uint {
byte := @as(u8, 10)
_ = sum(byte, byte)
same_type_as_byte := @as(@TypeOf(byte), 30)
wide_uint := @as(u32, 40)
_ = sum(wide_uint, wide_uint)
truncated_uint := @as(u8, @intcast(wide_uint))
widened_float := @as(f64, @floatcast(1.))
int_from_float := @as(int, @fti(1.))
@ -445,6 +447,8 @@ main := fn(): uint {
return @inline(foo.foo)
}
$sum := fn(a: @any(), b: @TypeOf(a)): @TypeOf(a) return a + b
// in module: foo.hb
Type := struct {

View file

@ -2106,8 +2106,42 @@ impl<'a> Codegen<'a> {
};
let mut covered_values = vec![Pos::MAX; self.tys.enum_field_range(e).len()];
let mut scopes = vec![];
let mut else_branch = None::<Expr>;
if let Kind::CInt { value: cnst } = self.ci.nodes[value.id].kind {
let mut matching_branch = None::<Expr>;
for &MatchBranch { pat, pos: bp, body } in branches {
if let Expr::Wildcard { .. } = pat {
if let Some(prev) = else_branch {
self.error(bp, "duplicate branch");
self.error(prev.pos(), "...first branch declared here");
}
else_branch = Some(body);
continue;
}
let pat_val = self.eval_const(self.ci.file, self.ci.parent, &pat, value.ty);
if covered_values[pat_val as usize] != Pos::MAX {
self.error(bp, "duplicate branch");
self.error(
covered_values[pat_val as usize],
"...first branch declared here",
);
continue;
}
covered_values[pat_val as usize] = bp;
if pat_val == cnst as u64 {
matching_branch = Some(body);
}
}
if let Some(body) = else_branch.or(matching_branch) {
self.expr(&body)?;
}
} else {
let mut scopes = vec![];
for &MatchBranch { pat, pos: bp, body } in branches {
if let Expr::Wildcard { .. } = pat {
if let Some(prev) = else_branch {
@ -2158,21 +2192,9 @@ impl<'a> Codegen<'a> {
&mut self.ci.nodes,
);
}
let mut rcntrl = if let Some(ebr) = else_branch {
self.expr(&ebr).map_or(Nid::MAX, |_| self.ci.ctrl.get())
} else {
let missing_branches = covered_values
.into_iter()
.zip(self.tys.enum_fields(e))
.filter(|&(f, _)| f == Pos::MAX)
.map(|(_, f)| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
if !missing_branches.is_empty() {
self.error(pos, fa!("not all cases covered, missing '{missing_branches}'"));
}
self.ci.ctrl.get()
};
@ -2187,6 +2209,21 @@ impl<'a> Codegen<'a> {
if rcntrl == Nid::MAX {
return None;
}
}
if else_branch.is_none() {
let missing_branches = covered_values
.into_iter()
.zip(self.tys.enum_fields(e))
.filter(|&(f, _)| f == Pos::MAX)
.map(|(_, f)| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
if !missing_branches.is_empty() {
self.error(pos, fa!("not all cases covered, missing '{missing_branches}'"));
}
}
Some(Value::VOID)
}
@ -3817,6 +3854,9 @@ impl<'a> Codegen<'a> {
break 'b None;
}
let ty = self.parse_ty(sc.anon(), &arg.ty);
if ty == ty::Id::ANY_TYPE {
break 'b None;
}
self.tys.tmp.args.push(ty);
}

View file

@ -380,6 +380,7 @@ builtin_type! {
INT;
F32;
F64;
ANY_TYPE;
}
macro_rules! type_kind {