fixing the false return location

This commit is contained in:
Jakub Doka 2024-11-17 18:15:58 +01:00
parent a7718e1220
commit 8892dd729a
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
6 changed files with 135 additions and 91 deletions

View file

@ -75,7 +75,12 @@ impl Options {
}
}
pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std::io::Result<()> {
pub fn run_compiler(
root_file: &str,
options: Options,
out: &mut Vec<u8>,
warnings: &mut String,
) -> std::io::Result<()> {
let parsed = parse_from_fs(options.extra_threads, root_file)?;
if (options.fmt || options.fmt_stdout) && !parsed.errors.is_empty() {
@ -101,10 +106,11 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
let mut ctx = crate::son::CodegenCtx::default();
*ctx.parser.errors.get_mut() = parsed.errors;
let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
codegen.push_embeds(parsed.embeds);
codegen.generate(ty::Module::MAIN);
*warnings = core::mem::take(&mut *codegen.warnings.borrow_mut());
if !codegen.errors.borrow().is_empty() {
drop(codegen);
*out = ctx.parser.errors.into_inner().into_bytes();

View file

@ -2,23 +2,28 @@
fn main() {
use std::io::Write;
fn run(out: &mut Vec<u8>) -> std::io::Result<()> {
fn run(out: &mut Vec<u8>, warnings: &mut String) -> std::io::Result<()> {
let args = std::env::args().collect::<Vec<_>>();
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
let opts = hblang::Options::from_args(&args, out)?;
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
hblang::run_compiler(file, opts, out)
hblang::run_compiler(file, opts, out, warnings)
}
log::set_logger(&hblang::fs::Logger).unwrap();
log::set_max_level(log::LevelFilter::Error);
let mut out = Vec::new();
match run(&mut out) {
Ok(_) => std::io::stdout().write_all(&out).unwrap(),
let mut warnings = String::new();
match run(&mut out, &mut warnings) {
Ok(_) => {
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
std::io::stdout().write_all(&out).unwrap()
}
Err(_) => {
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
std::io::stderr().write_all(&out).unwrap();
std::process::exit(1);
}

View file

@ -79,6 +79,7 @@ struct ScopeIdent {
ident: Ident,
declared: bool,
ordered: bool,
used: bool,
flags: IdentFlags,
}
@ -261,6 +262,7 @@ impl<'a, 'b> Parser<'a, 'b> {
self.ctx.idents.push(ScopeIdent {
ident,
declared: false,
used: false,
ordered: false,
flags: 0,
});
@ -626,6 +628,8 @@ impl<'a, 'b> Parser<'a, 'b> {
if !&self.ctx.idents[i].declared {
self.ctx.idents.swap(i, undeclared_count);
undeclared_count += 1;
} else if !self.ctx.idents[i].used {
self.warn(self.ctx.idents[i].ident.pos(), "unused identifier");
}
}
@ -705,6 +709,19 @@ impl<'a, 'b> Parser<'a, 'b> {
}
}
#[track_caller]
fn warn(&mut self, pos: Pos, msg: impl fmt::Display) {
if log::log_enabled!(log::Level::Error) {
use core::fmt::Write;
writeln!(
self.ctx.warnings.get_mut(),
"(W) {}",
Report::new(self.lexer.source(), self.path, pos, msg)
)
.unwrap();
}
}
#[track_caller]
fn report(&mut self, pos: Pos, msg: impl fmt::Display) -> Option<!> {
if log::log_enabled!(log::Level::Error) {
@ -1148,6 +1165,7 @@ impl core::fmt::Display for Display<'_> {
#[derive(Default)]
pub struct Ctx {
pub errors: RefCell<String>,
pub warnings: RefCell<String>,
symbols: Vec<Symbol>,
stack: StackAlloc,
idents: Vec<ScopeIdent>,

View file

@ -89,7 +89,7 @@ impl crate::ctx_map::CtxEntry for Nid {
macro_rules! inference {
($ty:ident, $ctx:expr, $self:expr, $pos:expr, $subject:literal, $example:literal) => {
let Some($ty) = $ctx.ty else {
$self.report(
$self.error(
$pos,
concat!(
"resulting ",
@ -152,7 +152,7 @@ impl Nodes {
}
depth
}
Kind::Start | Kind::End | Kind::Die | Kind::Return => 1,
Kind::Start | Kind::End | Kind::Die | Kind::Return { .. } => 1,
u => unreachable!("{u:?}"),
});
@ -1010,7 +1010,7 @@ impl Nodes {
return Some(NEVER);
}
}
K::Return => {
K::Return { file } => {
if self[target].inputs[0] == NEVER {
return Some(NEVER);
}
@ -1065,7 +1065,7 @@ impl Nodes {
}
if new_inps.as_slice() != self[target].inputs.as_slice() {
return Some(self.new_node_nop(ty::Id::VOID, Kind::Return, new_inps));
return Some(self.new_node_nop(ty::Id::VOID, Kind::Return { file }, new_inps));
}
}
K::Phi => {
@ -1544,7 +1544,7 @@ impl Nodes {
Kind::End => return Ok(()),
Kind::If => write!(out, " if: "),
Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"),
Kind::Return => write!(out, " ret: "),
Kind::Return { .. } => write!(out, " ret: "),
Kind::Die => write!(out, " die: "),
Kind::CInt { value } => write!(out, "cint: #{value:<4}"),
Kind::Phi => write!(out, " phi: "),
@ -1642,7 +1642,7 @@ impl Nodes {
}
node = cfg_index;
}
Kind::Return | Kind::Die => {
Kind::Return { .. } | Kind::Die => {
node = self[node].outputs[0];
}
Kind::Then | Kind::Else | Kind::Entry => {
@ -1847,7 +1847,7 @@ impl Nodes {
fn is_data_dep(&self, val: Nid, user: Nid) -> bool {
match self[user].kind {
Kind::Return => self[user].inputs[1] == val,
Kind::Return { .. } => self[user].inputs[1] == val,
_ if self.is_cfg(user) && !matches!(self[user].kind, Kind::Call { .. } | Kind::If) => {
false
}
@ -1925,7 +1925,9 @@ pub enum Kind {
// [entry, back]
Loop,
// [ctrl, ?value]
Return,
Return {
file: ty::Module,
},
// [ctrl]
Die,
// [ctrl]
@ -1986,7 +1988,7 @@ impl Kind {
self,
Self::Start
| Self::End
| Self::Return
| Self::Return { .. }
| Self::Die
| Self::Entry
| Self::Then
@ -1999,7 +2001,7 @@ impl Kind {
}
fn ends_basic_block(&self) -> bool {
matches!(self, Self::Return | Self::If | Self::End | Self::Die)
matches!(self, Self::Return { .. } | Self::If | Self::End | Self::Die)
}
fn starts_basic_block(&self) -> bool {
@ -2443,6 +2445,7 @@ impl CodegenCtx {
pub struct Codegen<'a> {
pub files: &'a [parser::Ast],
pub errors: &'a RefCell<String>,
pub warnings: &'a RefCell<String>,
tys: &'a mut Types,
ci: ItemCtx,
pool: &'a mut Pool,
@ -2455,7 +2458,7 @@ impl Drop for Codegen<'_> {
fn drop(&mut self) {
if debug::panicking() {
if let Some(&pos) = self.ci.pos.last() {
self.report(pos, "panic occured here");
self.error(pos, "panic occured here");
}
if !self.errors.borrow().is_empty() {
@ -2474,6 +2477,7 @@ impl<'a> Codegen<'a> {
Self {
files,
errors: &ctx.parser.errors,
warnings: &ctx.parser.warnings,
tys: &mut ctx.tys,
ci: Default::default(),
pool: &mut ctx.pool,
@ -2519,8 +2523,10 @@ impl<'a> Codegen<'a> {
}
fn emit_and_eval(&mut self, file: Module, ret: ty::Id, ret_loc: &mut [u8]) -> u64 {
let mut rets =
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
let mut rets = self.ci.nodes[NEVER]
.inputs
.iter()
.filter(|&&i| matches!(self.ci.nodes[i].kind, Kind::Return { .. }));
if let Some(&ret) = rets.next()
&& rets.next().is_none()
&& let Kind::CInt { value } = self.ci.nodes[self.ci.nodes[ret].inputs[1]].kind
@ -2672,7 +2678,7 @@ impl<'a> Codegen<'a> {
inference!(oty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
let Some(ty) = self.tys.inner_of(oty) else {
self.report(
self.error(
pos,
fa!(
"'null' expression was inferred to be '{}',
@ -2739,7 +2745,7 @@ impl<'a> Codegen<'a> {
let literal = &literal[1..literal.len() - 1];
let report = |bytes: &core::str::Bytes, message: &str| {
self.report(pos + (literal.len() - bytes.len()) as u32 - 1, message)
self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message)
};
let mut data = Vec::<u8>::with_capacity(literal.len());
@ -2786,7 +2792,11 @@ impl<'a> Codegen<'a> {
}
}
let ret = self.ci.nodes.new_node_nop(ty::Id::VOID, Kind::Return, inps);
let ret = self.ci.nodes.new_node_nop(
ty::Id::VOID,
Kind::Return { file: self.ci.file },
inps,
);
self.ci.ctrl.set(NEVER, &mut self.ci.nodes);
self.ci.nodes[ret].pos = pos;
self.ci.nodes.bind(ret, NEVER);
@ -2887,7 +2897,7 @@ impl<'a> Codegen<'a> {
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
self.report(
self.error(
pos,
fa!(
"the '{}' does not have this field, \
@ -2901,7 +2911,7 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
}
_ => {
self.report(
self.error(
pos,
fa!(
"the '{}' is not a struct, or pointer to one, or enum, \
@ -2937,7 +2947,7 @@ impl<'a> Codegen<'a> {
self.implicit_unwrap(val.pos(), &mut vl);
let Some(base) = self.tys.base_of(vl.ty) else {
self.report(
self.error(
pos,
fa!("the '{}' can not be dereferneced", self.ty_display(vl.ty)),
);
@ -2951,7 +2961,7 @@ impl<'a> Codegen<'a> {
inference!(ty, ctx, self, pos, "enum type", "<EnumTy>.Variant");
let ty::Kind::Enum(e) = ty.expand() else {
self.report(
self.error(
pos,
fa!("expected inferred type to be enum but got '{}'", self.ty_display(ty)),
);
@ -2980,7 +2990,7 @@ impl<'a> Codegen<'a> {
self.tys,
))
} else {
self.report(pos, fa!("cant negate '{}'", self.ty_display(val.ty)));
self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty)));
Value::NEVER
}
}
@ -2995,7 +3005,7 @@ impl<'a> Codegen<'a> {
self.tys,
))
} else {
self.report(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)));
self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)));
Value::NEVER
}
}
@ -3034,13 +3044,13 @@ impl<'a> Codegen<'a> {
} else if dest.ptr {
self.store_mem(dest.id, dest.ty, value.id);
} else {
self.report(pos, "cannot assign to this expression");
self.error(pos, "cannot assign to this expression");
}
Some(Value::VOID)
}
Expr::BinOp { left: &Expr::Null { pos }, .. } => {
self.report(pos, "'null' must always be no the right side of an expression");
self.error(pos, "'null' must always be no the right side of an expression");
Value::NEVER
}
Expr::BinOp {
@ -3053,7 +3063,7 @@ impl<'a> Codegen<'a> {
self.strip_var(&mut cmped);
let Some(ty) = self.tys.inner_of(cmped.ty) else {
self.report(
self.error(
left.pos(),
fa!("'{}' is never null, remove this check", self.ty_display(cmped.ty)),
);
@ -3135,7 +3145,7 @@ impl<'a> Codegen<'a> {
.or(Value::NEVER)
}
_ => {
self.report(
self.error(
pos,
fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty)),
);
@ -3153,7 +3163,7 @@ impl<'a> Codegen<'a> {
}
let ty::Kind::Slice(s) = bs.ty.expand() else {
self.report(
self.error(
base.pos(),
fa!(
"cant index into '{}' which is not array nor slice",
@ -3209,7 +3219,7 @@ impl<'a> Codegen<'a> {
let (got, expected) = (self.tys.size_of(val.ty), self.tys.size_of(ty));
if got != expected {
self.report(
self.error(
pos,
fa!(
"cast from '{}' to '{}' is not supported, \
@ -3239,7 +3249,7 @@ impl<'a> Codegen<'a> {
self.strip_var(&mut val);
if !val.ty.is_optional() {
self.report(
self.error(
expr.pos(),
fa!(
"only optional types can be unwrapped ('{}' is not optional)",
@ -3256,7 +3266,7 @@ impl<'a> Codegen<'a> {
let mut val = self.expr(expr)?;
if !val.ty.is_integer() {
self.report(
self.error(
expr.pos(),
fa!(
"only integers can be truncated ('{}' is not an integer)",
@ -3269,7 +3279,7 @@ impl<'a> Codegen<'a> {
inference!(ty, ctx, self, pos, "integer", "@as(<ty>, @intcast(<expr>))");
if !ty.is_integer() {
self.report(
self.error(
expr.pos(),
fa!(
"intcast is inferred to output '{}', which is not an integer",
@ -3289,7 +3299,7 @@ impl<'a> Codegen<'a> {
let val = self.expr(expr)?;
if !val.ty.is_float() {
self.report(
self.error(
expr.pos(),
fa!(
"only floats can be truncated ('{}' is not a float)",
@ -3302,7 +3312,7 @@ impl<'a> Codegen<'a> {
inference!(ty, ctx, self, pos, "float", "@as(<floaty>, @floatcast(<expr>))");
if !ty.is_float() {
self.report(
self.error(
expr.pos(),
fa!(
"floatcast is inferred to output '{}', which is not a float",
@ -3328,7 +3338,7 @@ impl<'a> Codegen<'a> {
let ret_ty = match val.ty {
ty::Id::F32 | ty::Id::F64 => ty::Id::INT,
_ => {
self.report(
self.error(
expr.pos(),
fa!("expected float ('{}' is not a float)", self.ty_display(val.ty)),
);
@ -3368,7 +3378,7 @@ impl<'a> Codegen<'a> {
&& ity.try_upcast(ty) == Some(ty)
&& val.ty == ity
{
self.report(pos, "the type is known at this point, remove the hint");
self.error(pos, "the type is known at this point, remove the hint");
}
self.strip_var(&mut val);
self.assert_ty(expr.pos(), &mut val, ty, "hinted expr");
@ -3432,7 +3442,7 @@ impl<'a> Codegen<'a> {
let mut offs = OffsetIter::new(s, self.tys);
for field in fields {
let Some((ty, offset)) = offs.next_ty(self.tys) else {
self.report(
self.error(
field.pos(),
"this init argumen overflows the field count",
);
@ -3453,7 +3463,7 @@ impl<'a> Codegen<'a> {
.collect::<String>();
if !field_list.is_empty() {
self.report(
self.error(
pos,
fa!("the struct initializer is missing {field_list} \
(append them to the end of the constructor)"),
@ -3471,7 +3481,7 @@ impl<'a> Codegen<'a> {
.map_or_else(|| self.tys.make_array(elem, len as ArrayLen), |_| sty);
if len != fields.len() {
self.report(
self.error(
pos,
fa!(
"expected '{}' but constructor has {} elements",
@ -3497,7 +3507,7 @@ impl<'a> Codegen<'a> {
}
_ => {
let inferred = if ty.is_some() { "" } else { "inferred " };
self.report(
self.error(
pos,
fa!(
"the {inferred}type of the constructor is `{}`, \
@ -3521,7 +3531,7 @@ impl<'a> Codegen<'a> {
let ty::Kind::Struct(s) = sty.expand() else {
let inferred = if ty.is_some() { "" } else { "inferred " };
self.report(
self.error(
pos,
fa!(
"the {inferred}type of the constructor is `{}`, \
@ -3540,7 +3550,7 @@ impl<'a> Codegen<'a> {
let mem = self.new_stack(pos, sty);
for field in fields {
let Some(index) = self.tys.find_struct_field(s, field.name) else {
self.report(
self.error(
field.pos,
fa!("struct '{}' does not have this field", self.ty_display(sty)),
);
@ -3551,8 +3561,8 @@ impl<'a> Codegen<'a> {
mem::replace(&mut offs[index], (ty::Id::UNDECLARED, field.pos));
if ty == ty::Id::UNDECLARED {
self.report(field.pos, "the struct field is already initialized");
self.report(offset, "previous initialization is here");
self.error(field.pos, "the struct field is already initialized");
self.error(offset, "previous initialization is here");
continue;
}
@ -3573,7 +3583,7 @@ impl<'a> Codegen<'a> {
.collect::<String>();
if !field_list.is_empty() {
self.report(pos, fa!("the struct initializer is missing {field_list}"));
self.error(pos, fa!("the struct initializer is missing {field_list}"));
}
Some(Value::ptr(mem).ty(sty))
@ -3587,7 +3597,7 @@ impl<'a> Codegen<'a> {
ret = ret.and(self.expr(stmt));
if let Some(mut id) = ret {
if id.ty != ty::Id::VOID {
self.report(
self.error(
stmt.pos(),
fa!(
"statements need to evaluate to 'void', \
@ -3890,7 +3900,7 @@ impl<'a> Codegen<'a> {
let value = self.expr(value)?;
let ty::Kind::Enum(e) = value.ty.expand() else {
self.report(
self.error(
pos,
fa!(
"match operates on enums (for now), '{}' is not an enum",
@ -3906,8 +3916,8 @@ impl<'a> Codegen<'a> {
for &MatchBranch { pat, pos: bp, body } in branches {
if let Expr::Wildcard { .. } = pat {
if let Some(prev) = else_branch {
self.report(bp, "duplicate branch");
self.report(prev.pos(), "...first branch declared here");
self.error(bp, "duplicate branch");
self.error(prev.pos(), "...first branch declared here");
}
else_branch = Some(body);
@ -3916,8 +3926,8 @@ impl<'a> Codegen<'a> {
let pat_val = self.eval_const(self.ci.file, &pat, value.ty);
if covered_values[pat_val as usize] != Pos::MAX {
self.report(bp, "duplicate branch");
self.report(
self.error(bp, "duplicate branch");
self.error(
covered_values[pat_val as usize],
"...first branch declared here",
);
@ -3966,10 +3976,7 @@ impl<'a> Codegen<'a> {
.collect::<String>();
if !missing_branches.is_empty() {
self.report(
pos,
fa!("not all cases covered, missing '{missing_branches}'"),
);
self.error(pos, fa!("not all cases covered, missing '{missing_branches}'"));
}
self.ci.ctrl.get()
};
@ -3989,7 +3996,7 @@ impl<'a> Codegen<'a> {
Some(Value::VOID)
}
ref e => {
self.report_unhandled_ast(e, "bruh");
self.error_unhandled_ast(e, "bruh");
Value::NEVER
}
}
@ -4035,7 +4042,7 @@ impl<'a> Codegen<'a> {
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
self.report(
self.error(
pos,
fa!(
"the '{}' does not have this variant, \
@ -4070,7 +4077,7 @@ impl<'a> Codegen<'a> {
fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> {
let ty = self.ty(func);
let ty::Kind::Func(mut fu) = ty.expand() else {
self.report(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
return Value::NEVER;
};
@ -4083,7 +4090,7 @@ impl<'a> Codegen<'a> {
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
if args.len() != cargs.len() {
self.report(
self.error(
func.pos(),
fa!(
"expected {} function argumenr{}, got {}",
@ -4095,7 +4102,7 @@ impl<'a> Codegen<'a> {
}
if inline && is_inline {
self.report(
self.error(
func.pos(),
"function is declared as inline so this @inline directive only reduces readability",
);
@ -4133,7 +4140,7 @@ impl<'a> Codegen<'a> {
if sig.ret == ty::Id::VOID {
self.expr(&Expr::Return { pos: body.pos(), val: None });
} else {
self.report(
self.error(
body.pos(),
"expected all paths in the fucntion to return \
or the return type to be 'void'",
@ -4160,7 +4167,7 @@ impl<'a> Codegen<'a> {
&& (!self.ci.nodes[ctrl.get()].kind.is_eca()
|| self.ci.nodes[ctrl.get()].inputs[0] != prev_ctrl)
{
self.report(body.pos(), "function is makred inline but it contains controlflow");
self.error(body.pos(), "function is makred inline but it contains controlflow");
}
scope.vars.drain(var_base..).for_each(|v| v.remove(&mut self.ci.nodes));
@ -4301,13 +4308,13 @@ impl<'a> Codegen<'a> {
}
ty::Kind::Struct(is) => {
if !self.struct_op(pos, op, is, dst, lhs, rhs) {
self.report(
self.error(
pos,
fa!("... when appliing '{0} {op} {0}'", self.ty_display(s.into())),
);
}
}
_ => self.report(pos, fa!("'{0} {op} {0}' is not supported", self.ty_display(ty))),
_ => self.error(pos, fa!("'{0} {op} {0}' is not supported", self.ty_display(ty))),
}
}
@ -4344,7 +4351,7 @@ impl<'a> Codegen<'a> {
ty::Kind::Struct(is) => match self.struct_fold_op(pos, op, fold_op, is, lhs, rhs) {
Some(v) => v.id,
None => {
self.report(
self.error(
pos,
fa!("...when appliing '{0} {op} {0}'", self.ty_display(s.into())),
);
@ -4352,7 +4359,7 @@ impl<'a> Codegen<'a> {
}
},
_ => {
self.report(pos, fa!("'{0} {op} {0}' is not supported", self.ty_display(ty)));
self.error(pos, fa!("'{0} {op} {0}' is not supported", self.ty_display(ty)));
return None;
}
};
@ -4398,7 +4405,7 @@ impl<'a> Codegen<'a> {
ty::Id::UNDECLARED
} else {
if ty != ty::Id::TYPE {
self.report(
self.error(
arg.pos(),
fa!(
"arbitrary comptime types are not supported yet \
@ -4424,7 +4431,7 @@ impl<'a> Codegen<'a> {
}
let Some(args) = self.tys.pack_args(arg_base) else {
self.report(pos, "function instance has too many arguments");
self.error(pos, "function instance has too many arguments");
return None;
};
let ret = self.ty_in(file, ret);
@ -4463,20 +4470,20 @@ impl<'a> Codegen<'a> {
}
Expr::Ctor { pos, fields, .. } => {
let ty::Kind::Struct(idx) = right.ty.expand() else {
self.report(pos, "can't use struct destruct on non struct value (TODO: shold work with modules)");
self.error(pos, "can't use struct destruct on non struct value (TODO: shold work with modules)");
return;
};
for &CtorField { pos, name, ref value } in fields {
let Some((offset, ty)) = OffsetIter::offset_of(self.tys, idx, name) else {
self.report(pos, format_args!("field not found: {name:?}"));
self.error(pos, format_args!("field not found: {name:?}"));
continue;
};
let off = self.offset(right.id, offset);
self.assign_pattern(value, Value::ptr(off).ty(ty));
}
}
ref pat => self.report_unhandled_ast(pat, "pattern"),
ref pat => self.error_unhandled_ast(pat, "pattern"),
}
}
@ -4521,7 +4528,7 @@ impl<'a> Codegen<'a> {
fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Value> {
let Some(mut loob) = self.ci.loops.last_mut() else {
self.report(pos, "break outside a loop");
self.error(pos, "break outside a loop");
return None;
};
@ -4639,7 +4646,7 @@ impl<'a> Codegen<'a> {
if sig.ret == ty::Id::VOID {
self.expr(&Expr::Return { pos: body.pos(), val: None });
} else {
self.report(
self.error(
body.pos(),
fa!(
"expected all paths in the fucntion to return \
@ -4693,23 +4700,25 @@ impl<'a> Codegen<'a> {
}
_ => unreachable!(),
};
self.report(pos, msg);
self.error(pos, msg);
}
for &node in self.ci.nodes[NEVER].inputs.iter() {
if self.ci.nodes[node].kind == Kind::Return
if let Kind::Return { file } = self.ci.nodes[node].kind
&& self.ci.nodes[self.ci.nodes.aclass_index(self.ci.nodes[node].inputs[1]).1].kind
== Kind::Stck
{
self.report(
let pfile = mem::replace(&mut self.ci.file, file);
self.error(
self.ci.nodes[node].pos,
"returning value with local provenance \
(pointer will be invalid after function returns)",
);
self.report(
self.error(
self.ci.nodes[self.ci.nodes.aclass_index(self.ci.nodes[node].inputs[1]).1].pos,
"...the pointer points to stack allocation created here",
);
self.ci.file = pfile;
}
}
@ -4783,7 +4792,7 @@ impl<'a> Codegen<'a> {
} else {
let ty = self.ty_display(lhs.ty);
let expected = self.ty_display(rhs.ty);
self.report(pos, fa!("'{ty} {op} {expected}' is not supported"));
self.error(pos, fa!("'{ty} {op} {expected}' is not supported"));
(ty::Id::NEVER, VOID)
}
}
@ -4945,7 +4954,7 @@ impl<'a> Codegen<'a> {
let ty = self.ty_display(src.ty);
let expected = self.ty_display(expected);
self.report(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
self.error(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
false
}
}
@ -4958,16 +4967,22 @@ impl<'a> Codegen<'a> {
value.ty = to;
}
//#[track_caller]
//fn warn(&self, pos: Pos, msg: impl core::fmt::Display) {
// let mut buf = self.warnings.borrow_mut();
// write!(buf, "{}", self.file().report(pos, msg)).unwrap();
//}
#[track_caller]
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
fn error(&self, pos: Pos, msg: impl core::fmt::Display) {
let mut buf = self.errors.borrow_mut();
write!(buf, "{}", self.file().report(pos, msg)).unwrap();
}
#[track_caller]
fn report_unhandled_ast(&self, ast: &Expr, hint: impl Display) {
fn error_unhandled_ast(&self, ast: &Expr, hint: impl Display) {
log::info!("{ast:#?}");
self.report(ast.pos(), fa!("compiler does not (yet) know how to handle ({hint})"));
self.error(ast.pos(), fa!("compiler does not (yet) know how to handle ({hint})"));
}
fn file(&self) -> &'a parser::Ast {

View file

@ -238,7 +238,7 @@ impl Backend for HbvmBackend {
debug_assert_matches!(
nodes[stck].kind,
Kind::Phi
| Kind::Return
| Kind::Return { .. }
| Kind::Load
| Kind::Call { .. }
| Kind::Stre
@ -524,7 +524,7 @@ impl HbvmBackend {
self.emit(instrs::jmp(0));
}
}
Kind::Return => {
Kind::Return { .. } => {
match retl {
Some(PLoc::Reg(r, size)) if sig.ret.loc(tys) == Loc::Stack => {
self.emit(instrs::ld(r, allocs[0], 0, size))

View file

@ -183,7 +183,7 @@ impl HbvmBackend {
}
is_next_block = res.backrefs[nid as usize] as usize == i + 1;
}
Kind::Return => {
Kind::Return { .. } => {
let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
match retl {
Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => {
@ -423,7 +423,7 @@ impl<'a> Function<'a> {
self.emit_node(o);
}
}
Kind::Return | Kind::Die => {
Kind::Return { .. } | Kind::Die => {
self.close_block(nid);
self.emit_node(node.outputs[0]);
}