Removing repetative code, adding ent slice to properly index modules

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-01 19:04:27 +01:00
parent 9ce446b507
commit c553c3d9e9
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
8 changed files with 285 additions and 243 deletions

15
foo.hb Normal file
View file

@ -0,0 +1,15 @@
Res := fn($O: type, $E: type): type return union(enum) {
ok: O,
err: E,
}
main := fn(): uint {
r := do_something()
if r == .err return v.err
return v.ok
}
do_something := fn(): Res(uint, uint) {
return .{ok: 0}
}

View file

@ -5,7 +5,7 @@ use {
parser, parser,
son::{Kind, Nid, Node, Nodes, MEM, VOID}, son::{Kind, Nid, Node, Nodes, MEM, VOID},
ty::{self, Arg, Loc, Module, Offset, Sig, Size, Types}, ty::{self, Arg, Loc, Module, Offset, Sig, Size, Types},
utils::{Ent, EntVec}, utils::{EntSlice, EntVec},
}, },
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec}, alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
core::{assert_matches::debug_assert_matches, mem, ops::Range}, core::{assert_matches::debug_assert_matches, mem, ops::Range},
@ -213,7 +213,7 @@ impl Backend for HbvmBackend {
mut sluce: &[u8], mut sluce: &[u8],
eca_handler: &mut dyn FnMut(&mut &[u8]), eca_handler: &mut dyn FnMut(&mut &[u8]),
types: &'a Types, types: &'a Types,
files: &'a [parser::Ast], files: &'a EntSlice<Module, parser::Ast>,
output: &mut String, output: &mut String,
) -> Result<(), hbbytecode::DisasmError<'a>> { ) -> Result<(), hbbytecode::DisasmError<'a>> {
use hbbytecode::DisasmItem; use hbbytecode::DisasmItem;
@ -225,7 +225,7 @@ impl Backend for HbvmBackend {
.filter(|(_, f)| f.offset != u32::MAX) .filter(|(_, f)| f.offset != u32::MAX)
.map(|(f, fd)| { .map(|(f, fd)| {
let name = if f.file != Module::default() { let name = if f.file != Module::default() {
let file = &files[f.file.index()]; let file = &files[f.file];
file.ident_str(f.name) file.ident_str(f.name)
} else { } else {
"target_fn" "target_fn"
@ -243,7 +243,7 @@ impl Backend for HbvmBackend {
let name = if g.file == Module::default() { let name = if g.file == Module::default() {
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8") core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
} else { } else {
let file = &files[g.file.index()]; let file = &files[g.file];
file.ident_str(g.name) file.ident_str(g.name)
}; };
(gd.offset, (name, g.data.len() as Size, DisasmItem::Global)) (gd.offset, (name, g.data.len() as Size, DisasmItem::Global))
@ -253,14 +253,26 @@ impl Backend for HbvmBackend {
hbbytecode::disasm(&mut sluce, &functions, output, eca_handler) hbbytecode::disasm(&mut sluce, &functions, output, eca_handler)
} }
fn emit_ct_body(&mut self, id: ty::Func, nodes: &Nodes, tys: &Types, files: &[parser::Ast]) { fn emit_ct_body(
&mut self,
id: ty::Func,
nodes: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
self.emit_body(id, nodes, tys, files); self.emit_body(id, nodes, tys, files);
let fd = &mut self.funcs[id]; let fd = &mut self.funcs[id];
fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0); fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0);
emit(&mut fd.code, instrs::tx()); emit(&mut fd.code, instrs::tx());
} }
fn emit_body(&mut self, id: ty::Func, nodes: &Nodes, tys: &Types, files: &[parser::Ast]) { fn emit_body(
&mut self,
id: ty::Func,
nodes: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
let sig = tys.ins.funcs[id].sig.unwrap(); let sig = tys.ins.funcs[id].sig.unwrap();
debug_assert!(self.code.is_empty()); debug_assert!(self.code.is_empty());
@ -432,11 +444,18 @@ struct InstrCtx<'a> {
allocs: &'a [u8], allocs: &'a [u8],
nodes: &'a Nodes, nodes: &'a Nodes,
tys: &'a Types, tys: &'a Types,
files: &'a [parser::Ast], files: &'a EntSlice<Module, parser::Ast>,
} }
impl HbvmBackend { impl HbvmBackend {
fn extend(&mut self, base: ty::Id, dest: ty::Id, reg: Reg, tys: &Types, files: &[parser::Ast]) { fn extend(
&mut self,
base: ty::Id,
dest: ty::Id,
reg: Reg,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
if reg == 0 { if reg == 0 {
return; return;
} }

View file

@ -6,8 +6,8 @@ use {
}, },
parser, quad_sort, parser, quad_sort,
son::{Kind, ARG_START, MEM, VOID}, son::{Kind, ARG_START, MEM, VOID},
ty::{self, Arg, Loc, Sig, Types}, ty::{self, Arg, Loc, Module, Sig, Types},
utils::BitSet, utils::{BitSet, EntSlice},
}, },
alloc::{borrow::ToOwned, vec::Vec}, alloc::{borrow::ToOwned, vec::Vec},
core::{assert_matches::debug_assert_matches, mem, ops::Range}, core::{assert_matches::debug_assert_matches, mem, ops::Range},
@ -20,7 +20,7 @@ impl HbvmBackend {
nodes: &Nodes, nodes: &Nodes,
sig: Sig, sig: Sig,
tys: &Types, tys: &Types,
files: &[parser::Ast], files: &EntSlice<Module, parser::Ast>,
) -> (usize, bool) { ) -> (usize, bool) {
let tail = Function::build(nodes, tys, &mut self.ralloc, sig); let tail = Function::build(nodes, tys, &mut self.ralloc, sig);

View file

@ -69,7 +69,8 @@ pub mod backend {
crate::{ crate::{
parser, parser,
son::Nodes, son::Nodes,
ty::{self, Types}, ty::{self, Module, Types},
utils::EntSlice,
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
}; };
@ -94,12 +95,24 @@ pub mod backend {
sluce: &[u8], sluce: &[u8],
eca_handler: &mut dyn FnMut(&mut &[u8]), eca_handler: &mut dyn FnMut(&mut &[u8]),
types: &'a Types, types: &'a Types,
files: &'a [parser::Ast], files: &'a EntSlice<Module, parser::Ast>,
output: &mut String, output: &mut String,
) -> Result<(), hbbytecode::DisasmError<'a>>; ) -> Result<(), hbbytecode::DisasmError<'a>>;
fn emit_body(&mut self, id: ty::Func, ci: &Nodes, tys: &Types, files: &[parser::Ast]); fn emit_body(
&mut self,
id: ty::Func,
ci: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
);
fn emit_ct_body(&mut self, id: ty::Func, ci: &Nodes, tys: &Types, files: &[parser::Ast]) { fn emit_ct_body(
&mut self,
id: ty::Func,
ci: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
self.emit_body(id, ci, tys, files); self.emit_body(id, ci, tys, files);
} }

View file

@ -1079,9 +1079,11 @@ generate_expr! {
} }
impl Expr<'_> { impl Expr<'_> {
pub fn declares(&self, iden: Result<Ident, &str>, source: &str) -> Option<Ident> { pub fn declares(&self, iden: DeclId, source: &str) -> Option<Ident> {
match *self { match *self {
Self::Ident { id, .. } if iden == Ok(id) || iden == Err(&source[id.range()]) => { Self::Ident { id, .. }
if iden == DeclId::Ident(id) || iden == DeclId::Name(&source[id.range()]) =>
{
Some(id) Some(id)
} }
Self::Ctor { fields, .. } => fields.iter().find_map(|f| f.value.declares(iden, source)), Self::Ctor { fields, .. } => fields.iter().find_map(|f| f.value.declares(iden, source)),
@ -1389,7 +1391,7 @@ impl Ast {
unsafe { self.0.as_ref() } unsafe { self.0.as_ref() }
} }
pub fn find_decl(&self, id: Result<Ident, &str>) -> Option<(&Expr, Ident)> { pub fn find_decl(&self, id: DeclId) -> Option<(&Expr, Ident)> {
find_decl(self.exprs(), &self.file, id) find_decl(self.exprs(), &self.file, id)
} }
@ -1401,7 +1403,7 @@ impl Ast {
pub fn find_decl<'a>( pub fn find_decl<'a>(
exprs: &'a [Expr<'a>], exprs: &'a [Expr<'a>],
file: &str, file: &str,
id: Result<Ident, &str>, id: DeclId,
) -> Option<(&'a Expr<'a>, Ident)> { ) -> Option<(&'a Expr<'a>, Ident)> {
exprs.iter().find_map(|expr| match expr { exprs.iter().find_map(|expr| match expr {
Expr::BinOp { left, op: TokenKind::Decl, .. } => { Expr::BinOp { left, op: TokenKind::Decl, .. } => {
@ -1411,6 +1413,24 @@ pub fn find_decl<'a>(
}) })
} }
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DeclId<'a> {
Ident(Ident),
Name(&'a str),
}
impl From<Ident> for DeclId<'_> {
fn from(value: Ident) -> Self {
Self::Ident(value)
}
}
impl<'a> From<&'a str> for DeclId<'a> {
fn from(value: &'a str) -> Self {
Self::Name(value)
}
}
impl Default for Ast { impl Default for Ast {
fn default() -> Self { fn default() -> Self {
Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader)) Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader))

View file

@ -11,14 +11,14 @@ use {
parser::{ parser::{
self, self,
idfl::{self}, idfl::{self},
CommentOr, CtorField, Expr, ExprRef, FieldList, MatchBranch, Pos, CommentOr, CtorField, DeclId, Expr, ExprRef, FieldList, MatchBranch, Pos,
}, },
ty::{ ty::{
self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData, self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData,
GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData, GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData,
StructField, SymKey, Tuple, TypeBase, TypeIns, Types, UnionData, StructField, SymKey, Tuple, TypeBase, TypeIns, Types, UnionData,
}, },
utils::{BitSet, Ent, Vc}, utils::{BitSet, EntSlice, Vc},
Ident, Ident,
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
@ -2506,7 +2506,12 @@ impl ItemCtx {
self.scope.aclasses.push(AClass::new(&mut self.nodes)); // GLOBAL self.scope.aclasses.push(AClass::new(&mut self.nodes)); // GLOBAL
} }
fn finalize(&mut self, stack: &mut Vec<Nid>, tys: &Types, _files: &[parser::Ast]) { fn finalize(
&mut self,
stack: &mut Vec<Nid>,
tys: &Types,
_files: &EntSlice<Module, parser::Ast>,
) {
self.scope.clear(&mut self.nodes); self.scope.clear(&mut self.nodes);
mem::take(&mut self.ctrl).soft_remove(&mut self.nodes); mem::take(&mut self.ctrl).soft_remove(&mut self.nodes);
@ -2535,6 +2540,7 @@ pub struct Pool {
used_cis: usize, used_cis: usize,
scratch1: Vec<Nid>, scratch1: Vec<Nid>,
scratch2: Vec<Nid>, scratch2: Vec<Nid>,
lit_buf: Vec<u8>,
nid_set: BitSet, nid_set: BitSet,
} }
@ -2546,7 +2552,7 @@ impl Pool {
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
target: &mut ItemCtx, target: &mut ItemCtx,
) { ) -> &mut ItemCtx {
if let Some(slot) = self.cis.get_mut(self.used_cis) { if let Some(slot) = self.cis.get_mut(self.used_cis) {
mem::swap(slot, target); mem::swap(slot, target);
} else { } else {
@ -2555,6 +2561,7 @@ impl Pool {
} }
target.init(file, parent, ret, task_base); target.init(file, parent, ret, task_base);
self.used_cis += 1; self.used_cis += 1;
&mut self.cis[self.used_cis - 1]
} }
fn pop_ci(&mut self, target: &mut ItemCtx) { fn pop_ci(&mut self, target: &mut ItemCtx) {
@ -2633,7 +2640,7 @@ impl CodegenCtx {
} }
pub struct Codegen<'a> { pub struct Codegen<'a> {
pub files: &'a [parser::Ast], pub files: &'a EntSlice<Module, parser::Ast>,
pub errors: &'a RefCell<String>, pub errors: &'a RefCell<String>,
pub warnings: &'a RefCell<String>, pub warnings: &'a RefCell<String>,
tys: &'a mut Types, tys: &'a mut Types,
@ -2665,7 +2672,7 @@ impl<'a> Codegen<'a> {
ctx: &'a mut CodegenCtx, ctx: &'a mut CodegenCtx,
) -> Self { ) -> Self {
Self { Self {
files, files: files.into(),
errors: &ctx.parser.errors, errors: &ctx.parser.errors,
warnings: &ctx.parser.warnings, warnings: &ctx.parser.warnings,
tys: &mut ctx.tys, tys: &mut ctx.tys,
@ -2678,7 +2685,7 @@ impl<'a> Codegen<'a> {
} }
pub fn generate(&mut self, entry: Module) { pub fn generate(&mut self, entry: Module) {
self.find_type_in_file(0, entry, Err("main")); self.find_type(0, entry, entry, "main");
if self.tys.ins.funcs.is_empty() { if self.tys.ins.funcs.is_empty() {
return; return;
} }
@ -2925,46 +2932,37 @@ impl<'a> Codegen<'a> {
Some(Value::var(index).ty(var.ty)) Some(Value::var(index).ty(var.ty))
} }
Expr::Ident { id, pos, .. } => { Expr::Ident { id, pos, .. } => self.find_type_as_value(pos, self.ci.parent, id, ctx),
let decl = self.find_type_in_scope(pos, Ok(id));
match decl.expand() {
ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
_ => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, decl)),
}
}
Expr::Comment { .. } => Some(Value::VOID), Expr::Comment { .. } => Some(Value::VOID),
Expr::String { pos, literal } => { Expr::String { pos, literal } => {
let literal = &literal[1..literal.len() - 1]; let literal = &literal[1..literal.len() - 1];
let mut data = std::mem::take(&mut self.pool.lit_buf);
debug_assert!(data.is_empty());
let report = |bytes: &core::str::Bytes, message: &str| { let report = |bytes: &core::str::Bytes, message: &str| {
self.error(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());
crate::endoce_string(literal, &mut data, report).unwrap(); crate::endoce_string(literal, &mut data, report).unwrap();
let ty = self.tys.make_ptr(ty::Id::U8); let ty = self.tys.make_ptr(ty::Id::U8);
let global = match self.tys.strings.entry(&data, &self.tys.ins.globals) { let global = self
(hash_map::RawEntryMut::Occupied(occupied_entry), _) => { .tys
occupied_entry.get_key_value().0.value.0 .strings
} .get_or_insert(&data, &mut self.tys.ins.globals, |globals| {
(hash_map::RawEntryMut::Vacant(vacant_entry), hash) => { StringRef(globals.push(GlobalData {
let global = self.tys.ins.globals.push(GlobalData { data: data.clone(),
data,
ty, ty,
..Default::default() ..Default::default()
}); }))
vacant_entry })
.insert(crate::ctx_map::Key { value: StringRef(global), hash }, ()) .0;
.0
.value
.0
}
};
let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]); let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]);
self.ci.nodes[global].aclass = GLOBAL_ACLASS as _; self.ci.nodes[global].aclass = GLOBAL_ACLASS as _;
data.clear();
self.pool.lit_buf = data;
Some(Value::new(global).ty(ty)) Some(Value::new(global).ty(ty))
} }
Expr::Defer { pos, value } => { Expr::Defer { pos, value } => {
@ -3080,9 +3078,7 @@ impl<'a> Codegen<'a> {
self.ci.nodes.new_node_nop(ty::Id::VOID, Kind::Die, [self.ci.ctrl.get()]), self.ci.nodes.new_node_nop(ty::Id::VOID, Kind::Die, [self.ci.ctrl.get()]),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
self.ci.nodes.bind(self.ci.ctrl.get(), NEVER);
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl.get());
self.ci.nodes[self.ci.ctrl.get()].outputs.push(NEVER);
None None
} }
Expr::Field { target, name, pos } => { Expr::Field { target, name, pos } => {
@ -3115,11 +3111,10 @@ 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.error( return 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)),
); );
return Value::NEVER;
}; };
vl.ptr = true; vl.ptr = true;
vl.ty = base; vl.ty = base;
@ -3129,11 +3124,10 @@ 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.error( return 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)),
); );
return Value::NEVER;
}; };
let intrnd = self.tys.names.project(self.file().ident_str(id)); let intrnd = self.tys.names.project(self.file().ident_str(id));
@ -3158,8 +3152,7 @@ impl<'a> Codegen<'a> {
self.tys, self.tys,
)) ))
} else { } else {
self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty))); self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty)))
Value::NEVER
} }
} }
Expr::UnOp { pos, op: op @ TokenKind::Not, val } => { Expr::UnOp { pos, op: op @ TokenKind::Not, val } => {
@ -3173,8 +3166,7 @@ impl<'a> Codegen<'a> {
self.tys, self.tys,
)) ))
} else { } else {
self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty))); self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)))
Value::NEVER
} }
} }
Expr::BinOp { left, op: TokenKind::Decl, right, pos } => { Expr::BinOp { left, op: TokenKind::Decl, right, pos } => {
@ -3218,8 +3210,7 @@ impl<'a> Codegen<'a> {
Some(Value::VOID) Some(Value::VOID)
} }
Expr::BinOp { left: &Expr::Null { pos }, .. } => { Expr::BinOp { left: &Expr::Null { pos }, .. } => {
self.error(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 { Expr::BinOp {
left, left,
@ -3231,11 +3222,10 @@ 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.error( return 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)),
); );
return Value::NEVER;
}; };
Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::Id::BOOL)) Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::Id::BOOL))
@ -3316,13 +3306,8 @@ impl<'a> Codegen<'a> {
self.struct_fold_op(left.pos(), op, binding_op, s, lhs.id, rhs.id) self.struct_fold_op(left.pos(), op, binding_op, s, lhs.id, rhs.id)
.or(Value::NEVER) .or(Value::NEVER)
} }
_ => { _ => self
self.error( .error(pos, fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty))),
pos,
fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty)),
);
Value::NEVER
}
} }
} }
Expr::Index { base, index } => { Expr::Index { base, index } => {
@ -3335,14 +3320,13 @@ impl<'a> Codegen<'a> {
} }
let ty::Kind::Slice(s) = bs.ty.expand() else { let ty::Kind::Slice(s) = bs.ty.expand() else {
self.error( return 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",
self.ty_display(bs.ty) self.ty_display(bs.ty)
), ),
); );
return Value::NEVER;
}; };
let elem = self.tys.ins.slices[s].elem; let elem = self.tys.ins.slices[s].elem;
@ -3421,14 +3405,13 @@ 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.error( return 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)",
self.ty_display(val.ty) self.ty_display(val.ty)
), ),
); );
return Value::NEVER;
}; };
self.explicit_unwrap(expr.pos(), &mut val); self.explicit_unwrap(expr.pos(), &mut val);
@ -3438,14 +3421,13 @@ 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.error( return 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)",
self.ty_display(val.ty) self.ty_display(val.ty)
), ),
); );
return Value::NEVER;
} }
inference!(ty, ctx, self, pos, "integer", "@as(<ty>, @intcast(<expr>))"); inference!(ty, ctx, self, pos, "integer", "@as(<ty>, @intcast(<expr>))");
@ -3471,14 +3453,13 @@ 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.error( return 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)",
self.ty_display(val.ty) self.ty_display(val.ty)
), ),
); );
return Value::NEVER;
} }
inference!(ty, ctx, self, pos, "float", "@as(<floaty>, @floatcast(<expr>))"); inference!(ty, ctx, self, pos, "float", "@as(<floaty>, @floatcast(<expr>))");
@ -3510,11 +3491,10 @@ 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.error( return 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)),
); )
return Value::NEVER;
} }
}; };
@ -3653,7 +3633,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.error( return self.error(
pos, pos,
fa!( fa!(
"expected '{}' but constructor has {} elements", "expected '{}' but constructor has {} elements",
@ -3661,7 +3641,6 @@ impl<'a> Codegen<'a> {
fields.len() fields.len()
), ),
); );
return Value::NEVER;
} }
let mem = self.new_stack(pos, aty); let mem = self.new_stack(pos, aty);
@ -3677,18 +3656,15 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(mem).ty(aty)) Some(Value::ptr(mem).ty(aty))
} }
_ => { _ => self.error(
let inferred = if ty.is_some() { "" } else { "inferred " };
self.error(
pos, pos,
fa!( fa!(
"the {inferred}type of the constructor is `{}`, \ "the {}type of the constructor is `{}`, \
but thats not a struct nor slice or array", but thats not a struct nor slice or array",
self.ty_display(sty) if ty.is_some() { "" } else { "inferred " },
self.ty_display(sty),
),
), ),
);
Value::NEVER
}
} }
} }
Expr::Struct { .. } => { Expr::Struct { .. } => {
@ -3712,15 +3688,14 @@ impl<'a> Codegen<'a> {
let mem = self.new_stack(pos, sty); let mem = self.new_stack(pos, sty);
let Some(index) = self.tys.find_union_field(u, name) else { let Some((_, field)) = self.tys.find_union_field(u, name) else {
self.error( return self.error(
fpos, fpos,
fa!("union '{}' does not have this field", self.ty_display(sty)), fa!("union '{}' does not have this field", self.ty_display(sty)),
); );
return Value::NEVER;
}; };
let (ty, offset) = (self.tys.union_fields(u)[index].ty, 0); let (ty, offset) = (field.ty, 0);
let mut value = self.expr_ctx(&value, Ctx::default().with_ty(ty))?; let mut value = self.expr_ctx(&value, Ctx::default().with_ty(ty))?;
self.assert_ty(fpos, &mut value, ty, fa!("field {}", name)); self.assert_ty(fpos, &mut value, ty, fa!("field {}", name));
@ -4118,14 +4093,13 @@ 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.error( return 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",
self.ty_display(value.ty) self.ty_display(value.ty)
), ),
); );
return Value::NEVER;
}; };
let mut covered_values = vec![Pos::MAX; self.tys.enum_field_range(e).len()]; let mut covered_values = vec![Pos::MAX; self.tys.enum_field_range(e).len()];
@ -4142,7 +4116,7 @@ impl<'a> Codegen<'a> {
continue; continue;
} }
let pat_val = self.eval_const(self.ci.file, &pat, value.ty); let pat_val = self.eval_const(self.ci.file, self.ci.parent, &pat, value.ty);
if covered_values[pat_val as usize] != Pos::MAX { if covered_values[pat_val as usize] != Pos::MAX {
self.error(bp, "duplicate branch"); self.error(bp, "duplicate branch");
self.error( self.error(
@ -4241,93 +4215,78 @@ impl<'a> Codegen<'a> {
let tty = vtarget.ty; let tty = vtarget.ty;
match self.tys.base_of(tty).unwrap_or(tty).expand() { match self.tys.base_of(tty).unwrap_or(tty).expand() {
ty::Kind::Module(m) => self.find_type_as_value(pos, m, m, Err(name), ctx), ty::Kind::Module(m) => self.find_type_as_value(pos, m, name, ctx),
ty::Kind::Enum(e) => { ty::Kind::Enum(e) => {
let intrnd = self.tys.names.project(name); let intrnd = self.tys.names.project(name);
self.gen_enum_variant(pos, e, intrnd) self.gen_enum_variant(pos, e, intrnd)
} }
ty::Kind::Union(u) => { ty::Kind::Union(u) => {
let TypeBase { ast, file, .. } = *self.tys.ins.unions[u]; if let Some((_, f)) = self.tys.find_union_field(u, name) {
if let Some(f) =
self.tys.find_union_field(u, name).map(|i| &self.tys.union_fields(u)[i])
{
Some(Value::ptr(vtarget.id).ty(f.ty)) Some(Value::ptr(vtarget.id).ty(f.ty))
} else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } = } else if let ty = self.find_type(pos, self.ci.file, u, name)
ast.get(&self.files[file.index()])
&& let ty = self.find_type(pos, self.ci.file, file, u.into(), Err(name))
&& let ty::Kind::Func(_) = ty.expand() && let ty::Kind::Func(_) = ty.expand()
{ {
return Some(Err((ty, vtarget))); return Some(Err((ty, vtarget)));
} else { } else {
let field_list = self self.error(
.tys pos,
fa!(
"the '{}' does not have this field, \
but it does have '{}'",
self.ty_display(tty),
self.tys
.union_fields(u) .union_fields(u)
.iter() .iter()
.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.error(
pos,
fa!(
"the '{}' does not have this field, \
but it does have '{field_list}'",
self.ty_display(tty)
), ),
); )
Value::NEVER
} }
} }
ty::Kind::Struct(s) => { ty::Kind::Struct(s) => {
let TypeBase { ast, file, .. } = *self.tys.ins.structs[s];
if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) { if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) {
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
} else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } = } else if let ty = self.find_type(pos, self.ci.file, s, name)
ast.get(&self.files[file.index()])
&& let ty = self.find_type(pos, self.ci.file, file, s.into(), Err(name))
&& let ty::Kind::Func(_) = ty.expand() && let ty::Kind::Func(_) = ty.expand()
{ {
return Some(Err((ty, vtarget))); return Some(Err((ty, vtarget)));
} else { } else {
let field_list = self
.tys
.struct_fields(s)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
self.error( self.error(
pos, pos,
fa!( fa!(
"the '{}' does not have this field, \ "the '{}' does not have this field, \
but it does have '{field_list}'", but it does have '{}'",
self.ty_display(tty) self.ty_display(tty),
self.tys
.struct_fields(s)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>()
), ),
); )
Value::NEVER
} }
} }
ty::Kind::TYPE => match self.ci.nodes.as_ty(vtarget.id).expand() { ty::Kind::TYPE => match self.ci.nodes.as_ty(vtarget.id).expand() {
ty::Kind::Struct(s) => { ty::Kind::Module(m) => self.find_type_as_value(pos, m, name, ctx),
let TypeBase { file, .. } = *self.tys.ins.structs[s]; ty::Kind::Enum(e)
self.find_type_as_value(pos, file, s, Err(name), ctx) if let intrnd = self.tys.names.project(name)
} && let Some(index) =
ty::Kind::Union(u) => { self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd) =>
let TypeBase { file, .. } = *self.tys.ins.unions[u];
self.find_type_as_value(pos, file, u, Err(name), ctx)
}
ty::Kind::Module(m) => self.find_type_as_value(pos, m, m, Err(name), ctx),
ty::Kind::Enum(e) => {
let intrnd = self.tys.names.project(name);
if let Some(index) =
self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd)
{ {
Some(self.ci.nodes.new_const_lit(e.into(), index as i64)) Some(self.ci.nodes.new_const_lit(e.into(), index as i64))
} else {
let TypeBase { file, .. } = *self.tys.ins.enums[e];
self.find_type_as_value(pos, file, e, Err(name), ctx)
} }
ty @ (ty::Kind::Struct(_) | ty::Kind::Enum(_) | ty::Kind::Union(_)) => {
self.find_type_as_value(pos, ty.compress(), name, ctx)
} }
ty => self.error( ty @ (ty::Kind::Builtin(_)
| ty::Kind::Ptr(_)
| ty::Kind::Slice(_)
| ty::Kind::Opt(_)
| ty::Kind::Func(_)
| ty::Kind::Global(_)
| ty::Kind::Const(_)) => self.error(
pos, pos,
fa!( fa!(
"accesing scope on '{}' is not supported yet", "accesing scope on '{}' is not supported yet",
@ -4380,22 +4339,20 @@ impl<'a> Codegen<'a> {
fn gen_enum_variant(&mut self, pos: Pos, e: ty::Enum, intrnd: Option<Ident>) -> Option<Value> { fn gen_enum_variant(&mut self, pos: Pos, e: ty::Enum, intrnd: Option<Ident>) -> Option<Value> {
let Some(index) = self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd) let Some(index) = self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd)
else { else {
let field_list = self return self.error(
.tys pos,
fa!(
"the '{}' does not have this variant, \
but it does have '{}'",
self.ty_display(e.into()),
self.tys
.enum_fields(e) .enum_fields(e)
.iter() .iter()
.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.error(
pos,
fa!(
"the '{}' does not have this variant, \
but it does have '{field_list}'",
self.ty_display(e.into())
), ),
); );
return Value::NEVER;
}; };
Some(self.ci.nodes.new_const_lit(e.into(), index as i64)) Some(self.ci.nodes.new_const_lit(e.into(), index as i64))
@ -4445,7 +4402,7 @@ impl<'a> Codegen<'a> {
inline |= sig.ret == ty::Id::TYPE; inline |= sig.ret == ty::Id::TYPE;
let FuncData { expr, file, is_inline, parent, .. } = self.tys.ins.funcs[fu]; let FuncData { expr, file, is_inline, parent, .. } = self.tys.ins.funcs[fu];
let ast = &self.files[file.index()]; let ast = &self.files[file];
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() }; let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
let arg_count = args.len() + caller.is_some() as usize; let arg_count = args.len() + caller.is_some() as usize;
@ -4661,7 +4618,7 @@ impl<'a> Codegen<'a> {
let c = &self.tys.ins.consts[cnst]; let c = &self.tys.ins.consts[cnst];
let prev_file = mem::replace(&mut self.ci.file, c.file); let prev_file = mem::replace(&mut self.ci.file, c.file);
let prev_parent = mem::replace(&mut self.ci.parent, c.parent); let prev_parent = mem::replace(&mut self.ci.parent, c.parent);
let f = &self.files[c.file.index()]; let f = &self.files[c.file];
let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() }; let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() };
let mut value = left let mut value = left
@ -4806,7 +4763,7 @@ impl<'a> Codegen<'a> {
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> { fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
let FuncData { file, expr, sig, parent, .. } = self.tys.ins.funcs[*func]; let FuncData { file, expr, sig, parent, .. } = self.tys.ins.funcs[*func];
let fast = &self.files[file.index()]; let fast = &self.files[file];
let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else { let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else {
unreachable!(); unreachable!();
}; };
@ -5035,7 +4992,7 @@ impl<'a> Codegen<'a> {
debug_assert_eq!(cct, ct); debug_assert_eq!(cct, ct);
func.comp_state[cct as usize] = CompState::Compiled; func.comp_state[cct as usize] = CompState::Compiled;
let sig = func.sig.expect("to emmit only concrete functions"); let sig = func.sig.expect("to emmit only concrete functions");
let ast = &self.files[file.index()]; let ast = &self.files[file];
let expr = func.expr.get(ast); let expr = func.expr.get(ast);
self.pool.push_ci(file, func.parent, Some(sig.ret), 0, &mut self.ci); self.pool.push_ci(file, func.parent, Some(sig.ret), 0, &mut self.ci);
@ -5445,22 +5402,18 @@ impl<'a> Codegen<'a> {
} }
fn file(&self) -> &'a parser::Ast { fn file(&self) -> &'a parser::Ast {
&self.files[self.ci.file.index()] &self.files[self.ci.file]
} }
fn eval_const(&mut self, file: Module, expr: &Expr, ret: ty::Id) -> u64 { fn eval_const(&mut self, file: Module, parent: ty::Id, expr: &Expr, ret: ty::Id) -> u64 {
self.ct.activate(); self.ct.activate();
let scope = self let prev = self.pool.push_ci(file, parent, Some(ret), self.tys.tasks.len(), &mut self.ci);
.ci
.scope prev.scope
.vars .vars
.iter() .iter()
.filter(|v| v.ty == ty::Id::TYPE) .filter(|v| v.ty == ty::Id::TYPE)
.map(|v| (self.ci.nodes.as_ty(v.value()), v.id)) .map(|v| (prev.nodes.as_ty(v.value()), v.id))
.collect::<Vec<_>>();
self.pool.push_ci(file, self.ci.parent, Some(ret), self.tys.tasks.len(), &mut self.ci);
self.ci.scope.vars = scope
.into_iter()
.map(|(v, id)| { .map(|(v, id)| {
Variable::new( Variable::new(
id, id,
@ -5470,14 +5423,17 @@ impl<'a> Codegen<'a> {
&mut self.ci.nodes, &mut self.ci.nodes,
) )
}) })
.collect(); .collect_into(&mut self.ci.scope.vars);
let prev_err_len = self.errors.borrow().len(); let prev_err_len = self.errors.borrow().len();
self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) }); self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) });
let res = let res = if self.finalize(prev_err_len) {
if self.finalize(prev_err_len) { self.emit_and_eval(file, ret, &mut []) } else { 1 }; self.emit_and_eval(file, ret, &mut [])
} else {
i64::from(ty::Id::UNDECLARED) as _
};
self.pool.pop_ci(&mut self.ci); self.pool.pop_ci(&mut self.ci);
@ -5532,13 +5488,13 @@ impl<'a> Codegen<'a> {
fn error_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id { fn error_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
let mut buf = self.errors.borrow_mut(); let mut buf = self.errors.borrow_mut();
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap(); write!(buf, "{}", self.files[file].report(pos, msg)).unwrap();
ty::Id::NEVER ty::Id::NEVER
} }
fn warn_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id { fn warn_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
let mut buf = self.warnings.borrow_mut(); let mut buf = self.warnings.borrow_mut();
write!(buf, "(W) {}", self.files[file.index()].report(pos, msg)).unwrap(); write!(buf, "(W) {}", self.files[file].report(pos, msg)).unwrap();
ty::Id::NEVER ty::Id::NEVER
} }
@ -5551,23 +5507,14 @@ impl<'a> Codegen<'a> {
.map(|v| self.ci.nodes.as_ty(v.value())) .map(|v| self.ci.nodes.as_ty(v.value()))
} }
fn find_type_in_file(&mut self, pos: Pos, file: Module, id: Result<Ident, &str>) -> ty::Id {
self.find_type(pos, file, file, file.into(), id)
}
fn find_type_in_scope(&mut self, pos: Pos, id: Result<Ident, &str>) -> ty::Id {
self.find_type(pos, self.ci.file, self.ci.file, self.ci.parent, id)
}
fn find_type_as_value( fn find_type_as_value(
&mut self, &mut self,
pos: Pos, pos: Pos,
file: Module,
parent: impl Into<ty::Id>, parent: impl Into<ty::Id>,
id: Result<Ident, &str>, id: impl Into<DeclId>,
ctx: Ctx, ctx: Ctx,
) -> Option<Value> { ) -> Option<Value> {
match self.find_type(pos, self.ci.file, file, parent.into(), id).expand() { match self.find_type(pos, self.ci.file, parent, id).expand() {
ty::Kind::NEVER => Value::NEVER, ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
@ -5579,21 +5526,29 @@ impl<'a> Codegen<'a> {
&mut self, &mut self,
pos: Pos, pos: Pos,
from_file: Module, from_file: Module,
file: Module, parent: impl Into<ty::Id>,
parent: ty::Id, id: impl Into<DeclId>,
id: Result<Ident, &str>,
) -> ty::Id { ) -> ty::Id {
let ty = if let Ok(id) = id self.find_type_low(pos, from_file, parent.into(), id.into())
}
fn find_type_low(&mut self, pos: Pos, from_file: Module, parent: ty::Id, id: DeclId) -> ty::Id {
let file = match parent.expand() {
ty::Kind::Module(m) => m,
_ => self.tys.type_base_of(parent).unwrap().file,
};
let ty = if let DeclId::Ident(id) = id
&& let Some(ty) = self.find_local_ty(id) && let Some(ty) = self.find_local_ty(id)
{ {
ty ty
} else if let Ok(id) = id } else if let DeclId::Ident(id) = id
&& let Some(&ty) = self.tys.syms.get(SymKey::Decl(parent, id), &self.tys.ins) && let Some(&ty) = self.tys.syms.get(SymKey::Decl(parent, id), &self.tys.ins)
{ {
self.on_reuse(ty); self.on_reuse(ty);
ty ty
} else { } else {
let f = &self.files[file.index()]; let f = &self.files[file];
let mut piter = parent; let mut piter = parent;
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = (loop { let Some((expr @ Expr::BinOp { left, right, .. }, name)) = (loop {
@ -5604,7 +5559,7 @@ impl<'a> Codegen<'a> {
} }
if let Some((captures, capture_tuple)) = self.tys.captures_of(piter, f) if let Some((captures, capture_tuple)) = self.tys.captures_of(piter, f)
&& let Some(idx) = captures.iter().position(|&cid| Ok(cid) == id) && let Some(idx) = captures.iter().position(|&cid| DeclId::Ident(cid) == id)
{ {
return self.tys.ins.args[capture_tuple.range().start + idx]; return self.tys.ins.args[capture_tuple.range().start + idx];
} }
@ -5620,11 +5575,11 @@ impl<'a> Codegen<'a> {
}; };
}) else { }) else {
return match id { return match id {
Ok(_) => { DeclId::Ident(id) => {
debug_assert_eq!(from_file, file); debug_assert_eq!(from_file, file, "{}", f.ident_str(id));
self.error_low(file, pos, "somehow this was not found") self.error_low(file, pos, "somehow this was not found")
} }
Err("main") => self.error_low( DeclId::Name("main") => self.error_low(
from_file, from_file,
pos, pos,
format_args!( format_args!(
@ -5634,7 +5589,7 @@ impl<'a> Codegen<'a> {
f.path f.path
), ),
), ),
Err(name) => self.error_low( DeclId::Name(name) => self.error_low(
from_file, from_file,
pos, pos,
format_args!("undefined indentifier: {name}"), format_args!("undefined indentifier: {name}"),
@ -5648,9 +5603,7 @@ impl<'a> Codegen<'a> {
} else { } else {
let (is_ct, ty) = left let (is_ct, ty) = left
.find_pattern_path(name, right, |right, is_ct| { .find_pattern_path(name, right, |right, is_ct| {
( let ty = if is_ct && !matches!(right, Expr::Closure { .. }) {
is_ct,
if is_ct && !matches!(right, Expr::Closure { .. }) {
self.tys self.tys
.ins .ins
.consts .consts
@ -5661,8 +5614,8 @@ impl<'a> Codegen<'a> {
TyScope { file, parent, name: Some(name), alloc_const: true }, TyScope { file, parent, name: Some(name), alloc_const: true },
right, right,
) )
}, };
) (is_ct, ty)
}) })
.unwrap_or_else(|_| unreachable!()); .unwrap_or_else(|_| unreachable!());
if let ty::Kind::Func(f) = ty.expand() if let ty::Kind::Func(f) = ty.expand()
@ -5715,11 +5668,11 @@ impl<'a> Codegen<'a> {
self.tys.make_opt(base) self.tys.make_opt(base)
} }
Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(), Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(),
Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.file, sc.parent, Ok(id)), Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.parent, id),
Expr::Field { target, pos, name } Expr::Field { target, pos, name }
if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() => if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() =>
{ {
self.find_type(pos, sc.file, inside, inside.into(), Err(name)) self.find_type(pos, sc.file, inside, name)
} }
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr), Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
Expr::Slice { size: None, item, .. } => { Expr::Slice { size: None, item, .. } => {
@ -5732,8 +5685,9 @@ impl<'a> Codegen<'a> {
} }
Expr::Slice { size, item, .. } => { Expr::Slice { size, item, .. } => {
let ty = self.parse_ty(sc.anon(), item); let ty = self.parse_ty(sc.anon(), item);
let len = size let len = size.map_or(ArrayLen::MAX, |expr| {
.map_or(ArrayLen::MAX, |expr| self.eval_const(sc.file, expr, ty::Id::U32) as _); self.eval_const(sc.file, sc.parent, expr, ty::Id::U32) as _
});
self.tys.make_array(ty, len) self.tys.make_array(ty, len)
} }
Expr::Struct { pos, fields, packed, captured, .. } => self.parse_base_ty( Expr::Struct { pos, fields, packed, captured, .. } => self.parse_base_ty(
@ -5786,8 +5740,7 @@ impl<'a> Codegen<'a> {
sig: 'b: { sig: 'b: {
let arg_base = self.tys.tmp.args.len(); let arg_base = self.tys.tmp.args.len();
for arg in args { for arg in args {
let sym = let sym = parser::find_symbol(&self.files[sc.file].symbols, arg.id);
parser::find_symbol(&self.files[sc.file.index()].symbols, arg.id);
if sym.flags & idfl::COMPTIME != 0 { if sym.flags & idfl::COMPTIME != 0 {
self.tys.tmp.args.truncate(arg_base); self.tys.tmp.args.truncate(arg_base);
break 'b None; break 'b None;
@ -5815,7 +5768,9 @@ impl<'a> Codegen<'a> {
{ {
self.eval_global(sc.file, name, expr) self.eval_global(sc.file, name, expr)
} }
_ if sc.alloc_const => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)), _ if sc.alloc_const => {
ty::Id::from(self.eval_const(sc.file, sc.parent, expr, ty::Id::TYPE))
}
ref e => { ref e => {
self.error_unhandled_ast(e, "bruh"); self.error_unhandled_ast(e, "bruh");
ty::Id::NEVER ty::Id::NEVER

View file

@ -3,7 +3,7 @@ use {
ctx_map, ctx_map,
lexer::TokenKind, lexer::TokenKind,
parser::{self, CommentOr, Expr, ExprRef, Pos}, parser::{self, CommentOr, Expr, ExprRef, Pos},
utils::{self, Ent, EntVec}, utils::{self, Ent, EntSlice, EntVec},
Ident, Ident,
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
@ -480,12 +480,12 @@ impl Default for Kind {
pub struct Display<'a> { pub struct Display<'a> {
tys: &'a Types, tys: &'a Types,
files: &'a [parser::Ast], files: &'a EntSlice<Module, parser::Ast>,
ty: Id, ty: Id,
} }
impl<'a> Display<'a> { impl<'a> Display<'a> {
pub fn new(tys: &'a Types, files: &'a [parser::Ast], ty: Id) -> Self { pub fn new(tys: &'a Types, files: &'a EntSlice<Module, parser::Ast>, ty: Id) -> Self {
Self { tys, files, ty } Self { tys, files, ty }
} }
@ -500,7 +500,7 @@ impl core::fmt::Display for Display<'_> {
match TK::from_ty(self.ty) { match TK::from_ty(self.ty) {
TK::Module(idx) => { TK::Module(idx) => {
f.write_str("@use(\"")?; f.write_str("@use(\"")?;
self.files[idx.index()].path.fmt(f)?; self.files[idx].path.fmt(f)?;
f.write_str(")[")?; f.write_str(")[")?;
idx.fmt(f)?; idx.fmt(f)?;
f.write_str("]") f.write_str("]")
@ -532,7 +532,7 @@ impl core::fmt::Display for Display<'_> {
} }
f.write_str("}") f.write_str("}")
} else { } else {
let file = &self.files[record.file.index()]; let file = &self.files[record.file];
f.write_str(file.ident_str(record.name)) f.write_str(file.ident_str(record.name))
} }
} }
@ -554,14 +554,14 @@ impl core::fmt::Display for Display<'_> {
} }
f.write_str("}") f.write_str("}")
} else { } else {
let file = &self.files[record.file.index()]; let file = &self.files[record.file];
f.write_str(file.ident_str(record.name)) f.write_str(file.ident_str(record.name))
} }
} }
TK::Enum(idx) => { TK::Enum(idx) => {
let enm = &self.tys.ins.enums[idx]; let enm = &self.tys.ins.enums[idx];
debug_assert!(!enm.name.is_null()); debug_assert!(!enm.name.is_null());
let file = &self.files[enm.file.index()]; let file = &self.files[enm.file];
f.write_str(file.ident_str(enm.name)) f.write_str(file.ident_str(enm.name))
} }
TK::Func(idx) => { TK::Func(idx) => {
@ -570,7 +570,7 @@ impl core::fmt::Display for Display<'_> {
} }
TK::Global(idx) => { TK::Global(idx) => {
let global = &self.tys.ins.globals[idx]; let global = &self.tys.ins.globals[idx];
let file = &self.files[global.file.index()]; let file = &self.files[global.file];
f.write_str(file.ident_str(global.name))?; f.write_str(file.ident_str(global.name))?;
f.write_str(" (global)") f.write_str(" (global)")
} }
@ -586,7 +586,7 @@ impl core::fmt::Display for Display<'_> {
} }
TK::Const(idx) => { TK::Const(idx) => {
let cnst = &self.tys.ins.consts[idx]; let cnst = &self.tys.ins.consts[idx];
let file = &self.files[cnst.file.index()]; let file = &self.files[cnst.file];
f.write_str(file.ident_str(cnst.name))?; f.write_str(file.ident_str(cnst.name))?;
f.write_str(" (const)") f.write_str(" (const)")
} }
@ -1029,9 +1029,9 @@ impl Types {
self.struct_fields(s).iter().position(|f| f.name == name) self.struct_fields(s).iter().position(|f| f.name == name)
} }
pub fn find_union_field(&self, u: Union, name: &str) -> Option<usize> { pub fn find_union_field(&self, u: Union, name: &str) -> Option<(usize, &StructField)> {
let name = self.names.project(name)?; let name = self.names.project(name)?;
self.union_fields(u).iter().position(|f| f.name == name) self.union_fields(u).iter().enumerate().find(|(_, f)| f.name == name)
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {
@ -1053,7 +1053,7 @@ impl Types {
debug_assert_eq!(self.tasks.len(), 0); debug_assert_eq!(self.tasks.len(), 0);
} }
fn type_base_of(&self, id: Id) -> Option<&TypeBase> { pub fn type_base_of(&self, id: Id) -> Option<&TypeBase> {
Some(match id.expand() { Some(match id.expand() {
Kind::Struct(s) => &*self.ins.structs[s], Kind::Struct(s) => &*self.ins.structs[s],
Kind::Enum(e) => &*self.ins.enums[e], Kind::Enum(e) => &*self.ins.enums[e],

View file

@ -559,6 +559,26 @@ pub trait Ent: Copy {
fn index(self) -> usize; fn index(self) -> usize;
} }
#[repr(transparent)]
pub struct EntSlice<K: Ent, T> {
k: PhantomData<fn(K)>,
data: [T],
}
impl<'a, K: Ent, T> From<&'a [T]> for &'a EntSlice<K, T> {
fn from(value: &'a [T]) -> Self {
unsafe { core::mem::transmute(value) }
}
}
impl<K: Ent, T> core::ops::Index<K> for EntSlice<K, T> {
type Output = T;
fn index(&self, index: K) -> &Self::Output {
&self.data[index.index()]
}
}
pub struct EntVec<K: Ent, T> { pub struct EntVec<K: Ent, T> {
data: ::alloc::vec::Vec<T>, data: ::alloc::vec::Vec<T>,
k: PhantomData<fn(K)>, k: PhantomData<fn(K)>,