λ Support functions! #5

Open
acw wants to merge 59 commits from awick/functions into develop
6 changed files with 145 additions and 42 deletions
Showing only changes of commit 854fd60132 - Show all commits

View File

@@ -15,6 +15,7 @@
mod arbitrary; mod arbitrary;
pub mod ast; pub mod ast;
mod eval; mod eval;
mod fields;
mod pretty; mod pretty;
mod strings; mod strings;
mod top_level; mod top_level;

View File

@@ -1,4 +1,5 @@
use crate::eval::PrimitiveType; use crate::eval::PrimitiveType;
pub use crate::ir::fields::Fields;
use crate::syntax::{ConstantType, Location}; use crate::syntax::{ConstantType, Location};
use internment::ArcIntern; use internment::ArcIntern;
use proptest::arbitrary::Arbitrary; use proptest::arbitrary::Arbitrary;
@@ -247,7 +248,7 @@ impl Value {
pub enum Type { pub enum Type {
Primitive(PrimitiveType), Primitive(PrimitiveType),
Function(Vec<Type>, Box<Type>), Function(Vec<Type>, Box<Type>),
Structure(HashMap<ArcIntern<String>, Type>), Structure(Fields<Type>),
} }
impl Type { impl Type {
@@ -281,7 +282,7 @@ pub enum TypeOrVar {
Primitive(PrimitiveType), Primitive(PrimitiveType),
Variable(Location, ArcIntern<String>), Variable(Location, ArcIntern<String>),
Function(Vec<TypeOrVar>, Box<TypeOrVar>), Function(Vec<TypeOrVar>, Box<TypeOrVar>),
Structure(HashMap<ArcIntern<String>, TypeOrVar>), Structure(Fields<TypeOrVar>),
} }
impl Default for TypeOrVar { impl Default for TypeOrVar {
@@ -330,7 +331,7 @@ impl TypeOrVar {
TypeOrVar::Primitive(_) => false, TypeOrVar::Primitive(_) => false,
TypeOrVar::Structure(fields) => { TypeOrVar::Structure(fields) => {
fields.values_mut().any(|x| x.replace(name, replace_with)) fields.types_mut().any(|x| x.replace(name, replace_with))
} }
} }
} }
@@ -344,7 +345,7 @@ impl TypeOrVar {
TypeOrVar::Function(args, ret) => { TypeOrVar::Function(args, ret) => {
args.iter().all(TypeOrVar::is_resolved) && ret.is_resolved() args.iter().all(TypeOrVar::is_resolved) && ret.is_resolved()
} }
TypeOrVar::Structure(fields) => fields.values().all(TypeOrVar::is_resolved), TypeOrVar::Structure(fields) => fields.types().all(TypeOrVar::is_resolved),
} }
} }
} }
@@ -364,7 +365,7 @@ impl PartialEq<Type> for TypeOrVar {
Type::Structure(fields1) => match self { Type::Structure(fields1) => match self {
TypeOrVar::Structure(fields2) => { TypeOrVar::Structure(fields2) => {
fields1.len() == fields2.len() fields1.count() == fields2.count()
&& fields1.iter().all(|(name, subtype)| { && fields1.iter().all(|(name, subtype)| {
fields2.get(name).map(|x| x == subtype).unwrap_or(false) fields2.get(name).map(|x| x == subtype).unwrap_or(false)
}) })
@@ -418,9 +419,7 @@ impl<T: Into<Type>> From<T> for TypeOrVar {
args.into_iter().map(Into::into).collect(), args.into_iter().map(Into::into).collect(),
Box::new((*ret).into()), Box::new((*ret).into()),
), ),
Type::Structure(fields) => { Type::Structure(fields) => TypeOrVar::Structure(fields.map(Into::into)),
TypeOrVar::Structure(fields.into_iter().map(|(n, t)| (n, t.into())).collect())
}
} }
} }
} }
@@ -450,16 +449,21 @@ impl TryFrom<TypeOrVar> for Type {
TypeOrVar::Primitive(t) => Ok(Type::Primitive(t)), TypeOrVar::Primitive(t) => Ok(Type::Primitive(t)),
TypeOrVar::Structure(fields) => { TypeOrVar::Structure(fields) => {
let mut new_fields = HashMap::with_capacity(fields.len()); let mut new_fields = Fields::new(fields.ordering());
let mut errored = false;
for (name, field) in fields.iter() { for (name, field) in fields.iter() {
if let Ok(new_field) = field.clone().try_into() { if let Ok(new_field) = field.clone().try_into() {
new_fields.insert(name.clone(), new_field); new_fields.insert(name.clone(), new_field);
} else { } else {
return Err(TypeOrVar::Structure(fields)); errored = true;
} }
} }
if errored {
return Err(TypeOrVar::Structure(fields));
}
Ok(Type::Structure(new_fields)) Ok(Type::Structure(new_fields))
} }

101
src/ir/fields.rs Normal file
View File

@@ -0,0 +1,101 @@
use internment::ArcIntern;
use std::fmt;
#[derive(Clone, PartialEq, Eq)]
pub struct Fields<T> {
ordering: FieldOrdering,
fields: Vec<(ArcIntern<String>, T)>,
}
impl<T: fmt::Debug> fmt::Debug for Fields<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Fields:")?;
self.fields.fmt(f)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FieldOrdering {
Standard,
}
impl<T> Default for Fields<T> {
fn default() -> Self {
Self::new(FieldOrdering::Standard)
}
}
impl<T> Fields<T> {
pub fn new(ordering: FieldOrdering) -> Fields<T> {
Fields {
ordering,
fields: vec![],
}
}
pub fn ordering(&self) -> FieldOrdering {
self.ordering
}
pub fn insert(&mut self, name: ArcIntern<String>, t: T) {
self.fields.push((name, t));
}
pub fn get(&self, name: &ArcIntern<String>) -> Option<&T> {
for (n, res) in self.fields.iter() {
if n == name {
return Some(res);
}
}
None
}
pub fn map<T2, F: Fn(T) -> T2>(self, f: F) -> Fields<T2> {
Fields {
ordering: self.ordering,
fields: self.fields.into_iter().map(|(n, t)| (n, f(t))).collect(),
}
}
pub fn count(&self) -> usize {
self.fields.len()
}
pub fn has_field(&self, name: &ArcIntern<String>) -> bool {
self.fields.iter().any(|(current, _)| current == name)
}
pub fn remove_field(&mut self, name: &ArcIntern<String>) -> Option<T> {
let mut field_index = None;
for (idx, (current, _)) in self.fields.iter().enumerate() {
if current == name {
field_index = Some(idx);
break;
}
}
field_index.map(|i| self.fields.remove(i).1)
}
pub fn iter(&self) -> impl Iterator<Item = (&ArcIntern<String>, &T)> {
self.fields.iter().map(|(x, y)| (x, y))
}
pub fn into_iter(self) -> impl Iterator<Item = (ArcIntern<String>, T)> {
self.fields.into_iter()
}
pub fn field_names(&self) -> impl Iterator<Item = &ArcIntern<String>> {
self.fields.iter().map(|(n, _)| n)
}
pub fn types(&self) -> impl Iterator<Item = &T> {
self.fields.iter().map(|(_, x)| x)
}
pub fn types_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.fields.iter_mut().map(|(_, x)| x)
}
}

View File

@@ -149,15 +149,15 @@ fn convert_top_level(
convert_statement(stmt, constraint_db, renames, bindings), convert_statement(stmt, constraint_db, renames, bindings),
)), )),
syntax::TopLevel::Structure(_loc, name, fields) => TopLevelItem::Type( syntax::TopLevel::Structure(_loc, name, fields) => {
name.intern(), let mut updated_fields = ir::Fields::default();
ir::TypeOrVar::Structure(
fields for (name, field_type) in fields.into_iter() {
.into_iter() updated_fields.insert(name.intern(), convert_type(field_type, constraint_db));
.map(|(name, t)| (name.intern(), convert_type(t, constraint_db))) }
.collect(),
), TopLevelItem::Type(name.intern(), ir::TypeOrVar::Structure(updated_fields))
), }
} }
} }
@@ -294,7 +294,7 @@ fn convert_expression(
syntax::Expression::Constructor(loc, name, fields) => { syntax::Expression::Constructor(loc, name, fields) => {
let mut result_fields = HashMap::new(); let mut result_fields = HashMap::new();
let mut type_fields = HashMap::new(); let mut type_fields = ir::Fields::default();
let mut prereqs = vec![]; let mut prereqs = vec![];
let result_type = ir::TypeOrVar::new(); let result_type = ir::TypeOrVar::new();
@@ -479,18 +479,18 @@ fn convert_type(ty: syntax::Type, constraint_db: &mut Vec<Constraint>) -> ir::Ty
} }
Ok(v) => ir::TypeOrVar::Primitive(v), Ok(v) => ir::TypeOrVar::Primitive(v),
}, },
syntax::Type::Struct(fields) => ir::TypeOrVar::Structure( syntax::Type::Struct(fields) => {
fields let mut new_fields = ir::Fields::default();
.into_iter()
.map(|(n, t)| { for (name, field_type) in fields.into_iter() {
( let new_field_type = field_type
n.intern(), .map(|x| convert_type(x, constraint_db))
t.map(|x| convert_type(x, constraint_db)) .unwrap_or_else(ir::TypeOrVar::new);
.unwrap_or_else(ir::TypeOrVar::new), new_fields.insert(name.intern(), new_field_type);
) }
})
.collect(), ir::TypeOrVar::Structure(new_fields)
), }
} }
} }

View File

@@ -134,12 +134,9 @@ fn finalize_type(ty: TypeOrVar, resolutions: &TypeResolutions) -> Type {
.collect(), .collect(),
Box::new(finalize_type(*ret, resolutions)), Box::new(finalize_type(*ret, resolutions)),
), ),
TypeOrVar::Structure(fields) => Type::Structure( TypeOrVar::Structure(fields) => {
fields Type::Structure(fields.map(|subtype| finalize_type(subtype, resolutions)))
.into_iter() }
.map(|(name, subtype)| (name, finalize_type(subtype, resolutions)))
.collect(),
),
} }
} }

View File

@@ -446,7 +446,7 @@ pub fn solve_constraints(
TypeOrVar::Structure(mut fields), TypeOrVar::Structure(mut fields),
field, field,
result_type, result_type,
) => match fields.remove(&field) { ) => match fields.remove_field(&field) {
None => { None => {
let reconstituted = TypeOrVar::Structure(fields); let reconstituted = TypeOrVar::Structure(fields);
tracing::trace!(structure_type = %reconstituted, %field, "no field found in type"); tracing::trace!(structure_type = %reconstituted, %field, "no field found in type");
@@ -772,12 +772,12 @@ pub fn solve_constraints(
TypeOrVar::Structure(fields1), TypeOrVar::Structure(fields1),
TypeOrVar::Structure(mut fields2), TypeOrVar::Structure(mut fields2),
) => { ) => {
if fields1.len() == fields2.len() if fields1.count() == fields2.count()
&& fields1.keys().all(|x| fields2.contains_key(x)) && fields1.field_names().all(|x| fields2.has_field(x))
{ {
for (name, subtype1) in fields1.into_iter() { for (name, subtype1) in fields1.into_iter() {
let subtype2 = fields2 let subtype2 = fields2
.remove(&name) .remove_field(&name)
.expect("can find matching field after equivalence check"); .expect("can find matching field after equivalence check");
new_constraints.push(Constraint::Equivalent( new_constraints.push(Constraint::Equivalent(
loc.clone(), loc.clone(),