Adding assignments to solver

This commit is contained in:
Richard Feldman 2019-08-28 21:01:23 -04:00
parent 44bdcdb3f3
commit 49cd2ede8a
4 changed files with 153 additions and 72 deletions

View file

@ -14,10 +14,13 @@
// }
use subs::{Subs, Variable, Descriptor, Content, FlatType};
use collections::ImMap;
use types::Constraint::{self, *};
use types::Type::{self, *};
pub fn solve(subs: &mut Subs, constraint: Constraint) {
type Env = ImMap<String, Variable>;
pub fn solve(env: &Env, subs: &mut Subs, constraint: Constraint) {
println!("\nSolving:\n\n\t{:?}\n\n", constraint);
match constraint {
True => (),
@ -29,63 +32,55 @@ pub fn solve(subs: &mut Subs, constraint: Constraint) {
},
And(sub_constraints) => {
for sub_constraint in sub_constraints {
solve(subs, sub_constraint);
solve(env, subs, sub_constraint);
}
},
Let(box_let_constraint) => {
let let_con = *box_let_constraint;
let no_rigid_vars = let_con.rigid_vars.is_empty();
// CLet [] flexs _ headerCon CTrue ->
// do introduce rank pools flexs
// solve env rank pools state headerCon
match let_con.ret_constraint {
True if no_rigid_vars => {
// If the return expression is guaranteed to solve,
// and there are no rigid vars to worry about,
// solve the assignments themselves and move on.
solve(env, subs, let_con.assignments_constraint)
},
body_con => {
if no_rigid_vars && let_con.flex_vars.is_empty() {
// Solve the assignments' constraints first.
solve(env, subs, let_con.assignments_constraint);
// CLet [] [] header headerCon subCon ->
// do state1 <- solve env rank pools state headerCon
// locals <- traverse (A.traverse (typeToVariable rank pools)) header
// let newEnv = Map.union env (Map.map A.toValue locals)
// state2 <- solve newEnv rank pools state1 subCon
// foldM occurs state2 $ Map.toList locals
// Add a variable for each assignment to the env.
let new_env = env.clone();
// CLet rigids flexs header headerCon subCon ->
// do
// -- work in the next pool to localize header
// let nextRank = rank + 1
// let poolsLength = MVector.length pools
// nextPools <-
// if nextRank < poolsLength
// then return pools
// else MVector.grow pools poolsLength
for (name, loc_type) in let_con.assignment_types {
let var = type_to_variable(subs, loc_type.value);
// -- introduce variables
// let vars = rigids ++ flexs
// forM_ vars $ \var ->
// UF.modify var $ \(Descriptor content _ mark copy) ->
// Descriptor content nextRank mark copy
// MVector.write nextPools nextRank vars
new_env.insert(name, var);
}
// -- run solver in next pool
// locals <- traverse (A.traverse (typeToVariable nextRank nextPools)) header
// (State savedEnv mark errors) <-
// solve env nextRank nextPools state headerCon
// Now solve the body, using the new env which includes
// the assignments' name-to-variable mappings.
solve(&new_env, subs, let_con.ret_constraint);
// let youngMark = mark
// let visitMark = nextMark youngMark
// let finalMark = nextMark visitMark
// TODO do an occurs check for each of the assignments!
} else {
let vars = let_con.rigid_vars;
// -- pop pool
// generalize youngMark visitMark nextRank nextPools
// MVector.write nextPools nextRank []
vars.extend(let_con.flex_vars);
// -- check that things went well
// mapM_ isGeneric rigids
// let newEnv = Map.union env (Map.map A.toValue locals)
// let tempState = State savedEnv finalMark errors
// newState <- solve newEnv rank nextPools tempState subCon
// foldM occurs newState (Map.toList locals)
// Add a variable for each assignment to the env.
let new_env = env.clone();
for (name, loc_type) in let_con.assignment_types {
let var = type_to_variable(subs, loc_type.value);
new_env.insert(name, var);
}
}
}
}
},
}
}

View file

@ -2,8 +2,7 @@ use subs::Variable;
use region::Region;
use operator::Operator;
use region::Located;
use canonicalize::Symbol;
use collections::MutMap;
use collections::ImMap;
type ModuleName = String;
@ -56,9 +55,9 @@ pub enum Constraint {
pub struct LetConstraint {
pub rigid_vars: Vec<Variable>,
pub flex_vars: Vec<Variable>,
pub header: MutMap<Symbol, Located<Type>>,
pub header_constraint: Constraint,
pub body_constraint: Constraint,
pub assignment_types: ImMap<String, Located<Type>>,
pub assignments_constraint: Constraint,
pub ret_constraint: Constraint,
}

View file

@ -1,5 +1,6 @@
use std::marker::PhantomData;
use std::hash::{Hash, Hasher};
use std::ops::{Add, Sub, Mul, Neg};
/// Approx is stored as an f64 under the hood.
///
@ -89,15 +90,19 @@ impl<T> Approximation<T> {
}
}
impl<T> From<f64> for Approximation<T> {
impl<Valid> From<f64> for Approximation<Valid> {
fn from(num: f64) -> Self {
if num.is_finite() {
Approximation { value: num, phantom: PhantomData }
} else {
panic!("Tried to convert {:?} to Float.", num)
}
}
}
impl<T> From<f32> for Approximation<T> {
impl<Valid> From<f32> for Approximation<Valid> {
fn from(num: f32) -> Self {
Approximation { value: num as f64, phantom: PhantomData }
(num as f64).into()
}
}
@ -107,8 +112,39 @@ impl<T> Into<f64> for Approximation<T> {
}
}
impl<T> Into<f32> for Approximation<T> {
fn into(self) -> f32 {
self.value as f32
impl Add for Approximation<Valid> {
type Output = Approximation<Valid>;
fn add(self, other: Self) -> Self {
assert_no_overflow(self.value.add(other.value), "addition")
}
}
impl Mul for Approximation<Valid> {
type Output = Approximation<Valid>;
fn mul(self, other: Self) -> Self {
assert_no_overflow(self.value.mul(other.value), "multiplication")
}
}
impl Sub for Approximation<Valid> {
type Output = Approximation<Valid>;
fn sub(self, other: Self) -> Self {
assert_no_overflow(self.value.sub(other.value), "subtraction")
}
}
#[inline(always)]
fn assert_no_overflow(num: f64, op: &'static str) -> Approximation<Valid> {
if num.is_finite() {
Approximation { value: num, phantom: PhantomData }
} else if num.is_infinity() {
panic!("Float overflowed during ", op)
} else if num.is_negative_infinity() {
panic!("Float underflowed during ", op)
} else {
panic!("Float was NaN during ", op)
}
}

View file

@ -68,22 +68,22 @@ mod test_infer {
}
#[test]
fn infer_empty_record() {
fn empty_record() {
infer_eq("{}", "{}");
}
#[test]
fn infer_int() {
fn int_literal() {
infer_eq("5", "Num.Num *");
}
#[test]
fn infer_fractional() {
fn fractional_literal() {
infer_eq("0.5", "Num.Num (Num.Fractional *)");
}
#[test]
fn infer_string() {
fn string_literal() {
infer_eq(
indoc!(r#"
"type inference!"
@ -93,7 +93,7 @@ mod test_infer {
}
#[test]
fn infer_empty_string() {
fn empty_string() {
infer_eq(
indoc!(r#"
""
@ -107,7 +107,7 @@ mod test_infer {
#[test]
fn infer_empty_list() {
fn empty_list() {
infer_eq(
indoc!(r#"
[]
@ -117,7 +117,7 @@ mod test_infer {
}
#[test]
fn infer_list_of_lists() {
fn list_of_lists() {
infer_eq(
indoc!(r#"
[[]]
@ -127,7 +127,7 @@ mod test_infer {
}
#[test]
fn infer_triple_nested_list() {
fn triple_nested_list() {
infer_eq(
indoc!(r#"
[[[]]]
@ -137,7 +137,17 @@ mod test_infer {
}
#[test]
fn infer_list_of_one_num() {
fn nested_empty_list() {
infer_eq(
indoc!(r#"
[ [], [ [] ] ]
"#),
"List.List (List.List (List.List *))"
);
}
#[test]
fn list_of_one_num() {
infer_eq(
indoc!(r#"
[42]
@ -147,7 +157,7 @@ mod test_infer {
}
#[test]
fn infer_triple_nested_num_list() {
fn triple_nested_num_list() {
infer_eq(
indoc!(r#"
[[[ 5 ]]]
@ -157,7 +167,7 @@ mod test_infer {
}
#[test]
fn infer_list_of_nums() {
fn list_of_nums() {
infer_eq(
indoc!(r#"
[ 1, 2, 3 ]
@ -167,7 +177,17 @@ mod test_infer {
}
#[test]
fn infer_list_of_one_string() {
fn nested_list_of_nums() {
infer_eq(
indoc!(r#"
[ [ 1 ], [ 2, 3 ] ]
"#),
"List.List (List.List (Num.Num *))"
);
}
#[test]
fn list_of_one_string() {
infer_eq(
indoc!(r#"
[ "cowabunga" ]
@ -177,7 +197,7 @@ mod test_infer {
}
#[test]
fn infer_triple_nested_string_list() {
fn triple_nested_string_list() {
infer_eq(
indoc!(r#"
[[[ "foo" ]]]
@ -186,9 +206,8 @@ mod test_infer {
);
}
#[test]
fn infer_list_of_strings() {
fn list_of_strings() {
infer_eq(
indoc!(r#"
[ "foo", "bar" ]
@ -197,6 +216,38 @@ mod test_infer {
);
}
// LIST MISMATCH
#[test]
fn mismatch_heterogeneous_list() {
infer_eq(
indoc!(r#"
[ "foo", 5 ]
"#),
"List.List <type mismatch>"
);
}
#[test]
fn mismatch_heterogeneous_nested_list() {
infer_eq(
indoc!(r#"
[ [ "foo", 5 ] ]
"#),
"List.List (List.List <type mismatch>)"
);
}
#[test]
fn mismatch_heterogeneous_nested_empty_list() {
infer_eq(
indoc!(r#"
[ [ 1 ], [ [] ] ]
"#),
"List.List (List.List <type mismatch>)"
);
}
// #[test]
// fn infer_interpolated_string() {