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 subs::{Subs, Variable, Descriptor, Content, FlatType};
use collections::ImMap;
use types::Constraint::{self, *}; use types::Constraint::{self, *};
use types::Type::{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); println!("\nSolving:\n\n\t{:?}\n\n", constraint);
match constraint { match constraint {
True => (), True => (),
@ -29,63 +32,55 @@ pub fn solve(subs: &mut Subs, constraint: Constraint) {
}, },
And(sub_constraints) => { And(sub_constraints) => {
for sub_constraint in sub_constraints { for sub_constraint in sub_constraints {
solve(subs, sub_constraint); solve(env, subs, sub_constraint);
} }
}, },
Let(box_let_constraint) => { Let(box_let_constraint) => {
let let_con = *box_let_constraint; let let_con = *box_let_constraint;
let no_rigid_vars = let_con.rigid_vars.is_empty();
// CLet [] flexs _ headerCon CTrue -> match let_con.ret_constraint {
// do introduce rank pools flexs True if no_rigid_vars => {
// solve env rank pools state headerCon // 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 -> // Add a variable for each assignment to the env.
// do state1 <- solve env rank pools state headerCon let new_env = env.clone();
// 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
// CLet rigids flexs header headerCon subCon -> for (name, loc_type) in let_con.assignment_types {
// do let var = type_to_variable(subs, loc_type.value);
// -- 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
// -- introduce variables new_env.insert(name, var);
// let vars = rigids ++ flexs }
// forM_ vars $ \var ->
// UF.modify var $ \(Descriptor content _ mark copy) ->
// Descriptor content nextRank mark copy
// MVector.write nextPools nextRank vars
// -- run solver in next pool // Now solve the body, using the new env which includes
// locals <- traverse (A.traverse (typeToVariable nextRank nextPools)) header // the assignments' name-to-variable mappings.
// (State savedEnv mark errors) <- solve(&new_env, subs, let_con.ret_constraint);
// solve env nextRank nextPools state headerCon
// let youngMark = mark // TODO do an occurs check for each of the assignments!
// let visitMark = nextMark youngMark } else {
// let finalMark = nextMark visitMark let vars = let_con.rigid_vars;
// -- pop pool vars.extend(let_con.flex_vars);
// generalize youngMark visitMark nextRank nextPools
// MVector.write nextPools nextRank []
// -- check that things went well // Add a variable for each assignment to the env.
// mapM_ isGeneric rigids let new_env = env.clone();
// 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)
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 region::Region;
use operator::Operator; use operator::Operator;
use region::Located; use region::Located;
use canonicalize::Symbol; use collections::ImMap;
use collections::MutMap;
type ModuleName = String; type ModuleName = String;
@ -56,9 +55,9 @@ pub enum Constraint {
pub struct LetConstraint { pub struct LetConstraint {
pub rigid_vars: Vec<Variable>, pub rigid_vars: Vec<Variable>,
pub flex_vars: Vec<Variable>, pub flex_vars: Vec<Variable>,
pub header: MutMap<Symbol, Located<Type>>, pub assignment_types: ImMap<String, Located<Type>>,
pub header_constraint: Constraint, pub assignments_constraint: Constraint,
pub body_constraint: Constraint, pub ret_constraint: Constraint,
} }

View file

@ -1,5 +1,6 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::{Add, Sub, Mul, Neg};
/// Approx is stored as an f64 under the hood. /// 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 { fn from(num: f64) -> Self {
if num.is_finite() {
Approximation { value: num, phantom: PhantomData } 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 { 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> { impl Add for Approximation<Valid> {
fn into(self) -> f32 { type Output = Approximation<Valid>;
self.value as f32
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] #[test]
fn infer_empty_record() { fn empty_record() {
infer_eq("{}", "{}"); infer_eq("{}", "{}");
} }
#[test] #[test]
fn infer_int() { fn int_literal() {
infer_eq("5", "Num.Num *"); infer_eq("5", "Num.Num *");
} }
#[test] #[test]
fn infer_fractional() { fn fractional_literal() {
infer_eq("0.5", "Num.Num (Num.Fractional *)"); infer_eq("0.5", "Num.Num (Num.Fractional *)");
} }
#[test] #[test]
fn infer_string() { fn string_literal() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
"type inference!" "type inference!"
@ -93,7 +93,7 @@ mod test_infer {
} }
#[test] #[test]
fn infer_empty_string() { fn empty_string() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
"" ""
@ -107,7 +107,7 @@ mod test_infer {
#[test] #[test]
fn infer_empty_list() { fn empty_list() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[] []
@ -117,7 +117,7 @@ mod test_infer {
} }
#[test] #[test]
fn infer_list_of_lists() { fn list_of_lists() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[[]] [[]]
@ -127,7 +127,7 @@ mod test_infer {
} }
#[test] #[test]
fn infer_triple_nested_list() { fn triple_nested_list() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[[[]]] [[[]]]
@ -137,7 +137,17 @@ mod test_infer {
} }
#[test] #[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( infer_eq(
indoc!(r#" indoc!(r#"
[42] [42]
@ -147,7 +157,7 @@ mod test_infer {
} }
#[test] #[test]
fn infer_triple_nested_num_list() { fn triple_nested_num_list() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[[[ 5 ]]] [[[ 5 ]]]
@ -157,7 +167,7 @@ mod test_infer {
} }
#[test] #[test]
fn infer_list_of_nums() { fn list_of_nums() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[ 1, 2, 3 ] [ 1, 2, 3 ]
@ -167,7 +177,17 @@ mod test_infer {
} }
#[test] #[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( infer_eq(
indoc!(r#" indoc!(r#"
[ "cowabunga" ] [ "cowabunga" ]
@ -177,7 +197,7 @@ mod test_infer {
} }
#[test] #[test]
fn infer_triple_nested_string_list() { fn triple_nested_string_list() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[[[ "foo" ]]] [[[ "foo" ]]]
@ -186,9 +206,8 @@ mod test_infer {
); );
} }
#[test] #[test]
fn infer_list_of_strings() { fn list_of_strings() {
infer_eq( infer_eq(
indoc!(r#" indoc!(r#"
[ "foo", "bar" ] [ "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] // #[test]
// fn infer_interpolated_string() { // fn infer_interpolated_string() {