Locked in type model

This commit is contained in:
2026-10-08 07:28:51 +00:00
parent 2b612d19ed
commit 316a2fcd75
13 changed files with 1707 additions and 1358 deletions
+102
View File
@@ -0,0 +1,102 @@
//! Calls of fns, natives and proto links
use super::*;
impl<'a> Emitter<'a> {
/// A call from `place`. The callee's cell tells which code runs, and the
/// callee is its own env. A callee that is not a fn throws
pub(super) fn call(&mut self, res: &InferResult, place: Place, instr: &RegInstr, out: &mut String) {
let arg_types: Vec<Type> = instr.args.iter().map(|&a| res.val_types[a].clone()).collect();
let operands: Vec<(String, Rep)> = (instr.args.iter().zip(&arg_types))
.map(|(a, ty)| (format!("v{a}"), self.rep(ty)))
.collect();
let dst = (instr.dsts[0], self.rep(&res.val_types[instr.dsts[0]]));
self.dispatch(&operands[0].0, &arg_types[0], "jsrt_type_error();", out, |e, member, callee, rep| {
let Type::Obj(cell) = member else {
return None;
};
let mut arg_types = arg_types.clone();
let mut operands = operands.clone();
arg_types[0] = member.clone();
operands[0] = (callee.into(), rep);
let (call, ret) = e.call_code(cell.code()?, place, &arg_types, &operands);
Some(e.call_result(instr.op, &call, &ret, &operands[THIS_ARG as usize], dst))
});
}
/// The statement that runs `call`, which gives a value of type `ret`, and
/// puts the call's result in `dst` (its value, and its rep). `new` gives
/// what the constructor returns if that is an object, else the new object
/// itself, `this` (see infer)
pub(super) fn call_result(&self, op: OpCode, call: &str, ret: &Type, this: &(String, Rep), dst: (usize, Rep)) -> String {
let (dst, dst_rep) = (format!("v{}", dst.0), dst.1);
let ret_rep = self.rep(ret);
let members = ret.members();
let objects = members.iter().filter(|m| matches!(m, Type::Obj(_))).count();
let this = self.conv(&this.0, this.1, dst_rep);
match op {
_ if *ret == Type::Unknown => format!("{call};"),
OpCode::CallConstructor if objects == 0 => format!("{call}; {dst} = {this};"),
OpCode::CallConstructor if objects < members.len() => {
let is_object = match self.tagged("r", ret_rep) {
Some(a) => format!("__any_is_object({a})"),
None => format!("!{}", self.nullish("r", ret)),
};
let value = self.conv("r", ret_rep, dst_rep);
format!("{{ {} r = {call}; {dst} = {is_object} ? {value} : {this}; }}", self.c_type(ret_rep))
}
_ => format!("{dst} = {};", self.conv(call, ret_rep, dst_rep)),
}
}
/// The C call of `code` with these operands (the callee, `this`, then the
/// args, each with its rep) whose types are `arg_types`, and the type it
/// returns
pub(super) fn call_code(&mut self, code: Code, place: Place, arg_types: &[Type], operands: &[(String, Rep)]) -> (String, Type) {
// An operand as a value of rep `to`. One that the call does not pass is
// undefined
let operand = |e: &Self, i: usize, to: Rep| match operands.get(i) {
Some((value, rep)) => e.conv(value, *rep, to),
None => e.conv("(undefined_t){0}", Rep::Undefined, to),
};
match code {
Code::Fn(fn_id) => {
let w = self.cache.find(fn_id, place, arg_types, self.fns);
self.use_walk(w);
let walk = &self.cache.walks[w];
let args: Vec<String> = (walk.req.arg_types.iter().enumerate())
.map(|(i, param)| operand(self, i, self.rep(param)))
.collect();
let ret = walk.result.as_ref().unwrap().ret_type.clone();
(format!("{}({})", self.fn_name(w), args.join(", ")), ret)
}
// A native whose args cannot be of its params' kinds throws
Code::Native(id) if native::ret_type(id, &arg_types[FIRST_ARG as usize..]) == Type::Unknown => {
("jsrt_type_error()".into(), Type::Unknown)
}
Code::Native(id) => {
let native = &NATIVES[id];
let args: Vec<String> = (native.args.iter().enumerate())
.map(|(i, param)| operand(self, FIRST_ARG as usize + i, self.rep(param)))
.collect();
(format!("{}({})", native.name, args.join(", ")), native.ret.clone())
}
// Keeps the prototype where field reads on primitives find it
Code::ProtoLink(kind) => {
let value = operand(self, FIRST_ARG as usize, self.rep(&self.cache.protos[kind as usize]));
(format!("({} = {value}, (undefined_t){{0}})", proto_global(kind)), Type::Undefined)
}
}
}
}