Skip to content

Commit

Permalink
perf: Allocate AppVec directly instead of using intermediate Vecs
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Nov 10, 2016
1 parent a26c106 commit b0bc41f
Show file tree
Hide file tree
Showing 26 changed files with 118 additions and 84 deletions.
3 changes: 2 additions & 1 deletion base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ log = "0.3.6"
quick-error = "1.0.0"
fnv = "1.0.3"
pretty = "0.1.0"
smallvec = "0.2.0"
smallvec = { git = "https://github.com/servo/rust-smallvec", rev = "cc04c67174dfcd1aa9e893cd55b13b583180f8a9" }
collect-mac = "0.1.0"
4 changes: 2 additions & 2 deletions base/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::borrow::Cow;
use std::collections::hash_map::Entry;

use types;
use types::{AliasData, Type, Generic, ArcType, TypeEnv};
use types::{AliasData, AppVec, Type, Generic, ArcType, TypeEnv};
use symbol::Symbol;
use fnv::FnvMap;

Expand Down Expand Up @@ -134,7 +134,7 @@ pub fn type_of_alias(alias: &AliasData<Symbol, ArcType>, args: &[ArcType]) -> Op
.count();
if alias_args.len() - args.len() <= allowed_missing_args {
// Remove the args at the end of the aliased type
let arg_types: Vec<_> = arg_types.iter()
let arg_types: AppVec<_> = arg_types.iter()
.take(arg_types.len() - (alias_args.len() - args.len()))
.cloned()
.collect();
Expand Down
2 changes: 2 additions & 0 deletions base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ extern crate log;
extern crate quick_error;
extern crate pretty;
extern crate smallvec;
#[macro_use]
extern crate collect_mac;

pub mod ast;
pub mod error;
Expand Down
18 changes: 8 additions & 10 deletions base/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,10 @@ impl<Id, T> Type<Id, T>
}

pub fn array(typ: T) -> T {
Type::app(Type::builtin(BuiltinType::Array), vec![typ])
Type::app(Type::builtin(BuiltinType::Array), collect![typ])
}

pub fn app<I>(id: T, args: I) -> T
where I: IntoIterator<Item = T>,
{
let args: AppVec<T> = args.into_iter().collect();
pub fn app(id: T, args: AppVec<T>) -> T {
if args.is_empty() {
id
} else {
Expand Down Expand Up @@ -341,7 +338,7 @@ impl<Id, T> Type<Id, T>
args.into_iter()
.rev()
.fold(ret,
|body, arg| Type::app(function.clone(), vec![arg, body]))
|body, arg| Type::app(function.clone(), collect![arg, body]))
}

pub fn generic(typ: Generic<Id>) -> T {
Expand Down Expand Up @@ -1056,13 +1053,13 @@ pub fn walk_move_type_opt<F: ?Sized, I, T>(typ: &Type<I, T>, f: &mut F) -> Optio
{
match *typ {
Type::App(ref id, ref args) => {
let new_args = walk_move_types(AppVec::new(), args, |t| f.visit(t));
let new_args = walk_move_types(args, |t| f.visit(t));
merge(id, f.visit(id), args, new_args, Type::app)
}
Type::Record(ref row) => f.visit(row).map(|row| T::from(Type::Record(row))),
Type::Variant(ref row) => f.visit(row).map(|row| T::from(Type::Variant(row))),
Type::ExtendRow { ref types, ref fields, ref rest } => {
let new_fields = walk_move_types(Vec::new(), fields, |field| {
let new_fields = walk_move_types(fields, |field| {
f.visit(&field.typ).map(|typ| {
Field {
name: field.name.clone(),
Expand All @@ -1089,12 +1086,13 @@ pub fn walk_move_type_opt<F: ?Sized, I, T>(typ: &Type<I, T>, f: &mut F) -> Optio
}

// FIXME Add R: Default and remove the `out` parameter
pub fn walk_move_types<'a, I, F, T, R>(mut out: R, types: I, mut f: F) -> Option<R>
pub fn walk_move_types<'a, I, F, T, R>(types: I, mut f: F) -> Option<R>
where I: IntoIterator<Item = &'a T>,
F: FnMut(&'a T) -> Option<T>,
T: Clone + 'a,
R: VecLike<T> + DerefMut<Target = [T]>,
R: Default + VecLike<T> + DerefMut<Target = [T]>,
{
let mut out = R::default();
walk_move_types2(types.into_iter(), false, &mut out, &mut f);
if out.is_empty() {
None
Expand Down
2 changes: 2 additions & 0 deletions base/tests/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
extern crate gluon_base as base;
#[macro_use]
extern crate collect_mac;

use std::ops::Deref;

Expand Down
5 changes: 4 additions & 1 deletion check/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ documentation = "https://docs.rs/gluon"
env_logger = { version = "0.3.4", optional = true }
log = "0.3.6"
union-find = "0.3.1"
smallvec = "0.2.0"
smallvec = { git = "https://github.com/servo/rust-smallvec", rev = "cc04c67174dfcd1aa9e893cd55b13b583180f8a9" }
gluon_base = { path = "../base", version = "0.2.2" }
gluon_parser = { path = "../parser", version = "0.2.2", optional = true }

[dev-dependencies]
collect-mac = "0.1.0"

[features]
test = ["gluon_parser", "env_logger"]
4 changes: 2 additions & 2 deletions check/src/kindcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt;
use base::ast;
use base::kind::{self, ArcKind, Kind, KindEnv};
use base::symbol::Symbol;
use base::types::{self, ArcType, BuiltinType, Field, Generic, Type, Walker};
use base::types::{self, AppVec, ArcType, BuiltinType, Field, Generic, Type, Walker};

use substitution::{Substitution, Substitutable};
use unify;
Expand Down Expand Up @@ -172,7 +172,7 @@ impl<'a> KindCheck<'a> {
Type::Builtin(builtin_typ) => Ok((self.builtin_kind(builtin_typ), typ.clone())),
Type::App(ref ctor, ref args) => {
let (mut kind, ctor) = try!(self.kindcheck(ctor));
let mut new_args = Vec::new();
let mut new_args = AppVec::new();
for arg in args {
let f = Kind::function(self.subs.new_var(), self.subs.new_var());
kind = try!(self.unify(&f, kind));
Expand Down
22 changes: 12 additions & 10 deletions check/src/typecheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use base::instantiate::{self, Instantiator};
use base::kind::{Kind, KindEnv, ArcKind};
use base::pos::{BytePos, Span, Spanned};
use base::symbol::{Symbol, SymbolRef, SymbolModule, Symbols};
use base::types::{self, Alias, AliasData, ArcType, Field, Generic};
use base::types::{self, Alias, AliasData, AppVec, ArcType, Field, Generic};
use base::types::{PrimitiveEnv, Type, TypeEnv, TypeVariable};
use kindcheck::{self, KindCheck};
use substitution::Substitution;
Expand Down Expand Up @@ -299,7 +299,7 @@ impl<'a> Typecheck<'a> {
self.stack_var(field.name, field.typ);
}
}
let generic_args = alias.args.iter().cloned().map(Type::generic);
let generic_args = alias.args.iter().cloned().map(Type::generic).collect();
let typ = Type::<_, ArcType>::app(alias.as_ref().clone(), generic_args);
{
// FIXME: Workaround so that both the types name in this module and its global
Expand Down Expand Up @@ -1112,7 +1112,7 @@ impl<'a> Typecheck<'a> {
Some(gen)
}
Type::ExtendRow { ref types, ref fields, ref rest } => {
let new_fields = types::walk_move_types(Vec::new(), fields, |field| {
let new_fields = types::walk_move_types(fields, |field| {
// Make a new name base for any unbound variables in the record field
// Gives { id : a0 -> a0, const : b0 -> b1 -> b1 }
// instead of { id : a0 -> a0, const : a1 -> a2 -> a2 }
Expand Down Expand Up @@ -1445,6 +1445,8 @@ fn primitive_type(op_type: &str) -> ArcType {
/// Example:
///
/// ```rust
/// #[macro_use]
/// extern crate collect_mac;
/// extern crate gluon_base;
/// extern crate gluon_check;
///
Expand All @@ -1454,17 +1456,17 @@ fn primitive_type(op_type: &str) -> ArcType {
/// # fn main() {
/// let i: ArcType = Type::int();
/// let s: ArcType = Type::string();
/// assert_eq!(unroll_typ(&*Type::app(Type::app(i.clone(), vec![s.clone()]), vec![i.clone()])),
/// Some(Type::app(i.clone(), vec![s.clone(), i.clone()])));
/// assert_eq!(unroll_typ(&*Type::app(Type::app(i.clone(), vec![i.clone()]), vec![s.clone()])),
/// Some(Type::app(i.clone(), vec![i.clone(), s.clone()])));
/// assert_eq!(unroll_typ(&*Type::app(Type::app(i.clone(), collect![s.clone()]), collect![i.clone()])),
/// Some(Type::app(i.clone(), collect![s.clone(), i.clone()])));
/// assert_eq!(unroll_typ(&*Type::app(Type::app(i.clone(), collect![i.clone()]), collect![s.clone()])),
/// Some(Type::app(i.clone(), collect![i.clone(), s.clone()])));
/// let f: ArcType = Type::builtin(BuiltinType::Function);
/// assert_eq!(unroll_typ(&*Type::app(Type::app(f.clone(), vec![i.clone()]), vec![s.clone()])),
/// Some(Type::function(vec![i.clone()], s.clone())));
/// assert_eq!(unroll_typ(&*Type::app(Type::app(f.clone(), collect![i.clone()]), collect![s.clone()])),
/// Some(Type::function(collect![i.clone()], s.clone())));
/// # }
/// ```
pub fn unroll_typ(typ: &Type<Symbol>) -> Option<ArcType> {
let mut args = Vec::new();
let mut args = AppVec::new();
let mut current = match *typ {
Type::App(ref l, ref rest) => {
// No need to unroll if `l` is not an application as that will just result in returning
Expand Down
67 changes: 35 additions & 32 deletions check/src/unify_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::mem;
use smallvec::VecLike;

use base::error::Errors;
use base::types::{self, AppVec, ArcType, Field, Type, TypeVariable, TypeEnv, merge};
use base::types::{self, ArcType, Field, Type, TypeVariable, TypeEnv, merge};
use base::symbol::{Symbol, SymbolRef};
use base::instantiate;
use base::scoped_map::ScopedMap;
Expand Down Expand Up @@ -176,26 +176,29 @@ fn do_zip_match<'a, U>(self_: &ArcType,
match l_args.len().cmp(&r_args.len()) {
Equal => {
let new_type = unifier.try_match(l, r);
let new_args = walk_move_types(AppVec::new(),
l_args.iter().zip(r_args),
let new_args = walk_move_types(l_args.iter().zip(r_args),
|l, r| unifier.try_match(l, r));
Ok(merge(l, new_type, l_args, new_args, Type::app))
}
Less => {
let offset = r_args.len() - l_args.len();
let new_type =
unifier.try_match(l, &Type::app(r.clone(), r_args[..offset].iter().cloned()));
let new_args = walk_move_types(AppVec::new(),
l_args.iter().zip(&r_args[offset..]),

let reduced_r = Type::app(r.clone(),
r_args[..offset].iter().cloned().collect());
let new_type = unifier.try_match(l, &reduced_r);

let new_args = walk_move_types(l_args.iter().zip(&r_args[offset..]),
|l, r| unifier.try_match(l, r));
Ok(merge(l, new_type, l_args, new_args, Type::app))
}
Greater => {
let offset = l_args.len() - r_args.len();
let new_type =
unifier.try_match(&Type::app(l.clone(), l_args[..offset].iter().cloned()), r);
let new_args = walk_move_types(AppVec::new(),
l_args[offset..].iter().zip(r_args),

let reduced_l = Type::app(l.clone(),
l_args[..offset].iter().cloned().collect());
let new_type = unifier.try_match(&reduced_l, r);

let new_args = walk_move_types(l_args[offset..].iter().zip(r_args),
|l, r| unifier.try_match(l, r));
Ok(merge(r, new_type, r_args, new_args, Type::app))
}
Expand All @@ -217,7 +220,7 @@ fn do_zip_match<'a, U>(self_: &ArcType,
if l_args.len() == r_args.len() &&
l_args.iter().zip(r_args).all(|(l, r)| l.name.name_eq(&r.name)) &&
l_types == r_types {
let new_args = walk_move_types(Vec::new(), l_args.iter().zip(r_args), |l, r| {
let new_args = walk_move_types(l_args.iter().zip(r_args), |l, r| {
unifier.try_match(&l.typ, &r.typ)
.map(|typ| {
types::Field {
Expand All @@ -242,22 +245,21 @@ fn do_zip_match<'a, U>(self_: &ArcType,
// HACK For non polymorphic records we need to care about field order as the
// compiler assumes the order the fields occur in the type determines how
// to access them
let new_args =
walk_move_types(Vec::new(), l_args.iter().zip(r_args.iter()), |l, r| {
let opt_type = if !l.name.name_eq(&r.name) {
let err = TypeError::FieldMismatch(l.name.clone(), r.name.clone());
unifier.report_error(UnifyError::Other(err));
None
} else {
unifier.try_match(&l.typ, &r.typ)
};
opt_type.map(|typ| {
types::Field {
name: l.name.clone(),
typ: typ,
}
})
});
let new_args = walk_move_types(l_args.iter().zip(r_args.iter()), |l, r| {
let opt_type = if !l.name.name_eq(&r.name) {
let err = TypeError::FieldMismatch(l.name.clone(), r.name.clone());
unifier.report_error(UnifyError::Other(err));
None
} else {
unifier.try_match(&l.typ, &r.typ)
};
opt_type.map(|typ| {
types::Field {
name: l.name.clone(),
typ: typ,
}
})
});
let new_rest = unifier.try_match(l_rest, r_rest);
Ok(merge(l_args,
new_args,
Expand Down Expand Up @@ -333,7 +335,7 @@ fn unify_rows<'a, U>(unifier: &mut UnifierState<'a, U>,
let mut types: Vec<_> = types_both.iter().map(|pair| pair.0.clone()).collect();

// Unify the fields that exists in both records
let new_both = walk_move_types(Vec::new(), both.iter().cloned(), |l, r| {
let new_both = walk_move_types(both.iter().cloned(), |l, r| {
unifier.try_match(&l.typ, &r.typ)
.map(|typ| {
types::Field {
Expand All @@ -344,7 +346,7 @@ fn unify_rows<'a, U>(unifier: &mut UnifierState<'a, U>,
});

// Pack all fields from both records into a single `Type::ExtendRow` value
let mut fields = match new_both {
let mut fields: Vec<_> = match new_both {
Some(fields) => fields,
None => both.iter().map(|pair| pair.0.clone()).collect(),
};
Expand Down Expand Up @@ -547,12 +549,13 @@ fn try_with_alias<'a, U>(unifier: &mut UnifierState<'a, U>,
}
}

fn walk_move_types<'a, I, F, T, R>(mut out: R, types: I, mut f: F) -> Option<R>
fn walk_move_types<'a, I, F, T, R>(types: I, mut f: F) -> Option<R>
where I: Iterator<Item = (&'a T, &'a T)>,
F: FnMut(&'a T, &'a T) -> Option<T>,
T: Clone + 'a,
R: VecLike<T>,
R: Default + VecLike<T>,
{
let mut out = R::default();
walk_move_types2(types, false, &mut out, &mut f);
if out[..].is_empty() {
None
Expand Down
2 changes: 2 additions & 0 deletions check/tests/completion.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[macro_use]
extern crate collect_mac;
extern crate env_logger;

extern crate gluon_base as base;
Expand Down
2 changes: 2 additions & 0 deletions check/tests/fail.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[macro_use]
extern crate collect_mac;
extern crate env_logger;

extern crate gluon_base as base;
Expand Down
2 changes: 2 additions & 0 deletions check/tests/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[macro_use]
extern crate collect_mac;
extern crate env_logger;

extern crate gluon_base as base;
Expand Down
Loading

0 comments on commit b0bc41f

Please sign in to comment.