mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Let constraint compiles
This commit is contained in:
parent
49cd2ede8a
commit
7308ef24c0
4 changed files with 40 additions and 54 deletions
|
@ -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"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
50
src/solve.rs
50
src/solve.rs
|
@ -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,48 +38,31 @@ 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);
|
||||||
|
|
||||||
new_env.insert(name, var);
|
new_env.insert(name, var);
|
||||||
}
|
|
||||||
|
|
||||||
// Now solve the body, using the new env which includes
|
|
||||||
// the assignments' name-to-variable mappings.
|
|
||||||
solve(&new_env, subs, let_con.ret_constraint);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now solve the body, using the new env which includes
|
||||||
|
// the assignments' name-to-variable mappings.
|
||||||
|
solve(&new_env, subs, ret_con);
|
||||||
|
|
||||||
|
// TODO do an occurs check for each of the assignments!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue