diff --git a/foo.hb b/foo.hb new file mode 100644 index 00000000..8047a5bf --- /dev/null +++ b/foo.hb @@ -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} +} diff --git a/lang/src/backend/hbvm.rs b/lang/src/backend/hbvm.rs index 513e945b..0cb709d3 100644 --- a/lang/src/backend/hbvm.rs +++ b/lang/src/backend/hbvm.rs @@ -5,7 +5,7 @@ use { parser, son::{Kind, Nid, Node, Nodes, MEM, VOID}, ty::{self, Arg, Loc, Module, Offset, Sig, Size, Types}, - utils::{Ent, EntVec}, + utils::{EntSlice, EntVec}, }, alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec}, core::{assert_matches::debug_assert_matches, mem, ops::Range}, @@ -213,7 +213,7 @@ impl Backend for HbvmBackend { mut sluce: &[u8], eca_handler: &mut dyn FnMut(&mut &[u8]), types: &'a Types, - files: &'a [parser::Ast], + files: &'a EntSlice, output: &mut String, ) -> Result<(), hbbytecode::DisasmError<'a>> { use hbbytecode::DisasmItem; @@ -225,7 +225,7 @@ impl Backend for HbvmBackend { .filter(|(_, f)| f.offset != u32::MAX) .map(|(f, fd)| { let name = if f.file != Module::default() { - let file = &files[f.file.index()]; + let file = &files[f.file]; file.ident_str(f.name) } else { "target_fn" @@ -243,7 +243,7 @@ impl Backend for HbvmBackend { let name = if g.file == Module::default() { core::str::from_utf8(&g.data).unwrap_or("invalid utf-8") } else { - let file = &files[g.file.index()]; + let file = &files[g.file]; file.ident_str(g.name) }; (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) } - 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, + ) { self.emit_body(id, nodes, tys, files); let fd = &mut self.funcs[id]; fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0); 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, + ) { let sig = tys.ins.funcs[id].sig.unwrap(); debug_assert!(self.code.is_empty()); @@ -432,11 +444,18 @@ struct InstrCtx<'a> { allocs: &'a [u8], nodes: &'a Nodes, tys: &'a Types, - files: &'a [parser::Ast], + files: &'a EntSlice, } 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, + ) { if reg == 0 { return; } diff --git a/lang/src/backend/hbvm/regalloc.rs b/lang/src/backend/hbvm/regalloc.rs index 0b681bfa..55019be3 100644 --- a/lang/src/backend/hbvm/regalloc.rs +++ b/lang/src/backend/hbvm/regalloc.rs @@ -6,8 +6,8 @@ use { }, parser, quad_sort, son::{Kind, ARG_START, MEM, VOID}, - ty::{self, Arg, Loc, Sig, Types}, - utils::BitSet, + ty::{self, Arg, Loc, Module, Sig, Types}, + utils::{BitSet, EntSlice}, }, alloc::{borrow::ToOwned, vec::Vec}, core::{assert_matches::debug_assert_matches, mem, ops::Range}, @@ -20,7 +20,7 @@ impl HbvmBackend { nodes: &Nodes, sig: Sig, tys: &Types, - files: &[parser::Ast], + files: &EntSlice, ) -> (usize, bool) { let tail = Function::build(nodes, tys, &mut self.ralloc, sig); diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 2bea54ba..173ddbea 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -69,7 +69,8 @@ pub mod backend { crate::{ parser, son::Nodes, - ty::{self, Types}, + ty::{self, Module, Types}, + utils::EntSlice, }, alloc::{string::String, vec::Vec}, }; @@ -94,12 +95,24 @@ pub mod backend { sluce: &[u8], eca_handler: &mut dyn FnMut(&mut &[u8]), types: &'a Types, - files: &'a [parser::Ast], + files: &'a EntSlice, output: &mut String, ) -> 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, + ); - 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, + ) { self.emit_body(id, ci, tys, files); } diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 5e2b7cf9..b1bf9d61 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -1079,9 +1079,11 @@ generate_expr! { } impl Expr<'_> { - pub fn declares(&self, iden: Result, source: &str) -> Option { + pub fn declares(&self, iden: DeclId, source: &str) -> Option { 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) } Self::Ctor { fields, .. } => fields.iter().find_map(|f| f.value.declares(iden, source)), @@ -1389,7 +1391,7 @@ impl Ast { unsafe { self.0.as_ref() } } - pub fn find_decl(&self, id: Result) -> Option<(&Expr, Ident)> { + pub fn find_decl(&self, id: DeclId) -> Option<(&Expr, Ident)> { find_decl(self.exprs(), &self.file, id) } @@ -1401,7 +1403,7 @@ impl Ast { pub fn find_decl<'a>( exprs: &'a [Expr<'a>], file: &str, - id: Result, + id: DeclId, ) -> Option<(&'a Expr<'a>, Ident)> { exprs.iter().find_map(|expr| match expr { 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 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 { fn default() -> Self { Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader)) diff --git a/lang/src/son.rs b/lang/src/son.rs index 27cc4a50..be22353e 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -11,14 +11,14 @@ use { parser::{ self, idfl::{self}, - CommentOr, CtorField, Expr, ExprRef, FieldList, MatchBranch, Pos, + CommentOr, CtorField, DeclId, Expr, ExprRef, FieldList, MatchBranch, Pos, }, ty::{ self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData, GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData, StructField, SymKey, Tuple, TypeBase, TypeIns, Types, UnionData, }, - utils::{BitSet, Ent, Vc}, + utils::{BitSet, EntSlice, Vc}, Ident, }, alloc::{string::String, vec::Vec}, @@ -2506,7 +2506,12 @@ impl ItemCtx { self.scope.aclasses.push(AClass::new(&mut self.nodes)); // GLOBAL } - fn finalize(&mut self, stack: &mut Vec, tys: &Types, _files: &[parser::Ast]) { + fn finalize( + &mut self, + stack: &mut Vec, + tys: &Types, + _files: &EntSlice, + ) { self.scope.clear(&mut self.nodes); mem::take(&mut self.ctrl).soft_remove(&mut self.nodes); @@ -2535,6 +2540,7 @@ pub struct Pool { used_cis: usize, scratch1: Vec, scratch2: Vec, + lit_buf: Vec, nid_set: BitSet, } @@ -2546,7 +2552,7 @@ impl Pool { ret: Option, task_base: usize, target: &mut ItemCtx, - ) { + ) -> &mut ItemCtx { if let Some(slot) = self.cis.get_mut(self.used_cis) { mem::swap(slot, target); } else { @@ -2555,6 +2561,7 @@ impl Pool { } target.init(file, parent, ret, task_base); self.used_cis += 1; + &mut self.cis[self.used_cis - 1] } fn pop_ci(&mut self, target: &mut ItemCtx) { @@ -2633,7 +2640,7 @@ impl CodegenCtx { } pub struct Codegen<'a> { - pub files: &'a [parser::Ast], + pub files: &'a EntSlice, pub errors: &'a RefCell, pub warnings: &'a RefCell, tys: &'a mut Types, @@ -2665,7 +2672,7 @@ impl<'a> Codegen<'a> { ctx: &'a mut CodegenCtx, ) -> Self { Self { - files, + files: files.into(), errors: &ctx.parser.errors, warnings: &ctx.parser.warnings, tys: &mut ctx.tys, @@ -2678,7 +2685,7 @@ impl<'a> Codegen<'a> { } 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() { return; } @@ -2925,46 +2932,37 @@ impl<'a> Codegen<'a> { Some(Value::var(index).ty(var.ty)) } - Expr::Ident { id, pos, .. } => { - 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::Ident { id, pos, .. } => self.find_type_as_value(pos, self.ci.parent, id, ctx), Expr::Comment { .. } => Some(Value::VOID), Expr::String { pos, literal } => { 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| { self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message); }; - let mut data = Vec::::with_capacity(literal.len()); crate::endoce_string(literal, &mut data, report).unwrap(); let ty = self.tys.make_ptr(ty::Id::U8); - let global = match self.tys.strings.entry(&data, &self.tys.ins.globals) { - (hash_map::RawEntryMut::Occupied(occupied_entry), _) => { - occupied_entry.get_key_value().0.value.0 - } - (hash_map::RawEntryMut::Vacant(vacant_entry), hash) => { - let global = self.tys.ins.globals.push(GlobalData { - data, + let global = self + .tys + .strings + .get_or_insert(&data, &mut self.tys.ins.globals, |globals| { + StringRef(globals.push(GlobalData { + data: data.clone(), ty, ..Default::default() - }); - vacant_entry - .insert(crate::ctx_map::Key { value: StringRef(global), hash }, ()) - .0 - .value - .0 - } - }; + })) + }) + .0; let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]); self.ci.nodes[global].aclass = GLOBAL_ACLASS as _; + + data.clear(); + self.pool.lit_buf = data; + Some(Value::new(global).ty(ty)) } 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()]), &mut self.ci.nodes, ); - - self.ci.nodes[NEVER].inputs.push(self.ci.ctrl.get()); - self.ci.nodes[self.ci.ctrl.get()].outputs.push(NEVER); + self.ci.nodes.bind(self.ci.ctrl.get(), NEVER); None } Expr::Field { target, name, pos } => { @@ -3115,11 +3111,10 @@ impl<'a> Codegen<'a> { self.implicit_unwrap(val.pos(), &mut vl); let Some(base) = self.tys.base_of(vl.ty) else { - self.error( + return self.error( pos, fa!("the '{}' can not be dereferneced", self.ty_display(vl.ty)), ); - return Value::NEVER; }; vl.ptr = true; vl.ty = base; @@ -3129,11 +3124,10 @@ impl<'a> Codegen<'a> { inference!(ty, ctx, self, pos, "enum type", ".Variant"); let ty::Kind::Enum(e) = ty.expand() else { - self.error( + return self.error( pos, 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)); @@ -3158,8 +3152,7 @@ impl<'a> Codegen<'a> { self.tys, )) } else { - self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty))); - Value::NEVER + self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty))) } } Expr::UnOp { pos, op: op @ TokenKind::Not, val } => { @@ -3173,8 +3166,7 @@ impl<'a> Codegen<'a> { self.tys, )) } else { - self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty))); - Value::NEVER + self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty))) } } Expr::BinOp { left, op: TokenKind::Decl, right, pos } => { @@ -3218,8 +3210,7 @@ impl<'a> Codegen<'a> { Some(Value::VOID) } Expr::BinOp { left: &Expr::Null { pos }, .. } => { - self.error(pos, "'null' must always be no the right side of an expression"); - Value::NEVER + self.error(pos, "'null' must always be no the right side of an expression") } Expr::BinOp { left, @@ -3231,11 +3222,10 @@ impl<'a> Codegen<'a> { self.strip_var(&mut cmped); let Some(ty) = self.tys.inner_of(cmped.ty) else { - self.error( + return self.error( left.pos(), 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)) @@ -3316,13 +3306,8 @@ impl<'a> Codegen<'a> { self.struct_fold_op(left.pos(), op, binding_op, s, lhs.id, rhs.id) .or(Value::NEVER) } - _ => { - self.error( - pos, - fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty)), - ); - Value::NEVER - } + _ => self + .error(pos, fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty))), } } Expr::Index { base, index } => { @@ -3335,14 +3320,13 @@ impl<'a> Codegen<'a> { } let ty::Kind::Slice(s) = bs.ty.expand() else { - self.error( + return self.error( base.pos(), fa!( "cant index into '{}' which is not array nor slice", self.ty_display(bs.ty) ), ); - return Value::NEVER; }; let elem = self.tys.ins.slices[s].elem; @@ -3421,14 +3405,13 @@ impl<'a> Codegen<'a> { self.strip_var(&mut val); if !val.ty.is_optional() { - self.error( + return self.error( expr.pos(), fa!( "only optional types can be unwrapped ('{}' is not optional)", self.ty_display(val.ty) ), ); - return Value::NEVER; }; self.explicit_unwrap(expr.pos(), &mut val); @@ -3438,14 +3421,13 @@ impl<'a> Codegen<'a> { let mut val = self.expr(expr)?; if !val.ty.is_integer() { - self.error( + return self.error( expr.pos(), fa!( "only integers can be truncated ('{}' is not an integer)", self.ty_display(val.ty) ), ); - return Value::NEVER; } inference!(ty, ctx, self, pos, "integer", "@as(, @intcast())"); @@ -3471,14 +3453,13 @@ impl<'a> Codegen<'a> { let val = self.expr(expr)?; if !val.ty.is_float() { - self.error( + return self.error( expr.pos(), fa!( "only floats can be truncated ('{}' is not a float)", self.ty_display(val.ty) ), ); - return Value::NEVER; } inference!(ty, ctx, self, pos, "float", "@as(, @floatcast())"); @@ -3510,11 +3491,10 @@ impl<'a> Codegen<'a> { let ret_ty = match val.ty { ty::Id::F32 | ty::Id::F64 => ty::Id::INT, _ => { - self.error( + return self.error( expr.pos(), 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); if len != fields.len() { - self.error( + return self.error( pos, fa!( "expected '{}' but constructor has {} elements", @@ -3661,7 +3641,6 @@ impl<'a> Codegen<'a> { fields.len() ), ); - return Value::NEVER; } let mem = self.new_stack(pos, aty); @@ -3677,18 +3656,15 @@ impl<'a> Codegen<'a> { Some(Value::ptr(mem).ty(aty)) } - _ => { - let inferred = if ty.is_some() { "" } else { "inferred " }; - self.error( - pos, - fa!( - "the {inferred}type of the constructor is `{}`, \ + _ => self.error( + pos, + fa!( + "the {}type of the constructor is `{}`, \ but thats not a struct nor slice or array", - self.ty_display(sty) - ), - ); - Value::NEVER - } + if ty.is_some() { "" } else { "inferred " }, + self.ty_display(sty), + ), + ), } } Expr::Struct { .. } => { @@ -3712,15 +3688,14 @@ impl<'a> Codegen<'a> { let mem = self.new_stack(pos, sty); - let Some(index) = self.tys.find_union_field(u, name) else { - self.error( + let Some((_, field)) = self.tys.find_union_field(u, name) else { + return self.error( fpos, 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))?; self.assert_ty(fpos, &mut value, ty, fa!("field {}", name)); @@ -4118,14 +4093,13 @@ impl<'a> Codegen<'a> { let value = self.expr(value)?; let ty::Kind::Enum(e) = value.ty.expand() else { - self.error( + return self.error( pos, fa!( "match operates on enums (for now), '{}' is not an enum", self.ty_display(value.ty) ), ); - return Value::NEVER; }; let mut covered_values = vec![Pos::MAX; self.tys.enum_field_range(e).len()]; @@ -4142,7 +4116,7 @@ impl<'a> Codegen<'a> { 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 { self.error(bp, "duplicate branch"); self.error( @@ -4241,93 +4215,78 @@ impl<'a> Codegen<'a> { let tty = vtarget.ty; 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) => { let intrnd = self.tys.names.project(name); self.gen_enum_variant(pos, e, intrnd) } ty::Kind::Union(u) => { - let TypeBase { ast, file, .. } = *self.tys.ins.unions[u]; - if let Some(f) = - self.tys.find_union_field(u, name).map(|i| &self.tys.union_fields(u)[i]) - { + if let Some((_, f)) = self.tys.find_union_field(u, name) { Some(Value::ptr(vtarget.id).ty(f.ty)) - } else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } = - ast.get(&self.files[file.index()]) - && let ty = self.find_type(pos, self.ci.file, file, u.into(), Err(name)) + } else if let ty = self.find_type(pos, self.ci.file, u, name) && let ty::Kind::Func(_) = ty.expand() { return Some(Err((ty, vtarget))); } else { - let field_list = self - .tys - .union_fields(u) - .iter() - .map(|f| self.tys.names.ident_str(f.name)) - .intersperse("', '") - .collect::(); self.error( pos, fa!( "the '{}' does not have this field, \ - but it does have '{field_list}'", - self.ty_display(tty) + but it does have '{}'", + self.ty_display(tty), + self.tys + .union_fields(u) + .iter() + .map(|f| self.tys.names.ident_str(f.name)) + .intersperse("', '") + .collect::() ), - ); - Value::NEVER + ) } } 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) { Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) - } else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } = - ast.get(&self.files[file.index()]) - && let ty = self.find_type(pos, self.ci.file, file, s.into(), Err(name)) + } else if let ty = self.find_type(pos, self.ci.file, s, name) && let ty::Kind::Func(_) = ty.expand() { return Some(Err((ty, vtarget))); } else { - let field_list = self - .tys - .struct_fields(s) - .iter() - .map(|f| self.tys.names.ident_str(f.name)) - .intersperse("', '") - .collect::(); self.error( pos, fa!( "the '{}' does not have this field, \ - but it does have '{field_list}'", - self.ty_display(tty) + but it does have '{}'", + self.ty_display(tty), + self.tys + .struct_fields(s) + .iter() + .map(|f| self.tys.names.ident_str(f.name)) + .intersperse("', '") + .collect::() ), - ); - Value::NEVER + ) } } ty::Kind::TYPE => match self.ci.nodes.as_ty(vtarget.id).expand() { - ty::Kind::Struct(s) => { - let TypeBase { file, .. } = *self.tys.ins.structs[s]; - self.find_type_as_value(pos, file, s, Err(name), ctx) + ty::Kind::Module(m) => self.find_type_as_value(pos, m, name, ctx), + ty::Kind::Enum(e) + if let intrnd = self.tys.names.project(name) + && 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)) } - ty::Kind::Union(u) => { - let TypeBase { file, .. } = *self.tys.ins.unions[u]; - self.find_type_as_value(pos, file, u, Err(name), ctx) + ty @ (ty::Kind::Struct(_) | ty::Kind::Enum(_) | ty::Kind::Union(_)) => { + self.find_type_as_value(pos, ty.compress(), 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)) - } else { - let TypeBase { file, .. } = *self.tys.ins.enums[e]; - self.find_type_as_value(pos, file, e, Err(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, fa!( "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) -> Option { let Some(index) = self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd) else { - let field_list = self - .tys - .enum_fields(e) - .iter() - .map(|f| self.tys.names.ident_str(f.name)) - .intersperse("', '") - .collect::(); - self.error( + return self.error( pos, fa!( "the '{}' does not have this variant, \ - but it does have '{field_list}'", - self.ty_display(e.into()) + but it does have '{}'", + self.ty_display(e.into()), + self.tys + .enum_fields(e) + .iter() + .map(|f| self.tys.names.ident_str(f.name)) + .intersperse("', '") + .collect::() ), ); - return Value::NEVER; }; 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; 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 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 prev_file = mem::replace(&mut self.ci.file, c.file); 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 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 { 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 { unreachable!(); }; @@ -5035,7 +4992,7 @@ impl<'a> Codegen<'a> { debug_assert_eq!(cct, ct); func.comp_state[cct as usize] = CompState::Compiled; 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); 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 { - &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(); - let scope = self - .ci - .scope + let prev = self.pool.push_ci(file, parent, Some(ret), self.tys.tasks.len(), &mut self.ci); + + prev.scope .vars .iter() .filter(|v| v.ty == ty::Id::TYPE) - .map(|v| (self.ci.nodes.as_ty(v.value()), v.id)) - .collect::>(); - 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| (prev.nodes.as_ty(v.value()), v.id)) .map(|(v, id)| { Variable::new( id, @@ -5470,14 +5423,17 @@ impl<'a> Codegen<'a> { &mut self.ci.nodes, ) }) - .collect(); + .collect_into(&mut self.ci.scope.vars); let prev_err_len = self.errors.borrow().len(); self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) }); - let res = - if self.finalize(prev_err_len) { self.emit_and_eval(file, ret, &mut []) } else { 1 }; + let res = if self.finalize(prev_err_len) { + self.emit_and_eval(file, ret, &mut []) + } else { + i64::from(ty::Id::UNDECLARED) as _ + }; 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 { 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 } fn warn_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id { 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 } @@ -5551,23 +5507,14 @@ impl<'a> Codegen<'a> { .map(|v| self.ci.nodes.as_ty(v.value())) } - fn find_type_in_file(&mut self, pos: Pos, file: Module, id: Result) -> ty::Id { - self.find_type(pos, file, file, file.into(), id) - } - - fn find_type_in_scope(&mut self, pos: Pos, id: Result) -> ty::Id { - self.find_type(pos, self.ci.file, self.ci.file, self.ci.parent, id) - } - fn find_type_as_value( &mut self, pos: Pos, - file: Module, parent: impl Into, - id: Result, + id: impl Into, ctx: Ctx, ) -> Option { - 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::Global(global) => self.gen_global(global), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), @@ -5579,21 +5526,29 @@ impl<'a> Codegen<'a> { &mut self, pos: Pos, from_file: Module, - file: Module, - parent: ty::Id, - id: Result, + parent: impl Into, + id: impl Into, ) -> 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) { 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) { self.on_reuse(ty); ty } else { - let f = &self.files[file.index()]; + let f = &self.files[file]; let mut piter = parent; 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) - && 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]; } @@ -5620,11 +5575,11 @@ impl<'a> Codegen<'a> { }; }) else { return match id { - Ok(_) => { - debug_assert_eq!(from_file, file); + DeclId::Ident(id) => { + debug_assert_eq!(from_file, file, "{}", f.ident_str(id)); self.error_low(file, pos, "somehow this was not found") } - Err("main") => self.error_low( + DeclId::Name("main") => self.error_low( from_file, pos, format_args!( @@ -5634,7 +5589,7 @@ impl<'a> Codegen<'a> { f.path ), ), - Err(name) => self.error_low( + DeclId::Name(name) => self.error_low( from_file, pos, format_args!("undefined indentifier: {name}"), @@ -5648,21 +5603,19 @@ impl<'a> Codegen<'a> { } else { let (is_ct, ty) = left .find_pattern_path(name, right, |right, is_ct| { - ( - is_ct, - if is_ct && !matches!(right, Expr::Closure { .. }) { - self.tys - .ins - .consts - .push(ConstData { ast: ExprRef::new(expr), name, file, parent }) - .into() - } else { - self.parse_ty( - TyScope { file, parent, name: Some(name), alloc_const: true }, - right, - ) - }, - ) + let ty = if is_ct && !matches!(right, Expr::Closure { .. }) { + self.tys + .ins + .consts + .push(ConstData { ast: ExprRef::new(expr), name, file, parent }) + .into() + } else { + self.parse_ty( + TyScope { file, parent, name: Some(name), alloc_const: true }, + right, + ) + }; + (is_ct, ty) }) .unwrap_or_else(|_| unreachable!()); if let ty::Kind::Func(f) = ty.expand() @@ -5715,11 +5668,11 @@ impl<'a> Codegen<'a> { self.tys.make_opt(base) } 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 } 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::Slice { size: None, item, .. } => { @@ -5732,8 +5685,9 @@ impl<'a> Codegen<'a> { } Expr::Slice { size, item, .. } => { let ty = self.parse_ty(sc.anon(), item); - let len = size - .map_or(ArrayLen::MAX, |expr| self.eval_const(sc.file, expr, ty::Id::U32) as _); + let len = size.map_or(ArrayLen::MAX, |expr| { + self.eval_const(sc.file, sc.parent, expr, ty::Id::U32) as _ + }); self.tys.make_array(ty, len) } Expr::Struct { pos, fields, packed, captured, .. } => self.parse_base_ty( @@ -5786,8 +5740,7 @@ impl<'a> Codegen<'a> { sig: 'b: { let arg_base = self.tys.tmp.args.len(); for arg in args { - let sym = - parser::find_symbol(&self.files[sc.file.index()].symbols, arg.id); + let sym = parser::find_symbol(&self.files[sc.file].symbols, arg.id); if sym.flags & idfl::COMPTIME != 0 { self.tys.tmp.args.truncate(arg_base); break 'b None; @@ -5815,7 +5768,9 @@ impl<'a> Codegen<'a> { { 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 => { self.error_unhandled_ast(e, "bruh"); ty::Id::NEVER diff --git a/lang/src/ty.rs b/lang/src/ty.rs index afd14085..e382d20b 100644 --- a/lang/src/ty.rs +++ b/lang/src/ty.rs @@ -3,7 +3,7 @@ use { ctx_map, lexer::TokenKind, parser::{self, CommentOr, Expr, ExprRef, Pos}, - utils::{self, Ent, EntVec}, + utils::{self, Ent, EntSlice, EntVec}, Ident, }, alloc::{string::String, vec::Vec}, @@ -480,12 +480,12 @@ impl Default for Kind { pub struct Display<'a> { tys: &'a Types, - files: &'a [parser::Ast], + files: &'a EntSlice, ty: Id, } 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, ty: Id) -> Self { Self { tys, files, ty } } @@ -500,7 +500,7 @@ impl core::fmt::Display for Display<'_> { match TK::from_ty(self.ty) { TK::Module(idx) => { f.write_str("@use(\"")?; - self.files[idx.index()].path.fmt(f)?; + self.files[idx].path.fmt(f)?; f.write_str(")[")?; idx.fmt(f)?; f.write_str("]") @@ -532,7 +532,7 @@ impl core::fmt::Display for Display<'_> { } f.write_str("}") } else { - let file = &self.files[record.file.index()]; + let file = &self.files[record.file]; f.write_str(file.ident_str(record.name)) } } @@ -554,14 +554,14 @@ impl core::fmt::Display for Display<'_> { } f.write_str("}") } else { - let file = &self.files[record.file.index()]; + let file = &self.files[record.file]; f.write_str(file.ident_str(record.name)) } } TK::Enum(idx) => { let enm = &self.tys.ins.enums[idx]; 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)) } TK::Func(idx) => { @@ -570,7 +570,7 @@ impl core::fmt::Display for Display<'_> { } TK::Global(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(" (global)") } @@ -586,7 +586,7 @@ impl core::fmt::Display for Display<'_> { } TK::Const(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(" (const)") } @@ -1029,9 +1029,9 @@ impl Types { self.struct_fields(s).iter().position(|f| f.name == name) } - pub fn find_union_field(&self, u: Union, name: &str) -> Option { + pub fn find_union_field(&self, u: Union, name: &str) -> Option<(usize, &StructField)> { 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) { @@ -1053,7 +1053,7 @@ impl Types { 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() { Kind::Struct(s) => &*self.ins.structs[s], Kind::Enum(e) => &*self.ins.enums[e], diff --git a/lang/src/utils.rs b/lang/src/utils.rs index 40da23f4..3f069a29 100644 --- a/lang/src/utils.rs +++ b/lang/src/utils.rs @@ -559,6 +559,26 @@ pub trait Ent: Copy { fn index(self) -> usize; } +#[repr(transparent)] +pub struct EntSlice { + k: PhantomData, + data: [T], +} + +impl<'a, K: Ent, T> From<&'a [T]> for &'a EntSlice { + fn from(value: &'a [T]) -> Self { + unsafe { core::mem::transmute(value) } + } +} + +impl core::ops::Index for EntSlice { + type Output = T; + + fn index(&self, index: K) -> &Self::Output { + &self.data[index.index()] + } +} + pub struct EntVec { data: ::alloc::vec::Vec, k: PhantomData,