mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
make Str + Result work
This commit is contained in:
parent
d1d7cfef44
commit
c0d3543d5a
12 changed files with 401 additions and 142 deletions
|
@ -12,7 +12,7 @@ use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
use roc_types::types::{AliasKind, Type};
|
use roc_types::types::{AliasKind, Type};
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub(crate) struct HostedGeneratedFunctions {
|
pub(crate) struct HostedGeneratedFunctions {
|
||||||
pub(crate) after: bool,
|
pub(crate) after: bool,
|
||||||
pub(crate) map: bool,
|
pub(crate) map: bool,
|
||||||
|
|
|
@ -65,48 +65,33 @@ fn validate_generate_with<'a>(
|
||||||
(functions, unknown)
|
(functions, unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO trim these down
|
#[derive(Debug)]
|
||||||
#[allow(clippy::too_many_arguments)]
|
enum GeneratedInfo<'a> {
|
||||||
pub fn canonicalize_module_defs<'a>(
|
Hosted {
|
||||||
arena: &Bump,
|
|
||||||
loc_defs: &'a [Loc<ast::Def<'a>>],
|
|
||||||
header_for: &roc_parse::header::HeaderFor,
|
|
||||||
home: ModuleId,
|
|
||||||
module_ids: &ModuleIds,
|
|
||||||
exposed_ident_ids: IdentIds,
|
|
||||||
dep_idents: &'a MutMap<ModuleId, IdentIds>,
|
|
||||||
aliases: MutMap<Symbol, Alias>,
|
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
|
||||||
exposed_symbols: &MutSet<Symbol>,
|
|
||||||
var_store: &mut VarStore,
|
|
||||||
) -> Result<ModuleOutput, RuntimeError> {
|
|
||||||
let mut can_exposed_imports = MutMap::default();
|
|
||||||
let mut scope = Scope::new(home, var_store);
|
|
||||||
let mut env = Env::new(home, dep_idents, module_ids, exposed_ident_ids);
|
|
||||||
let num_deps = dep_idents.len();
|
|
||||||
|
|
||||||
for (name, alias) in aliases.into_iter() {
|
|
||||||
scope.add_alias(
|
|
||||||
name,
|
|
||||||
alias.region,
|
|
||||||
alias.type_variables,
|
|
||||||
alias.typ,
|
|
||||||
alias.kind,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Hosted {
|
|
||||||
effect_symbol: Symbol,
|
effect_symbol: Symbol,
|
||||||
generated_functions: HostedGeneratedFunctions,
|
generated_functions: HostedGeneratedFunctions,
|
||||||
|
},
|
||||||
|
Builtin {
|
||||||
|
generated_functions: &'a [Symbol],
|
||||||
|
},
|
||||||
|
NotSpecial,
|
||||||
}
|
}
|
||||||
|
|
||||||
let hosted_info = if let HeaderFor::Hosted {
|
impl<'a> GeneratedInfo<'a> {
|
||||||
|
fn from_header_for(
|
||||||
|
env: &mut Env,
|
||||||
|
scope: &mut Scope,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
header_for: &HeaderFor<'a>,
|
||||||
|
) -> Self {
|
||||||
|
match header_for {
|
||||||
|
HeaderFor::Hosted {
|
||||||
generates,
|
generates,
|
||||||
generates_with,
|
generates_with,
|
||||||
} = header_for
|
} => {
|
||||||
{
|
|
||||||
let name: &str = generates.into();
|
let name: &str = generates.into();
|
||||||
let (generated_functions, unknown_generated) = validate_generate_with(generates_with);
|
let (generated_functions, unknown_generated) =
|
||||||
|
validate_generate_with(generates_with);
|
||||||
|
|
||||||
for unknown in unknown_generated {
|
for unknown in unknown_generated {
|
||||||
env.problem(Problem::UnknownGeneratesWith(unknown));
|
env.problem(Problem::UnknownGeneratesWith(unknown));
|
||||||
|
@ -141,13 +126,67 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Hosted {
|
GeneratedInfo::Hosted {
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
generated_functions,
|
generated_functions,
|
||||||
})
|
}
|
||||||
} else {
|
}
|
||||||
None
|
HeaderFor::Builtin { generates_with } => GeneratedInfo::Builtin {
|
||||||
};
|
generated_functions: generates_with,
|
||||||
|
},
|
||||||
|
_ => GeneratedInfo::NotSpecial,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_no_implementation(expr: &Expr) -> bool {
|
||||||
|
match expr {
|
||||||
|
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. }) => true,
|
||||||
|
Expr::Closure(closure_data)
|
||||||
|
if matches!(
|
||||||
|
closure_data.loc_body.value,
|
||||||
|
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. })
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO trim these down
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn canonicalize_module_defs<'a>(
|
||||||
|
arena: &Bump,
|
||||||
|
loc_defs: &'a [Loc<ast::Def<'a>>],
|
||||||
|
header_for: &roc_parse::header::HeaderFor,
|
||||||
|
home: ModuleId,
|
||||||
|
module_ids: &ModuleIds,
|
||||||
|
exposed_ident_ids: IdentIds,
|
||||||
|
dep_idents: &'a MutMap<ModuleId, IdentIds>,
|
||||||
|
aliases: MutMap<Symbol, Alias>,
|
||||||
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
|
exposed_symbols: &MutSet<Symbol>,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
) -> Result<ModuleOutput, RuntimeError> {
|
||||||
|
let mut can_exposed_imports = MutMap::default();
|
||||||
|
let mut scope = Scope::new(home, var_store);
|
||||||
|
let mut env = Env::new(home, dep_idents, module_ids, exposed_ident_ids);
|
||||||
|
let num_deps = dep_idents.len();
|
||||||
|
|
||||||
|
for (name, alias) in aliases.into_iter() {
|
||||||
|
scope.add_alias(
|
||||||
|
name,
|
||||||
|
alias.region,
|
||||||
|
alias.type_variables,
|
||||||
|
alias.typ,
|
||||||
|
alias.kind,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let generated_info =
|
||||||
|
GeneratedInfo::from_header_for(&mut env, &mut scope, var_store, header_for);
|
||||||
|
|
||||||
// Desugar operators (convert them to Apply calls, taking into account
|
// Desugar operators (convert them to Apply calls, taking into account
|
||||||
// operator precedence and associativity rules), before doing other canonicalization.
|
// operator precedence and associativity rules), before doing other canonicalization.
|
||||||
|
@ -206,11 +245,13 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
} else {
|
} else {
|
||||||
// This is a type alias
|
// This is a type alias
|
||||||
|
|
||||||
|
dbg!(scope.aliases.keys().collect::<Vec<_>>());
|
||||||
// the symbol should already be added to the scope when this module is canonicalized
|
// the symbol should already be added to the scope when this module is canonicalized
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
scope.contains_alias(symbol),
|
scope.contains_alias(symbol),
|
||||||
"apparently, {:?} is not actually a type alias",
|
"The {:?} is not a type alias known in {:?}",
|
||||||
symbol
|
symbol,
|
||||||
|
home
|
||||||
);
|
);
|
||||||
|
|
||||||
// but now we know this symbol by a different identifier, so we still need to add it to
|
// but now we know this symbol by a different identifier, so we still need to add it to
|
||||||
|
@ -291,10 +332,10 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
(Ok(mut declarations), output) => {
|
(Ok(mut declarations), output) => {
|
||||||
use crate::def::Declaration::*;
|
use crate::def::Declaration::*;
|
||||||
|
|
||||||
if let Some(Hosted {
|
if let GeneratedInfo::Hosted {
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
generated_functions,
|
generated_functions,
|
||||||
}) = hosted_info
|
} = generated_info
|
||||||
{
|
{
|
||||||
let mut exposed_symbols = MutSet::default();
|
let mut exposed_symbols = MutSet::default();
|
||||||
|
|
||||||
|
@ -327,9 +368,23 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
// Temporary hack: we don't know exactly what symbols are hosted symbols,
|
// Temporary hack: we don't know exactly what symbols are hosted symbols,
|
||||||
// and which are meant to be normal definitions without a body. So for now
|
// and which are meant to be normal definitions without a body. So for now
|
||||||
// we just assume they are hosted functions (meant to be provided by the platform)
|
// we just assume they are hosted functions (meant to be provided by the platform)
|
||||||
if let Some(Hosted { effect_symbol, .. }) = hosted_info {
|
if has_no_implementation(&def.loc_expr.value) {
|
||||||
macro_rules! make_hosted_def {
|
match generated_info {
|
||||||
() => {
|
GeneratedInfo::Builtin {
|
||||||
|
generated_functions,
|
||||||
|
} => {
|
||||||
|
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
||||||
|
match crate::builtins::builtin_defs_map(*symbol, var_store) {
|
||||||
|
None => {
|
||||||
|
panic!("A builtin module contains a signature without implementation")
|
||||||
|
}
|
||||||
|
Some(mut replacement_def) => {
|
||||||
|
replacement_def.annotation = def.annotation.take();
|
||||||
|
*def = replacement_def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GeneratedInfo::Hosted { effect_symbol, .. } => {
|
||||||
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
||||||
let ident_id = symbol.ident_id();
|
let ident_id = symbol.ident_id();
|
||||||
let ident =
|
let ident =
|
||||||
|
@ -353,27 +408,8 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
*def = hosted_def;
|
*def = hosted_def;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
match &def.loc_expr.value {
|
|
||||||
Expr::RuntimeError(RuntimeError::NoImplementationNamed {
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
make_hosted_def!();
|
|
||||||
}
|
|
||||||
Expr::Closure(closure_data)
|
|
||||||
if matches!(
|
|
||||||
closure_data.loc_body.value,
|
|
||||||
Expr::RuntimeError(
|
|
||||||
RuntimeError::NoImplementationNamed { .. }
|
|
||||||
)
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
make_hosted_def!();
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,7 +444,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
|
|
||||||
let mut aliases = MutMap::default();
|
let mut aliases = MutMap::default();
|
||||||
|
|
||||||
if let Some(Hosted { effect_symbol, .. }) = hosted_info {
|
if let GeneratedInfo::Hosted { effect_symbol, .. } = generated_info {
|
||||||
// Remove this from exposed_symbols,
|
// Remove this from exposed_symbols,
|
||||||
// so that at the end of the process,
|
// so that at the end of the process,
|
||||||
// we can see if there were any
|
// we can see if there were any
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub struct Scope {
|
||||||
symbols: SendMap<Symbol, Region>,
|
symbols: SendMap<Symbol, Region>,
|
||||||
|
|
||||||
/// The type aliases currently in scope
|
/// The type aliases currently in scope
|
||||||
aliases: SendMap<Symbol, Alias>,
|
pub aliases: SendMap<Symbol, Alias>,
|
||||||
|
|
||||||
/// The current module being processed. This will be used to turn
|
/// The current module being processed. This will be used to turn
|
||||||
/// unqualified idents into Symbols.
|
/// unqualified idents into Symbols.
|
||||||
|
@ -88,13 +88,17 @@ impl Scope {
|
||||||
pub fn lookup(&self, ident: &Ident, region: Region) -> Result<Symbol, RuntimeError> {
|
pub fn lookup(&self, ident: &Ident, region: Region) -> Result<Symbol, RuntimeError> {
|
||||||
match self.idents.get(ident) {
|
match self.idents.get(ident) {
|
||||||
Some((symbol, _)) => Ok(*symbol),
|
Some((symbol, _)) => Ok(*symbol),
|
||||||
None => Err(RuntimeError::LookupNotInScope(
|
None => {
|
||||||
|
let error = RuntimeError::LookupNotInScope(
|
||||||
Loc {
|
Loc {
|
||||||
region,
|
region,
|
||||||
value: ident.clone(),
|
value: ident.clone(),
|
||||||
},
|
},
|
||||||
self.idents.keys().map(|v| v.as_ref().into()).collect(),
|
self.idents.keys().map(|v| v.as_ref().into()).collect(),
|
||||||
)),
|
);
|
||||||
|
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ pub fn pre_constrain_imports(
|
||||||
// We used this module, so clearly it is not unused!
|
// We used this module, so clearly it is not unused!
|
||||||
unused_imports.remove(&module_id);
|
unused_imports.remove(&module_id);
|
||||||
|
|
||||||
if module_id.is_builtin() {
|
if module_id.is_builtin() && module_id != ModuleId::STR {
|
||||||
// For builtin modules, we create imports from the
|
// For builtin modules, we create imports from the
|
||||||
// hardcoded builtin map.
|
// hardcoded builtin map.
|
||||||
match stdlib.types.get(&symbol) {
|
match stdlib.types.get(&symbol) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ use roc_mono::ir::{
|
||||||
UpdateModeIds,
|
UpdateModeIds,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
||||||
use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral};
|
use roc_parse::ast::{self, Collection, ExtractSpaces, Spaced, StrLiteral};
|
||||||
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
||||||
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
||||||
use roc_parse::ident::UppercaseIdent;
|
use roc_parse::ident::UppercaseIdent;
|
||||||
|
@ -65,7 +65,7 @@ const PKG_CONFIG_FILE_NAME: &str = "Package-Config";
|
||||||
/// The . in between module names like Foo.Bar.Baz
|
/// The . in between module names like Foo.Bar.Baz
|
||||||
const MODULE_SEPARATOR: char = '.';
|
const MODULE_SEPARATOR: char = '.';
|
||||||
|
|
||||||
const SHOW_MESSAGE_LOG: bool = false;
|
const SHOW_MESSAGE_LOG: bool = true;
|
||||||
|
|
||||||
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
|
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ macro_rules! log {
|
||||||
const BUILTIN_MODULES: &[(ModuleId, &[ModuleId])] = &[(ModuleId::RESULT, &[])];
|
const BUILTIN_MODULES: &[(ModuleId, &[ModuleId])] = &[(ModuleId::RESULT, &[])];
|
||||||
|
|
||||||
/// Struct storing various intermediate stages by their ModuleId
|
/// Struct storing various intermediate stages by their ModuleId
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
struct ModuleCache<'a> {
|
struct ModuleCache<'a> {
|
||||||
module_names: MutMap<ModuleId, PQModuleName<'a>>,
|
module_names: MutMap<ModuleId, PQModuleName<'a>>,
|
||||||
|
|
||||||
|
@ -101,6 +101,40 @@ struct ModuleCache<'a> {
|
||||||
sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ModuleCache<'_> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut module_names = MutMap::default();
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::RESULT,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::RESULT)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::STR,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::STR)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
module_names,
|
||||||
|
headers: Default::default(),
|
||||||
|
parsed: Default::default(),
|
||||||
|
aliases: Default::default(),
|
||||||
|
constrained: Default::default(),
|
||||||
|
typechecked: Default::default(),
|
||||||
|
found_specializations: Default::default(),
|
||||||
|
external_specializations_requested: Default::default(),
|
||||||
|
imports: Default::default(),
|
||||||
|
top_level_thunks: Default::default(),
|
||||||
|
documentation: Default::default(),
|
||||||
|
can_problems: Default::default(),
|
||||||
|
type_problems: Default::default(),
|
||||||
|
mono_problems: Default::default(),
|
||||||
|
sources: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_phase<'a>(
|
fn start_phase<'a>(
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
phase: Phase,
|
phase: Phase,
|
||||||
|
@ -130,15 +164,17 @@ fn start_phase<'a>(
|
||||||
let task = {
|
let task = {
|
||||||
match phase {
|
match phase {
|
||||||
Phase::LoadHeader => {
|
Phase::LoadHeader => {
|
||||||
let dep_name = state
|
let opt_dep_name = state.module_cache.module_names.get(&module_id);
|
||||||
.module_cache
|
|
||||||
.module_names
|
match opt_dep_name {
|
||||||
.get(&module_id)
|
None => {
|
||||||
.expect("module id is present")
|
panic!("Module {:?} is not in module_cache.module_names", module_id)
|
||||||
.clone();
|
}
|
||||||
|
Some(dep_name) => {
|
||||||
|
let module_name = dep_name.clone();
|
||||||
|
|
||||||
BuildTask::LoadModule {
|
BuildTask::LoadModule {
|
||||||
module_name: dep_name,
|
module_name,
|
||||||
// Provide mutexes of ModuleIds and IdentIds by module,
|
// Provide mutexes of ModuleIds and IdentIds by module,
|
||||||
// so other modules can populate them as they load.
|
// so other modules can populate them as they load.
|
||||||
module_ids: Arc::clone(&state.arc_modules),
|
module_ids: Arc::clone(&state.arc_modules),
|
||||||
|
@ -146,6 +182,8 @@ fn start_phase<'a>(
|
||||||
ident_ids_by_module: Arc::clone(&state.ident_ids_by_module),
|
ident_ids_by_module: Arc::clone(&state.ident_ids_by_module),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Phase::Parse => {
|
Phase::Parse => {
|
||||||
// parse the file
|
// parse the file
|
||||||
let header = state.module_cache.headers.remove(&module_id).unwrap();
|
let header = state.module_cache.headers.remove(&module_id).unwrap();
|
||||||
|
@ -215,6 +253,8 @@ fn start_phase<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!(module_id, &parsed.imported_modules);
|
||||||
|
|
||||||
BuildTask::CanonicalizeAndConstrain {
|
BuildTask::CanonicalizeAndConstrain {
|
||||||
parsed,
|
parsed,
|
||||||
dep_idents,
|
dep_idents,
|
||||||
|
@ -1037,7 +1077,7 @@ fn load<'a>(
|
||||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||||
// When compiling to wasm, we cannot spawn extra threads
|
// When compiling to wasm, we cannot spawn extra threads
|
||||||
// so we have a single-threaded implementation
|
// so we have a single-threaded implementation
|
||||||
if cfg!(target_family = "wasm") {
|
if true || cfg!(target_family = "wasm") {
|
||||||
load_single_threaded(
|
load_single_threaded(
|
||||||
arena,
|
arena,
|
||||||
load_start,
|
load_start,
|
||||||
|
@ -1613,7 +1653,7 @@ fn update<'a>(
|
||||||
state.platform_path = PlatformPath::RootIsPkgConfig;
|
state.platform_path = PlatformPath::RootIsPkgConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Interface => {
|
Builtin { .. } | Interface => {
|
||||||
if header.is_root_module {
|
if header.is_root_module {
|
||||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
state.platform_path = PlatformPath::RootIsInterface;
|
state.platform_path = PlatformPath::RootIsInterface;
|
||||||
|
@ -1649,6 +1689,37 @@ fn update<'a>(
|
||||||
.exposed_symbols_by_module
|
.exposed_symbols_by_module
|
||||||
.insert(home, exposed_symbols);
|
.insert(home, exposed_symbols);
|
||||||
|
|
||||||
|
// add the prelude
|
||||||
|
let mut header = header;
|
||||||
|
// let mut imports = header.package_qualified_imported_modules.clone();
|
||||||
|
|
||||||
|
if header.module_id != ModuleId::RESULT {
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::RESULT));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::RESULT, Region::zero());
|
||||||
|
|
||||||
|
header.exposed_imports.insert(
|
||||||
|
Ident::from("Result"),
|
||||||
|
(Symbol::RESULT_RESULT, Region::zero()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !header.module_id.is_builtin() {
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::STR));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::STR, Region::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(header.module_id, &header.exposed_imports);
|
||||||
|
|
||||||
state
|
state
|
||||||
.module_cache
|
.module_cache
|
||||||
.imports
|
.imports
|
||||||
|
@ -1770,8 +1841,10 @@ fn update<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unused, region) in unused_imports.drain() {
|
for (unused, region) in unused_imports.drain() {
|
||||||
|
if !unused.is_builtin() {
|
||||||
existing.push(roc_problem::can::Problem::UnusedImport(unused, region));
|
existing.push(roc_problem::can::Problem::UnusedImport(unused, region));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
||||||
|
|
||||||
|
@ -2209,6 +2282,12 @@ fn load_pkg_config<'a>(
|
||||||
header
|
header
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
Ok((ast::Module::Hosted { header }, _parse_state)) => {
|
||||||
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
|
"expected platform/package module, got Hosted module with header\n{:?}",
|
||||||
|
header
|
||||||
|
)))
|
||||||
|
}
|
||||||
Ok((ast::Module::App { header }, _parse_state)) => {
|
Ok((ast::Module::App { header }, _parse_state)) => {
|
||||||
Err(LoadingProblem::UnexpectedHeader(format!(
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
"expected platform/package module, got App with header\n{:?}",
|
"expected platform/package module, got App with header\n{:?}",
|
||||||
|
@ -2232,12 +2311,6 @@ fn load_pkg_config<'a>(
|
||||||
|
|
||||||
Ok(pkg_config_module_msg)
|
Ok(pkg_config_module_msg)
|
||||||
}
|
}
|
||||||
Ok((ast::Module::Hosted { header }, _parse_state)) => {
|
|
||||||
Err(LoadingProblem::UnexpectedHeader(format!(
|
|
||||||
"expected platform/package module, got Hosted module with header\n{:?}",
|
|
||||||
header
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
||||||
fail.map_problem(SyntaxError::Header)
|
fail.map_problem(SyntaxError::Header)
|
||||||
.into_file_error(filename),
|
.into_file_error(filename),
|
||||||
|
@ -2261,12 +2334,8 @@ fn load_module<'a>(
|
||||||
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
||||||
use PackageQualified::*;
|
|
||||||
|
|
||||||
let module_start_time = SystemTime::now();
|
let module_start_time = SystemTime::now();
|
||||||
|
|
||||||
dbg!(&module_name);
|
|
||||||
|
|
||||||
match module_name.as_inner().as_str() {
|
match module_name.as_inner().as_str() {
|
||||||
"Result" => {
|
"Result" => {
|
||||||
let parse_start = SystemTime::now();
|
let parse_start = SystemTime::now();
|
||||||
|
@ -2302,7 +2371,9 @@ fn load_module<'a>(
|
||||||
packages: &[],
|
packages: &[],
|
||||||
exposes: &EXPOSES,
|
exposes: &EXPOSES,
|
||||||
imports,
|
imports,
|
||||||
extra: HeaderFor::Interface,
|
extra: HeaderFor::Builtin {
|
||||||
|
generates_with: &[],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let src_bytes = r#"
|
let src_bytes = r#"
|
||||||
|
@ -2355,6 +2426,136 @@ fn load_module<'a>(
|
||||||
module_timing,
|
module_timing,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
"Str" => {
|
||||||
|
let parse_start = SystemTime::now();
|
||||||
|
let parse_header_duration = parse_start.elapsed().unwrap();
|
||||||
|
|
||||||
|
// Insert the first entries for this module's timings
|
||||||
|
let mut module_timing = ModuleTiming::new(module_start_time);
|
||||||
|
|
||||||
|
module_timing.read_roc_file = Default::default();
|
||||||
|
module_timing.parse_header = parse_header_duration;
|
||||||
|
|
||||||
|
let filename = PathBuf::from("Str.roc");
|
||||||
|
|
||||||
|
const EXPOSES: &[Loc<ExposedName>] = &[
|
||||||
|
Loc::at_zero(ExposedName::new("Utf8Problem")),
|
||||||
|
Loc::at_zero(ExposedName::new("Utf8ByteProblem")),
|
||||||
|
Loc::at_zero(ExposedName::new("isEmpty")),
|
||||||
|
Loc::at_zero(ExposedName::new("concat")),
|
||||||
|
Loc::at_zero(ExposedName::new("joinWith")),
|
||||||
|
Loc::at_zero(ExposedName::new("split")),
|
||||||
|
Loc::at_zero(ExposedName::new("repeat")),
|
||||||
|
Loc::at_zero(ExposedName::new("countGraphemes")),
|
||||||
|
Loc::at_zero(ExposedName::new("startsWithCodePt")),
|
||||||
|
Loc::at_zero(ExposedName::new("toUtf8")),
|
||||||
|
Loc::at_zero(ExposedName::new("fromUtf8")),
|
||||||
|
Loc::at_zero(ExposedName::new("fromUtf8Range")),
|
||||||
|
Loc::at_zero(ExposedName::new("startsWith")),
|
||||||
|
Loc::at_zero(ExposedName::new("endsWith")),
|
||||||
|
Loc::at_zero(ExposedName::new("trim")),
|
||||||
|
Loc::at_zero(ExposedName::new("trimLeft")),
|
||||||
|
Loc::at_zero(ExposedName::new("trimRight")),
|
||||||
|
Loc::at_zero(ExposedName::new("toDec")),
|
||||||
|
Loc::at_zero(ExposedName::new("toF64")),
|
||||||
|
Loc::at_zero(ExposedName::new("toF32")),
|
||||||
|
Loc::at_zero(ExposedName::new("toNat")),
|
||||||
|
Loc::at_zero(ExposedName::new("toU128")),
|
||||||
|
Loc::at_zero(ExposedName::new("toI128")),
|
||||||
|
Loc::at_zero(ExposedName::new("toU64")),
|
||||||
|
Loc::at_zero(ExposedName::new("toI64")),
|
||||||
|
Loc::at_zero(ExposedName::new("toU32")),
|
||||||
|
Loc::at_zero(ExposedName::new("toI32")),
|
||||||
|
Loc::at_zero(ExposedName::new("toU16")),
|
||||||
|
Loc::at_zero(ExposedName::new("toI16")),
|
||||||
|
Loc::at_zero(ExposedName::new("toU8")),
|
||||||
|
Loc::at_zero(ExposedName::new("toI8")),
|
||||||
|
];
|
||||||
|
const IMPORTS: &[Loc<ImportsEntry>] = &[Loc::at_zero(ImportsEntry::Module(
|
||||||
|
roc_parse::header::ModuleName::new("Result"),
|
||||||
|
Collection::with_items(&[Loc::at_zero(Spaced::Item(ExposedName::new("Result")))]),
|
||||||
|
))];
|
||||||
|
|
||||||
|
const GENERATES_WITH: &[Symbol] = &[Symbol::STR_IS_EMPTY, Symbol::STR_CONCAT];
|
||||||
|
|
||||||
|
let info = HeaderInfo {
|
||||||
|
loc_name: Loc {
|
||||||
|
region: Region::zero(),
|
||||||
|
value: ModuleNameEnum::Interface(roc_parse::header::ModuleName::new("Str")),
|
||||||
|
},
|
||||||
|
filename,
|
||||||
|
is_root_module: false,
|
||||||
|
opt_shorthand: None,
|
||||||
|
packages: &[],
|
||||||
|
exposes: &EXPOSES,
|
||||||
|
imports: &IMPORTS,
|
||||||
|
extra: HeaderFor::Builtin {
|
||||||
|
generates_with: GENERATES_WITH,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let src_bytes = r#"
|
||||||
|
Utf8ByteProblem :
|
||||||
|
[
|
||||||
|
InvalidStartByte,
|
||||||
|
UnexpectedEndOfSequence,
|
||||||
|
ExpectedContinuation,
|
||||||
|
OverlongEncoding,
|
||||||
|
CodepointTooLarge,
|
||||||
|
EncodesSurrogateHalf,
|
||||||
|
]
|
||||||
|
|
||||||
|
Utf8Problem : { byteIndex : Nat, problem : Utf8ByteProblem }
|
||||||
|
|
||||||
|
isEmpty : Str -> Bool
|
||||||
|
concat : Str, Str -> Str
|
||||||
|
joinWith : List Str, Str -> Str
|
||||||
|
split : Str, Str -> List Str
|
||||||
|
repeat : Str, Nat -> Str
|
||||||
|
countGraphemes : Str -> Nat
|
||||||
|
startsWithCodePt : Str, U32 -> Bool
|
||||||
|
|
||||||
|
toUtf8 : Str -> List U8
|
||||||
|
|
||||||
|
# fromUtf8 : List U8 -> Result Str [ BadUtf8 Utf8Problem ]*
|
||||||
|
# fromUtf8Range : List U8 -> Result Str [ BadUtf8 Utf8Problem, OutOfBounds ]*
|
||||||
|
|
||||||
|
fromUtf8 : List U8 -> Result Str [ BadUtf8 Utf8ByteProblem Nat ]*
|
||||||
|
fromUtf8Range : List U8 -> Result Str [ BadUtf8 Utf8ByteProblem Nat, OutOfBounds ]*
|
||||||
|
|
||||||
|
startsWith : Str, Str -> Bool
|
||||||
|
endsWith : Str, Str -> Bool
|
||||||
|
|
||||||
|
trim : Str -> Str
|
||||||
|
trimLeft : Str -> Str
|
||||||
|
trimRight : Str -> Str
|
||||||
|
|
||||||
|
toDec : Str -> Result Dec [ InvalidNumStr ]*
|
||||||
|
toF64 : Str -> Result F64 [ InvalidNumStr ]*
|
||||||
|
toF32 : Str -> Result F32 [ InvalidNumStr ]*
|
||||||
|
toNat : Str -> Result Nat [ InvalidNumStr ]*
|
||||||
|
toU128 : Str -> Result U128 [ InvalidNumStr ]*
|
||||||
|
toI128 : Str -> Result I128 [ InvalidNumStr ]*
|
||||||
|
toU64 : Str -> Result U64 [ InvalidNumStr ]*
|
||||||
|
toI64 : Str -> Result I64 [ InvalidNumStr ]*
|
||||||
|
toU32 : Str -> Result U32 [ InvalidNumStr ]*
|
||||||
|
toI32 : Str -> Result I32 [ InvalidNumStr ]*
|
||||||
|
toU16 : Str -> Result U16 [ InvalidNumStr ]*
|
||||||
|
toI16 : Str -> Result I16 [ InvalidNumStr ]*
|
||||||
|
toU8 : Str -> Result U8 [ InvalidNumStr ]*
|
||||||
|
toI8 : Str -> Result I8 [ InvalidNumStr ]*
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let parse_state = roc_parse::state::State::new(src_bytes.as_bytes());
|
||||||
|
|
||||||
|
return Ok(send_header(
|
||||||
|
info,
|
||||||
|
parse_state,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
));
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// fall through
|
// fall through
|
||||||
}
|
}
|
||||||
|
|
|
@ -1048,7 +1048,7 @@ define_builtins! {
|
||||||
0 STR_STR: "Str" imported // the Str.Str type alias
|
0 STR_STR: "Str" imported // the Str.Str type alias
|
||||||
1 STR_AT_STR: "@Str" // the Str.@Str private tag
|
1 STR_AT_STR: "@Str" // the Str.@Str private tag
|
||||||
2 STR_IS_EMPTY: "isEmpty"
|
2 STR_IS_EMPTY: "isEmpty"
|
||||||
3 STR_APPEND: "append"
|
3 STR_APPEND: "#append" // unused
|
||||||
4 STR_CONCAT: "concat"
|
4 STR_CONCAT: "concat"
|
||||||
5 STR_JOIN_WITH: "joinWith"
|
5 STR_JOIN_WITH: "joinWith"
|
||||||
6 STR_SPLIT: "split"
|
6 STR_SPLIT: "split"
|
||||||
|
|
|
@ -6589,7 +6589,19 @@ fn can_reuse_symbol<'a>(
|
||||||
if let roc_can::expr::Expr::Var(symbol) = expr {
|
if let roc_can::expr::Expr::Var(symbol) = expr {
|
||||||
let symbol = *symbol;
|
let symbol = *symbol;
|
||||||
|
|
||||||
if env.is_imported_symbol(symbol) {
|
let arguments = [
|
||||||
|
Symbol::ARG_1,
|
||||||
|
Symbol::ARG_2,
|
||||||
|
Symbol::ARG_3,
|
||||||
|
Symbol::ARG_4,
|
||||||
|
Symbol::ARG_5,
|
||||||
|
Symbol::ARG_6,
|
||||||
|
Symbol::ARG_7,
|
||||||
|
];
|
||||||
|
|
||||||
|
if arguments.contains(&symbol) {
|
||||||
|
Value(symbol)
|
||||||
|
} else if env.is_imported_symbol(symbol) {
|
||||||
Imported(symbol)
|
Imported(symbol)
|
||||||
} else if procs.partial_procs.contains_key(symbol) {
|
} else if procs.partial_procs.contains_key(symbol) {
|
||||||
LocalFunction(symbol)
|
LocalFunction(symbol)
|
||||||
|
|
|
@ -620,7 +620,7 @@ impl<'a, T> Collection<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_items(items: &'a [T]) -> Collection<'a, T> {
|
pub const fn with_items(items: &'a [T]) -> Collection<'a, T> {
|
||||||
Collection {
|
Collection {
|
||||||
items,
|
items,
|
||||||
final_comments: None,
|
final_comments: None,
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::string_literal;
|
use crate::string_literal;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -17,6 +18,10 @@ pub enum HeaderFor<'a> {
|
||||||
generates: UppercaseIdent<'a>,
|
generates: UppercaseIdent<'a>,
|
||||||
generates_with: &'a [Loc<ExposedName<'a>>],
|
generates_with: &'a [Loc<ExposedName<'a>>],
|
||||||
},
|
},
|
||||||
|
/// Only created during canonicalization, never actually parsed from source
|
||||||
|
Builtin {
|
||||||
|
generates_with: &'a [Symbol],
|
||||||
|
},
|
||||||
PkgConfig {
|
PkgConfig {
|
||||||
/// usually `pf`
|
/// usually `pf`
|
||||||
config_shorthand: &'a str,
|
config_shorthand: &'a str,
|
||||||
|
@ -60,11 +65,11 @@ impl<'a> From<ModuleName<'a>> for &'a str {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModuleName<'a> {
|
impl<'a> ModuleName<'a> {
|
||||||
pub fn new(name: &'a str) -> Self {
|
pub const fn new(name: &'a str) -> Self {
|
||||||
ModuleName(name)
|
ModuleName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_str(&'a self) -> &'a str {
|
pub const fn as_str(&'a self) -> &'a str {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,8 +126,15 @@ mod solve_expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
let mut buffer =
|
let mut buffer = String::from(indoc!(
|
||||||
String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
r#"
|
||||||
|
app "test"
|
||||||
|
imports [ Result.{ Result } ]
|
||||||
|
provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
// indent the body!
|
// indent the body!
|
||||||
|
@ -3503,7 +3510,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app "test" provides [ main ] to "./platform"
|
app "test" imports [ Result.{ Result } ] provides [ main ] to "./platform"
|
||||||
|
|
||||||
boom = \_ -> boom {}
|
boom = \_ -> boom {}
|
||||||
|
|
||||||
|
@ -4728,7 +4735,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
canIGo : _ -> Result _ _
|
canIGo : _ -> Result.Result _ _
|
||||||
canIGo = \color ->
|
canIGo = \color ->
|
||||||
when color is
|
when color is
|
||||||
"green" -> Ok "go!"
|
"green" -> Ok "go!"
|
||||||
|
|
|
@ -5,13 +5,4 @@ app "effect-example"
|
||||||
|
|
||||||
main : Effect.Effect {}
|
main : Effect.Effect {}
|
||||||
main =
|
main =
|
||||||
Effect.after
|
(Effect.putLine (Str.concat "It is known" "foo"))
|
||||||
(Effect.getLine)
|
|
||||||
\line ->
|
|
||||||
Effect.after
|
|
||||||
(Effect.putLine "You entered: \(line)")
|
|
||||||
\{ } ->
|
|
||||||
Effect.after
|
|
||||||
(Effect.putLine "It is known")
|
|
||||||
\{ } ->
|
|
||||||
Effect.always {}
|
|
||||||
|
|
|
@ -509,9 +509,12 @@ impl<'a> RocDocAllocator<'a> {
|
||||||
// debug_assert!(region.contains(&sub_region));
|
// debug_assert!(region.contains(&sub_region));
|
||||||
|
|
||||||
// If the outer region takes more than 1 full screen (~60 lines), only show the inner region
|
// If the outer region takes more than 1 full screen (~60 lines), only show the inner region
|
||||||
if region.end().line - region.start().line > 60 {
|
match region.end().line.checked_sub(region.start().line) {
|
||||||
|
Some(v) if v > 60 => {
|
||||||
return self.region_with_subregion(sub_region, sub_region);
|
return self.region_with_subregion(sub_region, sub_region);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
// if true, the final line of the snippet will be some ^^^ that point to the region where
|
// if true, the final line of the snippet will be some ^^^ that point to the region where
|
||||||
// the problem is. Otherwise, the snippet will have a > on the lines that are in the region
|
// the problem is. Otherwise, the snippet will have a > on the lines that are in the region
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue