diff --git a/compiler/constrain/src/module.rs b/compiler/constrain/src/module.rs index 082947fe2d..7a5d16729e 100644 --- a/compiler/constrain/src/module.rs +++ b/compiler/constrain/src/module.rs @@ -1,15 +1,15 @@ use crate::expr::constrain_decls; -use roc_builtins::std::Mode; +use roc_builtins::std::{Mode, StdLib}; use roc_can::constraint::{Constraint, LetConstraint}; use roc_can::module::ModuleOutput; use roc_collections::all::{ImMap, MutMap, MutSet, SendMap}; use roc_module::ident::Lowercase; use roc_module::symbol::{ModuleId, Symbol}; -use roc_region::all::Located; +use roc_region::all::{Located, Region}; use roc_types::boolean_algebra::{Atom, Bool}; use roc_types::solved_types::{BuiltinAlias, SolvedAtom, SolvedType}; use roc_types::subs::{VarId, VarStore, Variable}; -use roc_types::types::{Alias, Type}; +use roc_types::types::{Alias, Problem, Type}; pub type SubsByModule = MutMap; @@ -292,7 +292,7 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V Type::Alias(*symbol, type_variables, Box::new(actual)) } - Error => Type::Erroneous(roc_types::types::Problem::SolvedTypeError), + Error => Type::Erroneous(Problem::SolvedTypeError), Erroneous(problem) => Type::Erroneous(problem.clone()), } } @@ -362,3 +362,134 @@ pub fn constrain_imported_aliases( ret_constraint: body_con, })) } + +/// Run pre_constrain_imports to get imported_symbols and imported_aliases. +pub fn constrain_imports( + imported_symbols: Vec, + imported_aliases: MutMap, + constraint: Constraint, + var_store: &mut VarStore, +) -> Constraint { + let (_introduced_rigids, constraint) = + constrain_imported_values(imported_symbols, constraint, var_store); + + // TODO determine what to do with those rigids + // for var in introduced_rigids { + // output.ftv.insert(var, format!("internal_{:?}", var).into()); + // } + + constrain_imported_aliases(imported_aliases, constraint, var_store) +} + +pub struct ConstrainableImports { + pub imported_symbols: Vec, + pub imported_aliases: MutMap, + pub unused_imports: MutSet, +} + +/// Run this before constraining imports. +/// +/// Constraining imports is split into two different functions, because this +/// part of the work needs to be done on the main thread, whereas the rest of it +/// can be done on a different thread. +pub fn pre_constrain_imports( + home: ModuleId, + references: &MutSet, + imported_modules: MutSet, + exposed_types: &mut SubsByModule, + stdlib: &StdLib, +) -> ConstrainableImports { + let mut imported_symbols = Vec::with_capacity(references.len()); + let mut imported_aliases = MutMap::default(); + let mut unused_imports = imported_modules; // We'll remove these as we encounter them. + + // Translate referenced symbols into constraints. We do this on the main + // thread because we need exclusive access to the exposed_types map, in order + // to get the necessary constraint info for any aliases we imported. We also + // resolve builtin types now, so we can use a refernce to stdlib instead of + // having to either clone it or recreate it from scratch on the other thread. + for &symbol in references.iter() { + let module_id = symbol.module_id(); + + // We used this one, so clearly it is not unused! + unused_imports.remove(&module_id); + + if module_id.is_builtin() { + // For builtin modules, we create imports from the + // hardcoded builtin map. + match stdlib.types.get(&symbol) { + Some((solved_type, region)) => { + let loc_symbol = Located { + value: symbol, + region: *region, + }; + + imported_symbols.push(Import { + loc_symbol, + solved_type: solved_type.clone(), + }); + } + None => { + let is_valid_alias = stdlib.applies.contains(&symbol) + // This wasn't a builtin value or Apply; maybe it was a builtin alias. + || stdlib.aliases.contains_key(&symbol); + + if !is_valid_alias { + panic!( + "Could not find {:?} in builtin types {:?} or aliases {:?}", + symbol, stdlib.types, stdlib.aliases + ); + } + } + } + } else if module_id != home { + // We already have constraints for our own symbols. + let region = Region::zero(); // TODO this should be the region where this symbol was declared in its home module. Look that up! + let loc_symbol = Located { + value: symbol, + region, + }; + + match exposed_types.get(&module_id) { + Some(ExposedModuleTypes::Valid(solved_types, new_aliases)) => { + let solved_type = solved_types.get(&symbol).unwrap_or_else(|| { + panic!( + "Could not find {:?} in solved_types {:?}", + loc_symbol.value, solved_types + ) + }); + + // TODO should this be a union? + for (k, v) in new_aliases.clone() { + imported_aliases.insert(k, v); + } + + imported_symbols.push(Import { + loc_symbol, + solved_type: solved_type.clone(), + }); + } + Some(ExposedModuleTypes::Invalid) => { + // If that module was invalid, use True constraints + // for everything imported from it. + imported_symbols.push(Import { + loc_symbol, + solved_type: SolvedType::Erroneous(Problem::InvalidModule), + }); + } + None => { + panic!( + "Could not find module {:?} in exposed_types {:?}", + module_id, exposed_types + ); + } + } + } + } + + ConstrainableImports { + imported_symbols, + imported_aliases, + unused_imports, + } +} diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 2e53cd0cce..d18136937a 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2,10 +2,10 @@ use bumpalo::Bump; use roc_builtins::std::{Mode, StdLib}; use roc_can::constraint::Constraint; use roc_can::def::Declaration; -use roc_can::module::{Module, canonicalize_module_defs}; +use roc_can::module::{canonicalize_module_defs, Module}; use roc_collections::all::{default_hasher, MutMap, MutSet}; use roc_constrain::module::{ - constrain_imported_aliases, constrain_imported_values, load_builtin_aliases, Import, + constrain_imports, load_builtin_aliases, pre_constrain_imports, ConstrainableImports, }; use roc_constrain::module::{constrain_module, ExposedModuleTypes, SubsByModule}; use roc_module::ident::{Ident, ModuleName}; @@ -16,9 +16,8 @@ use roc_parse::parser::{Fail, Parser, State}; use roc_region::all::{Located, Region}; use roc_solve::module::SolvedModule; use roc_solve::solve; -use roc_types::solved_types::{Solved, SolvedType}; +use roc_types::solved_types::Solved; use roc_types::subs::{Subs, VarStore, Variable}; -use roc_types::types; use std::collections::{HashMap, HashSet}; use std::fs::read_to_string; use std::io; @@ -806,97 +805,22 @@ fn spawn_solve_module( exposed_types: &mut SubsByModule, stdlib: &StdLib, ) { - // Get the constriants for this module's imports. We do this on the main thread + let home = module.module_id; + + // Get the constraints for this module's imports. We do this on the main thread // 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 mut imported_symbols = Vec::with_capacity(module.references.len()); - let mut imported_aliases = MutMap::default(); - let mut unused_imports = imported_modules; // We'll remove these as we encounter them. - - // Translate referenced symbols into constraints. We do this on the main - // thread because we need exclusive access to the exposed_types map, in order - // to get the necessary constraint info for any aliases we imported. We also - // resolve builtin types now, so we can use a refernce to stdlib instead of - // having to either clone it or recreate it from scratch on the other thread. - for &symbol in module.references.iter() { - let module_id = symbol.module_id(); - - // We used this one, so clearly it is not unused! - unused_imports.remove(&module_id); - - if module_id.is_builtin() { - // For builtin modules, we create imports from the - // hardcoded builtin map. - match stdlib.types.get(&symbol) { - Some((solved_type, region)) => { - let loc_symbol = Located { - value: symbol, - region: *region, - }; - - imported_symbols.push(Import { - loc_symbol, - solved_type: solved_type.clone(), - }); - } - None => { - let is_valid_alias = stdlib.applies.contains(&symbol) - // This wasn't a builtin value or Apply; maybe it was a builtin alias. - || stdlib.aliases.contains_key(&symbol); - - if !is_valid_alias { - panic!( - "Could not find {:?} in builtin types {:?} or aliases {:?}", - symbol, stdlib.types, stdlib.aliases - ); - } - } - } - } else if module_id != home { - // We already have constraints for our own symbols. - let region = Region::zero(); // TODO this should be the region where this symbol was declared in its home module. Look that up! - let loc_symbol = Located { - value: symbol, - region, - }; - - match exposed_types.get(&module_id) { - Some(ExposedModuleTypes::Valid(solved_types, new_aliases)) => { - let solved_type = solved_types.get(&symbol).unwrap_or_else(|| { - panic!( - "Could not find {:?} in solved_types {:?}", - loc_symbol.value, solved_types - ) - }); - - // TODO should this be a union? - for (k, v) in new_aliases.clone() { - imported_aliases.insert(k, v); - } - - imported_symbols.push(Import { - loc_symbol, - solved_type: solved_type.clone(), - }); - } - Some(ExposedModuleTypes::Invalid) => { - // If that module was invalid, use True constraints - // for everything imported from it. - imported_symbols.push(Import { - loc_symbol, - solved_type: SolvedType::Erroneous(types::Problem::InvalidModule), - }); - } - None => { - panic!( - "Could not find module {:?} in exposed_types {:?}", - module_id, exposed_types - ); - } - } - } - } + let ConstrainableImports { + imported_symbols, + imported_aliases, + unused_imports, + } = pre_constrain_imports( + home, + &module.references, + imported_modules, + exposed_types, + stdlib, + ); for unused_import in unused_imports { todo!( @@ -920,10 +844,12 @@ fn spawn_solve_module( // Finish constraining the module by wrapping the existing Constraint // in the ones we just computed. We can do this off the main thread. - // TODO what to do with the introduced rigids? - let (_introduced_rigids, constraint) = - constrain_imported_values(imported_symbols, constraint, &mut var_store); - let constraint = constrain_imported_aliases(imported_aliases, constraint, &mut var_store); + let constraint = constrain_imports( + imported_symbols, + imported_aliases, + constraint, + &mut var_store, + ); let mut constraint = load_builtin_aliases(aliases, constraint, &mut var_store); // Turn Apply into Alias