From 7e381b4082727c79b310008e04002c44e2fe0586 Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Mon, 28 Aug 2023 20:00:12 -0400 Subject: [PATCH] Allow custom opaque functions --- crates/core/src/lib.rs | 21 +- crates/frontend/Cargo.toml | 1 + crates/frontend/src/translate.rs | 34 +- crates/interp/src/lib.rs | 167 ++++-- crates/validate/src/lib.rs | 882 ++++++++++++++++--------------- crates/web/src/lib.rs | 41 +- 6 files changed, 649 insertions(+), 497 deletions(-) diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 5004798..84ddb52 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -76,15 +76,28 @@ pub struct Function { pub body: Box<[Instr]>, } -/// Wrapper for a `Function` that knows how to resolve its `id::Function`s. -pub trait FuncNode { - fn def(&self) -> &Function; +pub trait Refs<'a> { + type Opaque; - fn get(&self, id: id::Function) -> Option + fn get(&self, id: id::Function) -> Option> where Self: Sized; } +pub enum Node<'a, O, T: Refs<'a, Opaque = O>> { + Transparent { + refs: T, + def: &'a Function, + }, + Opaque { + generics: &'a [EnumSet], + types: &'a [Ty], + params: &'a [id::Ty], + ret: id::Ty, + def: O, + }, +} + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug)] pub struct Instr { diff --git a/crates/frontend/Cargo.toml b/crates/frontend/Cargo.toml index b505c07..daa9075 100644 --- a/crates/frontend/Cargo.toml +++ b/crates/frontend/Cargo.toml @@ -10,6 +10,7 @@ indexmap = "2" lalrpop-util = "0.19" logos = "0.13" rose = { path = "../core" } +rose-interp = { path = "../interp" } thiserror = "1" [build-dependencies] diff --git a/crates/frontend/src/translate.rs b/crates/frontend/src/translate.rs index ed0a4a6..da5a118 100644 --- a/crates/frontend/src/translate.rs +++ b/crates/frontend/src/translate.rs @@ -113,19 +113,26 @@ pub struct Module<'input> { funcs: IndexMap<&'input str, rose::Function>, } -#[derive(Clone, Copy, Debug)] -pub struct FuncRef<'input, 'a> { - m: &'a Module<'input>, - id: id::Function, +pub enum Opaque {} + +impl rose_interp::Opaque for Opaque { + fn call( + &self, + _: &IndexSet, + _: &[id::Ty], + _: &[rose_interp::Val], + ) -> rose_interp::Val { + match *self {} + } } -impl<'input, 'a> rose::FuncNode for FuncRef<'input, 'a> { - fn def(&self) -> &rose::Function { - &self.m.funcs[self.id.function()] - } +impl<'input, 'a> rose::Refs<'a> for &'a Module<'input> { + type Opaque = Opaque; - fn get(&self, id: id::Function) -> Option { - Some(Self { m: self.m, id }) + fn get(&self, id: id::Function) -> Option> { + self.funcs + .get_index(id.function()) + .map(|(_, def)| ir::Node::Transparent { refs: *self, def }) } } @@ -134,12 +141,9 @@ impl Module<'_> { self.types.get(name) } - pub fn get_func(&self, name: &str) -> Option { + pub fn get_func(&self, name: &str) -> Option> { let i = self.funcs.get_index_of(name)?; - Some(FuncRef { - m: self, - id: id::function(i), - }) + ir::Refs::get(&self, id::function(i)) } } diff --git a/crates/interp/src/lib.rs b/crates/interp/src/lib.rs index 866aa2b..9f4fea8 100644 --- a/crates/interp/src/lib.rs +++ b/crates/interp/src/lib.rs @@ -1,5 +1,5 @@ use indexmap::IndexSet; -use rose::{id, Binop, Expr, FuncNode, Ty, Unop}; +use rose::{id, Binop, Expr, Function, Node, Refs, Ty, Unop}; use std::{cell::Cell, rc::Rc}; #[cfg(feature = "serde")] @@ -129,24 +129,35 @@ fn resolve(typemap: &mut IndexSet, generics: &[id::Ty], types: &[id::Ty], ty id::ty(i) } -struct Interpreter<'a, F: FuncNode> { - typemap: &'a mut IndexSet, - f: &'a F, // reference instead of value because otherwise borrow checker complains in `fn block` +pub trait Opaque { + fn call(&self, types: &IndexSet, generics: &[id::Ty], args: &[Val]) -> Val; +} + +struct Interpreter<'a, 'b, O: Opaque, T: Refs<'a, Opaque = O>> { + typemap: &'b mut IndexSet, + refs: T, + def: &'a Function, types: Vec, vars: Vec>, } -impl<'a, F: FuncNode> Interpreter<'a, F> { - fn new(typemap: &'a mut IndexSet, f: &'a F, generics: &'a [id::Ty]) -> Self { +impl<'a, 'b, O: Opaque, T: Refs<'a, Opaque = O>> Interpreter<'a, 'b, O, T> { + fn new( + typemap: &'b mut IndexSet, + refs: T, + def: &'a Function, + generics: &'b [id::Ty], + ) -> Self { let mut types = vec![]; - for ty in f.def().types.iter() { + for ty in def.types.iter() { types.push(resolve(typemap, generics, &types, ty)); } Self { typemap, - f, + refs, + def, types, - vars: vec![None; f.def().vars.len()], + vars: vec![None; def.vars.len()], } } @@ -229,10 +240,10 @@ impl<'a, F: FuncNode> Interpreter<'a, F> { Expr::Call { id, generics, args } => { let resolved: Vec = generics.iter().map(|id| self.types[id.ty()]).collect(); let vals = args.iter().map(|id| self.vars[id.var()].clone().unwrap()); - call(self.f.get(*id).unwrap(), self.typemap, &resolved, vals) + call(self.refs.get(*id).unwrap(), self.typemap, &resolved, vals) } Expr::For { arg, body, ret } => { - let n = match self.typemap[self.types[self.f.def().vars[arg.var()].ty()].ty()] { + let n = match self.typemap[self.types[self.def.vars[arg.var()].ty()].ty()] { Ty::Fin { size } => size, _ => unreachable!(), }; @@ -279,30 +290,44 @@ impl<'a, F: FuncNode> Interpreter<'a, F> { } /// Assumes `generics` and `arg` are valid. -fn call( - f: impl FuncNode, - types: &mut IndexSet, - generics: &[id::Ty], +fn call<'a, 'b, O: Opaque, T: Refs<'a, Opaque = O>>( + f: Node<'a, O, T>, + types: &'b mut IndexSet, + generics: &'b [id::Ty], args: impl Iterator, ) -> Val { - let mut interp = Interpreter::new(types, &f, generics); - for (var, arg) in f.def().params.iter().zip(args) { - interp.vars[var.var()] = Some(arg.clone()); - } - for instr in f.def().body.iter() { - interp.vars[instr.var.var()] = Some(interp.expr(&instr.expr)); + match f { + Node::Transparent { refs, def } => { + let mut interp = Interpreter::new(types, refs, def, generics); + for (var, arg) in def.params.iter().zip(args) { + interp.vars[var.var()] = Some(arg.clone()); + } + for instr in def.body.iter() { + interp.vars[instr.var.var()] = Some(interp.expr(&instr.expr)); + } + interp.vars[def.ret.var()].as_ref().unwrap().clone() + } + Node::Opaque { + generics: _, + types: _, + params: _, + ret: _, + def, + } => { + let vals: Box<[Val]> = args.collect(); + def.call(types, generics, &vals) + } } - interp.vars[f.def().ret.var()].as_ref().unwrap().clone() } #[derive(Debug, thiserror::Error)] pub enum Error {} /// Guaranteed not to panic if `f` is valid. -pub fn interp( - f: impl FuncNode, +pub fn interp<'a, O: Opaque, T: Refs<'a, Opaque = O>>( + f: Node<'a, O, T>, mut types: IndexSet, - generics: &[id::Ty], + generics: &'a [id::Ty], args: impl Iterator, ) -> Result { // TODO: check that `generics` and `arg` are valid @@ -314,21 +339,56 @@ mod tests { use super::*; use rose::{Function, Instr}; - #[derive(Clone, Copy, Debug)] + type CustomRef<'a> = &'a dyn Fn(&IndexSet, &[id::Ty], &[Val]) -> Val; + type CustomBox = Box, &[id::Ty], &[Val]) -> Val>; + + struct Custom<'a> { + f: CustomRef<'a>, + } + + impl Opaque for Custom<'_> { + fn call(&self, types: &IndexSet, generics: &[id::Ty], args: &[Val]) -> Val { + (self.f)(types, generics, args) + } + } + struct FuncInSlice<'a> { + custom: &'a [CustomBox], funcs: &'a [Function], id: id::Function, } - impl FuncNode for FuncInSlice<'_> { - fn def(&self) -> &Function { - &self.funcs[self.id.function()] + impl<'a> Refs<'a> for FuncInSlice<'a> { + type Opaque = Custom<'a>; + + fn get(&self, id: id::Function) -> Option, Self>> { + if id.function() < self.id.function() { + node(self.custom, self.funcs, id) + } else { + None + } } + } - fn get(&self, id: id::Function) -> Option { - Some(Self { - funcs: self.funcs, - id, + fn node<'a>( + custom: &'a [CustomBox], + funcs: &'a [Function], + id: id::Function, + ) -> Option, FuncInSlice<'a>>> { + let n = custom.len(); + let i = id.function(); + if i < n { + Some(Node::Opaque { + generics: &[], + types: &[], + params: &[], + ret: id::ty(0), + def: Custom { f: &custom[i] }, + }) + } else { + funcs.get(i - n).map(|def| Node::Transparent { + refs: FuncInSlice { custom, funcs, id }, + def, }) } } @@ -352,10 +412,7 @@ mod tests { .into(), }]; let answer = interp( - FuncInSlice { - funcs: &funcs, - id: id::function(0), - }, + node(&[], &funcs, id::function(0)).unwrap(), IndexSet::new(), &[], [val_f64(2.), val_f64(2.)].into_iter(), @@ -407,10 +464,7 @@ mod tests { }, ]; let answer = interp( - FuncInSlice { - funcs: &funcs, - id: id::function(1), - }, + node(&[], &funcs, id::function(1)).unwrap(), IndexSet::new(), &[], [].into_iter(), @@ -418,4 +472,35 @@ mod tests { .unwrap(); assert_eq!(answer, val_f64(1764.)); } + + #[test] + fn test_custom() { + let custom: [CustomBox; 1] = [Box::new(|_, _, args| { + Val::F64(Cell::new(args[0].f64().powf(args[1].f64()))) + })]; + let funcs = [Function { + generics: [].into(), + types: [Ty::F64].into(), + vars: [id::ty(0), id::ty(0), id::ty(0)].into(), + params: [id::var(0), id::var(1)].into(), + ret: id::var(2), + body: [Instr { + var: id::var(2), + expr: Expr::Call { + id: id::function(0), + generics: [].into(), + args: [id::var(0), id::var(1)].into(), + }, + }] + .into(), + }]; + let answer = interp( + node(&custom, &funcs, id::function(1)).unwrap(), + IndexSet::new(), + &[], + [val_f64(std::f64::consts::E), val_f64(std::f64::consts::PI)].into_iter(), + ) + .unwrap(); + assert_eq!(answer, val_f64(23.140692632779263)); + } } diff --git a/crates/validate/src/lib.rs b/crates/validate/src/lib.rs index 66580b2..794d650 100644 --- a/crates/validate/src/lib.rs +++ b/crates/validate/src/lib.rs @@ -1,6 +1,6 @@ use enumset::EnumSet; use indexmap::IndexMap; -use rose::{id, Binop, Constraint, Expr, FuncNode, Function, Instr, Ty, Unop}; +use rose::{id, Binop, Constraint, Expr, Function, Instr, Refs, Ty, Unop}; #[derive(Debug, Eq, thiserror::Error, PartialEq)] pub enum InstrError { @@ -284,9 +284,9 @@ enum Scope { Expired, } -struct Validator<'a, F: FuncNode> { - node: &'a F, - f: &'a Function, +struct Validator<'a, O, T: Refs<'a, Opaque = O>> { + refs: T, + def: &'a Function, constraints: IndexMap>, /// indices from `self.f.types` into `self.constraints` types: Vec, @@ -294,7 +294,7 @@ struct Validator<'a, F: FuncNode> { vars: Vec, } -impl Validator<'_, F> { +impl<'a, O, T: Refs<'a, Opaque = O>> Validator<'a, O, T> { fn ty(&self, t: id::Ty) -> &Ty { let (ty, _) = self.constraints.get_index(t.ty()).unwrap(); ty @@ -306,7 +306,7 @@ impl Validator<'_, F> { } fn var_ty_id(&self, x: id::Var) -> id::Ty { - self.types[self.f.vars[x.var()].ty()] + self.types[self.def.vars[x.var()].ty()] } fn get_ty_id(&self, x: id::Var) -> Option { @@ -539,15 +539,43 @@ impl Validator<'_, F> { check(*c == Ty::Bool && a == b && t == a, SelectType) } - Expr::Call { id, generics, args } => match self.node.get(*id) { + Expr::Call { id, generics, args } => match self.refs.get(*id) { Some(node) => { - let g = node.def(); - if generics.len() != g.generics.len() { + struct Stuff<'a> { + gens: &'a [EnumSet], + typs: &'a [Ty], + params: Box<[id::Ty]>, + ret: id::Ty, + } + let Stuff { + gens, + typs, + params, + ret, + } = match node { + rose::Node::Transparent { refs: _, def } => Stuff { + gens: &def.generics, + typs: &def.types, + params: def.params.iter().map(|x| def.vars[x.var()]).collect(), + ret: def.vars[def.ret.var()], + }, + rose::Node::Opaque { + generics, + types, + params, + ret, + def: _, + } => Stuff { + gens: generics, + typs: types, + params: params.into(), + ret, + }, + }; + if generics.len() != gens.len() { return Err(CallGenericsCount); } - for (i, (expected, actual)) in - g.generics.iter().zip(generics.iter()).enumerate() - { + for (i, (expected, actual)) in gens.iter().zip(generics.iter()).enumerate() { let id = id::generic(i); match self.types.get(actual.ty()) { Some(generic) => check( @@ -558,23 +586,20 @@ impl Validator<'_, F> { } } let mut types = vec![]; - for typ in g.types.iter() { + for typ in typs.iter() { let i = self.resolve(generics, &types, typ); types.push(i); } - if args.len() != g.params.len() { + if args.len() != params.len() { return Err(CallArgsCount); } - for (i, (expected, &actual)) in g.params.iter().zip(args.iter()).enumerate() { + for (i, (expected, &actual)) in params.iter().zip(args.iter()).enumerate() { match self.get_ty_id(actual) { - Some(arg) => check( - arg == types[g.vars[expected.var()].ty()].unwrap(), - CallArg(i), - )?, + Some(arg) => check(arg == types[expected.ty()].unwrap(), CallArg(i))?, None => return Err(CallInvalidArg(i)), } } - check(t == types[g.vars[g.ret.var()].ty()].unwrap(), CallRet) + check(t == types[ret.ty()].unwrap(), CallRet) } None => Err(CallFunction), }, @@ -737,9 +762,7 @@ pub enum Error { } /// Validate `f`, assuming that all of its referenced functions are valid. -pub fn validate(f: impl FuncNode) -> Result<(), Error> { - let def = f.def(); - +pub fn validate<'a, O, T: Refs<'a, Opaque = O>>(refs: T, def: &'a Function) -> Result<(), Error> { for (i, constrs) in def.generics.iter().enumerate() { // for now we have no compatible constraints if (constrs.contains(Constraint::Index) && !constrs.contains(Constraint::Value)) @@ -846,8 +869,8 @@ pub fn validate(f: impl FuncNode) -> Result<(), Error> { } let mut validator = Validator { - node: &f, - f: def, + refs, + def, constraints, types, vars, @@ -867,32 +890,39 @@ pub fn validate(f: impl FuncNode) -> Result<(), Error> { #[cfg(test)] mod tests { use super::*; + use rose::Node; struct FuncInSlice<'a> { funcs: &'a [Function], id: id::Function, } - impl FuncNode for FuncInSlice<'_> { - fn def(&self) -> &Function { - &self.funcs[self.id.function()] - } + impl<'a> Refs<'a> for FuncInSlice<'a> { + type Opaque = (); - fn get(&self, id: id::Function) -> Option { + fn get(&self, id: id::Function) -> Option> { if id.function() < self.id.function() { - Some(Self { - funcs: self.funcs, - id, - }) + node(self.funcs, id) } else { None } } } + fn node(funcs: &[Function], id: id::Function) -> Option> { + funcs.get(id.function()).map(|def| Node::Transparent { + refs: FuncInSlice { funcs, id }, + def, + }) + } + + fn validate_in_slice(funcs: &[Function], id: id::Function) -> Result<(), Error> { + validate(FuncInSlice { funcs, id }, &funcs[id.function()]) + } + fn example_constraints(constraints: EnumSet) { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [constraints].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -904,8 +934,8 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::ImpossibleConstraints(id::generic(0)))); } @@ -931,8 +961,8 @@ mod tests { #[test] fn test_invalid_generic() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Generic { id: id::generic(0) }].into(), vars: [id::ty(0)].into(), @@ -940,14 +970,14 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidGeneric(id::ty(0)))); } fn example_kind(kind: Constraint) { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -962,8 +992,8 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidKind(id::ty(1)))); } @@ -979,8 +1009,8 @@ mod tests { #[test] fn test_scope_id() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -995,15 +1025,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidRef(id::ty(1)))); } #[test] fn test_ref_scope() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1032,15 +1062,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidScope(id::ty(2)))); } #[test] fn test_inner() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1069,15 +1099,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidInner(id::ty(2)))); } #[test] fn test_nested_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1123,15 +1153,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InnerNotValue(id::ty(5)))); } #[test] fn test_invalid_index() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::F64, @@ -1147,15 +1177,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidIndex(id::ty(1)))); } #[test] fn test_invalid_elem() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1171,15 +1201,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidElem(id::ty(1)))); } #[test] fn test_not_index() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::F64, @@ -1194,15 +1224,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::NotIndex(id::ty(1)))); } #[test] fn test_elem_not_value() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::empty()].into(), types: [ Ty::Fin { size: 1 }, @@ -1218,15 +1248,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::ElemNotValue(id::ty(2)))); } #[test] fn test_invalid_member() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Tuple { @@ -1240,15 +1270,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidMember(id::ty(0), id::member(0)))); } #[test] fn test_member_not_value() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::empty()].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1262,15 +1292,15 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::MemberNotValue(id::ty(1), id::member(0)))); } #[test] fn test_invalid_var() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [].into(), vars: [id::ty(0)].into(), @@ -1282,15 +1312,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidVar(id::var(0)))); } #[test] fn test_invalid_param() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1302,15 +1332,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidParam(0))); } #[test] fn test_duplicate_param() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0), id::ty(0)].into(), @@ -1322,15 +1352,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::DuplicateParam(1))); } #[test] fn test_invalid_ret() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [].into(), vars: [].into(), @@ -1338,8 +1368,8 @@ mod tests { ret: id::var(0), body: [].into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, Err(Error::InvalidRet)); } @@ -1353,8 +1383,8 @@ mod tests { #[test] fn test_invalid_var() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1366,15 +1396,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, InvalidVar)); } #[test] fn test_redeclare() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1386,15 +1416,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, Redeclare)); } #[test] fn test_unit() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::F64].into(), vars: [id::ty(0)].into(), @@ -1406,15 +1436,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, UnitType)); } #[test] fn test_bool() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1426,14 +1456,14 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, BoolType)); } #[test] fn test_f64() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1445,15 +1475,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, F64Type)); } #[test] fn test_fin_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1465,15 +1495,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, FinType)); } #[test] fn test_fin_too_big() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Fin { size: 2 }].into(), vars: [id::ty(0)].into(), @@ -1485,15 +1515,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, FinTooBig)); } #[test] fn test_array_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1505,15 +1535,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ArrayType)); } #[test] fn test_array_index() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Unit, @@ -1533,15 +1563,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ArrayIndex)); } #[test] fn test_array_size() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Fin { size: 1 }, @@ -1560,15 +1590,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ArraySize)); } #[test] fn test_array_invalid_elem() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Fin { size: 1 }, @@ -1589,15 +1619,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ArrayInvalidElem(0))); } #[test] fn test_array_elem_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1619,15 +1649,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ArrayElemType(0))); } #[test] fn test_tuple_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -1639,15 +1669,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, TupleType)); } #[test] fn test_tuple_size() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1665,15 +1695,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, TupleSize)); } #[test] fn test_tuple_invalid_member() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1693,15 +1723,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, TupleInvalidMember(id::member(0)))); } #[test] fn test_tuple_member_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1722,15 +1752,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, TupleMemberType(id::member(0)))); } #[test] fn test_index_invalid_array() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1752,15 +1782,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, IndexInvalidArray)); } #[test] fn test_index_invalid_index() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1782,15 +1812,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, IndexInvalidIndex)); } #[test] fn test_index_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1813,15 +1843,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, IndexType)); } #[test] fn test_member_invalid_tuple() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1842,15 +1872,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, MemberInvalidTuple)); } #[test] fn test_member_not_tuple() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0), id::ty(0)].into(), @@ -1865,15 +1895,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, MemberNotTuple)); } #[test] fn test_member_invalid_member() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Tuple { members: [].into() }].into(), vars: [id::ty(0), id::ty(0)].into(), @@ -1888,15 +1918,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, MemberInvalidMember)); } #[test] fn test_member_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -1918,15 +1948,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, MemberType)); } #[test] fn test_slice_invalid_array() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1948,15 +1978,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SliceInvalidArray)); } #[test] fn test_slice_invalid_index() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -1978,15 +2008,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SliceInvalidIndex)); } #[test] fn test_slice_array_not_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -2008,15 +2038,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SliceArrayNotRef)); } #[test] fn test_slice_not_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index, EnumSet::empty()].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -2043,15 +2073,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SliceNotRef)); } #[test] fn test_slice_scope() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [ Constraint::Value | Constraint::Index, EnumSet::empty(), @@ -2088,15 +2118,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SliceScope)); } #[test] fn test_slice_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index, EnumSet::empty()].into(), types: [ Ty::Unit, @@ -2128,15 +2158,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SliceType)); } #[test] fn test_unary_invalid_arg() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Bool].into(), vars: [id::ty(0)].into(), @@ -2151,14 +2181,14 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, UnaryInvalidArg)); } fn example_unary_type(types: Box<[Ty]>, op: Unop) { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types, vars: [id::ty(0), id::ty(1)].into(), @@ -2173,8 +2203,8 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, UnaryType)); } @@ -2200,8 +2230,8 @@ mod tests { #[test] fn test_binary_invalid_left() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Bool].into(), vars: [id::ty(0)].into(), @@ -2217,15 +2247,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, BinaryInvalidLeft)); } #[test] fn test_binary_invalid_right() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Bool].into(), vars: [id::ty(0), id::ty(0)].into(), @@ -2241,14 +2271,14 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, BinaryInvalidRight)); } fn example_binary_type(types: Box<[Ty]>, op: Binop) { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types, vars: [id::ty(0), id::ty(1), id::ty(2)].into(), @@ -2264,8 +2294,8 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, BinaryType)); } @@ -2315,8 +2345,8 @@ mod tests { } fn example_select_invalid(cond: usize, then: usize, els: usize, e: InstrError) { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Bool].into(), vars: [id::ty(0), id::ty(0)].into(), @@ -2332,8 +2362,8 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, e)); } @@ -2354,8 +2384,8 @@ mod tests { #[test] fn test_select_type_cond() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0), id::ty(0), id::ty(0)].into(), @@ -2371,15 +2401,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SelectType)); } #[test] fn test_select_type_match() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Bool, Ty::Unit].into(), vars: [id::ty(0), id::ty(0), id::ty(1), id::ty(0)].into(), @@ -2395,15 +2425,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SelectType)); } #[test] fn test_select_type_ret() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Bool, Ty::Unit].into(), vars: [id::ty(0), id::ty(0), id::ty(0), id::ty(1)].into(), @@ -2419,15 +2449,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, SelectType)); } #[test] fn test_call_function() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [Ty::Unit].into(), vars: [id::ty(0)].into(), @@ -2443,15 +2473,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, CallFunction)); } #[test] fn test_call_generics_count() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [EnumSet::empty()].into(), types: [Ty::Unit].into(), @@ -2481,15 +2511,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallGenericsCount)); } #[test] fn test_call_invalid_generic() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [EnumSet::only(Constraint::Index)].into(), types: [Ty::Generic { id: id::generic(0) }].into(), @@ -2515,15 +2545,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallInvalidGeneric(id::generic(0)))); } #[test] fn test_call_generic() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [EnumSet::only(Constraint::Index)].into(), types: [Ty::Generic { id: id::generic(0) }].into(), @@ -2549,15 +2579,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallGeneric(id::generic(0)))); } #[test] fn test_call_args_count() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [].into(), types: [Ty::Unit].into(), @@ -2583,15 +2613,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallArgsCount)); } #[test] fn test_call_invalid_arg() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [].into(), types: [Ty::Unit].into(), @@ -2617,15 +2647,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallInvalidArg(0))); } #[test] fn test_call_arg() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [].into(), types: [Ty::Unit].into(), @@ -2651,15 +2681,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallArg(0))); } #[test] fn test_call_ret() { - let res = validate(FuncInSlice { - funcs: &[ + let res = validate_in_slice( + &[ Function { generics: [].into(), types: [Ty::Unit].into(), @@ -2685,15 +2715,15 @@ mod tests { .into(), }, ], - id: id::function(1), - }); + id::function(1), + ); assert_eq!(res, err(0, CallRet)); } #[test] fn test_for_invalid_arg() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -2716,15 +2746,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ForInvalidArg)); } #[test] fn test_for_body() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -2751,15 +2781,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ForBody(0, Box::new(UnitType)))); } #[test] fn test_for_invalid_ret() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Generic { id: id::generic(0) }, @@ -2782,15 +2812,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ForInvalidRet)); } #[test] fn test_for_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [Constraint::Value | Constraint::Index].into(), types: [ Ty::Unit, @@ -2818,15 +2848,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ForType)); } #[test] fn test_read_invalid_var() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -2854,15 +2884,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadInvalidVar)); } #[test] fn test_read_invalid_arg() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -2890,15 +2920,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadInvalidArg)); } #[test] fn test_read_not_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -2926,15 +2956,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadNotRef)); } #[test] fn test_read_not_scope() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Read)].into(), types: [ Ty::Unit, @@ -2959,15 +2989,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadNotScope)); } #[test] fn test_read_scope_kind() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -2995,15 +3025,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadScopeKind)); } #[test] fn test_read_scope_id() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3031,15 +3061,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadScopeId)); } #[test] fn test_read_inner() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3068,15 +3098,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadInner)); } #[test] fn test_read_body() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3108,15 +3138,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadBody(0, Box::new(Redeclare)))); } #[test] fn test_read_invalid_ret() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3144,15 +3174,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadInvalidRet)); } #[test] fn test_read_escape() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3180,15 +3210,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadEscape)); } #[test] fn test_read_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3217,15 +3247,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, ReadType)); } #[test] fn test_accum_invalid_shape() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3253,15 +3283,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumInvalidShape)); } #[test] fn test_accum_invalid_arg() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3289,15 +3319,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumInvalidArg)); } #[test] fn test_accum_not_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3325,15 +3355,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumNotRef)); } #[test] fn test_accum_not_scope() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Accum)].into(), types: [ Ty::Unit, @@ -3358,15 +3388,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumNotScope)); } #[test] fn test_accum_scope_kind() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3394,15 +3424,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumScopeKind)); } #[test] fn test_accum_scope_id() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3430,15 +3460,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumScopeId)); } #[test] fn test_accum_inner() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3467,15 +3497,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumInner)); } #[test] fn test_accum_body() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3507,15 +3537,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumBody(0, Box::new(Redeclare)))); } #[test] fn test_accum_invalid_ret() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3543,15 +3573,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumInvalidRet)); } #[test] fn test_accum_escape() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3579,15 +3609,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumEscape)); } #[test] fn test_accum_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [].into(), types: [ Ty::Unit, @@ -3616,15 +3646,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AccumType)); } #[test] fn test_ask_invalid_var() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Read)].into(), types: [ Ty::F64, @@ -3644,15 +3674,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AskInvalidVar)); } #[test] fn test_ask_not_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Read)].into(), types: [ Ty::F64, @@ -3672,15 +3702,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AskNotRef)); } #[test] fn test_ask_read() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::empty()].into(), types: [ Ty::F64, @@ -3700,15 +3730,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AskRead)); } #[test] fn test_ask_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Read)].into(), types: [ Ty::F64, @@ -3728,15 +3758,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AskType)); } #[test] fn add_invalid_accum() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Accum)].into(), types: [ Ty::Unit, @@ -3760,15 +3790,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AddInvalidAccum)); } #[test] fn add_invalid_addend() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Accum)].into(), types: [ Ty::Unit, @@ -3792,15 +3822,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AddInvalidAddend)); } #[test] fn add_not_ref() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Accum)].into(), types: [ Ty::Unit, @@ -3824,15 +3854,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AddNotRef)); } #[test] fn add_accum() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::empty()].into(), types: [ Ty::Unit, @@ -3856,15 +3886,15 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AddAccum)); } #[test] fn add_type() { - let res = validate(FuncInSlice { - funcs: &[Function { + let res = validate_in_slice( + &[Function { generics: [EnumSet::only(Constraint::Accum)].into(), types: [ Ty::Unit, @@ -3888,8 +3918,8 @@ mod tests { }] .into(), }], - id: id::function(0), - }); + id::function(0), + ); assert_eq!(res, err(0, AddType)); } } diff --git a/crates/web/src/lib.rs b/crates/web/src/lib.rs index fee11c3..6177a5b 100644 --- a/crates/web/src/lib.rs +++ b/crates/web/src/lib.rs @@ -40,6 +40,19 @@ pub fn layouts() -> Result { ]) } +enum Opaque {} + +impl rose_interp::Opaque for Opaque { + fn call( + &self, + _: &IndexSet, + _: &[id::Ty], + _: &[rose_interp::Val], + ) -> rose_interp::Val { + match *self {} + } +} + #[derive(Debug)] struct Inner { /// The functions this one depends on; see `rose::FuncNode`. @@ -54,6 +67,14 @@ struct Inner { structs: Box<[Option>]>, } +impl<'a> rose::Refs<'a> for &'a Inner { + type Opaque = Opaque; + + fn get(&self, id: id::Function) -> Option> { + self.deps.get(id.function()).map(|f| f.node()) + } +} + /// A node in a reference-counted acyclic digraph of functions. #[wasm_bindgen] #[derive(Clone, Debug)] @@ -61,18 +82,16 @@ pub struct Func { rc: Rc, } -impl<'a> rose::FuncNode for &'a Func { - fn def(&self) -> &rose::Function { - &self.rc.as_ref().def - } - - fn get(&self, id: id::Function) -> Option { - self.rc.as_ref().deps.get(id.function()) - } -} - #[wasm_bindgen] impl Func { + fn node(&self) -> rose::Node { + let inner = self.rc.as_ref(); + rose::Node::Transparent { + refs: inner, + def: &inner.def, + } + } + /// Return the ID of this function's return type. #[wasm_bindgen(js_name = "retType")] pub fn ret_type(&self) -> usize { @@ -105,7 +124,7 @@ impl Func { /// /// The return value is Serde-converted from `rose_interp::Val`. pub fn interp(&self) -> Result { - let ret = rose_interp::interp(self, IndexSet::new(), &[], [].into_iter())?; + let ret = rose_interp::interp(self.node(), IndexSet::new(), &[], [].into_iter())?; Ok(to_js_value(&ret)?) } }