implementing struct method for non generic contexts
This commit is contained in:
parent
58ee5c0a56
commit
24a3aed360
321
lang/src/son.rs
321
lang/src/son.rs
|
@ -27,6 +27,7 @@ use {
|
||||||
},
|
},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
hbbytecode::DisasmError,
|
hbbytecode::DisasmError,
|
||||||
|
std::intrinsics::vtable_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
const VOID: Nid = 0;
|
const VOID: Nid = 0;
|
||||||
|
@ -2954,125 +2955,10 @@ impl<'a> Codegen<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Expr::Field { target, name, pos } => {
|
Expr::Field { target, name, pos } => {
|
||||||
let mut vtarget = self.raw_expr(target)?;
|
self.gen_field(ctx, target, pos, name)?.ok().or_else(|| {
|
||||||
self.strip_var(&mut vtarget);
|
self.error(pos, "method can not be used like this");
|
||||||
self.implicit_unwrap(pos, &mut vtarget);
|
Value::NEVER
|
||||||
let tty = vtarget.ty;
|
})
|
||||||
|
|
||||||
match self.tys.base_of(tty).unwrap_or(tty).expand() {
|
|
||||||
ty::Kind::Module(m) => {
|
|
||||||
match self.find_type(pos, self.ci.file, m, Err(name)).expand() {
|
|
||||||
ty::Kind::NEVER => Value::NEVER,
|
|
||||||
ty::Kind::Global(global) => self.gen_global(global),
|
|
||||||
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
|
||||||
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::Kind::Enum(e) => {
|
|
||||||
let intrnd = self.tys.names.project(name);
|
|
||||||
self.gen_enum_variant(pos, e, intrnd)
|
|
||||||
}
|
|
||||||
ty::Kind::Struct(s) => {
|
|
||||||
let Struct { 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(scope))], ..
|
|
||||||
} = ast.get(&self.files[file.index()])
|
|
||||||
&& let ty = self.find_type_low(
|
|
||||||
pos,
|
|
||||||
self.ci.file,
|
|
||||||
file,
|
|
||||||
Some((s.into(), scope)),
|
|
||||||
Err(name),
|
|
||||||
)
|
|
||||||
&& ty != ty::Id::NEVER
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
} else {
|
|
||||||
let field_list = self
|
|
||||||
.tys
|
|
||||||
.struct_fields(s)
|
|
||||||
.iter()
|
|
||||||
.map(|f| self.tys.names.ident_str(f.name))
|
|
||||||
.intersperse("', '")
|
|
||||||
.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::TYPE => match ty::Id::from(match self.ci.nodes[vtarget.id].kind {
|
|
||||||
Kind::CInt { value } => value as u64,
|
|
||||||
_ => unreachable!(),
|
|
||||||
})
|
|
||||||
.expand()
|
|
||||||
{
|
|
||||||
ty::Kind::Struct(s) => {
|
|
||||||
let Struct { ast, file, .. } = self.tys.ins.structs[s];
|
|
||||||
let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } =
|
|
||||||
ast.get(&self.files[file.index()])
|
|
||||||
else {
|
|
||||||
self.error(
|
|
||||||
pos,
|
|
||||||
fa!("'{}' has not declarations", self.ty_display(s.into())),
|
|
||||||
);
|
|
||||||
return Value::NEVER;
|
|
||||||
};
|
|
||||||
|
|
||||||
match self
|
|
||||||
.find_type_low(
|
|
||||||
pos,
|
|
||||||
self.ci.file,
|
|
||||||
file,
|
|
||||||
Some((s.into(), scope)),
|
|
||||||
Err(name),
|
|
||||||
)
|
|
||||||
.expand()
|
|
||||||
{
|
|
||||||
ty::Kind::NEVER => Value::NEVER,
|
|
||||||
ty::Kind::Global(global) => self.gen_global(global),
|
|
||||||
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
|
||||||
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::Kind::Module(m) => {
|
|
||||||
match self.find_type(pos, self.ci.file, m, Err(name)).expand() {
|
|
||||||
ty::Kind::NEVER => Value::NEVER,
|
|
||||||
ty::Kind::Global(global) => self.gen_global(global),
|
|
||||||
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
|
||||||
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty => {
|
|
||||||
self.error(
|
|
||||||
pos,
|
|
||||||
fa!(
|
|
||||||
"accesing scope on '{}' is not supported yet",
|
|
||||||
self.ty_display(ty.compress())
|
|
||||||
),
|
|
||||||
);
|
|
||||||
Value::NEVER
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.error(
|
|
||||||
pos,
|
|
||||||
fa!(
|
|
||||||
"the '{}' is not a struct, or pointer to one, or enum, \
|
|
||||||
fo field access does not make sense",
|
|
||||||
self.ty_display(tty)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
Value::NEVER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Expr::UnOp { op: TokenKind::Band, val, pos } => {
|
Expr::UnOp { op: TokenKind::Band, val, pos } => {
|
||||||
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
|
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
|
||||||
|
@ -4158,6 +4044,126 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gen_field(
|
||||||
|
&mut self,
|
||||||
|
ctx: Ctx,
|
||||||
|
target: &Expr,
|
||||||
|
pos: Pos,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<Result<Value, (ty::Id, Value)>> {
|
||||||
|
let mut vtarget = self.raw_expr(target)?;
|
||||||
|
self.strip_var(&mut vtarget);
|
||||||
|
self.implicit_unwrap(pos, &mut vtarget);
|
||||||
|
let tty = vtarget.ty;
|
||||||
|
|
||||||
|
match self.tys.base_of(tty).unwrap_or(tty).expand() {
|
||||||
|
ty::Kind::Module(m) => match self.find_type(pos, self.ci.file, m, Err(name)).expand() {
|
||||||
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
|
ty::Kind::Global(global) => self.gen_global(global),
|
||||||
|
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
||||||
|
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
|
||||||
|
},
|
||||||
|
ty::Kind::Enum(e) => {
|
||||||
|
let intrnd = self.tys.names.project(name);
|
||||||
|
self.gen_enum_variant(pos, e, intrnd)
|
||||||
|
}
|
||||||
|
ty::Kind::Struct(s) => {
|
||||||
|
let Struct { 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(scope))], .. } =
|
||||||
|
ast.get(&self.files[file.index()])
|
||||||
|
&& let ty = self.find_type_low(
|
||||||
|
pos,
|
||||||
|
self.ci.file,
|
||||||
|
file,
|
||||||
|
Some((s.into(), scope)),
|
||||||
|
Err(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::<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::TYPE => match ty::Id::from(match self.ci.nodes[vtarget.id].kind {
|
||||||
|
Kind::CInt { value } => value as u64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.expand()
|
||||||
|
{
|
||||||
|
ty::Kind::Struct(s) => {
|
||||||
|
let Struct { ast, file, .. } = self.tys.ins.structs[s];
|
||||||
|
let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } =
|
||||||
|
ast.get(&self.files[file.index()])
|
||||||
|
else {
|
||||||
|
self.error(
|
||||||
|
pos,
|
||||||
|
fa!("'{}' has not declarations", self.ty_display(s.into())),
|
||||||
|
);
|
||||||
|
return Value::NEVER.map(Ok);
|
||||||
|
};
|
||||||
|
|
||||||
|
match self
|
||||||
|
.find_type_low(pos, self.ci.file, file, Some((s.into(), scope)), Err(name))
|
||||||
|
.expand()
|
||||||
|
{
|
||||||
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
|
ty::Kind::Global(global) => self.gen_global(global),
|
||||||
|
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
||||||
|
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Kind::Module(m) => {
|
||||||
|
match self.find_type(pos, self.ci.file, m, Err(name)).expand() {
|
||||||
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
|
ty::Kind::Global(global) => self.gen_global(global),
|
||||||
|
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
||||||
|
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty => {
|
||||||
|
self.error(
|
||||||
|
pos,
|
||||||
|
fa!(
|
||||||
|
"accesing scope on '{}' is not supported yet",
|
||||||
|
self.ty_display(ty.compress())
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Value::NEVER
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.error(
|
||||||
|
pos,
|
||||||
|
fa!(
|
||||||
|
"the '{}' is not a struct, or pointer to one, or enum, \
|
||||||
|
fo field access does not make sense",
|
||||||
|
self.ty_display(tty)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Value::NEVER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
fn close_if(&mut self, lcntrl: Nid, rcntrl: Nid, mut then_scope: Scope) -> Option<Nid> {
|
fn close_if(&mut self, lcntrl: Nid, rcntrl: Nid, mut then_scope: Scope) -> Option<Nid> {
|
||||||
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
||||||
then_scope.clear(&mut self.ci.nodes);
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
|
@ -4231,12 +4237,25 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> {
|
fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> {
|
||||||
let mut ty = self.expr(func)?;
|
let (ty, mut caller) = match *func {
|
||||||
self.assert_ty(func.pos(), &mut ty, ty::Id::TYPE, "function");
|
Expr::Field { target, pos, name } => {
|
||||||
let ty = ty::Id::from(match self.ci.nodes[ty.id].kind {
|
match self.gen_field(Ctx::default(), target, pos, name)? {
|
||||||
Kind::CInt { value } => value as u64,
|
Ok(mut fexpr) => {
|
||||||
_ => unreachable!(),
|
self.assert_ty(func.pos(), &mut fexpr, ty::Id::TYPE, "function");
|
||||||
});
|
(
|
||||||
|
ty::Id::from(match self.ci.nodes[fexpr.id].kind {
|
||||||
|
Kind::CInt { value } => value as u64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err((ty, val)) => (ty, Some(val)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref e => (self.ty(e), None),
|
||||||
|
};
|
||||||
|
|
||||||
let ty::Kind::Func(mut fu) = ty.expand() else {
|
let ty::Kind::Func(mut fu) = ty.expand() else {
|
||||||
self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
|
self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
|
@ -4250,14 +4269,15 @@ impl<'a> Codegen<'a> {
|
||||||
let ast = &self.files[file.index()];
|
let ast = &self.files[file.index()];
|
||||||
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
|
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
|
||||||
|
|
||||||
if args.len() != cargs.len() {
|
let arg_count = args.len() + caller.is_some() as usize;
|
||||||
|
if arg_count != cargs.len() {
|
||||||
self.error(
|
self.error(
|
||||||
func.pos(),
|
func.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"expected {} function argumenr{}, got {}",
|
"expected {} function argumenr{}, got {}",
|
||||||
cargs.len(),
|
cargs.len(),
|
||||||
if cargs.len() == 1 { "" } else { "s" },
|
if cargs.len() == 1 { "" } else { "s" },
|
||||||
args.len()
|
arg_count
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4273,6 +4293,32 @@ impl<'a> Codegen<'a> {
|
||||||
if is_inline || inline {
|
if is_inline || inline {
|
||||||
let var_base = self.ci.scope.vars.len();
|
let var_base = self.ci.scope.vars.len();
|
||||||
let aclass_base = self.ci.scope.aclasses.len();
|
let aclass_base = self.ci.scope.aclasses.len();
|
||||||
|
|
||||||
|
if let Some(caller) = &mut caller
|
||||||
|
&& let (Some(Arg::Value(ty)), Some(carg)) = (tys.next(self.tys), cargs.next())
|
||||||
|
{
|
||||||
|
match (caller.ty.is_pointer(), ty.is_pointer()) {
|
||||||
|
(true, false) => {
|
||||||
|
caller.ty = self.tys.base_of(caller.ty).unwrap();
|
||||||
|
caller.ptr = true;
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
caller.ty = self.tys.make_ptr(caller.ty);
|
||||||
|
caller.ptr = false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assert_ty(func.pos(), caller, ty, "caller");
|
||||||
|
self.ci.scope.vars.push(Variable::new(
|
||||||
|
carg.id,
|
||||||
|
ty,
|
||||||
|
caller.ptr,
|
||||||
|
caller.id,
|
||||||
|
&mut self.ci.nodes,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
while let (Some(aty), Some(arg)) = (tys.next(self.tys), args.next()) {
|
while let (Some(aty), Some(arg)) = (tys.next(self.tys), args.next()) {
|
||||||
let carg = cargs.next().unwrap();
|
let carg = cargs.next().unwrap();
|
||||||
let var = match aty {
|
let var = match aty {
|
||||||
|
@ -4356,6 +4402,27 @@ impl<'a> Codegen<'a> {
|
||||||
self.make_func_reachable(fu);
|
self.make_func_reachable(fu);
|
||||||
let mut inps = Vc::from([NEVER]);
|
let mut inps = Vc::from([NEVER]);
|
||||||
let mut clobbered_aliases = BitSet::default();
|
let mut clobbered_aliases = BitSet::default();
|
||||||
|
|
||||||
|
if let Some(caller) = &mut caller
|
||||||
|
&& let (Some(Arg::Value(ty)), Some(carg)) = (tys.next(self.tys), cargs.next())
|
||||||
|
{
|
||||||
|
match (caller.ty.is_pointer(), ty.is_pointer()) {
|
||||||
|
(true, false) => {
|
||||||
|
caller.ty = self.tys.base_of(caller.ty).unwrap();
|
||||||
|
caller.ptr = true;
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
caller.ty = self.tys.make_ptr(caller.ty);
|
||||||
|
caller.ptr = false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.assert_ty(func.pos(), caller, ty, fa!("caller argument {}", carg.name));
|
||||||
|
self.add_clobbers(*caller, &mut clobbered_aliases);
|
||||||
|
self.ci.nodes.lock(caller.id);
|
||||||
|
inps.push(caller.id);
|
||||||
|
}
|
||||||
|
|
||||||
while let (Some(ty), Some(arg)) = (tys.next(self.tys), args.next()) {
|
while let (Some(ty), Some(arg)) = (tys.next(self.tys), args.next()) {
|
||||||
let carg = cargs.next().unwrap();
|
let carg = cargs.next().unwrap();
|
||||||
let Arg::Value(ty) = ty else { continue };
|
let Arg::Value(ty) = ty else { continue };
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
main:
|
||||||
|
LI64 r13, 1d
|
||||||
|
CP r1, r13
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 32
|
||||||
|
ret: 1
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue