From 14cf5efaa560d09704a092e658573ec0737ecdcb Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Tue, 17 Dec 2024 19:01:01 +0100 Subject: [PATCH] handling comptime known match Signed-off-by: Jakub Doka --- lang/README.md | 4 ++ lang/src/nodes.rs | 2 +- lang/src/son.rs | 156 +++++++++++++++++++++++++++++----------------- lang/src/ty.rs | 1 + 4 files changed, 104 insertions(+), 59 deletions(-) diff --git a/lang/README.md b/lang/README.md index 6cbaca8..e14a3f4 100644 --- a/lang/README.md +++ b/lang/README.md @@ -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 { diff --git a/lang/src/nodes.rs b/lang/src/nodes.rs index 2299920..1d1f17f 100644 --- a/lang/src/nodes.rs +++ b/lang/src/nodes.rs @@ -707,7 +707,7 @@ impl Nodes { let free = self.free; for &d in node.inputs.as_slice() { debug_assert_ne!(d, free); - self.values[d as usize].as_mut().unwrap_or_else(|_| panic!("{d}")).outputs.push(free); + self.values[d as usize].as_mut().unwrap_or_else(|_| panic!("{d} ")).outputs.push(free); } self.free = mem::replace(&mut self.values[free as usize], Ok(node)).unwrap_err().0; diff --git a/lang/src/son.rs b/lang/src/son.rs index dffea11..3d6b438 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -2106,62 +2106,112 @@ 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::; - 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"); + + if let Kind::CInt { value: cnst } = self.ci.nodes[value.id].kind { + let mut matching_branch = None::; + 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; } - 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); + } } - 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", + 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 { + 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; + + let pat_val = self.ci.nodes.new_const(value.ty, pat_val as i64); + let cnd = self.ci.nodes.new_node( + ty::Id::BOOL, + Kind::BinOp { op: TokenKind::Eq }, + [VOID, value.id, pat_val], + self.tys, + ); + + let if_node = self.ci.nodes.new_node( + ty::Id::VOID, + Kind::If, + [self.ci.ctrl.get(), cnd], + self.tys, + ); + + let cached_scope = self.ci.scope.dup(&mut self.ci.nodes); + self.ci.ctrl.set( + self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node], self.tys), + &mut self.ci.nodes, + ); + let ctrl = self.expr(&body).map_or(Nid::MAX, |_| self.ci.ctrl.get()); + scopes.push((ctrl, mem::replace(&mut self.ci.scope, cached_scope))); + + self.ci.ctrl.set( + self.ci.nodes.new_node(ty::Id::VOID, Kind::Else, [if_node], self.tys), + &mut self.ci.nodes, ); - continue; } - covered_values[pat_val as usize] = bp; + let mut rcntrl = if let Some(ebr) = else_branch { + self.expr(&ebr).map_or(Nid::MAX, |_| self.ci.ctrl.get()) + } else { + self.ci.ctrl.get() + }; - let pat_val = self.ci.nodes.new_const(value.ty, pat_val as i64); - let cnd = self.ci.nodes.new_node( - ty::Id::BOOL, - Kind::BinOp { op: TokenKind::Eq }, - [VOID, value.id, pat_val], - self.tys, - ); + for (lcntrl, then_scope) in scopes.into_iter().rev() { + if let Some(v) = self.close_if(lcntrl, rcntrl, then_scope) + && v != VOID + { + rcntrl = v; + } + } - let if_node = self.ci.nodes.new_node( - ty::Id::VOID, - Kind::If, - [self.ci.ctrl.get(), cnd], - self.tys, - ); - - let cached_scope = self.ci.scope.dup(&mut self.ci.nodes); - self.ci.ctrl.set( - self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node], self.tys), - &mut self.ci.nodes, - ); - let ctrl = self.expr(&body).map_or(Nid::MAX, |_| self.ci.ctrl.get()); - scopes.push((ctrl, mem::replace(&mut self.ci.scope, cached_scope))); - - self.ci.ctrl.set( - self.ci.nodes.new_node(ty::Id::VOID, Kind::Else, [if_node], self.tys), - &mut self.ci.nodes, - ); + if rcntrl == Nid::MAX { + return None; + } } - let mut rcntrl = if let Some(ebr) = else_branch { - self.expr(&ebr).map_or(Nid::MAX, |_| self.ci.ctrl.get()) - } else { + if else_branch.is_none() { let missing_branches = covered_values .into_iter() .zip(self.tys.enum_fields(e)) @@ -2173,19 +2223,6 @@ impl<'a> Codegen<'a> { if !missing_branches.is_empty() { self.error(pos, fa!("not all cases covered, missing '{missing_branches}'")); } - self.ci.ctrl.get() - }; - - for (lcntrl, then_scope) in scopes.into_iter().rev() { - if let Some(v) = self.close_if(lcntrl, rcntrl, then_scope) - && v != VOID - { - rcntrl = v; - } - } - - if rcntrl == Nid::MAX { - return None; } 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); } diff --git a/lang/src/ty.rs b/lang/src/ty.rs index 0cf1e8b..af8018e 100644 --- a/lang/src/ty.rs +++ b/lang/src/ty.rs @@ -380,6 +380,7 @@ builtin_type! { INT; F32; F64; + ANY_TYPE; } macro_rules! type_kind {