mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Reorganize when solving and constraint gen happen
This commit is contained in:
parent
afacf1d6c4
commit
c386192e8b
16 changed files with 220 additions and 187 deletions
|
@ -453,9 +453,9 @@ pub fn uniq_expr_with(
|
||||||
|
|
||||||
let types = stdlib.types;
|
let types = stdlib.types;
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -529,9 +529,9 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> Result<Can
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -23,7 +23,6 @@ pub struct Module {
|
||||||
pub references: MutSet<Symbol>,
|
pub references: MutSet<Symbol>,
|
||||||
pub aliases: MutMap<Symbol, Alias>,
|
pub aliases: MutMap<Symbol, Alias>,
|
||||||
pub rigid_variables: MutMap<Variable, Lowercase>,
|
pub rigid_variables: MutMap<Variable, Lowercase>,
|
||||||
pub imported_modules: MutSet<ModuleId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::expr::constrain_decls;
|
use crate::expr::constrain_decls;
|
||||||
use roc_builtins::std::Mode;
|
use roc_builtins::std::Mode;
|
||||||
use roc_can::constraint::{Constraint, LetConstraint};
|
use roc_can::constraint::{Constraint, LetConstraint};
|
||||||
use roc_can::def::Declaration;
|
use roc_can::module::ModuleOutput;
|
||||||
use roc_collections::all::{ImMap, MutMap, SendMap};
|
use roc_collections::all::{ImMap, MutMap, MutSet, SendMap};
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use roc_region::all::Located;
|
use roc_region::all::Located;
|
||||||
|
@ -11,36 +11,52 @@ use roc_types::solved_types::{BuiltinAlias, SolvedAtom, SolvedType};
|
||||||
use roc_types::subs::{VarId, VarStore, Variable};
|
use roc_types::subs::{VarId, VarStore, Variable};
|
||||||
use roc_types::types::{Alias, Type};
|
use roc_types::types::{Alias, Type};
|
||||||
|
|
||||||
#[inline(always)]
|
pub type SubsByModule = MutMap<ModuleId, ExposedModuleTypes>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum ExposedModuleTypes {
|
||||||
|
Invalid,
|
||||||
|
Valid(MutMap<Symbol, SolvedType>, MutMap<Symbol, Alias>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConstrainedModule {
|
||||||
|
pub unused_imports: MutSet<ModuleId>,
|
||||||
|
pub constraint: Constraint,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn constrain_module(
|
pub fn constrain_module(
|
||||||
|
module: &ModuleOutput,
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
decls: &[Declaration],
|
|
||||||
aliases: &MutMap<Symbol, Alias>,
|
|
||||||
var_store: &VarStore,
|
var_store: &VarStore,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
use Mode::*;
|
let decls = &module.declarations;
|
||||||
|
let constraint = {
|
||||||
|
use Mode::*;
|
||||||
|
|
||||||
let mut send_aliases = SendMap::default();
|
let mut send_aliases = SendMap::default();
|
||||||
|
|
||||||
for (symbol, alias) in aliases {
|
for (symbol, alias) in module.aliases.iter() {
|
||||||
send_aliases.insert(*symbol, alias.clone());
|
send_aliases.insert(*symbol, alias.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
Standard => constrain_decls(home, decls, send_aliases),
|
Standard => constrain_decls(home, decls, send_aliases),
|
||||||
Uniqueness => crate::uniq::constrain_decls(home, decls, send_aliases, var_store),
|
Uniqueness => crate::uniq::constrain_decls(home, decls, send_aliases, &var_store),
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constraint
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Import<'a> {
|
pub struct Import {
|
||||||
pub loc_symbol: Located<Symbol>,
|
pub loc_symbol: Located<Symbol>,
|
||||||
pub solved_type: &'a SolvedType,
|
pub solved_type: SolvedType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constrain_imported_values(
|
pub fn constrain_imported_values(
|
||||||
imports: Vec<Import<'_>>,
|
imports: Vec<Import>,
|
||||||
body_con: Constraint,
|
body_con: Constraint,
|
||||||
var_store: &VarStore,
|
var_store: &VarStore,
|
||||||
) -> (Vec<Variable>, Constraint) {
|
) -> (Vec<Variable>, Constraint) {
|
||||||
|
@ -54,7 +70,7 @@ pub fn constrain_imported_values(
|
||||||
|
|
||||||
// an imported symbol can be either an alias or a value
|
// an imported symbol can be either an alias or a value
|
||||||
match import.solved_type {
|
match import.solved_type {
|
||||||
SolvedType::Alias(symbol, _, _) if symbol == &loc_symbol.value => {
|
SolvedType::Alias(symbol, _, _) if symbol == loc_symbol.value => {
|
||||||
// do nothing, in the future the alias definitions should not be in the list of imported values
|
// do nothing, in the future the alias definitions should not be in the list of imported values
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -170,10 +170,10 @@ pub fn uniq_expr_with(
|
||||||
|
|
||||||
let types = stdlib.types;
|
let types = stdlib.types;
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -275,10 +275,10 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,21 @@ use bumpalo::Bump;
|
||||||
use roc_builtins::std::{Mode, StdLib};
|
use roc_builtins::std::{Mode, StdLib};
|
||||||
use roc_can::constraint::Constraint;
|
use roc_can::constraint::Constraint;
|
||||||
use roc_can::def::Declaration;
|
use roc_can::def::Declaration;
|
||||||
use roc_can::module::{Module, canonicalize_module_defs, ModuleOutput};
|
use roc_can::module::{canonicalize_module_defs, Module};
|
||||||
use roc_collections::all::{default_hasher, MutMap, MutSet, SendMap};
|
use roc_constrain::module::{constrain_imported_values, load_builtin_aliases, Import, constrain_imported_aliases};
|
||||||
use roc_constrain::module::{
|
use roc_collections::all::{default_hasher, MutMap, MutSet};
|
||||||
constrain_imported_aliases, constrain_imported_values, constrain_module, load_builtin_aliases,
|
use roc_constrain::module::{constrain_module, ExposedModuleTypes, SubsByModule};
|
||||||
Import,
|
|
||||||
};
|
|
||||||
use roc_module::ident::{Ident, ModuleName};
|
use roc_module::ident::{Ident, ModuleName};
|
||||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_parse::ast::{self, Attempting, ExposesEntry, ImportsEntry};
|
use roc_parse::ast::{self, Attempting, ExposesEntry, ImportsEntry};
|
||||||
use roc_parse::module::module_defs;
|
use roc_parse::module::module_defs;
|
||||||
use roc_parse::parser::{Fail, Parser, State};
|
use roc_parse::parser::{Fail, Parser, State};
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_solve::solve::{self, ExposedModuleTypes, SubsByModule};
|
use roc_solve::solve;
|
||||||
|
use roc_solve::module::SolvedModule;
|
||||||
|
use roc_types::types;
|
||||||
use roc_types::solved_types::{Solved, SolvedType};
|
use roc_types::solved_types::{Solved, SolvedType};
|
||||||
use roc_types::subs::{Subs, VarStore, Variable};
|
use roc_types::subs::{Subs, VarStore, Variable};
|
||||||
use roc_types::types::{self, Alias};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -72,6 +71,7 @@ enum Msg {
|
||||||
Constrained {
|
Constrained {
|
||||||
module: Module,
|
module: Module,
|
||||||
declarations: Vec<Declaration>,
|
declarations: Vec<Declaration>,
|
||||||
|
imported_modules: MutSet<ModuleId>,
|
||||||
src: Box<str>,
|
src: Box<str>,
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
|
@ -81,11 +81,8 @@ enum Msg {
|
||||||
Solved {
|
Solved {
|
||||||
src: Box<str>,
|
src: Box<str>,
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
solved_types: MutMap<Symbol, SolvedType>,
|
solved_module: SolvedModule,
|
||||||
aliases: MutMap<Symbol, Alias>,
|
solved_subs: Arc<Solved<Subs>>,
|
||||||
subs: Arc<Solved<Subs>>,
|
|
||||||
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
|
||||||
problems: Vec<solve::TypeError>,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +225,7 @@ pub async fn load<'a>(
|
||||||
// If the relevant module's waiting_for_solve entry is now empty, solve the module.
|
// If the relevant module's waiting_for_solve entry is now empty, solve the module.
|
||||||
let mut solve_listeners: MutMap<ModuleId, Vec<ModuleId>> = MutMap::default();
|
let mut solve_listeners: MutMap<ModuleId, Vec<ModuleId>> = MutMap::default();
|
||||||
|
|
||||||
let mut unsolved_modules: MutMap<ModuleId, (Module, Box<str>, Constraint, VarStore)> = MutMap::default();
|
let mut unsolved_modules: MutMap<ModuleId, (Module, Box<str>, MutSet<ModuleId>, Constraint, VarStore)> = MutMap::default();
|
||||||
|
|
||||||
// Parse and canonicalize the module's deps
|
// Parse and canonicalize the module's deps
|
||||||
while let Some(msg) = msg_rx.recv().await {
|
while let Some(msg) = msg_rx.recv().await {
|
||||||
|
@ -356,6 +353,7 @@ pub async fn load<'a>(
|
||||||
declarations,
|
declarations,
|
||||||
src,
|
src,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
|
imported_modules,
|
||||||
constraint,
|
constraint,
|
||||||
problems,
|
problems,
|
||||||
var_store,
|
var_store,
|
||||||
|
@ -384,11 +382,12 @@ pub async fn load<'a>(
|
||||||
if waiting_for.is_empty() {
|
if waiting_for.is_empty() {
|
||||||
// All of our dependencies have already been solved. Great!
|
// All of our dependencies have already been solved. Great!
|
||||||
// That means we can proceed directly to solving.
|
// That means we can proceed directly to solving.
|
||||||
solve_module(
|
spawn_solve_module(
|
||||||
module,
|
module,
|
||||||
src,
|
src,
|
||||||
constraint,
|
constraint,
|
||||||
var_store,
|
var_store,
|
||||||
|
imported_modules,
|
||||||
msg_tx.clone(),
|
msg_tx.clone(),
|
||||||
&mut exposed_types,
|
&mut exposed_types,
|
||||||
stdlib,
|
stdlib,
|
||||||
|
@ -396,7 +395,7 @@ pub async fn load<'a>(
|
||||||
} else {
|
} else {
|
||||||
// We will have to wait for our dependencies to be solved.
|
// We will have to wait for our dependencies to be solved.
|
||||||
debug_assert!(!unsolved_modules.contains_key(&module_id));
|
debug_assert!(!unsolved_modules.contains_key(&module_id));
|
||||||
unsolved_modules.insert(module_id, (module, src, constraint, var_store));
|
unsolved_modules.insert(module_id, (module, src, imported_modules, constraint, var_store));
|
||||||
|
|
||||||
// Register a listener with each of these.
|
// Register a listener with each of these.
|
||||||
for dep_id in waiting_for.iter() {
|
for dep_id in waiting_for.iter() {
|
||||||
|
@ -409,21 +408,18 @@ pub async fn load<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Solved {
|
Solved {
|
||||||
module_id,
|
|
||||||
solved_types,
|
|
||||||
subs,
|
|
||||||
problems,
|
|
||||||
exposed_vars_by_symbol,
|
|
||||||
aliases,
|
|
||||||
src,
|
src,
|
||||||
|
module_id,
|
||||||
|
solved_module,
|
||||||
|
solved_subs,
|
||||||
} => {
|
} => {
|
||||||
type_problems.extend(problems);
|
type_problems.extend(solved_module.problems);
|
||||||
|
|
||||||
if module_id == root_id {
|
if module_id == root_id {
|
||||||
// Once we've solved the originally requested module, we're done!
|
// Once we've solved the originally requested module, we're done!
|
||||||
msg_rx.close();
|
msg_rx.close();
|
||||||
|
|
||||||
let solved = Arc::try_unwrap(subs).unwrap_or_else(|_| {
|
let solved = Arc::try_unwrap(solved_subs).unwrap_or_else(|_| {
|
||||||
panic!("There were still outstanding Arc references to Solved<Subs>")
|
panic!("There were still outstanding Arc references to Solved<Subs>")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -446,14 +442,14 @@ pub async fn load<'a>(
|
||||||
can_problems,
|
can_problems,
|
||||||
type_problems,
|
type_problems,
|
||||||
declarations_by_id,
|
declarations_by_id,
|
||||||
exposed_vars_by_symbol,
|
exposed_vars_by_symbol: solved_module.exposed_vars_by_symbol,
|
||||||
src,
|
src,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// This was a dependency. Write it down and keep processing messages.
|
// This was a dependency. Write it down and keep processing messages.
|
||||||
debug_assert!(!exposed_types.contains_key(&module_id));
|
debug_assert!(!exposed_types.contains_key(&module_id));
|
||||||
exposed_types
|
exposed_types
|
||||||
.insert(module_id, ExposedModuleTypes::Valid(solved_types, aliases));
|
.insert(module_id, ExposedModuleTypes::Valid(solved_module.solved_types, solved_module.aliases));
|
||||||
|
|
||||||
// Notify all the listeners that this solved.
|
// Notify all the listeners that this solved.
|
||||||
if let Some(listeners) = solve_listeners.remove(&module_id) {
|
if let Some(listeners) = solve_listeners.remove(&module_id) {
|
||||||
|
@ -468,23 +464,20 @@ pub async fn load<'a>(
|
||||||
|
|
||||||
// If it's no longer waiting for anything else, solve it.
|
// If it's no longer waiting for anything else, solve it.
|
||||||
if waiting_for.is_empty() {
|
if waiting_for.is_empty() {
|
||||||
let (module, src, constraint, var_store) = unsolved_modules
|
let (module, src, imported_modules, constraint, var_store) = unsolved_modules
|
||||||
.remove(&listener_id)
|
.remove(&listener_id)
|
||||||
.expect("Could not find listener ID in unsolved_modules");
|
.expect("Could not find listener ID in unsolved_modules");
|
||||||
let home = module.module_id;
|
|
||||||
let unused_modules = solve_module(
|
spawn_solve_module(
|
||||||
module,
|
module,
|
||||||
src,
|
src,
|
||||||
constraint,
|
constraint,
|
||||||
var_store,
|
var_store,
|
||||||
|
imported_modules,
|
||||||
msg_tx.clone(),
|
msg_tx.clone(),
|
||||||
&mut exposed_types,
|
&mut exposed_types,
|
||||||
stdlib,
|
stdlib,
|
||||||
);
|
);
|
||||||
|
|
||||||
for _unused_module_id in unused_modules.iter() {
|
|
||||||
panic!("TODO gracefully report unused imports for {:?}, namely {:?}", home, unused_modules);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -788,21 +781,23 @@ fn add_exposed_to_scope(
|
||||||
|
|
||||||
// TODO trim down these arguments - possibly by moving Constraint into Module
|
// TODO trim down these arguments - possibly by moving Constraint into Module
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn solve_module(
|
fn spawn_solve_module(
|
||||||
module: Module,
|
module: Module,
|
||||||
src: Box<str>,
|
src: Box<str>,
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
var_store: VarStore,
|
var_store: VarStore,
|
||||||
|
imported_modules: MutSet<ModuleId>,
|
||||||
msg_tx: MsgSender,
|
msg_tx: MsgSender,
|
||||||
exposed_types: &mut SubsByModule,
|
exposed_types: &mut SubsByModule,
|
||||||
stdlib: &StdLib,
|
stdlib: &StdLib,
|
||||||
) -> MutSet<ModuleId> /* returs a set of unused imports */ {
|
) {
|
||||||
// TODO do all this on a background thread too,
|
// Get the constriants for this module's imports. We do this on the main thread
|
||||||
// and don't report unused imports until it's all done.
|
// to avoid having to lock the map of exposed types, or to clone it
|
||||||
|
// (which would be more expensive for the main thread).
|
||||||
let home = module.module_id;
|
let home = module.module_id;
|
||||||
let mut imported_symbols = Vec::with_capacity(module.references.len());
|
let mut imported_symbols = Vec::with_capacity(module.references.len());
|
||||||
let mut imported_aliases = MutMap::default();
|
let mut imported_aliases = MutMap::default();
|
||||||
let mut unused_imports = module.imported_modules; // We'll remove these as we encounter them.
|
let mut unused_imports = imported_modules; // We'll remove these as we encounter them.
|
||||||
|
|
||||||
// Translate referenced symbols into constraints
|
// Translate referenced symbols into constraints
|
||||||
for &symbol in module.references.iter() {
|
for &symbol in module.references.iter() {
|
||||||
|
@ -823,7 +818,7 @@ fn solve_module(
|
||||||
|
|
||||||
imported_symbols.push(Import {
|
imported_symbols.push(Import {
|
||||||
loc_symbol,
|
loc_symbol,
|
||||||
solved_type,
|
solved_type: solved_type.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -867,7 +862,7 @@ fn solve_module(
|
||||||
|
|
||||||
imported_symbols.push(Import {
|
imported_symbols.push(Import {
|
||||||
loc_symbol,
|
loc_symbol,
|
||||||
solved_type,
|
solved_type: solved_type.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(ExposedModuleTypes::Invalid) => {
|
Some(ExposedModuleTypes::Invalid) => {
|
||||||
|
@ -875,7 +870,7 @@ fn solve_module(
|
||||||
// for everything imported from it.
|
// for everything imported from it.
|
||||||
imported_symbols.push(Import {
|
imported_symbols.push(Import {
|
||||||
loc_symbol,
|
loc_symbol,
|
||||||
solved_type: &SolvedType::Erroneous(types::Problem::InvalidModule),
|
solved_type: SolvedType::Erroneous(types::Problem::InvalidModule),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -888,66 +883,31 @@ fn solve_module(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap the existing module constraint in these imported constraints.
|
let constraint = load_builtin_aliases(&stdlib.aliases, constraint, &var_store);
|
||||||
|
|
||||||
// TODO what to do with the introduced rigids?
|
|
||||||
let (_introduced_rigids, constraint) =
|
|
||||||
constrain_imported_values(imported_symbols, constraint, &var_store);
|
|
||||||
let constraint = constrain_imported_aliases(imported_aliases, constraint, &var_store);
|
|
||||||
let mut constraint = load_builtin_aliases(&stdlib.aliases, constraint, &var_store);
|
|
||||||
|
|
||||||
// Turn Apply into Alias
|
for unused_import in unused_imports {
|
||||||
constraint.instantiate_aliases(&var_store);
|
todo!("TODO gracefully handle unused import {:?} from module {:?}", unused_import, home);
|
||||||
|
|
||||||
let exposed_vars_by_symbol: Vec<(Symbol, Variable)> = module.exposed_vars_by_symbol;
|
|
||||||
let env = solve::Env {
|
|
||||||
vars_by_symbol: SendMap::default(),
|
|
||||||
aliases: module.aliases,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut subs = Subs::new(var_store.into());
|
|
||||||
|
|
||||||
for (var, name) in module.rigid_variables {
|
|
||||||
subs.rigid_var(var, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start solving this module in the background.
|
// Start solving this module in the background.
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
// Now that the module is parsed, canonicalized, and constrained,
|
// Finish constraining the module by wrapping the existing Constraint
|
||||||
// we need to type check it.
|
// in the ones we just computed. We can do this off the main thread.
|
||||||
let mut problems = Vec::new();
|
|
||||||
|
// TODO what to do with the introduced rigids?
|
||||||
|
let (_introduced_rigids, constraint) =
|
||||||
|
constrain_imported_values(imported_symbols, constraint, &var_store);
|
||||||
|
let mut constraint = constrain_imported_aliases(imported_aliases, constraint, &var_store);
|
||||||
|
|
||||||
// Run the solver to populate Subs.
|
// Turn Apply into Alias
|
||||||
let (solved_subs, solved_env) = solve::run(&env, &mut problems, subs, &constraint);
|
constraint.instantiate_aliases(&var_store);
|
||||||
|
|
||||||
let mut solved_types = MutMap::default();
|
let (solved_subs, solved_module) = roc_solve::module::solve_module(
|
||||||
|
module,
|
||||||
for (symbol, alias) in solved_env.aliases.into_iter() {
|
constraint,
|
||||||
let mut args = Vec::with_capacity(alias.vars.len());
|
var_store,
|
||||||
|
);
|
||||||
for Located {
|
|
||||||
value: (name, var), ..
|
|
||||||
} in alias.vars.iter()
|
|
||||||
{
|
|
||||||
args.push((name.clone(), SolvedType::new(&solved_subs, *var)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let solved_type = SolvedType::from_type(&solved_subs, alias.typ);
|
|
||||||
let solved_alias = SolvedType::Alias(symbol, args, Box::new(solved_type));
|
|
||||||
|
|
||||||
solved_types.insert(symbol, solved_alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
// exposed_vars_by_symbol contains the Variables for all the Symbols
|
|
||||||
// this module exposes. We want to convert those into flat SolvedType
|
|
||||||
// annotations which are decoupled from our Subs, because that's how
|
|
||||||
// other modules will generate constraints for imported values
|
|
||||||
// within the context of their own Subs.
|
|
||||||
for (symbol, var) in exposed_vars_by_symbol.iter() {
|
|
||||||
let solved_type = SolvedType::new(&solved_subs, *var);
|
|
||||||
|
|
||||||
solved_types.insert(*symbol, solved_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut tx = msg_tx;
|
let mut tx = msg_tx;
|
||||||
|
@ -956,18 +916,13 @@ fn solve_module(
|
||||||
tx.send(Msg::Solved {
|
tx.send(Msg::Solved {
|
||||||
src,
|
src,
|
||||||
module_id: home,
|
module_id: home,
|
||||||
subs: Arc::new(solved_subs),
|
solved_subs: Arc::new(solved_subs),
|
||||||
exposed_vars_by_symbol,
|
solved_module
|
||||||
solved_types,
|
|
||||||
problems,
|
|
||||||
aliases: env.aliases,
|
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|_| panic!("Failed to send Solved message"));
|
.unwrap_or_else(|_| panic!("Failed to send Solved message"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
unused_imports
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -1070,29 +1025,18 @@ fn parse_and_constrain(
|
||||||
exposed_symbols,
|
exposed_symbols,
|
||||||
&var_store,
|
&var_store,
|
||||||
) {
|
) {
|
||||||
Ok(ModuleOutput {
|
Ok(module_output) => {
|
||||||
declarations,
|
let constraint = constrain_module(&module_output, module_id, mode, &var_store);
|
||||||
exposed_imports,
|
|
||||||
ident_ids,
|
|
||||||
exposed_vars_by_symbol,
|
|
||||||
references,
|
|
||||||
aliases,
|
|
||||||
rigid_variables,
|
|
||||||
problems,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
let constraint = constrain_module(module_id, mode, &declarations, &aliases, &var_store);
|
|
||||||
let module = Module {
|
let module = Module {
|
||||||
module_id,
|
module_id,
|
||||||
exposed_imports,
|
exposed_imports: module_output.exposed_imports,
|
||||||
exposed_vars_by_symbol,
|
exposed_vars_by_symbol: module_output.exposed_vars_by_symbol,
|
||||||
references,
|
references: module_output.references,
|
||||||
aliases,
|
aliases: module_output.aliases,
|
||||||
rigid_variables,
|
rigid_variables: module_output.rigid_variables,
|
||||||
imported_modules: header.imported_modules,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(module, declarations, ident_ids, constraint, problems)
|
(module, module_output.declarations, module_output.ident_ids, constraint, module_output.problems)
|
||||||
}
|
}
|
||||||
Err(runtime_error) => {
|
Err(runtime_error) => {
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -1103,6 +1047,7 @@ fn parse_and_constrain(
|
||||||
};
|
};
|
||||||
|
|
||||||
let src = header.src;
|
let src = header.src;
|
||||||
|
let imported_modules = header.imported_modules;
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut tx = msg_tx;
|
let mut tx = msg_tx;
|
||||||
|
@ -1112,6 +1057,7 @@ fn parse_and_constrain(
|
||||||
module,
|
module,
|
||||||
src,
|
src,
|
||||||
declarations,
|
declarations,
|
||||||
|
imported_modules,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
constraint,
|
constraint,
|
||||||
problems,
|
problems,
|
||||||
|
|
|
@ -166,10 +166,10 @@ pub fn uniq_expr_with(
|
||||||
|
|
||||||
let types = stdlib.types;
|
let types = stdlib.types;
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -247,10 +247,10 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ mod test_load {
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_load::file::{load, LoadedModule};
|
use roc_load::file::{load, LoadedModule};
|
||||||
use roc_module::symbol::{Interns, ModuleId};
|
use roc_module::symbol::{Interns, ModuleId};
|
||||||
use roc_solve::solve::SubsByModule;
|
use roc_constrain::module::SubsByModule;
|
||||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
|
@ -21,7 +21,7 @@ mod test_uniq_load {
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_load::file::{load, LoadedModule};
|
use roc_load::file::{load, LoadedModule};
|
||||||
use roc_module::symbol::{Interns, ModuleId};
|
use roc_module::symbol::{Interns, ModuleId};
|
||||||
use roc_solve::solve::SubsByModule;
|
use roc_constrain::module::SubsByModule;
|
||||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
|
@ -147,10 +147,10 @@ pub fn uniq_expr_with(
|
||||||
|
|
||||||
let types = stdlib.types;
|
let types = stdlib.types;
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -230,10 +230,10 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -183,10 +183,10 @@ pub fn can_expr_with(
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ roc_module = { path = "../module" }
|
||||||
roc_types = { path = "../types" }
|
roc_types = { path = "../types" }
|
||||||
roc_can = { path = "../can" }
|
roc_can = { path = "../can" }
|
||||||
roc_unify = { path = "../unify" }
|
roc_unify = { path = "../unify" }
|
||||||
|
roc_constrain = { path = "../constrain" }
|
||||||
|
roc_builtins = { path = "../builtins" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
roc_constrain = { path = "../constrain" }
|
roc_constrain = { path = "../constrain" }
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
// re-enable this when working on performance optimizations than have it block PRs.
|
// re-enable this when working on performance optimizations than have it block PRs.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
|
||||||
|
pub mod module;
|
||||||
pub mod solve;
|
pub mod solve;
|
||||||
|
|
77
compiler/solve/src/module.rs
Normal file
77
compiler/solve/src/module.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use crate::solve;
|
||||||
|
use roc_can::constraint::Constraint;
|
||||||
|
use roc_can::module::Module;
|
||||||
|
use roc_collections::all::{MutMap, SendMap};
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
|
use roc_types::solved_types::{Solved, SolvedType};
|
||||||
|
use roc_types::subs::{Subs, VarStore, Variable};
|
||||||
|
use roc_types::types::Alias;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SolvedModule {
|
||||||
|
pub solved_types: MutMap<Symbol, SolvedType>,
|
||||||
|
pub aliases: MutMap<Symbol, Alias>,
|
||||||
|
pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||||
|
pub problems: Vec<solve::TypeError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn solve_module(
|
||||||
|
module: Module,
|
||||||
|
constraint: Constraint,
|
||||||
|
var_store: VarStore,
|
||||||
|
) -> (Solved<Subs>, SolvedModule) {
|
||||||
|
let exposed_vars_by_symbol: Vec<(Symbol, Variable)> = module.exposed_vars_by_symbol;
|
||||||
|
let env = solve::Env {
|
||||||
|
vars_by_symbol: SendMap::default(),
|
||||||
|
aliases: module.aliases,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut subs = Subs::new(var_store.into());
|
||||||
|
|
||||||
|
for (var, name) in module.rigid_variables {
|
||||||
|
subs.rigid_var(var, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that the module is parsed, canonicalized, and constrained,
|
||||||
|
// we need to type check it.
|
||||||
|
let mut problems = Vec::new();
|
||||||
|
|
||||||
|
// Run the solver to populate Subs.
|
||||||
|
let (solved_subs, solved_env) = solve::run(&env, &mut problems, subs, &constraint);
|
||||||
|
let mut solved_types = MutMap::default();
|
||||||
|
|
||||||
|
for (symbol, alias) in solved_env.aliases {
|
||||||
|
let mut args = Vec::with_capacity(alias.vars.len());
|
||||||
|
|
||||||
|
for loc_named_var in alias.vars {
|
||||||
|
let (name, var) = loc_named_var.value;
|
||||||
|
|
||||||
|
args.push((name.clone(), SolvedType::new(&solved_subs, var)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let solved_type = SolvedType::from_type(&solved_subs, alias.typ);
|
||||||
|
let solved_alias = SolvedType::Alias(symbol, args, Box::new(solved_type));
|
||||||
|
|
||||||
|
solved_types.insert(symbol, solved_alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
// exposed_vars_by_symbol contains the Variables for all the Symbols
|
||||||
|
// this module exposes. We want to convert those into flat SolvedType
|
||||||
|
// annotations which are decoupled from our Subs, because that's how
|
||||||
|
// other modules will generate constraints for imported values
|
||||||
|
// within the context of their own Subs.
|
||||||
|
for (symbol, var) in exposed_vars_by_symbol.iter() {
|
||||||
|
let solved_type = SolvedType::new(&solved_subs, *var);
|
||||||
|
|
||||||
|
solved_types.insert(*symbol, solved_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
let solved_module = SolvedModule {
|
||||||
|
exposed_vars_by_symbol,
|
||||||
|
solved_types,
|
||||||
|
problems,
|
||||||
|
aliases: env.aliases,
|
||||||
|
};
|
||||||
|
|
||||||
|
(solved_subs, solved_module)
|
||||||
|
}
|
|
@ -2,10 +2,10 @@ use roc_can::constraint::Constraint::{self, *};
|
||||||
use roc_can::expected::{Expected, PExpected};
|
use roc_can::expected::{Expected, PExpected};
|
||||||
use roc_collections::all::{ImMap, MutMap, SendMap};
|
use roc_collections::all::{ImMap, MutMap, SendMap};
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_types::boolean_algebra::{self, Atom};
|
use roc_types::boolean_algebra::{self, Atom};
|
||||||
use roc_types::solved_types::{Solved, SolvedType};
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{Content, Descriptor, FlatType, Mark, OptVariable, Rank, Subs, Variable};
|
use roc_types::subs::{Content, Descriptor, FlatType, Mark, OptVariable, Rank, Subs, Variable};
|
||||||
use roc_types::types::Type::{self, *};
|
use roc_types::types::Type::{self, *};
|
||||||
use roc_types::types::{Alias, Category, ErrorType, PatternCategory};
|
use roc_types::types::{Alias, Category, ErrorType, PatternCategory};
|
||||||
|
@ -24,14 +24,6 @@ pub enum TypeError {
|
||||||
BadType(roc_types::types::Problem),
|
BadType(roc_types::types::Problem),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SubsByModule = MutMap<ModuleId, ExposedModuleTypes>;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum ExposedModuleTypes {
|
|
||||||
Invalid,
|
|
||||||
Valid(MutMap<Symbol, SolvedType>, MutMap<Symbol, Alias>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
pub vars_by_symbol: SendMap<Symbol, Variable>,
|
pub vars_by_symbol: SendMap<Symbol, Variable>,
|
||||||
|
|
|
@ -168,10 +168,10 @@ pub fn uniq_expr_with(
|
||||||
|
|
||||||
let types = stdlib.types;
|
let types = stdlib.types;
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -251,10 +251,10 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -168,10 +168,10 @@ pub fn uniq_expr_with(
|
||||||
|
|
||||||
let types = stdlib.types;
|
let types = stdlib.types;
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -251,10 +251,10 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let types = roc_builtins::std::types();
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
let imports: Vec<_> = types
|
let imports: Vec<_> = types
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(symbol, (solved_type, region))| Import {
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
loc_symbol: Located::at(*region, *symbol),
|
loc_symbol: Located::at(region, symbol),
|
||||||
solved_type: solved_type,
|
solved_type,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue