Let constraint compiles

This commit is contained in:
Richard Feldman 2019-08-28 21:08:11 -04:00
parent 49cd2ede8a
commit 7308ef24c0
4 changed files with 40 additions and 54 deletions

View file

@ -1,6 +1,6 @@
use canonicalize::{Pattern, Procedure, Symbol}; use canonicalize::{Pattern, Procedure, Symbol};
use canonicalize::Expr::{self, *}; use canonicalize::Expr::{self, *};
use collections::{ImMap, MutMap}; use collections::ImMap;
use region::{Located, Region}; use region::{Located, Region};
use subs::{Variable, Subs}; use subs::{Variable, Subs};
use types::{Expected, Expected::*, LetConstraint, Reason}; use types::{Expected, Expected::*, LetConstraint, Reason};
@ -117,10 +117,10 @@ pub fn constrain_def(
loc_expr: Located<Expr>, loc_expr: Located<Expr>,
bound_vars: BoundTypeVars, bound_vars: BoundTypeVars,
subs: &mut Subs, subs: &mut Subs,
body_constraint: Constraint ret_constraint: Constraint
) -> Constraint { ) -> Constraint {
let mut state = PatternState { let mut state = PatternState {
headers: MutMap::default(), assignment_types: ImMap::default(),
vars: Vec::with_capacity(1), vars: Vec::with_capacity(1),
reversed_constraints: Vec::with_capacity(1) reversed_constraints: Vec::with_capacity(1)
}; };
@ -131,16 +131,16 @@ pub fn constrain_def(
Let(Box::new(LetConstraint { Let(Box::new(LetConstraint {
rigid_vars: Vec::new(), rigid_vars: Vec::new(),
flex_vars: args.vars, flex_vars: args.vars,
header_constraint: assignments_constraint:
Let(Box::new(LetConstraint { Let(Box::new(LetConstraint {
rigid_vars: Vec::new(), rigid_vars: Vec::new(),
flex_vars: state.vars, flex_vars: state.vars,
header: state.headers, assignment_types: state.assignment_types,
header_constraint: And(state.reversed_constraints), assignments_constraint: And(state.reversed_constraints),
body_constraint: constrain(bound_vars, subs, loc_expr, NoExpectation(args.ret_type)) ret_constraint: constrain(bound_vars, subs, loc_expr, NoExpectation(args.ret_type))
})), })),
body_constraint, ret_constraint,
header: panic!("TODO Map.singleton name (A.At region tipe)"), assignment_types: panic!("TODO Map.singleton name (A.At region tipe)"),
})) }))
} }
@ -152,17 +152,17 @@ pub fn constrain_procedure(
expected: Expected<Type> expected: Expected<Type>
) -> Constraint { ) -> Constraint {
let mut state = PatternState { let mut state = PatternState {
headers: MutMap::default(), assignment_types: ImMap::default(),
vars: Vec::with_capacity(proc.args.len()), vars: Vec::with_capacity(proc.args.len()),
reversed_constraints: Vec::with_capacity(1) reversed_constraints: Vec::with_capacity(1)
}; };
let args = constrain_args(proc.args.into_iter(), subs, &mut state); let args = constrain_args(proc.args.into_iter(), subs, &mut state);
let body_type = NoExpectation(args.ret_type); let body_type = NoExpectation(args.ret_type);
let body_constraint = constrain(bound_vars, subs, proc.body, body_type); let ret_constraint = constrain(bound_vars, subs, proc.body, body_type);
state.reversed_constraints.reverse(); state.reversed_constraints.reverse();
let header_constraint = And(state.reversed_constraints); let assignments_constraint = And(state.reversed_constraints);
// panic!("TODO occurs check"); // panic!("TODO occurs check");
@ -170,9 +170,9 @@ pub fn constrain_procedure(
Let(Box::new(LetConstraint { Let(Box::new(LetConstraint {
rigid_vars: Vec::new(), rigid_vars: Vec::new(),
flex_vars: state.vars, flex_vars: state.vars,
header: state.headers, assignment_types: state.assignment_types,
header_constraint, assignments_constraint,
body_constraint ret_constraint
})), })),
Eq(args.typ, expected, region) Eq(args.typ, expected, region)
]) ])
@ -215,13 +215,13 @@ where I: Iterator<Item = Located<Pattern>>
} }
struct PatternState { struct PatternState {
headers: MutMap<Symbol, Located<Type>>, assignment_types: ImMap<Symbol, Located<Type>>,
vars: Vec<Variable>, vars: Vec<Variable>,
reversed_constraints: Vec<Constraint> reversed_constraints: Vec<Constraint>
} }
fn add_to_headers(region: Region, symbol: Symbol, expected: Expected<Type>, state: &mut PatternState) { fn add_to_assignment_types(region: Region, symbol: Symbol, expected: Expected<Type>, state: &mut PatternState) {
state.headers.insert(symbol, Located {region, value: expected.unwrap()}); state.assignment_types.insert(symbol, Located {region, value: expected.unwrap()});
} }
fn add_pattern(loc_pattern: Located<Pattern>, expected: Expected<Type>, state: &mut PatternState) { fn add_pattern(loc_pattern: Located<Pattern>, expected: Expected<Type>, state: &mut PatternState) {
@ -230,7 +230,7 @@ fn add_pattern(loc_pattern: Located<Pattern>, expected: Expected<Type>, state: &
let region = loc_pattern.region; let region = loc_pattern.region;
match loc_pattern.value { match loc_pattern.value {
Identifier(symbol) => add_to_headers(region, symbol, expected, state), Identifier(symbol) => add_to_assignment_types(region, symbol, expected, state),
Underscore => (), Underscore => (),
_ => panic!("TODO other patterns"), _ => panic!("TODO other patterns"),
} }

View file

@ -9,11 +9,12 @@ use constrain::constrain;
pub fn infer_expr(subs: &mut Subs, loc_expr: Located<Expr>, procedures: MutMap<Symbol, Procedure>) -> Content { pub fn infer_expr(subs: &mut Subs, loc_expr: Located<Expr>, procedures: MutMap<Symbol, Procedure>) -> Content {
let bound_vars = ImMap::default(); let bound_vars = ImMap::default();
let env = ImMap::default();
let variable = subs.mk_flex_var(); let variable = subs.mk_flex_var();
let expected = NoExpectation(Variable(variable)); let expected = NoExpectation(Variable(variable));
let constraint = constrain(bound_vars, subs, loc_expr, expected); let constraint = constrain(bound_vars, subs, loc_expr, expected);
solve(subs, constraint); solve(&env, subs, constraint);
subs.get(variable).content subs.get(variable).content
} }

View file

@ -15,10 +15,11 @@
use subs::{Subs, Variable, Descriptor, Content, FlatType}; use subs::{Subs, Variable, Descriptor, Content, FlatType};
use collections::ImMap; use collections::ImMap;
use canonicalize::Symbol;
use types::Constraint::{self, *}; use types::Constraint::{self, *};
use types::Type::{self, *}; use types::Type::{self, *};
type Env = ImMap<String, Variable>; type Env = ImMap<Symbol, Variable>;
pub fn solve(env: &Env, subs: &mut Subs, constraint: Constraint) { 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);
@ -37,22 +38,19 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: 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();
match let_con.ret_constraint { match let_con.ret_constraint {
True if no_rigid_vars => { True => {
// If the return expression is guaranteed to solve, // 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 the assignments themselves and move on.
solve(env, subs, let_con.assignments_constraint) solve(env, subs, let_con.assignments_constraint)
}, },
body_con => { ret_con => {
if no_rigid_vars && let_con.flex_vars.is_empty() {
// Solve the assignments' constraints first. // Solve the assignments' constraints first.
solve(env, subs, let_con.assignments_constraint); solve(env, subs, let_con.assignments_constraint);
// Add a variable for each assignment to the env. // Add a variable for each assignment to the env.
let new_env = env.clone(); let mut new_env = env.clone();
for (name, loc_type) in let_con.assignment_types { for (name, loc_type) in let_con.assignment_types {
let var = type_to_variable(subs, loc_type.value); let var = type_to_variable(subs, loc_type.value);
@ -62,23 +60,9 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: Constraint) {
// Now solve the body, using the new env which includes // Now solve the body, using the new env which includes
// the assignments' name-to-variable mappings. // the assignments' name-to-variable mappings.
solve(&new_env, subs, let_con.ret_constraint); solve(&new_env, subs, ret_con);
// TODO do an occurs check for each of the assignments! // TODO do an occurs check for each of the assignments!
} else {
let vars = let_con.rigid_vars;
vars.extend(let_con.flex_vars);
// 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,6 +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::ImMap;
type ModuleName = String; type ModuleName = String;
@ -55,7 +56,7 @@ 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 assignment_types: ImMap<String, Located<Type>>, pub assignment_types: ImMap<Symbol, Located<Type>>,
pub assignments_constraint: Constraint, pub assignments_constraint: Constraint,
pub ret_constraint: Constraint, pub ret_constraint: Constraint,
} }