mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Merge remote-tracking branch 'origin/trunk' into builtins-in-roc-delayed-alias
This commit is contained in:
commit
4e1197165b
181 changed files with 9495 additions and 2273 deletions
|
@ -1,19 +1,101 @@
|
|||
use roc_builtins::std::StdLib;
|
||||
use roc_can::constraint::{Constraint, Constraints};
|
||||
use roc_can::def::Declaration;
|
||||
use roc_collections::all::{MutMap, MutSet, SendMap};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_region::all::Loc;
|
||||
use roc_types::solved_types::{FreeVars, SolvedType};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{Alias, Problem};
|
||||
|
||||
pub type SubsByModule = MutMap<ModuleId, ExposedModuleTypes>;
|
||||
/// The types of all exposed values/functions of a collection of modules
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ExposedByModule {
|
||||
exposed: MutMap<ModuleId, ExposedModuleTypes>,
|
||||
}
|
||||
|
||||
impl ExposedByModule {
|
||||
pub fn insert(&mut self, module_id: ModuleId, exposed: ExposedModuleTypes) {
|
||||
self.exposed.insert(module_id, exposed);
|
||||
}
|
||||
|
||||
pub fn get(&self, module_id: &ModuleId) -> Option<&ExposedModuleTypes> {
|
||||
self.exposed.get(module_id)
|
||||
}
|
||||
|
||||
/// Convenient when you need mutable access to the StorageSubs in the ExposedModuleTypes
|
||||
pub fn get_mut(&mut self, module_id: &ModuleId) -> Option<&mut ExposedModuleTypes> {
|
||||
self.exposed.get_mut(module_id)
|
||||
}
|
||||
|
||||
/// Create a clone of `self` that has just a subset of the modules
|
||||
///
|
||||
/// Useful when we know what modules a particular module imports, and want just
|
||||
/// the exposed types for those exposed modules.
|
||||
pub fn retain_modules<'a>(&self, it: impl Iterator<Item = &'a ModuleId>) -> Self {
|
||||
let mut output = Self::default();
|
||||
|
||||
for module_id in it {
|
||||
match self.exposed.get(module_id) {
|
||||
None => {
|
||||
internal_error!("Module {:?} did not register its exposed values", module_id)
|
||||
}
|
||||
Some(exposed_types) => {
|
||||
output.exposed.insert(*module_id, exposed_types.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ExposedForModule {
|
||||
pub exposed_by_module: ExposedByModule,
|
||||
pub imported_values: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl ExposedForModule {
|
||||
pub fn new<'a>(
|
||||
it: impl Iterator<Item = &'a Symbol>,
|
||||
exposed_by_module: ExposedByModule,
|
||||
) -> Self {
|
||||
let mut imported_values = Vec::new();
|
||||
|
||||
for symbol in it {
|
||||
// Today, builtins are not actually imported,
|
||||
// but generated in each module that uses them
|
||||
//
|
||||
// This will change when we write builtins in roc
|
||||
if symbol.is_builtin() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(ExposedModuleTypes::Valid { .. }) =
|
||||
exposed_by_module.exposed.get(&symbol.module_id())
|
||||
{
|
||||
imported_values.push(*symbol);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
imported_values,
|
||||
exposed_by_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The types of all exposed values/functions of a module
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExposedModuleTypes {
|
||||
Invalid,
|
||||
Valid(MutMap<Symbol, SolvedType>, MutMap<Symbol, Alias>),
|
||||
Valid {
|
||||
stored_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||
storage_subs: roc_types::subs::StorageSubs,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn constrain_module(
|
||||
|
@ -30,17 +112,56 @@ pub struct Import {
|
|||
pub solved_type: SolvedType,
|
||||
}
|
||||
|
||||
pub fn constrain_imported_values(
|
||||
pub fn introduce_builtin_imports(
|
||||
constraints: &mut Constraints,
|
||||
imports: Vec<Import>,
|
||||
imports: Vec<Symbol>,
|
||||
body_con: Constraint,
|
||||
var_store: &mut VarStore,
|
||||
) -> (Vec<Variable>, Constraint) {
|
||||
let mut def_types = SendMap::default();
|
||||
) -> Constraint {
|
||||
let stdlib = roc_builtins::std::borrow_stdlib();
|
||||
let (rigid_vars, def_types) = constrain_builtin_imports(stdlib, imports, var_store);
|
||||
constraints.let_import_constraint(rigid_vars, def_types, body_con, &[])
|
||||
}
|
||||
|
||||
pub fn constrain_builtin_imports(
|
||||
stdlib: &StdLib,
|
||||
imports: Vec<Symbol>,
|
||||
var_store: &mut VarStore,
|
||||
) -> (Vec<Variable>, Vec<(Symbol, Loc<roc_types::types::Type>)>) {
|
||||
let mut def_types = Vec::new();
|
||||
let mut rigid_vars = Vec::new();
|
||||
|
||||
for import in imports {
|
||||
for symbol in imports {
|
||||
let mut free_vars = FreeVars::default();
|
||||
|
||||
let import = match stdlib.types.get(&symbol) {
|
||||
Some((solved_type, region)) => {
|
||||
let loc_symbol = Loc {
|
||||
value: symbol,
|
||||
region: *region,
|
||||
};
|
||||
|
||||
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.
|
||||
|| roc_types::builtin_aliases::aliases().contains_key(&symbol);
|
||||
|
||||
// if !is_valid_alias {
|
||||
// panic!(
|
||||
// "Could not find {:?} in builtin types {:?} or builtin aliases",
|
||||
// symbol, stdlib.types,
|
||||
// );
|
||||
// }
|
||||
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let loc_symbol = import.loc_symbol;
|
||||
|
||||
// an imported symbol can be either an alias or a value
|
||||
|
@ -55,13 +176,13 @@ pub fn constrain_imported_values(
|
|||
var_store,
|
||||
);
|
||||
|
||||
def_types.insert(
|
||||
def_types.push((
|
||||
loc_symbol.value,
|
||||
Loc {
|
||||
region: loc_symbol.region,
|
||||
value: typ,
|
||||
},
|
||||
);
|
||||
));
|
||||
|
||||
for (_, var) in free_vars.named_vars {
|
||||
rigid_vars.push(var);
|
||||
|
@ -80,188 +201,5 @@ pub fn constrain_imported_values(
|
|||
}
|
||||
}
|
||||
|
||||
(
|
||||
rigid_vars.clone(),
|
||||
constraints.let_constraint(rigid_vars, [], def_types, Constraint::True, body_con),
|
||||
)
|
||||
}
|
||||
|
||||
/// Run pre_constrain_imports to get imported_symbols and imported_aliases.
|
||||
pub fn constrain_imports(
|
||||
constraints: &mut Constraints,
|
||||
imported_symbols: Vec<Import>,
|
||||
constraint: Constraint,
|
||||
var_store: &mut VarStore,
|
||||
) -> Constraint {
|
||||
let (_introduced_rigids, constraint) =
|
||||
constrain_imported_values(constraints, 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());
|
||||
// }
|
||||
|
||||
constraint
|
||||
}
|
||||
|
||||
pub struct ConstrainableImports {
|
||||
pub imported_symbols: Vec<Import>,
|
||||
pub imported_aliases: MutMap<Symbol, Alias>,
|
||||
pub unused_imports: MutMap<ModuleId, Region>,
|
||||
}
|
||||
|
||||
/// 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<Symbol>,
|
||||
imported_modules: MutMap<ModuleId, Region>,
|
||||
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 reference 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 module, so clearly it is not unused!
|
||||
unused_imports.remove(&module_id);
|
||||
|
||||
let builtin_applies = [
|
||||
Symbol::LIST_LIST,
|
||||
Symbol::STR_STR,
|
||||
Symbol::DICT_DICT,
|
||||
Symbol::SET_SET,
|
||||
];
|
||||
|
||||
if module_id.is_builtin() && builtin_applies.contains(&symbol) {
|
||||
// For builtin modules, we create imports from the
|
||||
// hardcoded builtin map.
|
||||
match stdlib.types.get(&symbol) {
|
||||
Some((solved_type, region)) => {
|
||||
let loc_symbol = Loc {
|
||||
value: symbol,
|
||||
region: *region,
|
||||
};
|
||||
|
||||
imported_symbols.push(Import {
|
||||
loc_symbol,
|
||||
solved_type: solved_type.clone(),
|
||||
});
|
||||
}
|
||||
None => {
|
||||
if module_id == home {
|
||||
continue;
|
||||
}
|
||||
|
||||
if module_id == ModuleId::RESULT {
|
||||
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 = Loc {
|
||||
value: symbol,
|
||||
region,
|
||||
};
|
||||
|
||||
match exposed_types.get(&module_id) {
|
||||
Some(ExposedModuleTypes::Valid(solved_types, new_aliases)) => {
|
||||
// If the exposed value was invalid (e.g. it didn't have
|
||||
// a corresponding definition), it won't have an entry
|
||||
// in solved_types
|
||||
if let Some(solved_type) = solved_types.get(&symbol) {
|
||||
// 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!("Module {:?} does not have info for module {:?} in its exposed types", module_id, home)
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_valid_alias = stdlib.applies.contains(&symbol)
|
||||
// This wasn't a builtin value or Apply; maybe it was a builtin alias.
|
||||
|| roc_types::builtin_aliases::aliases().contains_key(&symbol);
|
||||
|
||||
if !is_valid_alias {
|
||||
panic!(
|
||||
"Could not find {:?} in builtin types {:?} or builtin aliases",
|
||||
symbol, stdlib.types,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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 = Loc {
|
||||
value: symbol,
|
||||
region,
|
||||
};
|
||||
|
||||
match exposed_types.get(&module_id) {
|
||||
Some(ExposedModuleTypes::Valid(solved_types, new_aliases)) => {
|
||||
// If the exposed value was invalid (e.g. it didn't have
|
||||
// a corresponding definition), it won't have an entry
|
||||
// in solved_types
|
||||
if let Some(solved_type) = solved_types.get(&symbol) {
|
||||
// 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!(
|
||||
"Module {:?} does not have info for module {:?} in its exposed types.\n I was looking for symbol {:?}",
|
||||
home, module_id, symbol,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConstrainableImports {
|
||||
imported_symbols,
|
||||
imported_aliases,
|
||||
unused_imports,
|
||||
}
|
||||
(rigid_vars, def_types)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue