From 659ccbd6370cb56f41634f5b651a8216d65493f7 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 13 Oct 2024 14:11:17 +0200 Subject: [PATCH] adding stricter typechecking --- lang/README.md | 50 ----------------------------- lang/src/codegen.rs | 76 ++++++++++++++++++++++++++++++++------------- lang/src/fmt.rs | 2 +- lang/src/lib.rs | 13 ++++++-- lang/src/son.rs | 2 +- 5 files changed, 66 insertions(+), 77 deletions(-) diff --git a/lang/README.md b/lang/README.md index 8c21031..aa4743e 100644 --- a/lang/README.md +++ b/lang/README.md @@ -388,56 +388,6 @@ main := fn(major: int, minor: int): OemIdent { ### Incomplete Examples -#### wired_mem_swap -```hb -Color := struct {x: int} - -put_trisquare := fn(pos: Vec2(int), size: Vec2(int), color: Color): void { - step := Vec2(int).(1, 1) - if size.x < 0 { - step.x = -1 - } - if size.y < 0 { - step.y = -1 - } - - target := pos + size - - loop if pos.x == target.x break else { - put_vline(pos.x, pos.y, target.y, color) - pos.x += step.x - } - - return -} - -put_vline := fn(x: int, y0: int, y1: int, color: Color): void { - return -} - - -Vec2 := fn($Expr: type): type { - return struct {x: Expr, y: Expr} -} - -MemSwap := fn($Expr: type): type { - return struct {a: Expr, b: Expr} -} - -memswap := fn($Expr: type, a: ^Expr, b: ^Expr): void { - MemSwap(Expr).(b, a) = MemSwap(Expr).(*a, *b) - return -} - -main := fn(): int { - put_trisquare(.(0, 0), .(0, 0), .(0)) - a := 10 - b := 50 - //memswap(int, a, b) - return a -} -``` - #### comptime_pointers ```hb main := fn(): int { diff --git a/lang/src/codegen.rs b/lang/src/codegen.rs index 87b0ea4..0d8c0ac 100644 --- a/lang/src/codegen.rs +++ b/lang/src/codegen.rs @@ -7,7 +7,8 @@ use { parser::{ self, find_symbol, idfl, CommentOr, CtorField, Expr, ExprRef, FileId, Pos, StructField, }, - ty, Field, Func, Global, LoggedMem, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey, + ty::{self, TyCheck}, + Field, Func, Global, LoggedMem, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey, TypedReloc, Types, HEADER_SIZE, }, alloc::{boxed::Box, string::String, vec::Vec}, @@ -607,6 +608,7 @@ struct FTask { struct Ctx { loc: Option, ty: Option, + check: TyCheck, } impl Ctx { @@ -618,6 +620,10 @@ impl Ctx { Self { ty: Some(ty.into()), ..self } } + pub fn with_check(self, check: TyCheck) -> Self { + Self { check, ..self } + } + fn into_value(self) -> Option { Some(Value { ty: self.ty.unwrap(), loc: self.loc? }) } @@ -625,7 +631,7 @@ impl Ctx { impl From for Ctx { fn from(value: Value) -> Self { - Self { loc: Some(value.loc), ty: Some(value.ty) } + Self { loc: Some(value.loc), ty: Some(value.ty), ..Default::default() } } } @@ -839,7 +845,13 @@ impl Codegen { base_val.loc = self.make_loc_owned(base_val.loc, base_val.ty); } let index_val = self.expr(index)?; - _ = self.assert_ty(index.pos(), index_val.ty, ty::Id::INT, "subsctipt"); + _ = self.assert_ty( + index.pos(), + index_val.ty, + ty::Id::INT, + TyCheck::BinOp, + "subsctipt", + ); if let Some(ty) = self.tys.base_of(base_val.ty) { base_val.ty = ty; @@ -1179,12 +1191,6 @@ impl Codegen { let loc = loc.as_ref().offset(offset); let ctx = Ctx::default().with_loc(loc).with_ty(ty); let value = self.expr_ctx(field, ctx)?; - std::println!( - "{} {} {}", - self.ty_display(ty), - self.ty_display(value.ty), - self.ast_display(field) - ); self.ci.free_loc(value.loc); } } @@ -1290,7 +1296,6 @@ impl Codegen { } E::UnOp { op: T::Xor, val, .. } => { let val = self.ty(val); - let ptr = self.tys.make_ptr(val); Some(Value::ty(self.tys.make_ptr(val))) } E::UnOp { op: T::Band, val, pos } => { @@ -1384,7 +1389,13 @@ impl Codegen { // TODO: pass the arg as dest let varg = self.expr_ctx(arg, Ctx::default().with_ty(ty))?; - _ = self.assert_ty(arg.pos(), varg.ty, ty, format_args!("argument({i})")); + _ = self.assert_ty( + arg.pos(), + varg.ty, + ty, + TyCheck::Assign, + format_args!("argument({i})"), + ); self.pass_arg(&varg, &mut parama); self.pool.arg_locs.push(varg.loc); should_momize = false; @@ -1443,14 +1454,16 @@ impl Codegen { _ => Some(Loc::reg(self.ci.ret_reg.as_ref()).into_derefed()), }; let value = if let Some(val) = val { - self.expr_ctx(val, Ctx { ty: self.ci.ret, loc })? + self.expr_ctx(val, Ctx { ty: self.ci.ret, loc, ..Default::default() })? } else { Value::void() }; match self.ci.ret { None => self.ci.ret = Some(value.ty), - Some(ret) => _ = self.assert_ty(pos, value.ty, ret, "return type"), + Some(ret) => { + _ = self.assert_ty(pos, value.ty, ret, TyCheck::Assign, "return type") + } } self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4)); @@ -1613,7 +1626,13 @@ impl Codegen { if let ty::Kind::Struct(_) = left.ty.expand() { let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?; - _ = self.assert_ty(expr.pos(), right.ty, left.ty, "right struct operand"); + _ = self.assert_ty( + expr.pos(), + right.ty, + left.ty, + TyCheck::Assign, + "right struct operand", + ); return self.struct_op(op, left.ty, ctx, left.loc, right.loc); } @@ -1636,10 +1655,17 @@ impl Codegen { let lhs = self.loc_to_reg(left.loc, lsize); (lhs.as_ref(), lhs, Loc::default()) }; - let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?; + let right = self + .expr_ctx(right, Ctx::default().with_ty(left.ty).with_check(TyCheck::BinOp))?; let rsize = self.tys.size_of(right.ty); - let ty = self.assert_ty(expr.pos(), right.ty, left.ty, "right sclalar operand"); + let ty = self.assert_ty( + expr.pos(), + right.ty, + left.ty, + TyCheck::BinOp, + "right sclalar operand", + ); let size = self.tys.size_of(ty); let signed = ty.is_signed(); @@ -1733,7 +1759,7 @@ impl Codegen { }?; if let Some(ty) = ctx.ty { - _ = self.assert_ty(expr.pos(), value.ty, ty, "something"); + _ = self.assert_ty(expr.pos(), value.ty, ty, ctx.check, "something"); } Some(match ctx.loc { @@ -1870,7 +1896,7 @@ impl Codegen { s.ci.ret_reg = reg; }; - let ctx = Ctx { loc: None, ty: s.ci.ret }; + let ctx = Ctx { ty: s.ci.ret, ..Default::default() }; if s.expr_ctx(&Expr::Return { pos: 0, val: Some(expr) }, ctx).is_some() { s.report(expr.pos(), "we fucked up"); }; @@ -1956,7 +1982,7 @@ impl Codegen { }; if let Some(expected) = ctx.ty { - _ = self.assert_ty(pos, ty, expected, "struct"); + _ = self.assert_ty(pos, ty, expected, TyCheck::Assign, "struct"); } match ty.expand() { @@ -2704,8 +2730,15 @@ impl Codegen { #[must_use] #[track_caller] - fn assert_ty(&self, pos: Pos, ty: ty::Id, expected: ty::Id, hint: impl Display) -> ty::Id { - if let Some(res) = ty.try_upcast(expected) { + fn assert_ty( + &self, + pos: Pos, + ty: ty::Id, + expected: ty::Id, + kind: TyCheck, + hint: impl Display, + ) -> ty::Id { + if let Some(res) = ty.try_upcast(expected, kind) { res } else { let dty = self.ty_display(ty); @@ -2822,7 +2855,6 @@ mod tests { struct_return_from_module_function; //comptime_pointers; sort_something_viredly; - wired_mem_swap; hex_octal_binary_literals; //comptime_min_reg_leak; // structs_in_registers; diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index dcbb760..749690f 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -4,7 +4,7 @@ use { lexer::{self, Lexer, TokenKind}, parser::{self, CommentOr, CtorField, Expr, Poser, Radix, StructField}, }, - core::{fmt, usize}, + core::fmt, }; pub fn display_radix(radix: Radix, mut value: u64, buf: &mut [u8; 64]) -> &str { diff --git a/lang/src/lib.rs b/lang/src/lib.rs index c1620a3..220c686 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -249,7 +249,7 @@ mod ty { lexer::TokenKind, parser::{self, Pos}, }, - core::{fmt::Write, num::NonZeroU32, ops::Range}, + core::{default, num::NonZeroU32, ops::Range}, }; pub type ArrayLen = u32; @@ -355,7 +355,7 @@ mod ty { matches!(Kind::from_ty(self), Kind::Ptr(_)) } - pub fn try_upcast(self, ob: Self) -> Option { + pub fn try_upcast(self, ob: Self, kind: TyCheck) -> Option { let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0))); let (a, b) = (oa.strip_pointer(), ob.strip_pointer()); Some(match () { @@ -365,7 +365,7 @@ mod ty { _ if oa.is_pointer() && ob.is_pointer() => return None, _ if a.is_signed() && b.is_signed() || a.is_unsigned() && b.is_unsigned() => ob, _ if a.is_unsigned() && b.is_signed() && a.repr() - U8 < b.repr() - I8 => ob, - _ if oa.is_integer() && ob.is_pointer() => ob, + _ if oa.is_integer() && ob.is_pointer() && kind == TyCheck::BinOp => ob, _ => return None, }) } @@ -384,6 +384,13 @@ mod ty { } } + #[derive(PartialEq, Eq, Default, Debug)] + pub enum TyCheck { + BinOp, + #[default] + Assign, + } + impl From for Id { fn from(id: u64) -> Self { Self(unsafe { NonZeroU32::new_unchecked(id as _) }) diff --git a/lang/src/son.rs b/lang/src/son.rs index 7eb0bbb..a5c16a3 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -2140,7 +2140,7 @@ impl Codegen { preserve_expected: bool, hint: impl fmt::Display, ) -> ty::Id { - if let Some(res) = ty.try_upcast(expected) + if let Some(res) = ty.try_upcast(expected, ty::TyCheck::BinOp) && (!preserve_expected || res == expected) { res