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 { loop {
random_x := @inline(random.integer, 0, 1024) random_x := @inline(random.integer, 0, 1024)
random_y := random.integer(0, 768) random_y := random.integer(0, 768)
a := @inline(screenidx, random_x, random_y) a := @inline(screenidx, random_x)
break break
} }
return return
@ -725,3 +725,15 @@ integer := fn(min: int, max: int): int {
return rng 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(); generated.pop();
writeln!(generated, " => {{")?; writeln!(generated, " => {{")?;
if iter_args(ty).count() != 0 { 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!( writeln!(
generated, generated,
" buf.extend([{}]);", " buf.extend([{}]);",
@ -119,7 +119,7 @@ fn gen_instrs() -> Result<(), Box<dyn std::error::Error>> {
) )
)?; )?;
} else { } else {
writeln!(generated, " bytes.take(..std::mem::size_of::<{ty}>())?;")?; writeln!(generated, " crate::decode::<{ty}>(bytes)?;")?;
} }
writeln!(generated, " }}")?; writeln!(generated, " }}")?;

View file

@ -8,7 +8,7 @@ use {
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos}, parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
HashMap, HashMap,
}, },
std::{ops::Range, rc::Rc, u32}, std::{fmt::Display, ops::Range, rc::Rc},
}; };
type Offset = u32; type Offset = u32;
@ -1438,7 +1438,7 @@ impl Codegen {
let mut base_val = self.expr(base)?; let mut base_val = self.expr(base)?;
base_val.loc = self.make_loc_owned(base_val.loc, base_val.ty); base_val.loc = self.make_loc_owned(base_val.loc, base_val.ty);
let index_val = self.expr(index)?; 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() { if let ty::Kind::Ptr(ty) = base_val.ty.expand() {
base_val.ty = self.tys.ptrs[ty as usize].base; base_val.ty = self.tys.ptrs[ty as usize].base;
@ -1501,6 +1501,8 @@ impl Codegen {
let scope = self.ci.vars.len(); let scope = self.ci.vars.len();
let sig = self.compute_signature(&mut func, func_ast.pos(), args)?; 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() { if scope == self.ci.vars.len() {
for ((arg, ty), carg) in for ((arg, ty), carg) in
args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs) 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 values = Vec::with_capacity(args.len());
let mut sig_args = sig.args.range(); let mut sig_args = sig.args.range();
let mut should_momize = !args.is_empty() && sig.ret == ty::Id::from(ty::TYPE); 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 ty = self.tys.args[sig_args.next().unwrap()];
let sym = parser::find_symbol(&ast.symbols, carg.id); let sym = parser::find_symbol(&ast.symbols, carg.id);
if sym.flags & idfl::COMPTIME != 0 { if sym.flags & idfl::COMPTIME != 0 {
@ -1891,6 +1896,7 @@ impl Codegen {
// TODO: pass the arg as dest // TODO: pass the arg as dest
let varg = self.expr_ctx(arg, Ctx::default().with_ty(ty))?; 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); self.pass_arg(&varg, &mut parama);
values.push(varg.loc); values.push(varg.loc);
should_momize = false; should_momize = false;
@ -1966,7 +1972,7 @@ impl Codegen {
match self.ci.ret { match self.ci.ret {
None => self.ci.ret = Some(ty), 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)); self.ci.ret_relocs.push(Reloc::new(self.local_offset(), 1, 4));
@ -1979,8 +1985,21 @@ impl Codegen {
} }
Some(Value::void()) Some(Value::void())
} }
E::Number { value, .. } => Some(Value { E::Number { value, pos, .. } => Some(Value {
ty: ctx.ty.map(ty::Id::strip_pointer).unwrap_or(ty::INT.into()), 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), loc: Loc::ct(value as u64),
}), }),
E::If { cond, then, else_, .. } => { E::If { cond, then, else_, .. } => {
@ -2090,7 +2109,7 @@ impl Codegen {
if let ty::Kind::Struct(_) = left.ty.expand() { if let ty::Kind::Struct(_) = left.ty.expand() {
let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?; 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); 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 right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?;
let rsize = self.tys.size_of(right.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 size = self.tys.size_of(ty);
let signed = ty.is_signed(); let signed = ty.is_signed();
@ -2181,7 +2200,7 @@ impl Codegen {
}?; }?;
if let Some(ty) = ctx.ty { 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 { Some(match ctx.loc {
@ -3300,13 +3319,20 @@ impl Codegen {
#[must_use] #[must_use]
#[track_caller] #[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) { if let Some(res) = ty.try_upcast(expected) {
res res
} else { } else {
let ty = self.ty_display(ty); let ty = self.ty_display(ty);
let expected = self.ty_display(expected); 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; comptime_function_from_another_file => README;
inline => README; inline => README;
inline_test => README; inline_test => README;
some_generic_code => README;
} }
} }

View file

@ -21,7 +21,6 @@ use {
parser::Ast, parser::Ast,
std::{ std::{
collections::{hash_map, VecDeque}, collections::{hash_map, VecDeque},
default,
io::{self, Read}, io::{self, Read},
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Mutex, sync::Mutex,
@ -131,6 +130,11 @@ unsafe fn encode<T>(instr: T) -> (usize, [u8; instrs::MAX_SIZE]) {
(std::mem::size_of::<T>(), buf) (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)] #[cfg(test)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum DisasmItem { enum DisasmItem {

View file

@ -1220,6 +1220,16 @@ impl ExprRef {
// allocations // allocations
Some(unsafe { { self.0 }.as_ref() }) 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 {} 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