adding more type checking

This commit is contained in:
mlokr 2024-09-04 16:54:34 +02:00
parent 00ad474881
commit 894f73ca35
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
7 changed files with 702 additions and 448 deletions

View file

@ -695,7 +695,7 @@ example := fn(): void {
loop {
random_x := @inline(random.integer, 0, 1024)
random_y := random.integer(0, 768)
a := @inline(screenidx, random_x, random_y)
a := @inline(screenidx, random_x)
break
}
return
@ -725,3 +725,15 @@ integer := fn(min: int, max: int): int {
return rng
}
```
#### some_generic_code
```hb
some_func := fn($Elem: type): void {
return
}
main := fn(): void {
some_func(0)
return
}
```

View file

@ -110,7 +110,7 @@ fn gen_instrs() -> Result<(), Box<dyn std::error::Error>> {
generated.pop();
writeln!(generated, " => {{")?;
if iter_args(ty).count() != 0 {
writeln!(generated, " let data = unsafe {{ std::ptr::read(bytes.take(..std::mem::size_of::<{ty}>())?.as_ptr() as *const {ty}) }};")?;
writeln!(generated, " let data = crate::decode::<{ty}>(bytes)?;")?;
writeln!(
generated,
" buf.extend([{}]);",
@ -119,7 +119,7 @@ fn gen_instrs() -> Result<(), Box<dyn std::error::Error>> {
)
)?;
} else {
writeln!(generated, " bytes.take(..std::mem::size_of::<{ty}>())?;")?;
writeln!(generated, " crate::decode::<{ty}>(bytes)?;")?;
}
writeln!(generated, " }}")?;

View file

@ -8,7 +8,7 @@ use {
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
HashMap,
},
std::{ops::Range, rc::Rc, u32},
std::{fmt::Display, ops::Range, rc::Rc},
};
type Offset = u32;
@ -1438,7 +1438,7 @@ impl Codegen {
let mut base_val = self.expr(base)?;
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::INT.into());
_ = self.assert_ty(index.pos(), index_val.ty, ty::INT.into(), "subsctipt");
if let ty::Kind::Ptr(ty) = base_val.ty.expand() {
base_val.ty = self.tys.ptrs[ty as usize].base;
@ -1501,6 +1501,8 @@ impl Codegen {
let scope = self.ci.vars.len();
let sig = self.compute_signature(&mut func, func_ast.pos(), args)?;
self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "inline function call");
if scope == self.ci.vars.len() {
for ((arg, ty), carg) in
args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs)
@ -1881,7 +1883,10 @@ impl Codegen {
let mut values = Vec::with_capacity(args.len());
let mut sig_args = sig.args.range();
let mut should_momize = !args.is_empty() && sig.ret == ty::Id::from(ty::TYPE);
for (arg, carg) in args.iter().zip(cargs) {
self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "function call");
for (i, (arg, carg)) in args.iter().zip(cargs).enumerate() {
let ty = self.tys.args[sig_args.next().unwrap()];
let sym = parser::find_symbol(&ast.symbols, carg.id);
if sym.flags & idfl::COMPTIME != 0 {
@ -1891,6 +1896,7 @@ 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.pass_arg(&varg, &mut parama);
values.push(varg.loc);
should_momize = false;
@ -1966,7 +1972,7 @@ impl Codegen {
match self.ci.ret {
None => self.ci.ret = Some(ty),
Some(ret) => _ = self.assert_ty(pos, ty, ret),
Some(ret) => _ = self.assert_ty(pos, ty, ret, "return type"),
}
self.ci.ret_relocs.push(Reloc::new(self.local_offset(), 1, 4));
@ -1979,8 +1985,21 @@ impl Codegen {
}
Some(Value::void())
}
E::Number { value, .. } => Some(Value {
ty: ctx.ty.map(ty::Id::strip_pointer).unwrap_or(ty::INT.into()),
E::Number { value, pos, .. } => Some(Value {
ty: {
let ty = ctx.ty.map(ty::Id::strip_pointer).unwrap_or(ty::INT.into());
if !ty.is_integer() && !ty.is_pointer() {
self.report(
pos,
format_args!(
"this integer was inferred to be '{}' \
which does not make sense",
self.ty_display(ty)
),
);
}
ty
},
loc: Loc::ct(value as u64),
}),
E::If { cond, then, else_, .. } => {
@ -2090,7 +2109,7 @@ 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(), left.ty, right.ty);
_ = self.assert_ty(expr.pos(), right.ty, left.ty, "right struct operand");
return self.struct_op(op, left.ty, ctx, left.loc, right.loc);
}
@ -2100,7 +2119,7 @@ impl Codegen {
let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?;
let rsize = self.tys.size_of(right.ty);
let ty = self.assert_ty(expr.pos(), left.ty, right.ty);
let ty = self.assert_ty(expr.pos(), right.ty, left.ty, "right sclalar operand");
let size = self.tys.size_of(ty);
let signed = ty.is_signed();
@ -2181,7 +2200,7 @@ impl Codegen {
}?;
if let Some(ty) = ctx.ty {
_ = self.assert_ty(expr.pos(), value.ty, ty);
_ = self.assert_ty(expr.pos(), value.ty, ty, "a thing");
}
Some(match ctx.loc {
@ -3300,13 +3319,20 @@ impl Codegen {
#[must_use]
#[track_caller]
fn assert_ty(&self, pos: Pos, ty: ty::Id, expected: ty::Id) -> ty::Id {
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) {
res
} else {
let ty = self.ty_display(ty);
let expected = self.ty_display(expected);
self.report(pos, format_args!("expected {expected}, got {ty}"));
self.report(pos, format_args!("expected {hint} of type {expected}, got {ty}"));
}
}
fn assert_arg_count(&self, pos: Pos, got: usize, expected: usize, hint: impl Display) {
if got != expected {
let s = if expected != 1 { "s" } else { "" };
self.report(pos, format_args!("{hint} expected {expected} argument{s}, got {got}"))
}
}
@ -3523,5 +3549,6 @@ mod tests {
comptime_function_from_another_file => README;
inline => README;
inline_test => README;
some_generic_code => README;
}
}

View file

@ -21,7 +21,6 @@ use {
parser::Ast,
std::{
collections::{hash_map, VecDeque},
default,
io::{self, Read},
path::{Path, PathBuf},
sync::Mutex,
@ -131,6 +130,11 @@ unsafe fn encode<T>(instr: T) -> (usize, [u8; instrs::MAX_SIZE]) {
(std::mem::size_of::<T>(), buf)
}
#[inline]
fn decode<T>(binary: &mut &[u8]) -> Option<T> {
unsafe { Some(std::ptr::read(binary.take(..std::mem::size_of::<T>())?.as_ptr() as *const T)) }
}
#[cfg(test)]
#[derive(Clone, Copy)]
enum DisasmItem {

View file

@ -1220,6 +1220,16 @@ impl ExprRef {
// allocations
Some(unsafe { { self.0 }.as_ref() })
}
pub fn dangling() -> Self {
Self(NonNull::dangling())
}
}
impl Default for ExprRef {
fn default() -> Self {
Self::dangling()
}
}
unsafe impl Send for Ast {}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
0: Start
2: Tuple { index: 0 }
7: return [2] 0
1: End
Start.1