M benches/basic.rs +83 -19
@@ 5,7 5,7 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
-
+use garnet::*;
/// Each iteration creates about 32 sLOC
fn gen_dumb_test_code(count: usize) -> String {
@@ 66,33 66,22 @@ end
buf
}
-fn criterion_benchmark(c: &mut Criterion) {
+fn bench_with_rust_backend(c: &mut Criterion) {
let code = gen_dumb_test_code(103);
let lines = code.lines().count();
- let name = format!("compile {}ish lines", lines);
+ let name = format!("compile {}ish lines to Rust", lines);
c.bench_function(&name, |b| {
- b.iter(|| {
- garnet::compile(
- "criterion.gt",
- black_box(&code),
- garnet::backend::Backend::Rust,
- )
- })
+ b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Rust))
});
let code = gen_dumb_test_code(103 * 8);
let lines = code.lines().count();
- let name = format!("compile {}ish lines", lines);
+ let name = format!("compile {}ish lines to Rust", lines);
c.bench_function(&name, |b| {
- b.iter(|| {
- garnet::compile(
- "criterion.gt",
- black_box(&code),
- garnet::backend::Backend::Rust,
- )
- })
+ b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Rust))
});
+ /*
let code = gen_dumb_test_code(103 * 16);
let lines = code.lines().count();
let name = format!("compile {}ish lines", lines);
@@ 105,7 94,82 @@ fn criterion_benchmark(c: &mut Criterion
)
})
});
+ */
+}
+
+fn bench_with_null_backend(c: &mut Criterion) {
+ let code = gen_dumb_test_code(103);
+ let lines = code.lines().count();
+ let name = format!("compile {}ish lines to nothing", lines);
+ c.bench_function(&name, |b| {
+ b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Null))
+ });
+
+ let code = gen_dumb_test_code(103 * 8);
+ let lines = code.lines().count();
+ let name = format!("compile {}ish lines to nothing", lines);
+ c.bench_function(&name, |b| {
+ b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Null))
+ });
+
+ let code = gen_dumb_test_code(103 * 16);
+ let lines = code.lines().count();
+ let name = format!("compile {}ish lines to nothing", lines);
+ c.bench_function(&name, |b| {
+ b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Rust))
+ });
}
-criterion_group!(benches, criterion_benchmark);
+fn bench_stages(c: &mut Criterion) {
+ let code = gen_dumb_test_code(103 * 8);
+ let lines = code.lines().count();
+ let name = format!("Parse {} lines", lines);
+ c.bench_function(&name, |b| {
+ b.iter(|| {
+ let mut parser = parser::Parser::new("criterion.gt", black_box(&code));
+ parser.parse()
+ })
+ });
+
+ let mut parser = parser::Parser::new("criterion.gt", black_box(&code));
+ let ast = parser.parse();
+
+ c.bench_function("lower and run passes", |b| {
+ b.iter(|| {
+ let hir = hir::lower(black_box(&ast));
+ passes::run_passes(hir)
+ })
+ });
+
+ let hir = hir::lower(black_box(&ast));
+ let hir = passes::run_passes(hir);
+
+ c.bench_function("typecheck and borrowcheck", |b| {
+ b.iter(|| {
+ let tck = &mut typeck::typecheck(black_box(&hir)).unwrap();
+ borrowck::borrowck(&hir, tck).unwrap();
+ })
+ });
+
+ let tck = &mut typeck::typecheck(black_box(&hir)).unwrap();
+ borrowck::borrowck(&hir, tck).unwrap();
+
+ c.bench_function("typechecked passes", |b| {
+ b.iter(|| {
+ passes::run_typechecked_passes(black_box(hir.clone()), black_box(tck));
+ })
+ });
+
+ let hir = passes::run_typechecked_passes(hir, tck);
+ c.bench_function("codegen", |b| {
+ b.iter(|| backend::output(backend::Backend::Rust, black_box(&hir), black_box(tck)))
+ });
+}
+
+criterion_group!(
+ benches,
+ //bench_with_rust_backend,
+ //bench_with_null_backend,
+ bench_stages
+);
criterion_main!(benches);
M src/ast.rs +7 -7
@@ 96,11 96,11 @@ pub struct IfCase {
#[derive(Debug, Clone, PartialEq)]
pub struct Signature {
/// Parameters
- pub params: Vec<(Sym, Type)>,
+ pub params: Arc<Vec<(Sym, Type)>>,
/// Return type
pub rettype: Type,
/// Type parameters
- pub typeparams: Vec<Type>,
+ pub typeparams: Arc<Vec<Type>>,
}
impl Signature {
@@ 108,8 108,8 @@ impl Signature {
pub fn to_type(&self) -> Type {
let paramtypes = self.params.iter().map(|(_nm, ty)| ty.clone()).collect();
Type::Func(
- paramtypes,
- Box::new(self.rettype.clone()),
+ Arc::new(paramtypes),
+ Arc::new(self.rettype.clone()),
self.typeparams.clone(),
)
}
@@ 150,14 150,14 @@ impl Signature {
let new_params = self
.params
.iter()
- .zip(params)
+ .zip(params.as_ref())
.map(|((nm, _t1), t2)| (*nm, t2.clone()))
.collect();
let new_rettype = rettype.clone();
let new_type_params = typeparams.clone();
Self {
- params: new_params,
- rettype: *new_rettype,
+ params: Arc::new(new_params),
+ rettype: new_rettype.as_ref().clone(),
typeparams: new_type_params,
}
}
M src/backend/rust.rs +4 -4
@@ 44,7 44,7 @@ fn compile_typename(t: &Type) -> Cow<'st
Named(s, types) if s == &Sym::new("Tuple") => {
trace!("Compiling tuple {:?}...", t);
let mut accm = String::from("(");
- for typ in types {
+ for typ in &**types {
accm += &compile_typename(typ);
accm += ", ";
}
@@ 68,7 68,7 @@ fn compile_typename(t: &Type) -> Cow<'st
}
*/
accm += "(";
- for p in params {
+ for p in &**params {
accm += &compile_typename(p);
accm += ", ";
}
@@ 149,7 149,7 @@ fn compile_typename(t: &Type) -> Cow<'st
/// Driver that turns a pile of Ir into Rust code.
pub(super) fn output(lir: &hir::Ir, tck: &Tck) -> Vec<u8> {
let mut output = Vec::new();
- for builtin in &*builtins::BUILTINS {
+ for builtin in &*builtins::all() {
output.extend(builtin.code[&backend::Backend::Rust].as_bytes());
}
for decl in lir.decls.iter() {
@@ 223,7 223,7 @@ fn compile_decl(w: &mut impl Write, decl
params.iter().map(|sym| (*sym.val()).clone()).collect();
let args = param_strings.join(", ");
writeln!(w, "pub enum {}<{}> {{ ", nstr, args)?;
- for (nm, ty) in body {
+ for (nm, ty) in &**body {
writeln!(w, " {} ({}),", nm, compile_typename(ty))?;
}
writeln!(w, "}}")?;
M src/bin/garnetfmt.rs +0 -1
@@ 39,7 39,6 @@ fn main() -> io::Result<()> {
// anything
let formatted_data = &formatted_src.into_inner();
let formatted_str = String::from_utf8_lossy(formatted_data);
- println!("{}", formatted_str);
let formatted_ast = {
let mut parser = parser::Parser::new(filename, &formatted_str);
parser.parse()
M src/builtins.rs +45 -49
@@ 6,8 6,6 @@
use std::collections::BTreeMap;
-use once_cell::sync::Lazy;
-
use crate::backend::Backend;
use crate::*;
@@ 22,8 20,6 @@ pub struct Builtin {
pub code: BTreeMap<Backend, String>,
}
-pub static BUILTINS: Lazy<Vec<Builtin>> = Lazy::new(Builtin::all);
-
impl Builtin {
/// Generate all appropriate methods for the given numeric type.
/// Right now we just stick em in the toplevel with constructed names,
@@ 108,99 104,99 @@ fn __{name}_to_u32(x: {name}) -> u32 {{
vec![
Builtin {
name: Sym::new(format!("__println_{name}")),
- sig: Type::Func(vec![ty.clone()], Box::new(Type::unit()), vec![]),
+ sig: Type::function(&vec![ty.clone()], &Type::unit(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, println)]),
},
Builtin {
name: Sym::new(format!("__band_{name}")),
- sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, band)]),
},
Builtin {
name: Sym::new(format!("__bor_{name}")),
- sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, bor)]),
},
Builtin {
name: Sym::new(format!("__bxor_{name}")),
- sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, bxor)]),
},
Builtin {
name: Sym::new(format!("__bnot_{name}")),
- sig: Type::Func(vec![ty.clone()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, bnot)]),
},
Builtin {
name: Sym::new(format!("__rshift_{name}")),
- sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, rshift)]),
},
Builtin {
name: Sym::new(format!("__lshift_{name}")),
- sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, lshift)]),
},
Builtin {
name: Sym::new(format!("__rol_{name}")),
- sig: Type::Func(vec![ty.clone(), Type::i32()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), Type::i32()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, rol)]),
},
Builtin {
name: Sym::new(format!("__ror_{name}")),
- sig: Type::Func(vec![ty.clone(), Type::i32()], Box::new(ty.clone()), vec![]),
+ sig: Type::function(&vec![ty.clone(), Type::i32()], &ty.clone(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, ror)]),
},
Builtin {
name: Sym::new(format!("__{name}_to_i32")),
- sig: Type::Func(vec![ty.clone()], Box::new(Type::i32()), vec![]),
+ sig: Type::function(&vec![ty.clone()], &Type::i32(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, cast_i32)]),
},
Builtin {
name: Sym::new(format!("__{name}_to_u32")),
- sig: Type::Func(vec![ty.clone()], Box::new(Type::u32()), vec![]),
+ sig: Type::function(&vec![ty.clone()], &Type::u32(), &vec![]),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, cast_u32)]),
},
]
}
- /// A function that returns all the compiler builtin info. Just
- /// use the `BUILTINS` global instead, this is basically here
- /// to initialize it.
- fn all() -> Vec<Builtin> {
- let rust_println = r#"fn __println(x: i32) {
+}
+/// A function that returns all the compiler builtin info. Just
+/// use the `BUILTINS` global instead, this is basically here
+/// to initialize it.
+pub fn all() -> Vec<Builtin> {
+ let rust_println = r#"fn __println(x: i32) {
println!("{}", x);
}"#;
- let rust_println_bool = r#"
+ let rust_println_bool = r#"
fn __println_bool(x: bool) {
println!("{}", x);
}"#;
- let mut funcs = vec![
- Builtin {
- name: Sym::new("__println"),
- sig: Type::Func(vec![Type::i32()], Box::new(Type::unit()), vec![]),
- code: BTreeMap::from([
- (Backend::Null, "".into()),
- (Backend::Rust, rust_println.into()),
- ]),
- },
- Builtin {
- name: Sym::new("__println_bool"),
- sig: Type::Func(vec![Type::bool()], Box::new(Type::unit()), vec![]),
- code: BTreeMap::from([
- (Backend::Null, "".into()),
- (Backend::Rust, rust_println_bool.into()),
- ]),
- },
- ];
- funcs.extend(Self::generate_numerics_for("i8", Type::i8()));
- funcs.extend(Self::generate_numerics_for("i16", Type::i16()));
- funcs.extend(Self::generate_numerics_for("i32", Type::i32()));
- funcs.extend(Self::generate_numerics_for("i64", Type::i64()));
- funcs.extend(Self::generate_numerics_for("u8", Type::u8()));
- funcs.extend(Self::generate_numerics_for("u16", Type::u16()));
- funcs.extend(Self::generate_numerics_for("u32", Type::u32()));
- funcs.extend(Self::generate_numerics_for("u64", Type::u64()));
- funcs
- }
+ let mut funcs = vec![
+ Builtin {
+ name: Sym::new("__println"),
+ sig: Type::function(&vec![Type::i32()], &Type::unit(), &vec![]),
+ code: BTreeMap::from([
+ (Backend::Null, "".into()),
+ (Backend::Rust, rust_println.into()),
+ ]),
+ },
+ Builtin {
+ name: Sym::new("__println_bool"),
+ sig: Type::function(&vec![Type::bool()], &Type::unit(), &vec![]),
+ code: BTreeMap::from([
+ (Backend::Null, "".into()),
+ (Backend::Rust, rust_println_bool.into()),
+ ]),
+ },
+ ];
+ funcs.extend(Builtin::generate_numerics_for("i8", Type::i8()));
+ funcs.extend(Builtin::generate_numerics_for("i16", Type::i16()));
+ funcs.extend(Builtin::generate_numerics_for("i32", Type::i32()));
+ funcs.extend(Builtin::generate_numerics_for("i64", Type::i64()));
+ funcs.extend(Builtin::generate_numerics_for("u8", Type::u8()));
+ funcs.extend(Builtin::generate_numerics_for("u16", Type::u16()));
+ funcs.extend(Builtin::generate_numerics_for("u32", Type::u32()));
+ funcs.extend(Builtin::generate_numerics_for("u64", Type::u64()));
+ funcs
}
M src/hir.rs +12 -11
@@ 768,10 768,10 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
let struct_signature = ts
.iter()
//.map(|(enumname, _enumval)| (*enumname, ty.clone()))
- .map(|(enumname, _enumval)| (*enumname, Type::Named(name, vec![])))
+ .map(|(enumname, _enumval)| (*enumname, Type::Named(name, Arc::new(vec![]))))
.collect();
// Enums cannot have type parameters, so this works.
- let init_type = Type::Struct(struct_signature, vec![]);
+ let init_type = Type::Struct(Arc::new(struct_signature), Arc::new(vec![]));
let new_constdef = Const {
name,
typ: init_type,
@@ 798,7 798,7 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
.map(|(variant_name, variant_type)| {
let paramname = Sym::new("x");
let signature = ast::Signature {
- params: vec![(paramname, variant_type.clone())],
+ params: Arc::new(vec![(paramname, variant_type.clone())]),
rettype: Type::Named(name, generics.clone()),
typeparams: generics.clone(),
};
@@ 822,15 822,15 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
// `fn(variant_type) name`
(
*variant_name,
- Type::Func(
- vec![variant_type.clone()],
- Box::new(Type::Named(name, generics.clone())),
- generics.clone(),
+ Type::function(
+ &[variant_type.clone()],
+ &Type::Named(name, generics.clone()),
+ &generics,
),
)
})
.collect();
- let struct_type = Type::Struct(struct_typebody, generics.clone());
+ let struct_type = Type::Struct(Arc::new(struct_typebody), generics.clone());
let new_constdef = Const {
name: name.to_owned(),
typ: struct_type,
@@ 843,9 843,10 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
other => {
let s = Sym::new("x");
trace!("Lowering params {:?}", params);
- let type_params: Vec<_> = params.iter().map(|s| Type::Generic(*s)).collect();
+ let type_params: Arc<Vec<_>> =
+ Arc::new(params.iter().map(|s| Type::Generic(*s)).collect());
let signature = ast::Signature {
- params: vec![(s, other.clone())],
+ params: Arc::new(vec![(s, other.clone())]),
rettype: Type::Named(name.to_owned(), type_params.clone()),
typeparams: type_params.clone(),
};
@@ 853,7 854,7 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
// in a type constructor
let body = vec![ExprNode::new(Expr::TypeCtor {
name,
- type_params,
+ type_params: type_params.to_vec(),
body: ExprNode::new(Expr::Var { name: s }),
})];
//println!("{} is {:#?}", variant_name, e);
M src/lib.rs +40 -28
@@ 12,7 12,7 @@ use once_cell::sync::Lazy;
mod ast;
pub mod backend;
-mod borrowck;
+pub mod borrowck;
mod builtins;
pub mod format;
pub mod hir;
@@ 74,26 74,26 @@ pub enum Type {
/// Never type, the type of an infinite loop
Never,
/// A C-like enum, and the integer values it corresponds to
- Enum(Vec<(Sym, i32)>),
+ Enum(Arc<Vec<(Sym, i32)>>),
/// A nominal type of some kind; may be built-in (like Tuple)
/// or user-defined.
- Named(Sym, Vec<Type>),
+ Named(Sym, Arc<Vec<Type>>),
/// A function pointer.
///
/// The contents are arg types, return types, type parameters
- Func(Vec<Type>, Box<Type>, Vec<Type>),
+ Func(Arc<Vec<Type>>, Arc<Type>, Arc<Vec<Type>>),
/// An anonymous struct. The vec is type parameters.
- Struct(BTreeMap<Sym, Type>, Vec<Type>),
+ Struct(Arc<BTreeMap<Sym, Type>>, Arc<Vec<Type>>),
/// Sum type.
///
/// Like structs, contains a list of type parameters.
- Sum(BTreeMap<Sym, Type>, Vec<Type>),
+ Sum(Arc<BTreeMap<Sym, Type>>, Arc<Vec<Type>>),
/// Arrays are just a type and a number.
- Array(Box<Type>, usize),
+ Array(Arc<Type>, usize),
/// A generic type parameter that has been given an explicit name.
Generic(Sym),
/// Unique borrow
- Uniq(Box<Type>),
+ Uniq(Arc<Type>),
}
impl Type {
@@ 112,32 112,32 @@ impl Type {
Type::Never => (),
Type::Enum(_ts) => (),
Type::Named(_, generics) => {
- for g in generics {
+ for g in &**generics {
helper(g, accm);
}
}
Type::Func(args, rettype, typeparams) => {
- for t in args {
+ for t in &**args {
helper(t, accm);
}
- for t in typeparams {
+ for t in &**typeparams {
helper(t, accm);
}
helper(rettype, accm)
}
Type::Struct(body, generics) => {
- for (_, ty) in body {
+ for (_, ty) in &**body {
helper(ty, accm);
}
- for g in generics {
+ for g in &**generics {
helper(g, accm);
}
}
Type::Sum(body, generics) => {
- for (_, ty) in body {
+ for (_, ty) in &**body {
helper(ty, accm);
}
- for g in generics {
+ for g in &**generics {
helper(g, accm);
}
}
@@ 238,22 238,30 @@ impl Type {
/// Shortcut for getting the type for Unit
pub fn unit() -> Self {
- Self::Named(Sym::new("Tuple"), vec![])
+ Self::Named(Sym::new("Tuple"), Arc::new(vec![]))
}
/// Shortcut for getting the type for Never
pub fn never() -> Self {
- Self::Named(Sym::new("Never"), vec![])
+ Self::Named(Sym::new("Never"), Arc::new(vec![]))
}
/// Create a Tuple with the given values
- pub fn tuple(args: Vec<Self>) -> Self {
+ pub fn tuple(args: Arc<Vec<Self>>) -> Self {
Self::Named(Sym::new("Tuple"), args)
}
/// Used in some tests
pub fn array(t: &Type, len: usize) -> Self {
- Self::Array(Box::new(t.clone()), len)
+ Self::Array(Arc::new(t.clone()), len)
+ }
+
+ fn function(params: &[Type], rettype: &Type, generics: &[Type]) -> Self {
+ Type::Func(
+ Arc::new(Vec::from(params)),
+ Arc::new(rettype.clone()),
+ Arc::new(Vec::from(generics)),
+ )
}
fn _is_integer(&self) -> bool {
@@ 399,7 407,7 @@ impl Type {
// Types are identical, noop.
(s, o) if s == o => (),
(Type::Named(n1, args1), Type::Named(n2, args2)) if n1 == n2 => {
- for (p1, p2) in args1.iter().zip(args2) {
+ for (p1, p2) in (&**args1).iter().zip(&**args2) {
p1._find_substs(p2, substitutions);
}
}
@@ 416,7 424,7 @@ impl Type {
if typeparams1.len() > 0 {
todo!()
}
- for (p1, p2) in params1.iter().zip(params2) {
+ for (p1, p2) in (&**params1).iter().zip(&**params2) {
p1._find_substs(p2, substitutions);
}
rettype1._find_substs(rettype2, substitutions);
@@ 438,11 446,11 @@ impl Type {
if !body1.keys().eq(body2.keys()) {
panic!("subst for sum type had non-matching keys")
}
- for ((_nm1, t1), (_nm2, t2)) in body1.iter().zip(body2) {
+ for ((_nm1, t1), (_nm2, t2)) in (&**body1).iter().zip(&**body2) {
t1._find_substs(t2, substitutions);
}
- for (p1, p2) in generics1.iter().zip(generics2) {
+ for (p1, p2) in (&**generics1).iter().zip(&**generics2) {
p1._find_substs(p2, substitutions);
}
}
@@ 480,11 488,15 @@ impl Type {
if typeparams1.len() > 0 {
todo!("Hsfjkdslfjs");
}
- Type::Func(new_params, Box::new(new_rettype), vec![])
+ Type::Func(
+ Arc::new(new_params),
+ Arc::new(new_rettype),
+ Arc::new(vec![]),
+ )
}
Type::Named(n1, args1) => {
let new_args = args1.iter().map(|p1| p1._apply_substs(substs)).collect();
- Type::Named(*n1, new_args)
+ Type::Named(*n1, Arc::new(new_args))
}
Type::Struct(_, _) => unreachable!("see other unreachable in substitute()"),
Type::Sum(body, generics) => {
@@ 493,9 505,9 @@ impl Type {
.map(|(nm, ty)| (*nm, ty._apply_substs(substs)))
.collect();
let new_generics = generics.iter().map(|p1| p1._apply_substs(substs)).collect();
- Type::Sum(new_body, new_generics)
+ Type::Sum(Arc::new(new_body), Arc::new(new_generics))
}
- Type::Array(body, len) => Type::Array(Box::new(body._apply_substs(substs)), *len),
+ Type::Array(body, len) => Type::Array(Arc::new(body._apply_substs(substs)), *len),
Type::Generic(nm) => substs
.get(&nm)
.unwrap_or_else(|| panic!("No substitution found for generic named {}!", nm))
@@ 625,7 637,7 @@ mod tests {
#[test]
fn check_name_format() {
let args = vec![Type::i32(), Type::bool()];
- let def = Type::Func(args, Box::new(Type::i32()), vec![]);
+ let def = Type::function(&args, &Type::i32(), &vec![]);
let gotten_name = def.get_name();
let desired_name = "fn(I32, Bool) I32";
assert_eq!(&gotten_name, desired_name);
M src/parser.rs +12 -12
@@ 706,9 706,9 @@ impl<'input> Parser<'input> {
let (params, typeparams) = self.parse_fn_args();
let rettype = self.try_parse_type().unwrap_or(Type::unit());
ast::Signature {
- params,
+ params: Arc::new(params),
rettype,
- typeparams,
+ typeparams: Arc::new(typeparams),
}
}
@@ 795,7 795,7 @@ impl<'input> Parser<'input> {
fn parse_fn_type(&mut self) -> Type {
let (params, typeparams) = self.parse_type_list_with_typeparams();
let rettype = self.try_parse_type().unwrap_or(Type::unit());
- Type::Func(params, Box::new(rettype), typeparams)
+ Type::function(¶ms, &rettype, &typeparams)
}
/// Parse the fields for a struct *type decl*
@@ 890,19 890,19 @@ impl<'input> Parser<'input> {
}
});
self.expect(T::RBrace);
- Some(Type::tuple(body))
+ Some(Type::tuple(Arc::new(body)))
}
fn try_parse_struct_type(&mut self) -> Option<Type> {
let (fields, type_params) = self.parse_struct_fields();
self.expect(T::End);
- Some(Type::Struct(fields, type_params))
+ Some(Type::Struct(Arc::new(fields), Arc::new(type_params)))
}
fn parse_enum_type(&mut self) -> Type {
let variants = self.parse_enum_fields();
self.expect(T::End);
- Type::Enum(variants)
+ Type::Enum(Arc::new(variants))
}
/// isomorphic-ish with parse_type_list()
@@ 941,7 941,7 @@ impl<'input> Parser<'input> {
.map(|ty| Type::Generic(ty))
.collect();
*/
- Type::Sum(fields, generics)
+ Type::Sum(Arc::new(fields), Arc::new(generics))
}
fn parse_exprs(&mut self) -> Vec<ast::Expr> {
@@ 1384,7 1384,7 @@ impl<'input> Parser<'input> {
} else {
vec![]
};
- Type::Named(Sym::new(s), type_params)
+ Type::Named(Sym::new(s), Arc::new(type_params))
}
}
T::At => {
@@ 1401,11 1401,11 @@ impl<'input> Parser<'input> {
assert!(len >= 0);
self.expect(T::RBracket);
let inner = self.parse_type();
- Type::Array(Box::new(inner), len as usize)
+ Type::Array(Arc::new(inner), len as usize)
}
T::Ampersand => {
let next = self.try_parse_type()?;
- Type::Uniq(Box::new(next))
+ Type::Uniq(Arc::new(next))
}
_ => {
// Wind the parse stream back to wherever we started
@@ 1552,9 1552,9 @@ mod tests {
ast::Decl::Function {
name: Sym::new("foo"),
signature: ast::Signature {
- params: vec![(Sym::new("x"), i32_t.clone())],
+ params: Arc::new(vec![(Sym::new("x"), i32_t.clone())]),
rettype: i32_t,
- typeparams: vec![],
+ typeparams: Arc::new(vec![]),
},
body: vec![Expr::int(9)],
doc_comment: vec![],
M src/passes.rs +18 -15
@@ 319,8 319,8 @@ fn decl_map(
}
}
-fn types_map(typs: Vec<Type>, f: &mut dyn FnMut(Type) -> Type) -> Vec<Type> {
- typs.into_iter().map(|t| type_map(t, f)).collect()
+fn types_map(typs: Arc<Vec<Type>>, f: &mut dyn FnMut(Type) -> Type) -> Arc<Vec<Type>> {
+ Arc::new(typs.iter().cloned().map(|t| type_map(t, f)).collect())
}
/// Recursion scheme to turn one type into another.
@@ 330,15 330,17 @@ fn type_map(typ: Type, f: &mut dyn FnMut
/// it generic over any iterator, if we want to make life even harder for
/// ourself.
fn types_map_btree<K>(
- typs: BTreeMap<K, Type>,
+ typs: Arc<BTreeMap<K, Type>>,
f: &mut dyn FnMut(Type) -> Type,
- ) -> BTreeMap<K, Type>
+ ) -> Arc<BTreeMap<K, Type>>
where
- K: Ord,
+ K: Ord + Clone,
{
- typs.into_iter()
- .map(|(key, ty)| (key, type_map(ty, f)))
- .collect()
+ Arc::new(
+ typs.iter()
+ .map(|(key, ty)| (key.clone(), type_map(ty.clone(), f)))
+ .collect(),
+ )
}
let res = match typ {
Type::Struct(fields, generics) => {
@@ 349,12 351,12 @@ fn type_map(typ: Type, f: &mut dyn FnMut
let new_fields = types_map_btree(fields, f);
Type::Sum(new_fields, generics)
}
- Type::Array(ty, len) => Type::Array(Box::new(type_map(*ty, f)), len),
+ Type::Array(ty, len) => Type::array(&type_map(ty.as_ref().clone(), f), len),
Type::Func(args, rettype, typeparams) => {
let new_args = types_map(args, f);
- let new_rettype = type_map(*rettype, f);
+ let new_rettype = type_map(rettype.as_ref().clone(), f);
let new_typeparams = types_map(typeparams, f);
- Type::Func(new_args, Box::new(new_rettype), new_typeparams)
+ Type::function(&new_args, &new_rettype, &new_typeparams)
}
// Not super sure whether this is necessary, but can't hurt.
Type::Named(nm, tys) => Type::Named(nm, types_map(tys, f)),
@@ 363,8 365,8 @@ fn type_map(typ: Type, f: &mut dyn FnMut
Type::Enum(_) => typ,
Type::Generic(_) => typ,
Type::Uniq(t) => {
- let new_t = type_map(*t, f);
- Type::Uniq(Box::new(new_t))
+ let new_t = type_map(t.as_ref().clone(), f);
+ Type::Uniq(Arc::new(new_t))
}
};
f(res)
@@ 374,11 376,12 @@ fn type_map(typ: Type, f: &mut dyn FnMut
fn signature_map(sig: hir::Signature, f: &mut dyn FnMut(Type) -> Type) -> hir::Signature {
let new_params = sig
.params
- .into_iter()
+ .iter()
+ .cloned()
.map(|(sym, ty)| (sym, type_map(ty, f)))
.collect();
hir::Signature {
- params: new_params,
+ params: Arc::new(new_params),
rettype: type_map(sig.rettype, f),
typeparams: types_map(sig.typeparams, f),
}
M src/passes/struct_to_tuple.rs +10 -10
@@ 38,9 38,11 @@ fn tuplize_type(typ: Type) -> Type {
// on the field names.
// TODO: What do we do with generics? Anything?
- let tuple_fields = fields.values().map(|ty| type_map(ty.clone(), &mut tuplize_type))
+ let tuple_fields = fields
+ .values()
+ .map(|ty| type_map(ty.clone(), &mut tuplize_type))
.collect();
- Type::tuple(tuple_fields)
+ Type::tuple(Arc::new(tuple_fields))
}
other => other,
}
@@ 77,10 79,7 @@ fn tuplize_expr(expr: ExprNode, tck: &mu
.map(|(ky, vl)| (offset_of_field(type_body, ky), vl))
.collect();
ordered_body.sort_by(|a, b| a.0.cmp(&b.0));
- let new_body = ordered_body
- .into_iter()
- .map(|(_i, expr)| expr)
- .collect();
+ let new_body = ordered_body.into_iter().map(|(_i, expr)| expr).collect();
E::TupleCtor { body: new_body }
}
@@ 271,14 270,15 @@ mod tests {
let mut body = BTreeMap::new();
body.insert(Sym::new("foo"), Type::i32());
body.insert(Sym::new("bar"), Type::i64());
+ let body = Arc::new(body);
- let desired = tuplize_type(Type::Struct(body.clone(), vec![]));
- let inp = Type::Struct(body, vec![]);
+ let desired = tuplize_type(Type::Struct(body.clone(), Arc::new(vec![])));
+ let inp = Type::Struct(body, Arc::new(vec![]));
let out = type_map(inp.clone(), &mut tuplize_type);
assert_eq!(out, desired);
- let desired2 = Type::Array(Box::new(out), 3);
- let inp2 = Type::Array(Box::new(inp), 3);
+ let desired2 = Type::array(&out, 3);
+ let inp2 = Type::array(&inp, 3);
let out2 = type_map(inp2, &mut tuplize_type);
assert_eq!(out2, desired2);
}
M src/typeck.rs +20 -17
@@ 409,7 409,7 @@ impl Tck {
let tinfo = match t {
Type::Prim(ty) => TypeInfo::Prim(*ty),
Type::Never => TypeInfo::Never,
- Type::Enum(vals) => TypeInfo::Enum(vals.clone()),
+ Type::Enum(vals) => TypeInfo::Enum((&**vals).clone()),
Type::Named(s, args) => {
let new_args = args.iter().map(|t| self.insert_known(t)).collect();
TypeInfo::Named(*s, new_args)
@@ 726,11 726,11 @@ impl Tck {
Never => Ok(Type::Never),
Prim(ty) => Ok(Type::Prim(*ty)),
Ref(id) => self.reconstruct(*id),
- Enum(ts) => Ok(Type::Enum(ts.clone())),
+ Enum(ts) => Ok(Type::Enum(Arc::new(ts.clone()))),
Named(s, args) => {
let arg_types: Result<Vec<_>, _> =
args.iter().map(|x| self.reconstruct(*x)).collect();
- Ok(Type::Named(*s, arg_types?))
+ Ok(Type::Named(*s, Arc::new(arg_types?)))
}
Func(args, rettype, typeparams) => {
let real_args: Result<Vec<Type>, TypeError> =
@@ 738,10 738,12 @@ impl Tck {
let type_param_types: Result<Vec<Type>, _> =
typeparams.iter().map(|x| self.reconstruct(*x)).collect();
- Ok(Type::Func(
- real_args?,
- Box::new(self.reconstruct(*rettype)?),
- type_param_types?,
+ let real_args = real_args?;
+ let type_param_types = type_param_types?;
+ Ok(Type::function(
+ &real_args,
+ &self.reconstruct(*rettype)?,
+ &type_param_types,
))
}
TypeParam(name) => Ok(Type::Generic(*name)),
@@ 755,11 757,11 @@ impl Tck {
.collect();
// TODO: The empty params here feels suspicious, verify.
let params = vec![];
- Ok(Type::Struct(real_body?, params))
+ Ok(Type::Struct(Arc::new(real_body?), Arc::new(params)))
}
Array(ty, len) => {
let real_body = self.reconstruct(*ty)?;
- Ok(Type::Array(Box::new(real_body), len.unwrap()))
+ Ok(Type::array(&real_body, len.unwrap()))
}
Sum(body) => {
let real_body: Result<BTreeMap<_, _>, TypeError> = body
@@ 770,11 772,11 @@ impl Tck {
})
.collect();
let params = vec![];
- Ok(Type::Sum(real_body?, params))
+ Ok(Type::Sum(Arc::new(real_body?), Arc::new(params)))
}
Uniq(ty) => {
let inner_type = self.reconstruct(*ty)?;
- Ok(Type::Uniq(Box::new(inner_type)))
+ Ok(Type::Uniq(Arc::new(inner_type)))
}
}
}
@@ 804,7 806,7 @@ impl Tck {
let typeinfo = match t {
Type::Prim(val) => TypeInfo::Prim(*val),
Type::Never => TypeInfo::Never,
- Type::Enum(vals) => TypeInfo::Enum(vals.clone()),
+ Type::Enum(vals) => TypeInfo::Enum((**vals).clone()),
Type::Named(s, args) => {
let inst_args: Vec<_> =
args.iter().map(|t| helper(tck, named_types, t)).collect();
@@ 914,7 916,7 @@ impl Drop for ScopeGuard {
impl Symtbl {
fn add_builtins(&self, tck: &mut Tck) {
- for builtin in &*builtins::BUILTINS {
+ for builtin in &*builtins::all() {
let ty = tck.insert_known(&builtin.sig);
self.add_var(builtin.name, ty, false);
}
@@ 1008,7 1010,7 @@ fn typecheck_func_body(
*/
// Insert info about the function signature
let mut params = vec![];
- for (_paramname, paramtype) in &signature.params {
+ for (_paramname, paramtype) in &*signature.params {
let p = tck.insert_known(paramtype);
params.push(p);
}
@@ 1031,7 1033,7 @@ fn typecheck_func_body(
// Add params to function's scope
let _guard = symtbl.push_scope();
- for (paramname, paramtype) in &signature.params {
+ for (paramname, paramtype) in &*signature.params {
let p = tck.insert_known(paramtype);
symtbl.add_var(*paramname, p, false);
}
@@ 1472,7 1474,8 @@ fn typecheck_expr(
tck.unify(symtbl, tid, body_type)?;
trace!("Done unifying type ctor");
// The type the expression returns
- let constructed_type = tck.insert_known(&Type::Named(*name, type_params.clone()));
+ let constructed_type =
+ tck.insert_known(&Type::Named(*name, Arc::new(type_params.clone())));
tck.set_expr_type(expr, constructed_type);
Ok(constructed_type)
}
@@ 1623,7 1626,7 @@ fn predeclare_decls(tck: &mut Tck, symtb
} => {
// TODO: Kinda duplicated, not a huge fan.
let mut params = vec![];
- for (_paramname, paramtype) in &signature.params {
+ for (_paramname, paramtype) in &*signature.params {
let p = tck.insert_known(paramtype);
params.push(p);
}