Dividing function into template and instance, rmoving cumbersome options

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-02 15:51:12 +01:00
parent c5d5301b7b
commit 71ba2c2486
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
4 changed files with 241 additions and 142 deletions

View file

@ -273,7 +273,7 @@ impl Backend for HbvmBackend {
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
let sig = tys.ins.funcs[id].sig.unwrap();
let sig = tys.ins.funcs[id].sig;
debug_assert!(self.code.is_empty());

View file

@ -272,6 +272,10 @@ impl Ident {
self.0 & ((1 << Self::LEN_BITS) - 1)
}
pub fn is_type(self) -> bool {
ty::Builtin::try_from(self) == Ok(ty::Builtin::TYPE)
}
pub fn is_empty(self) -> bool {
self.len() == 0
}

View file

@ -16,7 +16,7 @@ use {
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,
StructField, SymKey, TemplateData, Tuple, TypeBase, TypeIns, Types, UnionData,
},
utils::{BitSet, EntSlice, Vc},
Ident,
@ -2782,7 +2782,7 @@ impl<'a> Codegen<'a> {
let fuc = self.tys.ins.funcs.push(FuncData {
file,
sig: Some(Sig { args: Tuple::empty(), ret }),
sig: Sig { args: Tuple::empty(), ret },
..Default::default()
});
@ -2894,8 +2894,8 @@ impl<'a> Codegen<'a> {
fn make_func_reachable(&mut self, func: ty::Func) {
let state_slot = self.ct.active() as usize;
let fuc = &mut self.tys.ins.funcs[func];
if fuc.comp_state[state_slot] == CompState::Dead {
fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _);
if CompState::from(fuc.comp_state[state_slot]) == CompState::Dead {
fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _).into();
self.tys.tasks.push(Some(FTask { file: fuc.file, id: func, ct: self.ct.active() }));
}
}
@ -4231,12 +4231,7 @@ impl<'a> Codegen<'a> {
}
ref e => {
let ty = self.parse_ty(
TyScope {
file: self.ci.file,
parent: self.ci.parent,
name: None,
alloc_const: false,
},
TyScope { file: self.ci.file, parent: self.ci.parent, ..Default::default() },
e,
);
Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, ty))
@ -4327,6 +4322,7 @@ impl<'a> Codegen<'a> {
| ty::Kind::Slice(_)
| ty::Kind::Opt(_)
| ty::Kind::Func(_)
| ty::Kind::Template(_)
| ty::Kind::Global(_)
| ty::Kind::Const(_)) => self.error(
pos,
@ -4432,21 +4428,16 @@ impl<'a> Codegen<'a> {
ref e => (self.ty(e), None),
};
let ty::Kind::Func(mut fu) = ty.expand() else {
self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
let Some(fu) = self.compute_signature(ty, func.pos(), args) else {
return Value::NEVER;
};
let Some(sig) = self.compute_signature(&mut fu, func.pos(), args) else {
return Value::NEVER;
};
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, sig, .. } = self.tys.ins.funcs[fu];
let ast = &self.files[file];
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
inline |= sig.ret == ty::Id::TYPE;
let arg_count = args.len() + caller.is_some() as usize;
if arg_count != cargs.len() {
self.error(
@ -4803,79 +4794,90 @@ impl<'a> Codegen<'a> {
}
}
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];
fn compute_signature(&mut self, func: ty::Id, pos: Pos, args: &[Expr]) -> Option<ty::Func> {
let template = match func.expand() {
ty::Kind::Func(f) => return Some(f),
ty::Kind::Template(t) => t,
_ => {
self.error(pos, fa!("compiler cant (yet) call '{}'", self.ty_display(func)));
return None;
}
};
let TemplateData { file, expr, parent, name, is_inline, .. } =
self.tys.ins.templates[template];
let fast = &self.files[file];
let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else {
let &Expr::Closure { pos, args: cargs, ret, .. } = expr.get(fast) else {
unreachable!();
};
Some(if let Some(sig) = sig {
sig
} else {
let arg_base = self.tys.tmp.args.len();
let arg_base = self.tys.tmp.args.len();
let base = self.ci.scope.vars.len();
for (arg, carg) in args.iter().zip(cargs) {
let ty = self.ty_in(file, parent, &carg.ty);
let base = self.ci.scope.vars.len();
for (arg, carg) in args.iter().zip(cargs) {
let ty = self.ty_in(file, parent, &carg.ty);
self.tys.tmp.args.push(ty);
let sym = parser::find_symbol(&fast.symbols, carg.id);
let ty = if sym.flags & idfl::COMPTIME == 0 {
// FIXME: could fuck us
continue;
} else {
if ty != ty::Id::TYPE {
self.error(
arg.pos(),
fa!(
"arbitrary comptime types are not supported yet \
self.tys.tmp.args.push(ty);
let sym = parser::find_symbol(&fast.symbols, carg.id);
let ty = if sym.flags & idfl::COMPTIME == 0 {
// FIXME: could fuck us
continue;
} else {
if ty != ty::Id::TYPE {
self.error(
arg.pos(),
fa!(
"arbitrary comptime types are not supported yet \
(expected '{}' got '{}')",
self.ty_display(ty::Id::TYPE),
self.ty_display(ty)
),
);
return None;
}
let ty = self.ty(arg);
self.tys.tmp.args.push(ty);
ty
};
self.ci.scope.vars.push(Variable::new(
carg.id,
ty::Id::TYPE,
false,
self.ci.nodes.new_const(ty::Id::TYPE, ty),
&mut self.ci.nodes,
));
}
let Some(args) = self.tys.pack_args(arg_base) else {
self.error(pos, "function instance has too many arguments");
return None;
self.ty_display(ty::Id::TYPE),
self.ty_display(ty)
),
);
return None;
}
let ty = self.ty(arg);
self.tys.tmp.args.push(ty);
ty
};
let ret = self.ty_in(file, parent, ret);
self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes));
self.ci.scope.vars.push(Variable::new(
carg.id,
ty::Id::TYPE,
false,
self.ci.nodes.new_const(ty::Id::TYPE, ty),
&mut self.ci.nodes,
));
}
let sym = SymKey::FuncInst(*func, args);
let ct = |ins: &mut TypeIns| {
let fuc = ins.funcs[*func];
debug_assert!(fuc.comp_state.iter().all(|&s| s == CompState::default()));
ins.funcs
.push(FuncData { base: Some(*func), sig: Some(Sig { args, ret }), ..fuc })
.into()
};
let ty::Kind::Func(f) =
self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand()
else {
unreachable!()
};
*func = f;
let Some(args) = self.tys.pack_args(arg_base) else {
self.error(pos, "function instance has too many arguments");
return None;
};
let ret = self.ty_in(file, parent, ret);
Sig { args, ret }
})
self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes));
let sym = SymKey::Type(parent, pos, args);
let ct = |ins: &mut TypeIns| {
ins.funcs
.push(FuncData {
file,
parent,
name,
pos,
expr,
sig: Sig { args, ret },
is_inline,
is_generic: true,
comp_state: Default::default(),
})
.into()
};
let ty::Kind::Func(f) = self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand()
else {
unreachable!()
};
Some(f)
}
fn assign_pattern(&mut self, pat: &Expr, mut right: Value) {
@ -5032,8 +5034,8 @@ impl<'a> Codegen<'a> {
debug_assert_eq!(func.file, file);
let cct = self.ct.active();
debug_assert_eq!(cct, ct);
func.comp_state[cct as usize] = CompState::Compiled;
let sig = func.sig.expect("to emmit only concrete functions");
func.comp_state[cct as usize] = CompState::Compiled.into();
let sig = func.sig;
let ast = &self.files[file];
let expr = func.expr.get(ast);
@ -5198,7 +5200,7 @@ impl<'a> Codegen<'a> {
}
fn ty_in(&mut self, file: Module, parent: ty::Id, expr: &Expr) -> ty::Id {
self.parse_ty(TyScope { file, parent, name: None, alloc_const: true }, expr)
self.parse_ty(TyScope { file, parent, alloc_const: true, ..Default::default() }, expr)
}
fn ty_display(&self, ty: ty::Id) -> ty::Display {
@ -5495,10 +5497,10 @@ impl<'a> Codegen<'a> {
let state_slot = self.ct.active() as usize;
if let ty::Kind::Func(id) = existing.expand()
&& let func = &mut self.tys.ins.funcs[id]
&& let CompState::Queued(idx) = func.comp_state[state_slot]
&& let CompState::Queued(idx) = func.comp_state[state_slot].into()
&& idx < self.tys.tasks.len()
{
func.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len());
func.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len()).into();
let task = self.tys.tasks[idx].take();
self.tys.tasks.push(task);
}
@ -5643,9 +5645,9 @@ impl<'a> Codegen<'a> {
{
ty
} else {
let (is_ct, ty) = left
let ty = left
.find_pattern_path(name, right, |right, is_ct| {
let ty = if is_ct && !matches!(right, Expr::Closure { .. }) {
if is_ct && !matches!(right, Expr::Closure { .. }) {
self.tys
.ins
.consts
@ -5653,23 +5655,23 @@ impl<'a> Codegen<'a> {
.into()
} else {
self.parse_ty(
TyScope { file, parent, name: Some(name), alloc_const: true },
TyScope {
file,
parent,
name: Some(name),
alloc_const: true,
is_ct,
},
right,
)
};
(is_ct, ty)
}
})
.unwrap_or_else(|_| unreachable!());
if let ty::Kind::Func(f) = ty.expand()
&& is_ct
{
self.tys.ins.funcs[f].is_inline = true;
}
self.tys.syms.insert(SymKey::Decl(parent, name), ty, &self.tys.ins);
ty
};
if let Err(proper_case) = self.tys.case(ty)(f.ident_str(name)) {
if let Err(proper_case) = self.tys.case(ty, self.files)(f.ident_str(name)) {
self.warn_low(
from_file,
pos,
@ -5775,35 +5777,53 @@ impl<'a> Codegen<'a> {
|s, base| s.ins.unions.push(UnionData { base, ..Default::default() }),
),
Expr::Closure { pos, args, ret, .. } if let Some(name) = sc.name => {
let func = FuncData {
file: sc.file,
parent: sc.parent,
name,
sig: 'b: {
let arg_base = self.tys.tmp.args.len();
for arg in args {
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;
}
let ty = self.parse_ty(sc.anon(), &arg.ty);
self.tys.tmp.args.push(ty);
let sig = 'b: {
let arg_base = self.tys.tmp.args.len();
for arg in args {
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;
}
let ty = self.parse_ty(sc.anon(), &arg.ty);
self.tys.tmp.args.push(ty);
}
let Some(args) = self.tys.pack_args(arg_base) else {
return self.error_low(sc.file, pos, "function has too many argumnets");
};
let ret = self.parse_ty(sc.anon(), ret);
let Some(args) = self.tys.pack_args(arg_base) else {
return self.error_low(sc.file, pos, "function has too many argumnets");
};
let ret = self.parse_ty(sc.anon(), ret);
Some(Sig { args, ret })
},
expr: ExprRef::new(expr),
returns_type: matches!(ret, &Expr::Ident { id, .. } if ty::Builtin::try_from(id) == Ok(ty::Builtin::TYPE)),
..Default::default()
Some(Sig { args, ret })
};
//let returns_type = matches!(ret, &Expr::Ident { id, .. } if );
self.tys.ins.funcs.push(func).into()
match sig {
Some(sig) => {
let func = FuncData {
file: sc.file,
parent: sc.parent,
name,
pos,
sig,
expr: ExprRef::new(expr),
is_inline: sc.is_ct,
is_generic: false,
comp_state: Default::default(),
};
self.tys.ins.funcs.push(func).into()
}
None => {
let template = TemplateData {
file: sc.file,
parent: sc.parent,
name,
expr: ExprRef::new(expr),
is_inline: sc.is_ct,
};
self.tys.ins.templates.push(template).into()
}
}
}
_ if sc.alloc_const
&& let Some(name) = sc.name =>
@ -5839,7 +5859,7 @@ impl<'a> Codegen<'a> {
}
let captured = self.tys.pack_args(captures_start).expect("TODO");
let sym = SymKey::Type(sc.file, pos, captured);
let sym = SymKey::Type(sc.parent, pos, captured);
if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) {
return ty;
}
@ -5871,17 +5891,18 @@ impl<'a> Codegen<'a> {
}
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
struct TyScope {
file: Module,
parent: ty::Id,
name: Option<Ident>,
alloc_const: bool,
is_ct: bool,
}
impl TyScope {
fn anon(self) -> Self {
Self { name: None, ..self }
Self { name: None, is_ct: false, ..self }
}
}

View file

@ -119,29 +119,32 @@ impl crate::ctx_map::CtxEntry for Id {
Kind::Struct(s) => {
let st = &ctx.structs[s];
debug_assert_ne!(st.pos, Pos::MAX);
SymKey::Type(st.file, st.pos, st.captured)
SymKey::Type(st.parent, st.pos, st.captured)
}
Kind::Enum(e) => {
let en = &ctx.enums[e];
debug_assert_ne!(en.pos, Pos::MAX);
SymKey::Type(en.file, en.pos, en.captured)
SymKey::Type(en.parent, en.pos, en.captured)
}
Kind::Union(e) => {
let en = &ctx.unions[e];
debug_assert_ne!(en.pos, Pos::MAX);
SymKey::Type(en.file, en.pos, en.captured)
SymKey::Type(en.parent, en.pos, en.captured)
}
Kind::Ptr(p) => SymKey::Pointer(&ctx.ptrs[p]),
Kind::Opt(p) => SymKey::Optional(&ctx.opts[p]),
Kind::Func(f) => {
let fc = &ctx.funcs[f];
if let Some(base) = fc.base {
// TODO: merge base and sig
SymKey::FuncInst(base, fc.sig.unwrap().args)
if fc.is_generic {
SymKey::Type(fc.parent, fc.pos, fc.sig.args)
} else {
SymKey::Decl(fc.parent, fc.name)
}
}
Kind::Template(t) => {
let tc = &ctx.templates[t];
SymKey::Decl(tc.parent, tc.name)
}
Kind::Global(g) => {
let gb = &ctx.globals[g];
SymKey::Decl(gb.file.into(), gb.name)
@ -271,7 +274,11 @@ impl Id {
Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg,
Kind::Struct(_) | Kind::Union(_) if tys.size_of(*self) == 0 => Loc::Reg,
Kind::Struct(_) | Kind::Union(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
c @ (Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_)) => {
c @ (Kind::Func(_)
| Kind::Global(_)
| Kind::Module(_)
| Kind::Const(_)
| Kind::Template(_)) => {
unreachable!("{c:?}")
}
}
@ -439,6 +446,7 @@ type_kind! {
Slice,
Opt,
Func,
Template,
Global,
Module,
Const,
@ -568,6 +576,10 @@ impl core::fmt::Display for Display<'_> {
f.write_str("fn")?;
idx.fmt(f)
}
TK::Template(idx) => {
f.write_str("fn")?;
idx.fmt(f)
}
TK::Global(idx) => {
let global = &self.tys.ins.globals[idx];
let file = &self.files[global.file];
@ -598,30 +610,71 @@ impl core::fmt::Display for Display<'_> {
pub enum SymKey<'a> {
Pointer(&'a PtrData),
Optional(&'a OptData),
Type(Module, Pos, Tuple),
FuncInst(Func, Tuple),
Type(Id, Pos, Tuple),
Decl(Id, Ident),
Array(&'a ArrayData),
Constant(&'a ConstData),
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
pub struct Sig {
pub args: Tuple,
pub ret: Id,
}
pub struct TemplateData {
pub file: Module,
pub parent: Id,
pub name: Ident,
pub expr: ExprRef,
pub is_inline: bool,
}
#[derive(Default, Clone, Copy)]
pub struct FuncData {
pub file: Module,
pub parent: Id,
pub name: Ident,
pub base: Option<Func>,
pub pos: Pos,
pub expr: ExprRef,
pub sig: Option<Sig>,
pub sig: Sig,
pub is_inline: bool,
pub returns_type: bool,
pub comp_state: [CompState; 2],
pub is_generic: bool,
pub comp_state: [PackedCompState; 2],
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct PackedCompState(u16);
impl Default for PackedCompState {
fn default() -> Self {
CompState::default().into()
}
}
impl PackedCompState {
const COMPILED: u16 = u16::MAX - 1;
const DEAD: u16 = u16::MAX;
}
impl From<PackedCompState> for CompState {
fn from(value: PackedCompState) -> Self {
match value.0 {
PackedCompState::DEAD => CompState::Dead,
PackedCompState::COMPILED => CompState::Compiled,
v => CompState::Queued(v as _),
}
}
}
impl From<CompState> for PackedCompState {
fn from(value: CompState) -> Self {
Self(match value {
CompState::Dead => Self::DEAD,
CompState::Queued(v) => v.try_into().unwrap(),
CompState::Compiled => Self::COMPILED,
})
}
}
#[derive(Default, PartialEq, Eq, Clone, Copy)]
@ -774,6 +827,7 @@ pub struct TypeIns {
pub struct_fields: Vec<StructField>,
pub enum_fields: Vec<EnumField>,
pub funcs: EntVec<Func, FuncData>,
pub templates: EntVec<Template, TemplateData>,
pub globals: EntVec<Global, GlobalData>,
pub consts: EntVec<Const, ConstData>,
pub structs: EntVec<Struct, StructData>,
@ -812,7 +866,11 @@ pub struct Types {
}
impl Types {
pub fn case(&self, ty: Id) -> fn(&str) -> Result<(), &'static str> {
pub fn case(
&self,
ty: Id,
files: &EntSlice<Module, parser::Ast>,
) -> fn(&str) -> Result<(), &'static str> {
match ty.expand() {
Kind::NEVER => |_| Ok(()),
Kind::Enum(_)
@ -822,8 +880,23 @@ impl Types {
| Kind::Ptr(_)
| Kind::Slice(_)
| Kind::Opt(_) => utils::is_pascal_case,
Kind::Func(f) if self.ins.funcs[f].returns_type => utils::is_pascal_case,
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => utils::is_snake_case,
Kind::Func(f)
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
self.ins.funcs[f].expr.get(&files[self.ins.funcs[f].file])
&& id.is_type() =>
{
utils::is_pascal_case
}
Kind::Template(f)
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
self.ins.templates[f].expr.get(&files[self.ins.templates[f].file])
&& id.is_type() =>
{
utils::is_pascal_case
}
Kind::Func(_) | Kind::Template(_) | Kind::Global(_) | Kind::Module(_) => {
utils::is_snake_case
}
Kind::Const(_) => utils::is_screaming_case,
}
}
@ -1063,6 +1136,7 @@ impl Types {
| Kind::Slice(_)
| Kind::Opt(_)
| Kind::Func(_)
| Kind::Template(_)
| Kind::Global(_)
| Kind::Module(_)
| Kind::Const(_) => return None,