Merge remote-tracking branch 'origin/trunk' into fix-module-constraints

This commit is contained in:
Richard Feldman 2020-02-11 20:42:00 -05:00
commit 8eb91807e4
16 changed files with 336 additions and 176 deletions

View File

@ -6,9 +6,10 @@ use crate::can::scope::Scope;
use crate::collections::{default_hasher, ImMap, MutMap, MutSet, SendMap};
use crate::module::symbol::Symbol;
use crate::parse::ast::{AssignedField, Tag, TypeAnnotation};
use crate::region::Located;
use crate::region::Region;
use crate::subs::{VarStore, Variable};
use crate::types::{Problem, Type};
use crate::types::{Alias, Problem, Type};
use std::collections::HashSet;
#[derive(Clone, Debug, PartialEq)]
@ -17,6 +18,7 @@ pub struct Annotation {
pub ftv: MutMap<Variable, Lowercase>,
pub rigids: ImMap<Lowercase, Variable>,
pub references: MutSet<Symbol>,
pub aliases: SendMap<Symbol, Alias>,
}
pub fn canonicalize_annotation(
@ -37,21 +39,17 @@ pub fn canonicalize_annotation(
// but a variable can only have one name. Therefore
// `ftv : SendMap<Variable, Lowercase>`.
let mut rigids = ImMap::default();
let mut local_aliases = Vec::new();
let (mut typ, references) = can_annotation_help(
let mut aliases = SendMap::default();
let (typ, references) = can_annotation_help(
env,
annotation,
region,
scope,
var_store,
&mut rigids,
&mut local_aliases,
&mut aliases,
);
for (symbol, tipe) in local_aliases {
typ.substitute_alias(symbol, &tipe);
}
let mut ftv = MutMap::default();
for (k, v) in rigids.clone() {
@ -63,6 +61,7 @@ pub fn canonicalize_annotation(
ftv,
references,
rigids,
aliases,
}
}
@ -73,8 +72,8 @@ fn can_annotation_help(
scope: &mut Scope,
var_store: &VarStore,
rigids: &mut ImMap<Lowercase, Variable>,
local_aliases: &mut Vec<(Symbol, crate::types::Type)>,
) -> (crate::types::Type, MutSet<Symbol>) {
local_aliases: &mut SendMap<Symbol, Alias>,
) -> (Type, MutSet<Symbol>) {
use crate::parse::ast::TypeAnnotation::*;
match annotation {
@ -166,41 +165,7 @@ fn can_annotation_help(
args.push(arg_ann);
}
if let Some(alias) = scope.lookup_alias(symbol) {
let ftv = &alias.vars;
let actual = &alias.typ;
if args.len() != ftv.len() {
panic!("TODO alias applied to incorrect number of type arguments");
}
let mut zipped_args: Vec<(Lowercase, Type)> = Vec::with_capacity(args.len());
let mut substitution = ImMap::default();
for (loc_var, arg) in ftv.iter().zip(args.iter()) {
substitution.insert(loc_var.value.1, arg.clone());
zipped_args.push((loc_var.value.0.clone(), arg.clone()));
}
let mut instantiated = actual.clone();
instantiated.substitute(&substitution);
if let Type::RecursiveTagUnion(rec, _, _) = &mut instantiated {
let new_rec = var_store.fresh();
let old = *rec;
*rec = new_rec;
let mut rec_substitution = ImMap::default();
rec_substitution.insert(old, Type::Variable(new_rec));
instantiated.substitute(&rec_substitution);
}
(
Type::Alias(symbol, zipped_args, Box::new(instantiated)),
references,
)
} else {
(Type::Apply(symbol, args), references)
}
(Type::Apply(symbol, args), references)
}
BoundVariable(v) => {
let name = Lowercase::from(*v);
@ -245,6 +210,7 @@ fn can_annotation_help(
local_aliases,
);
let mut vars = Vec::with_capacity(loc_vars.len());
let mut lowercase_vars = Vec::with_capacity(loc_vars.len());
references.insert(symbol);
@ -259,7 +225,9 @@ fn can_annotation_help(
let var = var_store.fresh();
rigids.insert(var_name.clone(), var);
vars.push((var_name, Type::Variable(var)));
vars.push((var_name.clone(), Type::Variable(var)));
lowercase_vars.push(Located::at(loc_var.region, (var_name, var)));
}
}
_ => {
@ -273,7 +241,7 @@ fn can_annotation_help(
}
}
let alias = if let Type::TagUnion(tags, ext) = inner_type {
let alias_actual = if let Type::TagUnion(tags, ext) = inner_type {
let rec_var = var_store.fresh();
let mut new_tags = Vec::with_capacity(tags.len());
@ -286,16 +254,20 @@ fn can_annotation_help(
}
new_tags.push((tag_name.clone(), new_args));
}
let rec_tag_union = Type::RecursiveTagUnion(rec_var, new_tags, ext);
Type::Alias(symbol, vars, Box::new(rec_tag_union))
Type::RecursiveTagUnion(rec_var, new_tags, ext)
} else {
Type::Alias(symbol, vars, Box::new(inner_type))
inner_type
};
local_aliases.push((symbol, alias.clone()));
let alias = Alias {
region,
vars: lowercase_vars,
typ: alias_actual.clone(),
};
local_aliases.insert(symbol, alias);
(alias, references)
let type_alias = Type::Alias(symbol, vars, Box::new(alias_actual));
(type_alias, references)
}
_ => {
// This is a syntactically invalid type alias.
@ -398,7 +370,7 @@ fn can_assigned_field<'a>(
scope: &mut Scope,
var_store: &VarStore,
rigids: &mut ImMap<Lowercase, Variable>,
local_aliases: &mut Vec<(Symbol, Type)>,
local_aliases: &mut SendMap<Symbol, Alias>,
field_types: &mut SendMap<Lowercase, Type>,
) -> MutSet<Symbol> {
use crate::parse::ast::AssignedField::*;
@ -460,7 +432,7 @@ fn can_tag<'a>(
scope: &mut Scope,
var_store: &VarStore,
rigids: &mut ImMap<Lowercase, Variable>,
local_aliases: &mut Vec<(Symbol, Type)>,
local_aliases: &mut SendMap<Symbol, Alias>,
tag_types: &mut Vec<(TagName, Vec<Type>)>,
) -> MutSet<Symbol> {
match tag {

View File

@ -18,18 +18,19 @@ use crate::module::symbol::Symbol;
use crate::parse::ast;
use crate::region::{Located, Region};
use crate::subs::{VarStore, Variable};
use crate::types::Type;
use crate::types::{Alias, Type};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt::Debug;
#[allow(clippy::type_complexity)]
#[derive(Clone, Debug, PartialEq)]
pub struct Def {
pub loc_pattern: Located<Pattern>,
pub loc_expr: Located<Expr>,
pub expr_var: Variable,
pub pattern_vars: SendMap<Symbol, Variable>,
pub annotation: Option<(Type, SendMap<Variable, Lowercase>)>,
pub annotation: Option<(Type, SendMap<Variable, Lowercase>, SendMap<Symbol, Alias>)>,
}
#[derive(Debug)]
@ -39,6 +40,7 @@ pub struct CanDefs {
pub refs_by_symbol: MutMap<Symbol, (Located<Ident>, References)>,
pub can_defs_by_symbol: MutMap<Symbol, Def>,
pub symbols_introduced: MutMap<Symbol, Region>,
pub aliases: SendMap<Symbol, Alias>,
}
/// A Def that has had patterns and type annnotations canonicalized,
/// but no Expr canonicalization has happened yet. Also, it has had spaces
@ -186,6 +188,8 @@ pub fn canonicalize_defs<'a>(
pending.sort_by(aliases_first);
let mut aliases = SendMap::default();
// Now that we have the scope completely assembled, and shadowing resolved,
// we're ready to canonicalize any body exprs.
for pending_def in pending.into_iter() {
@ -197,6 +201,7 @@ pub fn canonicalize_defs<'a>(
&mut can_defs_by_symbol,
var_store,
&mut refs_by_symbol,
&mut aliases,
);
// TODO we should do something with these references; they include
@ -227,6 +232,7 @@ pub fn canonicalize_defs<'a>(
refs_by_symbol,
can_defs_by_symbol,
symbols_introduced,
aliases,
},
scope,
output,
@ -243,8 +249,13 @@ pub fn sort_can_defs(
symbols_introduced,
refs_by_symbol,
can_defs_by_symbol,
aliases,
} = defs;
for (symbol, alias) in aliases.clone() {
output.aliases.insert(symbol, alias);
}
// Determine the full set of references by traversing the graph.
let mut visited_symbols = MutSet::default();
let returned_lookups = ImSet::clone(&output.references.lookups);
@ -653,6 +664,7 @@ fn canonicalize_pending_def<'a>(
can_defs_by_symbol: &mut MutMap<Symbol, Def>,
var_store: &VarStore,
refs_by_symbol: &mut MutMap<Symbol, (Located<Ident>, References)>,
aliases: &mut SendMap<Symbol, Alias>,
) -> Output {
use PendingDef::*;
@ -667,6 +679,10 @@ fn canonicalize_pending_def<'a>(
// use them. We discard them!
let ann = loc_ann.value;
for (symbol, alias) in ann.aliases.clone() {
aliases.insert(symbol, alias);
}
// union seen rigids with already found ones
for (k, v) in ann.ftv {
output.rigids.insert(k, v);
@ -740,15 +756,20 @@ fn canonicalize_pending_def<'a>(
value: loc_can_expr.value.clone(),
},
pattern_vars: im::HashMap::clone(&vars_by_symbol),
annotation: Some((typ.clone(), output.rigids.clone())),
annotation: Some((typ.clone(), output.rigids.clone(), ann.aliases.clone())),
},
);
}
}
Alias { ann, .. } => {
Alias { ann, name, .. } => {
let can_ann = canonicalize_annotation(env, scope, &ann.value, ann.region, var_store);
// For now, use the alias from the scope (which already deals with (mutual) recursion)
if let Some(alias) = scope.lookup_alias(name.value) {
aliases.insert(name.value, alias.clone());
}
// TODO should probably incorporate can_ann.references here - possibly by
// inserting them into refs_by_symbol?
@ -759,13 +780,17 @@ fn canonicalize_pending_def<'a>(
}
}
TypedBody(loc_pattern, loc_can_pattern, loc_annotation, loc_expr) => {
TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr) => {
// TODO we have ann.references here, which includes information about
// which symbols were referenced in type annotations, but we never
// use them. We discard them!
let ann = loc_annotation.value;
let ann = loc_ann.value;
let typ = ann.typ;
for (symbol, alias) in ann.aliases.clone() {
aliases.insert(symbol, alias);
}
// union seen rigids with already found ones
for (k, v) in ann.ftv {
output.rigids.insert(k, v);
@ -886,7 +911,7 @@ fn canonicalize_pending_def<'a>(
value: loc_can_expr.value.clone(),
},
pattern_vars: im::HashMap::clone(&vars_by_symbol),
annotation: Some((typ.clone(), output.rigids.clone())),
annotation: Some((typ.clone(), output.rigids.clone(), ann.aliases.clone())),
},
);
}
@ -1063,7 +1088,7 @@ pub fn can_defs_with_return<'a>(
for declaration in decls.into_iter().rev() {
loc_expr = Located {
region: Region::zero(),
value: decl_to_let(var_store, declaration, loc_expr),
value: decl_to_let(var_store, declaration, loc_expr, output.aliases.clone()),
};
}
@ -1073,12 +1098,19 @@ pub fn can_defs_with_return<'a>(
}
}
fn decl_to_let(var_store: &VarStore, decl: Declaration, loc_ret: Located<Expr>) -> Expr {
fn decl_to_let(
var_store: &VarStore,
decl: Declaration,
loc_ret: Located<Expr>,
aliases: SendMap<Symbol, Alias>,
) -> Expr {
match decl {
Declaration::Declare(def) => {
Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh())
Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh(), aliases)
}
Declaration::DeclareRec(defs) => {
Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh(), aliases)
}
Declaration::DeclareRec(defs) => Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh()),
Declaration::InvalidCycle(symbols, regions) => {
Expr::RuntimeError(RuntimeError::CircularDef(symbols, regions))
}

View File

@ -16,6 +16,7 @@ use crate::operator::CalledVia;
use crate::parse::ast;
use crate::region::{Located, Region};
use crate::subs::{VarStore, Variable};
use crate::types::Alias;
use std::fmt::Debug;
use std::i64;
use std::ops::Neg;
@ -25,6 +26,7 @@ pub struct Output {
pub references: References,
pub tail_call: Option<Symbol>,
pub rigids: SendMap<Variable, Lowercase>,
pub aliases: SendMap<Symbol, Alias>,
}
#[derive(Clone, Debug, PartialEq)]
@ -56,8 +58,8 @@ pub enum Expr {
},
// Let
LetRec(Vec<Def>, Box<Located<Expr>>, Variable),
LetNonRec(Box<Def>, Box<Located<Expr>>, Variable),
LetRec(Vec<Def>, Box<Located<Expr>>, Variable, Aliases),
LetNonRec(Box<Def>, Box<Located<Expr>>, Variable, Aliases),
/// This is *only* for calling functions, not for tag application.
/// The Tag variant contains any applied values inside it.
@ -114,6 +116,8 @@ pub enum Expr {
RuntimeError(RuntimeError),
}
type Aliases = SendMap<Symbol, Alias>;
#[derive(Clone, Debug, PartialEq)]
pub struct Field {
pub var: Variable,

View File

@ -11,10 +11,12 @@ use crate::module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
use crate::parse::ast;
use crate::region::{Located, Region};
use crate::subs::{VarStore, Variable};
use crate::types::Alias;
use bumpalo::Bump;
#[derive(Debug)]
pub struct ModuleOutput {
pub aliases: MutMap<Symbol, Alias>,
pub declarations: Vec<Declaration>,
pub exposed_imports: MutMap<Symbol, Variable>,
pub lookups: Vec<(Symbol, Variable, Region)>,
@ -98,7 +100,7 @@ pub fn canonicalize_module_defs<'a>(
}
}
let (defs, scope, output) = canonicalize_defs(
let (defs, populated_scope, output) = canonicalize_defs(
&mut env,
Output::default(),
var_store,
@ -178,9 +180,14 @@ pub fn canonicalize_module_defs<'a>(
references.insert(symbol);
}
dbg!(home, &references);
let mut aliases = MutMap::default();
for (symbol, alias) in populated_scope.aliases() {
aliases.insert(*symbol, alias.clone());
}
Ok(ModuleOutput {
aliases,
declarations,
references,
exposed_imports: can_exposed_imports,

View File

@ -4,14 +4,7 @@ use crate::collections::ImMap;
use crate::module::symbol::{IdentIds, ModuleId, Symbol};
use crate::region::{Located, Region};
use crate::subs::Variable;
use crate::types::Type;
#[derive(Clone, Debug, PartialEq)]
pub struct Alias {
pub region: Region,
pub vars: Vec<Located<(Lowercase, Variable)>>,
pub typ: Type,
}
use crate::types::{Alias, Type};
#[derive(Clone, Debug, PartialEq)]
pub struct Scope {

View File

@ -29,6 +29,7 @@ pub fn exists(flex_vars: Vec<Variable>, constraint: Constraint) -> Constraint {
rigid_vars: Vec::new(),
flex_vars,
def_types: SendMap::default(),
def_aliases: SendMap::default(),
defs_constraint: constraint,
ret_constraint: Constraint::True,
}))

View File

@ -11,6 +11,7 @@ use crate::constrain::pattern::{constrain_pattern, PatternState};
use crate::module::symbol::{ModuleId, Symbol};
use crate::region::{Located, Region};
use crate::subs::Variable;
use crate::types::Alias;
use crate::types::AnnotationSource::{self, *};
use crate::types::Constraint::{self, *};
use crate::types::Expected::{self, *};
@ -42,6 +43,23 @@ pub fn exists(flex_vars: Vec<Variable>, constraint: Constraint) -> Constraint {
rigid_vars: Vec::new(),
flex_vars,
def_types: SendMap::default(),
def_aliases: SendMap::default(),
defs_constraint: constraint,
ret_constraint: Constraint::True,
}))
}
#[inline(always)]
pub fn exists_with_aliases(
aliases: SendMap<Symbol, Alias>,
flex_vars: Vec<Variable>,
constraint: Constraint,
) -> Constraint {
Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars,
def_types: SendMap::default(),
def_aliases: aliases,
defs_constraint: constraint,
ret_constraint: Constraint::True,
}))
@ -283,6 +301,7 @@ pub fn constrain_expr(
rigid_vars: Vec::new(),
flex_vars: state.vars,
def_types: state.headers,
def_aliases: SendMap::default(),
defs_constraint,
ret_constraint,
})),
@ -540,10 +559,11 @@ pub fn constrain_expr(
),
)
}
LetRec(defs, loc_ret, var) => {
LetRec(defs, loc_ret, var, aliases) => {
let body_con = constrain_expr(env, loc_ret.region, &loc_ret.value, expected.clone());
exists(
exists_with_aliases(
aliases.clone(),
vec![*var],
And(vec![
constrain_recursive_defs(env, defs, body_con),
@ -553,10 +573,11 @@ pub fn constrain_expr(
]),
)
}
LetNonRec(def, loc_ret, var) => {
LetNonRec(def, loc_ret, var, aliases) => {
let body_con = constrain_expr(env, loc_ret.region, &loc_ret.value, expected.clone());
exists(
exists_with_aliases(
aliases.clone(),
vec![*var],
And(vec![
constrain_def(env, def, body_con),
@ -638,6 +659,7 @@ fn constrain_when_branch(
rigid_vars: Vec::new(),
flex_vars: state.vars,
def_types: state.headers,
def_aliases: SendMap::default(),
defs_constraint: Constraint::And(state.constraints),
ret_constraint,
}))
@ -716,10 +738,12 @@ pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
pattern_state.vars.push(expr_var);
let mut def_aliases = SendMap::default();
let mut new_rigids = Vec::new();
let expr_con = match &def.annotation {
Some((annotation, free_vars)) => {
Some((annotation, free_vars, ann_def_aliases)) => {
def_aliases = ann_def_aliases.clone();
let mut annotation = annotation.clone();
let rigids = &env.rigids;
let mut ftv: ImMap<Lowercase, Type> = rigids.clone();
@ -787,10 +811,12 @@ pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
rigid_vars: new_rigids,
flex_vars: pattern_state.vars,
def_types: pattern_state.headers,
def_aliases,
defs_constraint: Let(Box::new(LetConstraint {
rigid_vars: Vec::new(), // always empty
flex_vars: Vec::new(), // empty, because our functions have no arguments
def_types: SendMap::default(), // empty, because our functions have no arguments!
def_aliases: SendMap::default(),
defs_constraint: And(pattern_state.constraints),
ret_constraint: expr_con,
})),
@ -815,6 +841,7 @@ pub fn rec_defs_help(
mut rigid_info: Info,
mut flex_info: Info,
) -> Constraint {
let mut def_aliases = SendMap::default();
for def in defs {
let expr_var = def.expr_var;
let expr_type = Type::Variable(expr_var);
@ -851,6 +878,7 @@ pub fn rec_defs_help(
rigid_vars: Vec::new(),
flex_vars: Vec::new(), // empty because Roc function defs have no args
def_types: SendMap::default(), // empty because Roc function defs have no args
def_aliases: SendMap::default(),
defs_constraint: True, // I think this is correct, once again because there are no args
ret_constraint: expr_con,
}));
@ -860,7 +888,11 @@ pub fn rec_defs_help(
flex_info.def_types.extend(pattern_state.headers);
}
Some((annotation, seen_rigids)) => {
Some((annotation, seen_rigids, ann_def_aliases)) => {
for (symbol, alias) in ann_def_aliases.clone() {
def_aliases.insert(symbol, alias);
}
// TODO also do this for more complex patterns
if let Pattern::Identifier(symbol) = def.loc_pattern.value {
pattern_state.headers.insert(
@ -910,6 +942,7 @@ pub fn rec_defs_help(
rigid_vars: Vec::new(),
flex_vars: Vec::new(), // empty because Roc function defs have no args
def_types: SendMap::default(), // empty because Roc function defs have no args
def_aliases: SendMap::default(),
defs_constraint: True, // I think this is correct, once again because there are no args
ret_constraint: expr_con,
}));
@ -921,6 +954,7 @@ pub fn rec_defs_help(
rigid_vars: new_rigids,
flex_vars: Vec::new(), // no flex vars introduced
def_types: SendMap::default(), // no headers introduced (at this level)
def_aliases: SendMap::default(),
defs_constraint: def_con,
ret_constraint: True,
})));
@ -933,15 +967,18 @@ pub fn rec_defs_help(
rigid_vars: rigid_info.vars,
flex_vars: Vec::new(),
def_types: rigid_info.def_types,
def_aliases,
defs_constraint: True,
ret_constraint: Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: flex_info.vars,
def_types: flex_info.def_types.clone(),
def_aliases: SendMap::default(),
defs_constraint: Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: Vec::new(),
def_types: flex_info.def_types,
def_aliases: SendMap::default(),
defs_constraint: True,
ret_constraint: And(flex_info.constraints),
})),

View File

@ -151,6 +151,7 @@ fn constrain_imported_value(
// Importing a value doesn't constrain this module at all.
// All it does is introduce variables and provide def_types for lookups
def_types,
def_aliases: SendMap::default(),
defs_constraint: True,
ret_constraint: body_con,
}))

View File

@ -9,7 +9,11 @@ pub fn infer_expr(
constraint: &Constraint,
expr_var: Variable,
) -> (Content, Solved<Subs>) {
let (solved, _) = solve::run(&SendMap::default(), problems, subs, constraint);
let env = solve::Env {
aliases: SendMap::default(),
vars_by_symbol: SendMap::default(),
};
let (solved, _) = solve::run(&env, problems, subs, constraint);
let content = solved.inner().get_without_compacting(expr_var).content;

View File

@ -10,7 +10,7 @@ use crate::parse::parser::{Fail, Parser, State};
use crate::region::{Located, Region};
use crate::solve::{self, ExposedModuleTypes, Solved, SolvedType, SubsByModule};
use crate::subs::{Subs, VarStore, Variable};
use crate::types::{Constraint, Problem};
use crate::types::{Alias, Constraint, Problem};
use bumpalo::Bump;
use std::collections::{HashMap, HashSet};
use std::fs::read_to_string;
@ -33,6 +33,7 @@ pub struct Module {
pub exposed_imports: MutMap<Symbol, Variable>,
pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
pub references: MutSet<Symbol>,
pub aliases: MutMap<Symbol, Alias>,
}
pub struct LoadedModule {
@ -78,7 +79,7 @@ enum Msg {
solved_types: MutMap<Symbol, SolvedType>,
subs: Arc<Solved<Subs>>,
problems: Vec<Problem>,
new_vars_by_symbol: SendMap<Symbol, Variable>,
solved_env: solve::Env,
},
}
@ -194,7 +195,9 @@ pub async fn load<'a>(
let mut solve_listeners: MutMap<ModuleId, Vec<ModuleId>> = MutMap::default();
let mut unsolved_modules: MutMap<ModuleId, (Module, Constraint, VarStore)> = MutMap::default();
let mut vars_by_symbol = SendMap::default();
// TODO can be removed I think
let vars_by_symbol = SendMap::default();
// Parse and canonicalize the module's deps
while let Some(msg) = msg_rx.recv().await {
@ -370,7 +373,7 @@ pub async fn load<'a>(
solved_types,
subs,
problems,
new_vars_by_symbol,
..
} => {
all_problems.extend(problems);
@ -781,6 +784,12 @@ fn solve_module(
let exposed_vars_by_symbol: Vec<(Symbol, Variable)> = module.exposed_vars_by_symbol;
let mut aliases = SendMap::default();
for (symbol, alias) in module.aliases.clone() {
aliases.insert(symbol, alias);
}
// Start solving this module in the background.
spawn_blocking(move || {
// Now that the module is parsed, canonicalized, and constrained,
@ -788,9 +797,13 @@ fn solve_module(
let subs = Subs::new(var_store.into());
let mut problems = Vec::new();
let env = solve::Env {
vars_by_symbol,
aliases,
};
// Run the solver to populate Subs.
let (solved_subs, new_vars_by_symbol) =
solve::run(&vars_by_symbol, &mut problems, subs, &constraint);
let (solved_subs, solved_env) = solve::run(&env, &mut problems, subs, &constraint);
let mut solved_types = MutMap::default();
@ -815,7 +828,7 @@ fn solve_module(
module_id: home,
subs: Arc::new(solved_subs),
solved_types,
new_vars_by_symbol,
solved_env,
problems,
})
.await
@ -918,6 +931,7 @@ fn parse_and_constrain(
ident_ids,
exposed_vars_by_symbol,
references,
aliases,
..
}) => {
let constraint = constrain_module(module_id, &declarations, lookups);
@ -928,6 +942,7 @@ fn parse_and_constrain(
exposed_imports,
exposed_vars_by_symbol,
references,
aliases,
};
(module, ident_ids, constraint)

View File

@ -124,7 +124,7 @@ fn from_can<'a>(
Float(_, val) => Expr::Float(val),
Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)),
Var(symbol) => Expr::Load(symbol.emit()),
LetNonRec(def, ret_expr, _) => {
LetNonRec(def, ret_expr, _, _) => {
let arena = env.arena;
let loc_pattern = def.loc_pattern;
let loc_expr = def.loc_expr;

View File

@ -3,6 +3,7 @@ use crate::collections::{ImMap, MutMap, SendMap};
use crate::module::symbol::{ModuleId, Symbol};
use crate::region::Located;
use crate::subs::{Content, Descriptor, FlatType, Mark, OptVariable, Rank, Subs, Variable};
use crate::types::Alias;
use crate::types::Constraint::{self, *};
use crate::types::Problem;
use crate::types::Type::{self, *};
@ -165,7 +166,11 @@ impl SolvedType {
}
}
type Env = SendMap<Symbol, Variable>;
#[derive(Clone, Debug)]
pub struct Env {
pub vars_by_symbol: SendMap<Symbol, Variable>,
pub aliases: SendMap<Symbol, Alias>,
}
const DEFAULT_POOLS: usize = 8;
@ -218,7 +223,7 @@ impl Pools {
#[derive(Clone)]
struct State {
vars_by_symbol: Env,
env: Env,
mark: Mark,
}
@ -238,32 +243,26 @@ impl<T> Solved<T> {
}
pub fn run(
vars_by_symbol: &Env,
env: &Env,
problems: &mut Vec<Problem>,
mut subs: Subs,
constraint: &Constraint,
) -> (Solved<Subs>, Env) {
let mut pools = Pools::default();
let state = State {
vars_by_symbol: vars_by_symbol.clone(),
env: env.clone(),
mark: Mark::NONE.next(),
};
let rank = Rank::toplevel();
let state = solve(
vars_by_symbol,
state,
rank,
&mut pools,
problems,
&mut subs,
constraint,
env, state, rank, &mut pools, problems, &mut subs, constraint,
);
(Solved(subs), state.vars_by_symbol)
(Solved(subs), state.env)
}
fn solve(
vars_by_symbol: &Env,
env: &Env,
state: State,
rank: Rank,
pools: &mut Pools,
@ -276,13 +275,19 @@ fn solve(
SaveTheEnvironment => {
let mut copy = state;
copy.vars_by_symbol = vars_by_symbol.clone();
copy.env = env.clone();
copy
}
Eq(typ, expected_type, _region) => {
let actual = type_to_var(subs, rank, pools, typ);
let expected = type_to_var(subs, rank, pools, expected_type.get_type_ref());
let actual = type_to_var(subs, rank, pools, &env.aliases, typ);
let expected = type_to_var(
subs,
rank,
pools,
&env.aliases,
expected_type.get_type_ref(),
);
let Unified { vars, mismatches } = unify(subs, actual, expected);
// TODO use region when reporting a problem
@ -293,12 +298,12 @@ fn solve(
state
}
Lookup(symbol, expected_type, _region) => {
let var = *vars_by_symbol.get(&symbol).unwrap_or_else(|| {
let var = *env.vars_by_symbol.get(&symbol).unwrap_or_else(|| {
// TODO Instead of panicking, solve this as True and record
// a Problem ("module Foo does not expose `bar`") for later.
panic!(
"Could not find symbol {:?} in vars_by_symbol {:?}",
symbol, vars_by_symbol
symbol, env.vars_by_symbol
)
});
@ -324,7 +329,13 @@ fn solve(
// is being looked up in this module, then we use our Subs as both
// the source and destination.
let actual = deep_copy_var(subs, rank, pools, var);
let expected = type_to_var(subs, rank, pools, expected_type.get_type_ref());
let expected = type_to_var(
subs,
rank,
pools,
&env.aliases,
expected_type.get_type_ref(),
);
let Unified { vars, mismatches } = unify(subs, actual, expected);
// TODO use region when reporting a problem
@ -338,22 +349,14 @@ fn solve(
let mut state = state;
for sub_constraint in sub_constraints.iter() {
state = solve(
vars_by_symbol,
state,
rank,
pools,
problems,
subs,
sub_constraint,
);
state = solve(env, state, rank, pools, problems, subs, sub_constraint);
}
state
}
Pattern(_region, _category, typ, expected) => {
let actual = type_to_var(subs, rank, pools, typ);
let expected = type_to_var(subs, rank, pools, expected.get_type_ref());
let actual = type_to_var(subs, rank, pools, &env.aliases, typ);
let expected = type_to_var(subs, rank, pools, &env.aliases, expected.get_type_ref());
let Unified { vars, mismatches } = unify(subs, actual, expected);
// TODO use region when reporting a problem
@ -368,10 +371,16 @@ fn solve(
True if let_con.rigid_vars.is_empty() => {
introduce(subs, rank, pools, &let_con.flex_vars);
let mut new_env = env.clone();
for (symbol, alias) in let_con.def_aliases.iter() {
new_env.aliases.insert(*symbol, alias.clone());
}
// If the return expression is guaranteed to solve,
// solve the assignments themselves and move on.
solve(
vars_by_symbol,
&new_env,
state,
rank,
pools,
@ -382,7 +391,7 @@ fn solve(
}
ret_con if let_con.rigid_vars.is_empty() && let_con.flex_vars.is_empty() => {
let state = solve(
vars_by_symbol,
env,
state,
rank,
pools,
@ -391,11 +400,17 @@ fn solve(
&let_con.defs_constraint,
);
let mut new_env = env.clone();
for (symbol, alias) in let_con.def_aliases.iter() {
new_env.aliases.insert(*symbol, alias.clone());
}
// Add a variable for each def to new_vars_by_env.
let mut local_def_vars = ImMap::default();
for (symbol, loc_type) in let_con.def_types.iter() {
let var = type_to_var(subs, rank, pools, &loc_type.value);
let var = type_to_var(subs, rank, pools, &new_env.aliases, &loc_type.value);
local_def_vars.insert(
symbol.clone(),
@ -406,23 +421,13 @@ fn solve(
);
}
let mut new_vars_by_symbol = vars_by_symbol.clone();
for (symbol, loc_var) in local_def_vars.iter() {
if !new_vars_by_symbol.contains_key(&symbol) {
new_vars_by_symbol.insert(symbol.clone(), loc_var.value);
if !new_env.vars_by_symbol.contains_key(&symbol) {
new_env.vars_by_symbol.insert(symbol.clone(), loc_var.value);
}
}
let new_state = solve(
&new_vars_by_symbol,
state,
rank,
pools,
problems,
subs,
ret_con,
);
let new_state = solve(&new_env, state, rank, pools, problems, subs, ret_con);
for (symbol, loc_var) in local_def_vars {
check_for_infinite_type(subs, problems, symbol, loc_var);
@ -451,12 +456,26 @@ fn solve(
pool.extend(rigid_vars.iter());
pool.extend(flex_vars.iter());
let mut new_env = env.clone();
for (symbol, alias) in let_con.def_aliases.iter() {
new_env.aliases.insert(*symbol, alias.clone());
}
// Add a variable for each def to local_def_vars.
let mut local_def_vars = ImMap::default();
for (symbol, loc_type) in let_con.def_types.iter() {
let def_type = loc_type.value.clone();
let var = type_to_var(subs, next_rank, next_pools, &def_type);
// TODO should this use new aliases?
let var = type_to_var(
subs,
next_rank,
next_pools,
&new_env.aliases,
&def_type,
);
local_def_vars.insert(
symbol.clone(),
@ -471,7 +490,7 @@ fn solve(
// Solve the assignments' constraints first.
let new_state = solve(
vars_by_symbol,
&new_env,
state,
next_rank,
next_pools,
@ -516,31 +535,24 @@ fn solve(
failing.is_empty()
});
let mut new_vars_by_symbol = vars_by_symbol.clone();
for (symbol, loc_var) in local_def_vars.iter() {
if !new_vars_by_symbol.contains_key(&symbol) {
new_vars_by_symbol.insert(symbol.clone(), loc_var.value);
if !new_env.vars_by_symbol.contains_key(&symbol) {
new_env.vars_by_symbol.insert(symbol.clone(), loc_var.value);
}
}
// Note that this vars_by_symbol is the one returned by the
// previous call to solve()
let temp_state = State {
vars_by_symbol: new_state.vars_by_symbol,
env: new_state.env,
mark: final_mark,
};
// Now solve the body, using the new vars_by_symbol which includes
// the assignments' name-to-variable mappings.
let new_state = solve(
&new_vars_by_symbol,
temp_state,
rank,
next_pools,
problems,
subs,
&ret_con,
&new_env, temp_state, rank, next_pools, problems, subs, &ret_con,
);
for (symbol, loc_var) in local_def_vars {
@ -562,30 +574,83 @@ fn solve(
}
}
fn type_to_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, typ: &Type) -> Variable {
type_to_variable(subs, rank, pools, &ImMap::default(), typ)
fn type_to_var(
subs: &mut Subs,
rank: Rank,
pools: &mut Pools,
aliases: &SendMap<Symbol, Alias>,
typ: &Type,
) -> Variable {
type_to_variable(subs, rank, pools, aliases, typ)
}
fn type_to_variable(
subs: &mut Subs,
rank: Rank,
pools: &mut Pools,
aliases: &ImMap<Lowercase, Variable>,
aliases: &SendMap<Symbol, Alias>,
typ: &Type,
) -> Variable {
match typ {
Variable(var) => *var,
Apply(symbol, args) => {
let mut arg_vars = Vec::with_capacity(args.len());
if let Some(alias) = aliases.get(symbol) {
if args.len() != alias.vars.len() {
panic!(
"Alias {:?} applied to incorrect number of arguments",
symbol
);
}
for arg in args {
arg_vars.push(type_to_variable(subs, rank, pools, aliases, arg))
let mut actual = alias.typ.clone();
let mut substitution = ImMap::default();
let mut arg_vars = Vec::with_capacity(args.len());
for (
tipe,
Located {
value: (lowercase, var),
..
},
) in args.iter().zip(alias.vars.iter())
{
let new_var = type_to_variable(subs, rank, pools, aliases, tipe);
substitution.insert(*var, Type::Variable(new_var));
arg_vars.push((lowercase.clone(), new_var));
}
actual.substitute(&substitution);
// We must instantiate the recursion variable, otherwise all e.g. lists will be
// unified, List Int ~ List Float
if let Type::RecursiveTagUnion(rec_var, _, _) = actual {
let new_rec_var = subs.fresh_unnamed_flex_var();
substitution.clear();
substitution.insert(rec_var, Type::Variable(new_rec_var));
actual.substitute(&substitution);
if let Type::RecursiveTagUnion(_, tags, ext_var) = actual {
actual = Type::RecursiveTagUnion(new_rec_var, tags, ext_var);
}
}
let alias_var = type_to_variable(subs, rank, pools, aliases, &actual);
let content = Content::Alias(*symbol, arg_vars, alias_var);
register(subs, rank, pools, content)
} else {
let mut arg_vars = Vec::with_capacity(args.len());
for arg in args {
arg_vars.push(type_to_variable(subs, rank, pools, aliases, arg))
}
let flat_type = FlatType::Apply(*symbol, arg_vars);
let content = Content::Structure(flat_type);
register(subs, rank, pools, content)
}
let flat_type = FlatType::Apply(*symbol, arg_vars);
let content = Content::Structure(flat_type);
register(subs, rank, pools, content)
}
EmptyRec => {
let content = Content::Structure(FlatType::EmptyRecord);
@ -674,13 +739,13 @@ fn type_to_variable(
let mut new_aliases = ImMap::default();
for (arg, arg_type) in args {
let arg_var = type_to_variable(subs, rank, pools, &ImMap::default(), arg_type);
let arg_var = type_to_variable(subs, rank, pools, aliases, arg_type);
arg_vars.push((arg.clone(), arg_var));
new_aliases.insert(arg.clone(), arg_var);
}
let alias_var = type_to_variable(subs, rank, pools, &new_aliases, alias_type);
let alias_var = type_to_variable(subs, rank, pools, aliases, alias_type);
let content = Content::Alias(*symbol, arg_vars, alias_var);
register(subs, rank, pools, content)

View File

@ -571,10 +571,18 @@ pub struct LetConstraint {
pub rigid_vars: Vec<Variable>,
pub flex_vars: Vec<Variable>,
pub def_types: SendMap<Symbol, Located<Type>>,
pub def_aliases: SendMap<Symbol, Alias>,
pub defs_constraint: Constraint,
pub ret_constraint: Constraint,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Alias {
pub region: Region,
pub vars: Vec<Located<(Lowercase, Variable)>>,
pub typ: Type,
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Problem {
CanonicalizationProblem,

View File

@ -5,7 +5,7 @@ use crate::can::ident::{Ident, Lowercase, TagName};
use crate::can::pattern::{Pattern, RecordDestruct};
use crate::collections::{ImMap, ImSet, SendMap};
use crate::constrain::builtins;
use crate::constrain::expr::{exists, Env, Info};
use crate::constrain::expr::{exists, exists_with_aliases, Env, Info};
use crate::module::symbol::{ModuleId, Symbol};
use crate::region::{Located, Region};
use crate::subs::{VarStore, Variable};
@ -524,6 +524,7 @@ pub fn constrain_expr(
rigid_vars: Vec::new(),
flex_vars: state.vars,
def_types: state.headers,
def_aliases: SendMap::default(),
defs_constraint,
ret_constraint,
})),
@ -615,7 +616,7 @@ pub fn constrain_expr(
]),
)
}
LetRec(defs, loc_ret, var) => {
LetRec(defs, loc_ret, var, aliases) => {
// NOTE doesn't currently unregister bound symbols
// may be a problem when symbols are not globally unique
let body_con = constrain_expr(
@ -627,7 +628,9 @@ pub fn constrain_expr(
&loc_ret.value,
expected.clone(),
);
exists(
exists_with_aliases(
aliases.clone(),
vec![*var],
And(vec![
constrain_recursive_defs(
@ -644,7 +647,7 @@ pub fn constrain_expr(
]),
)
}
LetNonRec(def, loc_ret, var) => {
LetNonRec(def, loc_ret, var, aliases) => {
// NOTE doesn't currently unregister bound symbols
// may be a problem when symbols are not globally unique
let body_con = constrain_expr(
@ -657,7 +660,8 @@ pub fn constrain_expr(
expected.clone(),
);
exists(
exists_with_aliases(
aliases.clone(),
vec![*var],
And(vec![
constrain_def(
@ -1212,6 +1216,7 @@ fn constrain_when_branch(
rigid_vars: Vec::new(),
flex_vars: state.vars,
def_types: state.headers,
def_aliases: SendMap::default(),
defs_constraint: Constraint::And(state.constraints),
ret_constraint,
}))
@ -1420,10 +1425,12 @@ pub fn constrain_def(
pattern_state.vars.push(expr_var);
let mut def_aliases = SendMap::default();
let mut new_rigids = Vec::new();
let expr_con = match &def.annotation {
Some((annotation, free_vars)) => {
Some((annotation, free_vars, ann_def_aliases)) => {
def_aliases = ann_def_aliases.clone();
let rigids = &env.rigids;
let mut ftv: ImMap<Lowercase, Type> = rigids.clone();
let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation);
@ -1482,10 +1489,12 @@ pub fn constrain_def(
rigid_vars: new_rigids,
flex_vars: pattern_state.vars,
def_types: pattern_state.headers,
def_aliases,
defs_constraint: Let(Box::new(LetConstraint {
rigid_vars: Vec::new(), // always empty
flex_vars: Vec::new(), // empty, because our functions have no arguments
def_types: SendMap::default(), // empty, because our functions have no arguments!
def_aliases: SendMap::default(),
defs_constraint: And(pattern_state.constraints),
ret_constraint: expr_con,
})),
@ -1524,6 +1533,7 @@ pub fn rec_defs_help(
mut rigid_info: Info,
mut flex_info: Info,
) -> Constraint {
let mut def_aliases = SendMap::default();
for def in defs {
let expr_var = def.expr_var;
let expr_type = Type::Variable(expr_var);
@ -1545,6 +1555,7 @@ pub fn rec_defs_help(
pattern_expected,
);
// TODO see where aliases should go
let mut new_rigids = Vec::new();
match &def.annotation {
None => {
@ -1563,6 +1574,7 @@ pub fn rec_defs_help(
rigid_vars: Vec::new(),
flex_vars: Vec::new(), // empty because Roc function defs have no args
def_types: SendMap::default(), // empty because Roc function defs have no args
def_aliases: SendMap::default(),
defs_constraint: True, // I think this is correct, once again because there are no args
ret_constraint: expr_con,
}));
@ -1572,7 +1584,11 @@ pub fn rec_defs_help(
flex_info.def_types.extend(pattern_state.headers);
}
Some((annotation, seen_rigids)) => {
Some((annotation, seen_rigids, ann_def_aliases)) => {
for (symbol, alias) in ann_def_aliases.clone() {
def_aliases.insert(symbol, alias);
}
let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation);
// TODO also do this for more complex patterns
@ -1657,6 +1673,7 @@ pub fn rec_defs_help(
rigid_vars: Vec::new(),
flex_vars: Vec::new(), // empty because Roc function defs have no args
def_types: SendMap::default(), // empty because Roc function defs have no args
def_aliases: SendMap::default(),
defs_constraint: True, // I think this is correct, once again because there are no args
ret_constraint: expr_con,
}));
@ -1668,6 +1685,7 @@ pub fn rec_defs_help(
rigid_vars: new_rigids,
flex_vars: Vec::new(), // no flex vars introduced
def_types: SendMap::default(), // no headers introduced (at this level)
def_aliases: SendMap::default(),
defs_constraint: def_con,
ret_constraint: True,
})));
@ -1680,15 +1698,18 @@ pub fn rec_defs_help(
rigid_vars: rigid_info.vars,
flex_vars: Vec::new(),
def_types: rigid_info.def_types,
def_aliases,
defs_constraint: True,
ret_constraint: Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: flex_info.vars,
def_types: flex_info.def_types.clone(),
def_aliases: SendMap::default(),
defs_constraint: Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: Vec::new(),
def_types: flex_info.def_types,
def_aliases: SendMap::default(),
defs_constraint: True,
ret_constraint: And(flex_info.constraints),
})),

View File

@ -338,11 +338,11 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
annotate_usage(&loc_elem.value, usage);
}
}
LetNonRec(def, loc_expr, _) => {
LetNonRec(def, loc_expr, _, _) => {
annotate_usage(&def.loc_expr.value, usage);
annotate_usage(&loc_expr.value, usage);
}
LetRec(defs, loc_expr, _) => {
LetRec(defs, loc_expr, _, _) => {
// TODO test this with a practical example.
if defs.len() == 1 {
// just like a letrec, but mark defined symbol as Shared

View File

@ -222,7 +222,7 @@ mod test_canonicalize {
fn get_closure(expr: &Expr, i: usize) -> roc::can::expr::Recursive {
match expr {
LetRec(assignments, body, _) => {
LetRec(assignments, body, _, _) => {
match &assignments.get(i).map(|def| &def.loc_expr.value) {
Some(Closure(_, _, recursion, _, _)) => recursion.clone(),
Some(other @ _) => {
@ -237,7 +237,7 @@ mod test_canonicalize {
}
}
}
LetNonRec(def, body, _) => {
LetNonRec(def, body, _, _) => {
if i > 0 {
// recurse in the body (not the def!)
get_closure(&body.value, i - 1)