fixing the false return location
This commit is contained in:
parent
a7718e1220
commit
8892dd729a
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
|
|
177
lang/src/son.rs
177
lang/src/son.rs
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue