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)?;
|
let parsed = parse_from_fs(options.extra_threads, root_file)?;
|
||||||
|
|
||||||
if (options.fmt || options.fmt_stdout) && !parsed.errors.is_empty() {
|
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();
|
let mut ctx = crate::son::CodegenCtx::default();
|
||||||
*ctx.parser.errors.get_mut() = parsed.errors;
|
*ctx.parser.errors.get_mut() = parsed.errors;
|
||||||
let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
|
let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
|
||||||
|
|
||||||
codegen.push_embeds(parsed.embeds);
|
codegen.push_embeds(parsed.embeds);
|
||||||
codegen.generate(ty::Module::MAIN);
|
codegen.generate(ty::Module::MAIN);
|
||||||
|
|
||||||
|
*warnings = core::mem::take(&mut *codegen.warnings.borrow_mut());
|
||||||
|
|
||||||
if !codegen.errors.borrow().is_empty() {
|
if !codegen.errors.borrow().is_empty() {
|
||||||
drop(codegen);
|
drop(codegen);
|
||||||
*out = ctx.parser.errors.into_inner().into_bytes();
|
*out = ctx.parser.errors.into_inner().into_bytes();
|
||||||
|
|
|
@ -2,23 +2,28 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
use std::io::Write;
|
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 = std::env::args().collect::<Vec<_>>();
|
||||||
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
||||||
|
|
||||||
let opts = hblang::Options::from_args(&args, out)?;
|
let opts = hblang::Options::from_args(&args, out)?;
|
||||||
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
|
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_logger(&hblang::fs::Logger).unwrap();
|
||||||
log::set_max_level(log::LevelFilter::Error);
|
log::set_max_level(log::LevelFilter::Error);
|
||||||
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
match run(&mut out) {
|
let mut warnings = String::new();
|
||||||
Ok(_) => std::io::stdout().write_all(&out).unwrap(),
|
match run(&mut out, &mut warnings) {
|
||||||
|
Ok(_) => {
|
||||||
|
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
|
||||||
|
std::io::stdout().write_all(&out).unwrap()
|
||||||
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
|
||||||
std::io::stderr().write_all(&out).unwrap();
|
std::io::stderr().write_all(&out).unwrap();
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ struct ScopeIdent {
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
declared: bool,
|
declared: bool,
|
||||||
ordered: bool,
|
ordered: bool,
|
||||||
|
used: bool,
|
||||||
flags: IdentFlags,
|
flags: IdentFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,6 +262,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
self.ctx.idents.push(ScopeIdent {
|
self.ctx.idents.push(ScopeIdent {
|
||||||
ident,
|
ident,
|
||||||
declared: false,
|
declared: false,
|
||||||
|
used: false,
|
||||||
ordered: false,
|
ordered: false,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
});
|
});
|
||||||
|
@ -626,6 +628,8 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
if !&self.ctx.idents[i].declared {
|
if !&self.ctx.idents[i].declared {
|
||||||
self.ctx.idents.swap(i, undeclared_count);
|
self.ctx.idents.swap(i, undeclared_count);
|
||||||
undeclared_count += 1;
|
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]
|
#[track_caller]
|
||||||
fn report(&mut self, pos: Pos, msg: impl fmt::Display) -> Option<!> {
|
fn report(&mut self, pos: Pos, msg: impl fmt::Display) -> Option<!> {
|
||||||
if log::log_enabled!(log::Level::Error) {
|
if log::log_enabled!(log::Level::Error) {
|
||||||
|
@ -1148,6 +1165,7 @@ impl core::fmt::Display for Display<'_> {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Ctx {
|
pub struct Ctx {
|
||||||
pub errors: RefCell<String>,
|
pub errors: RefCell<String>,
|
||||||
|
pub warnings: RefCell<String>,
|
||||||
symbols: Vec<Symbol>,
|
symbols: Vec<Symbol>,
|
||||||
stack: StackAlloc,
|
stack: StackAlloc,
|
||||||
idents: Vec<ScopeIdent>,
|
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 {
|
macro_rules! inference {
|
||||||
($ty:ident, $ctx:expr, $self:expr, $pos:expr, $subject:literal, $example:literal) => {
|
($ty:ident, $ctx:expr, $self:expr, $pos:expr, $subject:literal, $example:literal) => {
|
||||||
let Some($ty) = $ctx.ty else {
|
let Some($ty) = $ctx.ty else {
|
||||||
$self.report(
|
$self.error(
|
||||||
$pos,
|
$pos,
|
||||||
concat!(
|
concat!(
|
||||||
"resulting ",
|
"resulting ",
|
||||||
|
@ -152,7 +152,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
depth
|
depth
|
||||||
}
|
}
|
||||||
Kind::Start | Kind::End | Kind::Die | Kind::Return => 1,
|
Kind::Start | Kind::End | Kind::Die | Kind::Return { .. } => 1,
|
||||||
u => unreachable!("{u:?}"),
|
u => unreachable!("{u:?}"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1010,7 +1010,7 @@ impl Nodes {
|
||||||
return Some(NEVER);
|
return Some(NEVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
K::Return => {
|
K::Return { file } => {
|
||||||
if self[target].inputs[0] == NEVER {
|
if self[target].inputs[0] == NEVER {
|
||||||
return Some(NEVER);
|
return Some(NEVER);
|
||||||
}
|
}
|
||||||
|
@ -1065,7 +1065,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_inps.as_slice() != self[target].inputs.as_slice() {
|
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 => {
|
K::Phi => {
|
||||||
|
@ -1544,7 +1544,7 @@ impl Nodes {
|
||||||
Kind::End => return Ok(()),
|
Kind::End => return Ok(()),
|
||||||
Kind::If => write!(out, " if: "),
|
Kind::If => write!(out, " if: "),
|
||||||
Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"),
|
Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"),
|
||||||
Kind::Return => write!(out, " ret: "),
|
Kind::Return { .. } => write!(out, " ret: "),
|
||||||
Kind::Die => write!(out, " die: "),
|
Kind::Die => write!(out, " die: "),
|
||||||
Kind::CInt { value } => write!(out, "cint: #{value:<4}"),
|
Kind::CInt { value } => write!(out, "cint: #{value:<4}"),
|
||||||
Kind::Phi => write!(out, " phi: "),
|
Kind::Phi => write!(out, " phi: "),
|
||||||
|
@ -1642,7 +1642,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
node = cfg_index;
|
node = cfg_index;
|
||||||
}
|
}
|
||||||
Kind::Return | Kind::Die => {
|
Kind::Return { .. } | Kind::Die => {
|
||||||
node = self[node].outputs[0];
|
node = self[node].outputs[0];
|
||||||
}
|
}
|
||||||
Kind::Then | Kind::Else | Kind::Entry => {
|
Kind::Then | Kind::Else | Kind::Entry => {
|
||||||
|
@ -1847,7 +1847,7 @@ impl Nodes {
|
||||||
|
|
||||||
fn is_data_dep(&self, val: Nid, user: Nid) -> bool {
|
fn is_data_dep(&self, val: Nid, user: Nid) -> bool {
|
||||||
match self[user].kind {
|
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) => {
|
_ if self.is_cfg(user) && !matches!(self[user].kind, Kind::Call { .. } | Kind::If) => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -1925,7 +1925,9 @@ pub enum Kind {
|
||||||
// [entry, back]
|
// [entry, back]
|
||||||
Loop,
|
Loop,
|
||||||
// [ctrl, ?value]
|
// [ctrl, ?value]
|
||||||
Return,
|
Return {
|
||||||
|
file: ty::Module,
|
||||||
|
},
|
||||||
// [ctrl]
|
// [ctrl]
|
||||||
Die,
|
Die,
|
||||||
// [ctrl]
|
// [ctrl]
|
||||||
|
@ -1986,7 +1988,7 @@ impl Kind {
|
||||||
self,
|
self,
|
||||||
Self::Start
|
Self::Start
|
||||||
| Self::End
|
| Self::End
|
||||||
| Self::Return
|
| Self::Return { .. }
|
||||||
| Self::Die
|
| Self::Die
|
||||||
| Self::Entry
|
| Self::Entry
|
||||||
| Self::Then
|
| Self::Then
|
||||||
|
@ -1999,7 +2001,7 @@ impl Kind {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ends_basic_block(&self) -> bool {
|
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 {
|
fn starts_basic_block(&self) -> bool {
|
||||||
|
@ -2443,6 +2445,7 @@ impl CodegenCtx {
|
||||||
pub struct Codegen<'a> {
|
pub struct Codegen<'a> {
|
||||||
pub files: &'a [parser::Ast],
|
pub files: &'a [parser::Ast],
|
||||||
pub errors: &'a RefCell<String>,
|
pub errors: &'a RefCell<String>,
|
||||||
|
pub warnings: &'a RefCell<String>,
|
||||||
tys: &'a mut Types,
|
tys: &'a mut Types,
|
||||||
ci: ItemCtx,
|
ci: ItemCtx,
|
||||||
pool: &'a mut Pool,
|
pool: &'a mut Pool,
|
||||||
|
@ -2455,7 +2458,7 @@ impl Drop for Codegen<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if debug::panicking() {
|
if debug::panicking() {
|
||||||
if let Some(&pos) = self.ci.pos.last() {
|
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() {
|
if !self.errors.borrow().is_empty() {
|
||||||
|
@ -2474,6 +2477,7 @@ impl<'a> Codegen<'a> {
|
||||||
Self {
|
Self {
|
||||||
files,
|
files,
|
||||||
errors: &ctx.parser.errors,
|
errors: &ctx.parser.errors,
|
||||||
|
warnings: &ctx.parser.warnings,
|
||||||
tys: &mut ctx.tys,
|
tys: &mut ctx.tys,
|
||||||
ci: Default::default(),
|
ci: Default::default(),
|
||||||
pool: &mut ctx.pool,
|
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 {
|
fn emit_and_eval(&mut self, file: Module, ret: ty::Id, ret_loc: &mut [u8]) -> u64 {
|
||||||
let mut rets =
|
let mut rets = self.ci.nodes[NEVER]
|
||||||
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.filter(|&&i| matches!(self.ci.nodes[i].kind, Kind::Return { .. }));
|
||||||
if let Some(&ret) = rets.next()
|
if let Some(&ret) = rets.next()
|
||||||
&& rets.next().is_none()
|
&& rets.next().is_none()
|
||||||
&& let Kind::CInt { value } = self.ci.nodes[self.ci.nodes[ret].inputs[1]].kind
|
&& 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)");
|
inference!(oty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
|
||||||
|
|
||||||
let Some(ty) = self.tys.inner_of(oty) else {
|
let Some(ty) = self.tys.inner_of(oty) else {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"'null' expression was inferred to be '{}',
|
"'null' expression was inferred to be '{}',
|
||||||
|
@ -2739,7 +2745,7 @@ impl<'a> Codegen<'a> {
|
||||||
let literal = &literal[1..literal.len() - 1];
|
let literal = &literal[1..literal.len() - 1];
|
||||||
|
|
||||||
let report = |bytes: &core::str::Bytes, message: &str| {
|
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());
|
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.ctrl.set(NEVER, &mut self.ci.nodes);
|
||||||
self.ci.nodes[ret].pos = pos;
|
self.ci.nodes[ret].pos = pos;
|
||||||
self.ci.nodes.bind(ret, NEVER);
|
self.ci.nodes.bind(ret, NEVER);
|
||||||
|
@ -2887,7 +2897,7 @@ impl<'a> Codegen<'a> {
|
||||||
.map(|f| self.tys.names.ident_str(f.name))
|
.map(|f| self.tys.names.ident_str(f.name))
|
||||||
.intersperse("', '")
|
.intersperse("', '")
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"the '{}' does not have this field, \
|
"the '{}' does not have this field, \
|
||||||
|
@ -2901,7 +2911,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
|
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"the '{}' is not a struct, or pointer to one, or enum, \
|
"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);
|
self.implicit_unwrap(val.pos(), &mut vl);
|
||||||
|
|
||||||
let Some(base) = self.tys.base_of(vl.ty) else {
|
let Some(base) = self.tys.base_of(vl.ty) else {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!("the '{}' can not be dereferneced", self.ty_display(vl.ty)),
|
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");
|
inference!(ty, ctx, self, pos, "enum type", "<EnumTy>.Variant");
|
||||||
|
|
||||||
let ty::Kind::Enum(e) = ty.expand() else {
|
let ty::Kind::Enum(e) = ty.expand() else {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!("expected inferred type to be enum but got '{}'", self.ty_display(ty)),
|
fa!("expected inferred type to be enum but got '{}'", self.ty_display(ty)),
|
||||||
);
|
);
|
||||||
|
@ -2980,7 +2990,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.tys,
|
self.tys,
|
||||||
))
|
))
|
||||||
} else {
|
} 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
|
Value::NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2995,7 +3005,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.tys,
|
self.tys,
|
||||||
))
|
))
|
||||||
} else {
|
} 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
|
Value::NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3034,13 +3044,13 @@ impl<'a> Codegen<'a> {
|
||||||
} else if dest.ptr {
|
} else if dest.ptr {
|
||||||
self.store_mem(dest.id, dest.ty, value.id);
|
self.store_mem(dest.id, dest.ty, value.id);
|
||||||
} else {
|
} else {
|
||||||
self.report(pos, "cannot assign to this expression");
|
self.error(pos, "cannot assign to this expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
Expr::BinOp { left: &Expr::Null { pos }, .. } => {
|
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
|
Value::NEVER
|
||||||
}
|
}
|
||||||
Expr::BinOp {
|
Expr::BinOp {
|
||||||
|
@ -3053,7 +3063,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.strip_var(&mut cmped);
|
self.strip_var(&mut cmped);
|
||||||
|
|
||||||
let Some(ty) = self.tys.inner_of(cmped.ty) else {
|
let Some(ty) = self.tys.inner_of(cmped.ty) else {
|
||||||
self.report(
|
self.error(
|
||||||
left.pos(),
|
left.pos(),
|
||||||
fa!("'{}' is never null, remove this check", self.ty_display(cmped.ty)),
|
fa!("'{}' is never null, remove this check", self.ty_display(cmped.ty)),
|
||||||
);
|
);
|
||||||
|
@ -3135,7 +3145,7 @@ impl<'a> Codegen<'a> {
|
||||||
.or(Value::NEVER)
|
.or(Value::NEVER)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty)),
|
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 {
|
let ty::Kind::Slice(s) = bs.ty.expand() else {
|
||||||
self.report(
|
self.error(
|
||||||
base.pos(),
|
base.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"cant index into '{}' which is not array nor slice",
|
"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));
|
let (got, expected) = (self.tys.size_of(val.ty), self.tys.size_of(ty));
|
||||||
if got != expected {
|
if got != expected {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"cast from '{}' to '{}' is not supported, \
|
"cast from '{}' to '{}' is not supported, \
|
||||||
|
@ -3239,7 +3249,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.strip_var(&mut val);
|
self.strip_var(&mut val);
|
||||||
|
|
||||||
if !val.ty.is_optional() {
|
if !val.ty.is_optional() {
|
||||||
self.report(
|
self.error(
|
||||||
expr.pos(),
|
expr.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"only optional types can be unwrapped ('{}' is not optional)",
|
"only optional types can be unwrapped ('{}' is not optional)",
|
||||||
|
@ -3256,7 +3266,7 @@ impl<'a> Codegen<'a> {
|
||||||
let mut val = self.expr(expr)?;
|
let mut val = self.expr(expr)?;
|
||||||
|
|
||||||
if !val.ty.is_integer() {
|
if !val.ty.is_integer() {
|
||||||
self.report(
|
self.error(
|
||||||
expr.pos(),
|
expr.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"only integers can be truncated ('{}' is not an integer)",
|
"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>))");
|
inference!(ty, ctx, self, pos, "integer", "@as(<ty>, @intcast(<expr>))");
|
||||||
|
|
||||||
if !ty.is_integer() {
|
if !ty.is_integer() {
|
||||||
self.report(
|
self.error(
|
||||||
expr.pos(),
|
expr.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"intcast is inferred to output '{}', which is not an integer",
|
"intcast is inferred to output '{}', which is not an integer",
|
||||||
|
@ -3289,7 +3299,7 @@ impl<'a> Codegen<'a> {
|
||||||
let val = self.expr(expr)?;
|
let val = self.expr(expr)?;
|
||||||
|
|
||||||
if !val.ty.is_float() {
|
if !val.ty.is_float() {
|
||||||
self.report(
|
self.error(
|
||||||
expr.pos(),
|
expr.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"only floats can be truncated ('{}' is not a float)",
|
"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>))");
|
inference!(ty, ctx, self, pos, "float", "@as(<floaty>, @floatcast(<expr>))");
|
||||||
|
|
||||||
if !ty.is_float() {
|
if !ty.is_float() {
|
||||||
self.report(
|
self.error(
|
||||||
expr.pos(),
|
expr.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"floatcast is inferred to output '{}', which is not a float",
|
"floatcast is inferred to output '{}', which is not a float",
|
||||||
|
@ -3328,7 +3338,7 @@ impl<'a> Codegen<'a> {
|
||||||
let ret_ty = match val.ty {
|
let ret_ty = match val.ty {
|
||||||
ty::Id::F32 | ty::Id::F64 => ty::Id::INT,
|
ty::Id::F32 | ty::Id::F64 => ty::Id::INT,
|
||||||
_ => {
|
_ => {
|
||||||
self.report(
|
self.error(
|
||||||
expr.pos(),
|
expr.pos(),
|
||||||
fa!("expected float ('{}' is not a float)", self.ty_display(val.ty)),
|
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)
|
&& ity.try_upcast(ty) == Some(ty)
|
||||||
&& val.ty == ity
|
&& 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.strip_var(&mut val);
|
||||||
self.assert_ty(expr.pos(), &mut val, ty, "hinted expr");
|
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);
|
let mut offs = OffsetIter::new(s, self.tys);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let Some((ty, offset)) = offs.next_ty(self.tys) else {
|
let Some((ty, offset)) = offs.next_ty(self.tys) else {
|
||||||
self.report(
|
self.error(
|
||||||
field.pos(),
|
field.pos(),
|
||||||
"this init argumen overflows the field count",
|
"this init argumen overflows the field count",
|
||||||
);
|
);
|
||||||
|
@ -3453,7 +3463,7 @@ impl<'a> Codegen<'a> {
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
if !field_list.is_empty() {
|
if !field_list.is_empty() {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!("the struct initializer is missing {field_list} \
|
fa!("the struct initializer is missing {field_list} \
|
||||||
(append them to the end of the constructor)"),
|
(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);
|
.map_or_else(|| self.tys.make_array(elem, len as ArrayLen), |_| sty);
|
||||||
|
|
||||||
if len != fields.len() {
|
if len != fields.len() {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"expected '{}' but constructor has {} elements",
|
"expected '{}' but constructor has {} elements",
|
||||||
|
@ -3497,7 +3507,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let inferred = if ty.is_some() { "" } else { "inferred " };
|
let inferred = if ty.is_some() { "" } else { "inferred " };
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"the {inferred}type of the constructor is `{}`, \
|
"the {inferred}type of the constructor is `{}`, \
|
||||||
|
@ -3521,7 +3531,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let ty::Kind::Struct(s) = sty.expand() else {
|
let ty::Kind::Struct(s) = sty.expand() else {
|
||||||
let inferred = if ty.is_some() { "" } else { "inferred " };
|
let inferred = if ty.is_some() { "" } else { "inferred " };
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"the {inferred}type of the constructor is `{}`, \
|
"the {inferred}type of the constructor is `{}`, \
|
||||||
|
@ -3540,7 +3550,7 @@ impl<'a> Codegen<'a> {
|
||||||
let mem = self.new_stack(pos, sty);
|
let mem = self.new_stack(pos, sty);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let Some(index) = self.tys.find_struct_field(s, field.name) else {
|
let Some(index) = self.tys.find_struct_field(s, field.name) else {
|
||||||
self.report(
|
self.error(
|
||||||
field.pos,
|
field.pos,
|
||||||
fa!("struct '{}' does not have this field", self.ty_display(sty)),
|
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));
|
mem::replace(&mut offs[index], (ty::Id::UNDECLARED, field.pos));
|
||||||
|
|
||||||
if ty == ty::Id::UNDECLARED {
|
if ty == ty::Id::UNDECLARED {
|
||||||
self.report(field.pos, "the struct field is already initialized");
|
self.error(field.pos, "the struct field is already initialized");
|
||||||
self.report(offset, "previous initialization is here");
|
self.error(offset, "previous initialization is here");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3573,7 +3583,7 @@ impl<'a> Codegen<'a> {
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
if !field_list.is_empty() {
|
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))
|
Some(Value::ptr(mem).ty(sty))
|
||||||
|
@ -3587,7 +3597,7 @@ impl<'a> Codegen<'a> {
|
||||||
ret = ret.and(self.expr(stmt));
|
ret = ret.and(self.expr(stmt));
|
||||||
if let Some(mut id) = ret {
|
if let Some(mut id) = ret {
|
||||||
if id.ty != ty::Id::VOID {
|
if id.ty != ty::Id::VOID {
|
||||||
self.report(
|
self.error(
|
||||||
stmt.pos(),
|
stmt.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"statements need to evaluate to 'void', \
|
"statements need to evaluate to 'void', \
|
||||||
|
@ -3890,7 +3900,7 @@ impl<'a> Codegen<'a> {
|
||||||
let value = self.expr(value)?;
|
let value = self.expr(value)?;
|
||||||
|
|
||||||
let ty::Kind::Enum(e) = value.ty.expand() else {
|
let ty::Kind::Enum(e) = value.ty.expand() else {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"match operates on enums (for now), '{}' is not an enum",
|
"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 {
|
for &MatchBranch { pat, pos: bp, body } in branches {
|
||||||
if let Expr::Wildcard { .. } = pat {
|
if let Expr::Wildcard { .. } = pat {
|
||||||
if let Some(prev) = else_branch {
|
if let Some(prev) = else_branch {
|
||||||
self.report(bp, "duplicate branch");
|
self.error(bp, "duplicate branch");
|
||||||
self.report(prev.pos(), "...first branch declared here");
|
self.error(prev.pos(), "...first branch declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
else_branch = Some(body);
|
else_branch = Some(body);
|
||||||
|
@ -3916,8 +3926,8 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let pat_val = self.eval_const(self.ci.file, &pat, value.ty);
|
let pat_val = self.eval_const(self.ci.file, &pat, value.ty);
|
||||||
if covered_values[pat_val as usize] != Pos::MAX {
|
if covered_values[pat_val as usize] != Pos::MAX {
|
||||||
self.report(bp, "duplicate branch");
|
self.error(bp, "duplicate branch");
|
||||||
self.report(
|
self.error(
|
||||||
covered_values[pat_val as usize],
|
covered_values[pat_val as usize],
|
||||||
"...first branch declared here",
|
"...first branch declared here",
|
||||||
);
|
);
|
||||||
|
@ -3966,10 +3976,7 @@ impl<'a> Codegen<'a> {
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
if !missing_branches.is_empty() {
|
if !missing_branches.is_empty() {
|
||||||
self.report(
|
self.error(pos, fa!("not all cases covered, missing '{missing_branches}'"));
|
||||||
pos,
|
|
||||||
fa!("not all cases covered, missing '{missing_branches}'"),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
self.ci.ctrl.get()
|
self.ci.ctrl.get()
|
||||||
};
|
};
|
||||||
|
@ -3989,7 +3996,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
ref e => {
|
ref e => {
|
||||||
self.report_unhandled_ast(e, "bruh");
|
self.error_unhandled_ast(e, "bruh");
|
||||||
Value::NEVER
|
Value::NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4035,7 +4042,7 @@ impl<'a> Codegen<'a> {
|
||||||
.map(|f| self.tys.names.ident_str(f.name))
|
.map(|f| self.tys.names.ident_str(f.name))
|
||||||
.intersperse("', '")
|
.intersperse("', '")
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"the '{}' does not have this variant, \
|
"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> {
|
fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> {
|
||||||
let ty = self.ty(func);
|
let ty = self.ty(func);
|
||||||
let ty::Kind::Func(mut fu) = ty.expand() else {
|
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;
|
return Value::NEVER;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4083,7 +4090,7 @@ impl<'a> Codegen<'a> {
|
||||||
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
|
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
|
||||||
|
|
||||||
if args.len() != cargs.len() {
|
if args.len() != cargs.len() {
|
||||||
self.report(
|
self.error(
|
||||||
func.pos(),
|
func.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"expected {} function argumenr{}, got {}",
|
"expected {} function argumenr{}, got {}",
|
||||||
|
@ -4095,7 +4102,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if inline && is_inline {
|
if inline && is_inline {
|
||||||
self.report(
|
self.error(
|
||||||
func.pos(),
|
func.pos(),
|
||||||
"function is declared as inline so this @inline directive only reduces readability",
|
"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 {
|
if sig.ret == ty::Id::VOID {
|
||||||
self.expr(&Expr::Return { pos: body.pos(), val: None });
|
self.expr(&Expr::Return { pos: body.pos(), val: None });
|
||||||
} else {
|
} else {
|
||||||
self.report(
|
self.error(
|
||||||
body.pos(),
|
body.pos(),
|
||||||
"expected all paths in the fucntion to return \
|
"expected all paths in the fucntion to return \
|
||||||
or the return type to be 'void'",
|
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()].kind.is_eca()
|
||||||
|| self.ci.nodes[ctrl.get()].inputs[0] != prev_ctrl)
|
|| 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));
|
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) => {
|
ty::Kind::Struct(is) => {
|
||||||
if !self.struct_op(pos, op, is, dst, lhs, rhs) {
|
if !self.struct_op(pos, op, is, dst, lhs, rhs) {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!("... when appliing '{0} {op} {0}'", self.ty_display(s.into())),
|
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) {
|
ty::Kind::Struct(is) => match self.struct_fold_op(pos, op, fold_op, is, lhs, rhs) {
|
||||||
Some(v) => v.id,
|
Some(v) => v.id,
|
||||||
None => {
|
None => {
|
||||||
self.report(
|
self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!("...when appliing '{0} {op} {0}'", self.ty_display(s.into())),
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4398,7 +4405,7 @@ impl<'a> Codegen<'a> {
|
||||||
ty::Id::UNDECLARED
|
ty::Id::UNDECLARED
|
||||||
} else {
|
} else {
|
||||||
if ty != ty::Id::TYPE {
|
if ty != ty::Id::TYPE {
|
||||||
self.report(
|
self.error(
|
||||||
arg.pos(),
|
arg.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"arbitrary comptime types are not supported yet \
|
"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 {
|
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;
|
return None;
|
||||||
};
|
};
|
||||||
let ret = self.ty_in(file, ret);
|
let ret = self.ty_in(file, ret);
|
||||||
|
@ -4463,20 +4470,20 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
Expr::Ctor { pos, fields, .. } => {
|
Expr::Ctor { pos, fields, .. } => {
|
||||||
let ty::Kind::Struct(idx) = right.ty.expand() else {
|
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;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
for &CtorField { pos, name, ref value } in fields {
|
for &CtorField { pos, name, ref value } in fields {
|
||||||
let Some((offset, ty)) = OffsetIter::offset_of(self.tys, idx, name) else {
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
let off = self.offset(right.id, offset);
|
let off = self.offset(right.id, offset);
|
||||||
self.assign_pattern(value, Value::ptr(off).ty(ty));
|
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> {
|
fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Value> {
|
||||||
let Some(mut loob) = self.ci.loops.last_mut() else {
|
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;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4639,7 +4646,7 @@ impl<'a> Codegen<'a> {
|
||||||
if sig.ret == ty::Id::VOID {
|
if sig.ret == ty::Id::VOID {
|
||||||
self.expr(&Expr::Return { pos: body.pos(), val: None });
|
self.expr(&Expr::Return { pos: body.pos(), val: None });
|
||||||
} else {
|
} else {
|
||||||
self.report(
|
self.error(
|
||||||
body.pos(),
|
body.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"expected all paths in the fucntion to return \
|
"expected all paths in the fucntion to return \
|
||||||
|
@ -4693,23 +4700,25 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.report(pos, msg);
|
self.error(pos, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
for &node in self.ci.nodes[NEVER].inputs.iter() {
|
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
|
&& self.ci.nodes[self.ci.nodes.aclass_index(self.ci.nodes[node].inputs[1]).1].kind
|
||||||
== Kind::Stck
|
== Kind::Stck
|
||||||
{
|
{
|
||||||
self.report(
|
let pfile = mem::replace(&mut self.ci.file, file);
|
||||||
|
self.error(
|
||||||
self.ci.nodes[node].pos,
|
self.ci.nodes[node].pos,
|
||||||
"returning value with local provenance \
|
"returning value with local provenance \
|
||||||
(pointer will be invalid after function returns)",
|
(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,
|
self.ci.nodes[self.ci.nodes.aclass_index(self.ci.nodes[node].inputs[1]).1].pos,
|
||||||
"...the pointer points to stack allocation created here",
|
"...the pointer points to stack allocation created here",
|
||||||
);
|
);
|
||||||
|
self.ci.file = pfile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4783,7 +4792,7 @@ impl<'a> Codegen<'a> {
|
||||||
} else {
|
} else {
|
||||||
let ty = self.ty_display(lhs.ty);
|
let ty = self.ty_display(lhs.ty);
|
||||||
let expected = self.ty_display(rhs.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)
|
(ty::Id::NEVER, VOID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4945,7 +4954,7 @@ impl<'a> Codegen<'a> {
|
||||||
let ty = self.ty_display(src.ty);
|
let ty = self.ty_display(src.ty);
|
||||||
|
|
||||||
let expected = self.ty_display(expected);
|
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
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4958,16 +4967,22 @@ impl<'a> Codegen<'a> {
|
||||||
value.ty = to;
|
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]
|
#[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();
|
let mut buf = self.errors.borrow_mut();
|
||||||
write!(buf, "{}", self.file().report(pos, msg)).unwrap();
|
write!(buf, "{}", self.file().report(pos, msg)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[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:#?}");
|
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 {
|
fn file(&self) -> &'a parser::Ast {
|
||||||
|
|
|
@ -238,7 +238,7 @@ impl Backend for HbvmBackend {
|
||||||
debug_assert_matches!(
|
debug_assert_matches!(
|
||||||
nodes[stck].kind,
|
nodes[stck].kind,
|
||||||
Kind::Phi
|
Kind::Phi
|
||||||
| Kind::Return
|
| Kind::Return { .. }
|
||||||
| Kind::Load
|
| Kind::Load
|
||||||
| Kind::Call { .. }
|
| Kind::Call { .. }
|
||||||
| Kind::Stre
|
| Kind::Stre
|
||||||
|
@ -524,7 +524,7 @@ impl HbvmBackend {
|
||||||
self.emit(instrs::jmp(0));
|
self.emit(instrs::jmp(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Return => {
|
Kind::Return { .. } => {
|
||||||
match retl {
|
match retl {
|
||||||
Some(PLoc::Reg(r, size)) if sig.ret.loc(tys) == Loc::Stack => {
|
Some(PLoc::Reg(r, size)) if sig.ret.loc(tys) == Loc::Stack => {
|
||||||
self.emit(instrs::ld(r, allocs[0], 0, size))
|
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;
|
is_next_block = res.backrefs[nid as usize] as usize == i + 1;
|
||||||
}
|
}
|
||||||
Kind::Return => {
|
Kind::Return { .. } => {
|
||||||
let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
|
let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
|
||||||
match retl {
|
match retl {
|
||||||
Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => {
|
Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => {
|
||||||
|
@ -423,7 +423,7 @@ impl<'a> Function<'a> {
|
||||||
self.emit_node(o);
|
self.emit_node(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Return | Kind::Die => {
|
Kind::Return { .. } | Kind::Die => {
|
||||||
self.close_block(nid);
|
self.close_block(nid);
|
||||||
self.emit_node(node.outputs[0]);
|
self.emit_node(node.outputs[0]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue