λ 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;
pub mod ast;
mod eval;
mod fields;
mod pretty;
mod strings;
mod top_level;

View File

@@ -1,4 +1,5 @@
use crate::eval::PrimitiveType;
pub use crate::ir::fields::Fields;
use crate::syntax::{ConstantType, Location};
use internment::ArcIntern;
use proptest::arbitrary::Arbitrary;
@@ -247,7 +248,7 @@ impl Value {
pub enum Type {
Primitive(PrimitiveType),
Function(Vec<Type>, Box<Type>),
Structure(HashMap<ArcIntern<String>, Type>),
Structure(Fields<Type>),
}
impl Type {
@@ -281,7 +282,7 @@ pub enum TypeOrVar {
Primitive(PrimitiveType),
Variable(Location, ArcIntern<String>),
Function(Vec<TypeOrVar>, Box<TypeOrVar>),
Structure(HashMap<ArcIntern<String>, TypeOrVar>),
Structure(Fields<TypeOrVar>),
}
impl Default for TypeOrVar {
@@ -330,7 +331,7 @@ impl TypeOrVar {
TypeOrVar::Primitive(_) => false,
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) => {
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 {
TypeOrVar::Structure(fields2) => {
fields1.len() == fields2.len()
fields1.count() == fields2.count()
&& fields1.iter().all(|(name, subtype)| {
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(),
Box::new((*ret).into()),
),
Type::Structure(fields) => {
TypeOrVar::Structure(fields.into_iter().map(|(n, t)| (n, t.into())).collect())
}
Type::Structure(fields) => TypeOrVar::Structure(fields.map(Into::into)),
}
}
}
@@ -450,16 +449,21 @@ impl TryFrom<TypeOrVar> for Type {
TypeOrVar::Primitive(t) => Ok(Type::Primitive(t)),
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() {
if let Ok(new_field) = field.clone().try_into() {
new_fields.insert(name.clone(), new_field);
} else {
return Err(TypeOrVar::Structure(fields));
errored = true;
}
}
if errored {
return Err(TypeOrVar::Structure(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),
)),
syntax::TopLevel::Structure(_loc, name, fields) => TopLevelItem::Type(
name.intern(),
ir::TypeOrVar::Structure(
fields
.into_iter()
.map(|(name, t)| (name.intern(), convert_type(t, constraint_db)))
.collect(),
),
),
syntax::TopLevel::Structure(_loc, name, fields) => {
let mut updated_fields = ir::Fields::default();
for (name, field_type) in fields.into_iter() {
updated_fields.insert(name.intern(), convert_type(field_type, constraint_db));
}
TopLevelItem::Type(name.intern(), ir::TypeOrVar::Structure(updated_fields))
}
}
}
@@ -294,7 +294,7 @@ fn convert_expression(
syntax::Expression::Constructor(loc, name, fields) => {
let mut result_fields = HashMap::new();
let mut type_fields = HashMap::new();
let mut type_fields = ir::Fields::default();
let mut prereqs = vec![];
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),
},
syntax::Type::Struct(fields) => ir::TypeOrVar::Structure(
fields
.into_iter()
.map(|(n, t)| {
(
n.intern(),
t.map(|x| convert_type(x, constraint_db))
.unwrap_or_else(ir::TypeOrVar::new),
)
})
.collect(),
),
syntax::Type::Struct(fields) => {
let mut new_fields = ir::Fields::default();
for (name, field_type) in fields.into_iter() {
let new_field_type = field_type
.map(|x| convert_type(x, constraint_db))
.unwrap_or_else(ir::TypeOrVar::new);
new_fields.insert(name.intern(), new_field_type);
}
ir::TypeOrVar::Structure(new_fields)
}
}
}

View File

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

View File

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