mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
Merge branch 'main' into repl-no-color-no-header-flags
This commit is contained in:
commit
aadc74a37b
186 changed files with 5322 additions and 3927 deletions
265
crates/compiler/builtins/roc/Task.roc
Normal file
265
crates/compiler/builtins/roc/Task.roc
Normal file
|
@ -0,0 +1,265 @@
|
|||
module [
|
||||
Task,
|
||||
ok,
|
||||
err,
|
||||
await,
|
||||
map,
|
||||
mapErr,
|
||||
onErr,
|
||||
attempt,
|
||||
forever,
|
||||
loop,
|
||||
fromResult,
|
||||
batch,
|
||||
sequence,
|
||||
forEach,
|
||||
result,
|
||||
]
|
||||
|
||||
import List
|
||||
import Result exposing [Result]
|
||||
|
||||
## A Task represents an effect; an interaction with state outside your Roc
|
||||
## program, such as the terminal's standard output, or a file.
|
||||
Task ok err := {} -> Result ok err
|
||||
|
||||
## Run a task repeatedly, until it fails with `err`. Note that this task does not return a success value.
|
||||
forever : Task a err -> Task * err
|
||||
forever = \@Task task ->
|
||||
looper = \{} ->
|
||||
when task {} is
|
||||
Err e -> Err e
|
||||
Ok _ -> looper {}
|
||||
|
||||
@Task \{} -> looper {}
|
||||
|
||||
## Run a task repeatedly, until it fails with `err` or completes with `done`.
|
||||
##
|
||||
## ```
|
||||
## sum =
|
||||
## Task.loop! 0 \total ->
|
||||
## numResult =
|
||||
## Stdin.line
|
||||
## |> Task.result!
|
||||
## |> Result.try Str.toU64
|
||||
##
|
||||
## when numResult is
|
||||
## Ok num -> Task.ok (Step (total + num))
|
||||
## Err (StdinErr EndOfFile) -> Task.ok (Done total)
|
||||
## Err InvalidNumStr -> Task.err NonNumberGiven
|
||||
## ```
|
||||
loop : state, (state -> Task [Step state, Done done] err) -> Task done err
|
||||
loop = \state, step ->
|
||||
looper = \current ->
|
||||
(@Task next) = step current
|
||||
when next {} is
|
||||
Err e -> Err e
|
||||
Ok (Done newResult) -> Ok newResult
|
||||
Ok (Step newState) -> looper (newState)
|
||||
|
||||
@Task \{} -> looper state
|
||||
|
||||
## Create a task that always succeeds with the value provided.
|
||||
##
|
||||
## ```
|
||||
## # Always succeeds with "Louis"
|
||||
## getName : Task.Task Str *
|
||||
## getName = Task.ok "Louis"
|
||||
## ```
|
||||
##
|
||||
ok : a -> Task a *
|
||||
ok = \a -> @Task \{} -> Ok a
|
||||
|
||||
## Create a task that always fails with the error provided.
|
||||
##
|
||||
## ```
|
||||
## # Always fails with the tag `CustomError Str`
|
||||
## customError : Str -> Task.Task {} [CustomError Str]
|
||||
## customError = \err -> Task.err (CustomError err)
|
||||
## ```
|
||||
##
|
||||
err : a -> Task * a
|
||||
err = \a -> @Task \{} -> Err a
|
||||
|
||||
## Transform a given Task with a function that handles the success or error case
|
||||
## and returns another task based on that. This is useful for chaining tasks
|
||||
## together or performing error handling and recovery.
|
||||
##
|
||||
## Consider the following task:
|
||||
##
|
||||
## `canFail : Task {} [Failure, AnotherFail, YetAnotherFail]`
|
||||
##
|
||||
## We can use [attempt] to handle the failure cases using the following:
|
||||
##
|
||||
## ```
|
||||
## Task.attempt canFail \result ->
|
||||
## when result is
|
||||
## Ok Success -> Stdout.line "Success!"
|
||||
## Err Failure -> Stdout.line "Oops, failed!"
|
||||
## Err AnotherFail -> Stdout.line "Ooooops, another failure!"
|
||||
## Err YetAnotherFail -> Stdout.line "Really big oooooops, yet again!"
|
||||
## ```
|
||||
##
|
||||
## Here we know that the `canFail` task may fail, and so we use
|
||||
## `Task.attempt` to convert the task to a `Result` and then use pattern
|
||||
## matching to handle the success and possible failure cases.
|
||||
attempt : Task a b, (Result a b -> Task c d) -> Task c d
|
||||
attempt = \@Task task, transform ->
|
||||
@Task \{} ->
|
||||
(@Task transformed) = transform (task {})
|
||||
|
||||
transformed {}
|
||||
|
||||
## Take the success value from a given [Task] and use that to generate a new [Task].
|
||||
##
|
||||
## We can [await] Task results with callbacks:
|
||||
##
|
||||
## ```
|
||||
## Task.await (Stdin.line "What's your name?") \name ->
|
||||
## Stdout.line "Your name is: $(name)"
|
||||
## ```
|
||||
##
|
||||
## Or we can more succinctly use the `!` bang operator, which desugars to [await]:
|
||||
##
|
||||
## ```
|
||||
## name = Stdin.line! "What's your name?"
|
||||
## Stdout.line "Your name is: $(name)"
|
||||
## ```
|
||||
await : Task a b, (a -> Task c b) -> Task c b
|
||||
await = \@Task task, transform ->
|
||||
@Task \{} ->
|
||||
when task {} is
|
||||
Ok a ->
|
||||
(@Task transformed) = transform a
|
||||
transformed {}
|
||||
|
||||
Err b ->
|
||||
Err b
|
||||
|
||||
## Take the error value from a given [Task] and use that to generate a new [Task].
|
||||
##
|
||||
## ```
|
||||
## # Prints "Something went wrong!" to standard error if `canFail` fails.
|
||||
## canFail
|
||||
## |> Task.onErr \_ -> Stderr.line "Something went wrong!"
|
||||
## ```
|
||||
onErr : Task a b, (b -> Task a c) -> Task a c
|
||||
onErr = \@Task task, transform ->
|
||||
@Task \{} ->
|
||||
when task {} is
|
||||
Ok a ->
|
||||
Ok a
|
||||
|
||||
Err b ->
|
||||
(@Task transformed) = transform b
|
||||
transformed {}
|
||||
|
||||
## Transform the success value of a given [Task] with a given function.
|
||||
##
|
||||
## ```
|
||||
## # Succeeds with a value of "Bonjour Louis!"
|
||||
## Task.ok "Louis"
|
||||
## |> Task.map (\name -> "Bonjour $(name)!")
|
||||
## ```
|
||||
map : Task a c, (a -> b) -> Task b c
|
||||
map = \@Task task, transform ->
|
||||
@Task \{} ->
|
||||
when task {} is
|
||||
Ok a -> Ok (transform a)
|
||||
Err b -> Err b
|
||||
|
||||
## Transform the error value of a given [Task] with a given function.
|
||||
##
|
||||
## ```
|
||||
## # Ignore the fail value, and map it to the tag `CustomError`
|
||||
## canFail
|
||||
## |> Task.mapErr \_ -> CustomError
|
||||
## ```
|
||||
mapErr : Task c a, (a -> b) -> Task c b
|
||||
mapErr = \@Task task, transform ->
|
||||
@Task \{} ->
|
||||
when task {} is
|
||||
Ok a -> Ok a
|
||||
Err b -> Err (transform b)
|
||||
|
||||
## Use a Result among other Tasks by converting it into a [Task].
|
||||
fromResult : Result a b -> Task a b
|
||||
fromResult = \res ->
|
||||
@Task \{} -> res
|
||||
|
||||
## Apply a task to another task applicatively. This can be used with
|
||||
## [ok] to build a [Task] that returns a record.
|
||||
##
|
||||
## The following example returns a Record with two fields, `apples` and
|
||||
## `oranges`, each of which is a `List Str`. If it fails it returns the tag
|
||||
## `NoFruitAvailable`.
|
||||
##
|
||||
## ```
|
||||
## getFruitBasket : Task { apples : List Str, oranges : List Str } [NoFruitAvailable]
|
||||
## getFruitBasket = Task.ok {
|
||||
## apples: <- getFruit Apples |> Task.batch,
|
||||
## oranges: <- getFruit Oranges |> Task.batch,
|
||||
## }
|
||||
## ```
|
||||
batch : Task a c -> (Task (a -> b) c -> Task b c)
|
||||
batch = \current ->
|
||||
\next ->
|
||||
await next \f ->
|
||||
map current f
|
||||
|
||||
## Apply each task in a list sequentially, and return a list of the resulting values.
|
||||
## Each task will be awaited before beginning the next task.
|
||||
##
|
||||
## ```
|
||||
## fetchAuthorTasks : List (Task Author [DbError])
|
||||
##
|
||||
## getAuthors : Task (List Author) [DbError]
|
||||
## getAuthors = Task.sequence fetchAuthorTasks
|
||||
## ```
|
||||
##
|
||||
sequence : List (Task ok err) -> Task (List ok) err
|
||||
sequence = \taskList ->
|
||||
Task.loop (taskList, List.withCapacity (List.len taskList)) \(tasks, values) ->
|
||||
when tasks is
|
||||
[task, .. as rest] ->
|
||||
value = task!
|
||||
Task.ok (Step (rest, List.append values value))
|
||||
|
||||
[] ->
|
||||
Task.ok (Done values)
|
||||
|
||||
## Apply a task repeatedly for each item in a list
|
||||
##
|
||||
## ```
|
||||
## authors : List Author
|
||||
## saveAuthor : Author -> Task {} [DbError]
|
||||
##
|
||||
## saveAuthors : Task (List Author) [DbError]
|
||||
## saveAuthors = Task.forEach authors saveAuthor
|
||||
## ```
|
||||
##
|
||||
forEach : List a, (a -> Task {} b) -> Task {} b
|
||||
forEach = \items, fn ->
|
||||
List.walk items (ok {}) \state, item ->
|
||||
state |> await \_ -> fn item
|
||||
|
||||
## Transform a task that can either succeed with `ok`, or fail with `err`, into
|
||||
## a task that succeeds with `Result ok err`.
|
||||
##
|
||||
## This is useful when chaining tasks using the `!` suffix. For example:
|
||||
##
|
||||
## ```
|
||||
## # Path.roc
|
||||
## checkFile : Str -> Task [Good, Bad] [IOError]
|
||||
##
|
||||
## # main.roc
|
||||
## when checkFile "/usr/local/bin/roc" |> Task.result! is
|
||||
## Ok Good -> "..."
|
||||
## Ok Bad -> "..."
|
||||
## Err IOError -> "..."
|
||||
## ```
|
||||
##
|
||||
result : Task ok err -> Task (Result ok err) *
|
||||
result = \@Task task ->
|
||||
@Task \{} ->
|
||||
Ok (task {})
|
|
@ -11,4 +11,5 @@ package [
|
|||
Hash,
|
||||
Box,
|
||||
Inspect,
|
||||
Task,
|
||||
] {}
|
||||
|
|
|
@ -16,6 +16,7 @@ pub fn module_source(module_id: ModuleId) -> &'static str {
|
|||
ModuleId::DECODE => DECODE,
|
||||
ModuleId::HASH => HASH,
|
||||
ModuleId::INSPECT => INSPECT,
|
||||
ModuleId::TASK => TASK,
|
||||
_ => internal_error!(
|
||||
"ModuleId {:?} is not part of the standard library",
|
||||
module_id
|
||||
|
@ -35,3 +36,4 @@ const ENCODE: &str = include_str!("../roc/Encode.roc");
|
|||
const DECODE: &str = include_str!("../roc/Decode.roc");
|
||||
const HASH: &str = include_str!("../roc/Hash.roc");
|
||||
const INSPECT: &str = include_str!("../roc/Inspect.roc");
|
||||
const TASK: &str = include_str!("../roc/Task.roc");
|
||||
|
|
|
@ -290,12 +290,14 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
Var(sym, var) => Var(*sym, sub!(*var)),
|
||||
ParamsVar {
|
||||
symbol,
|
||||
params,
|
||||
var,
|
||||
params_symbol,
|
||||
params_var,
|
||||
} => ParamsVar {
|
||||
symbol: *symbol,
|
||||
params: *params,
|
||||
var: sub!(*var),
|
||||
params_symbol: *params_symbol,
|
||||
params_var: sub!(*params_var),
|
||||
},
|
||||
ImportParams(module_id, region, opt_provided) => ImportParams(
|
||||
*module_id,
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::pattern::{canonicalize_def_header_pattern, BindingsFromPattern, Patte
|
|||
use crate::procedure::QualifiedReference;
|
||||
use crate::procedure::References;
|
||||
use crate::scope::create_alias;
|
||||
use crate::scope::SymbolLookup;
|
||||
use crate::scope::{PendingAbilitiesInScope, Scope};
|
||||
use roc_collections::ReferenceMatrix;
|
||||
use roc_collections::VecMap;
|
||||
|
@ -111,6 +112,23 @@ impl Annotation {
|
|||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn convert_to_fn(&mut self, argument_count: usize, var_store: &mut VarStore) {
|
||||
let mut arg_types = Vec::with_capacity(argument_count);
|
||||
|
||||
for _ in 0..argument_count {
|
||||
let var = var_store.fresh();
|
||||
self.introduced_variables.insert_inferred(Loc::at_zero(var));
|
||||
|
||||
arg_types.push(Type::Variable(var));
|
||||
}
|
||||
|
||||
self.signature = Type::Function(
|
||||
arg_types,
|
||||
Box::new(Type::Variable(var_store.fresh())),
|
||||
Box::new(self.signature.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -165,6 +183,7 @@ enum PendingValueDef<'a> {
|
|||
/// Module params from an import
|
||||
ImportParams {
|
||||
symbol: Symbol,
|
||||
variable: Variable,
|
||||
loc_pattern: Loc<Pattern>,
|
||||
module_id: ModuleId,
|
||||
opt_provided: Option<ast::Collection<'a, Loc<AssignedField<'a, ast::Expr<'a>>>>>,
|
||||
|
@ -186,6 +205,7 @@ impl PendingValueDef<'_> {
|
|||
PendingValueDef::ImportParams {
|
||||
loc_pattern,
|
||||
symbol: _,
|
||||
variable: _,
|
||||
module_id: _,
|
||||
opt_provided: _,
|
||||
} => loc_pattern,
|
||||
|
@ -1153,6 +1173,7 @@ fn canonicalize_value_defs<'a>(
|
|||
|
||||
pending_value_defs.push(PendingValueDef::ImportParams {
|
||||
symbol: params.symbol,
|
||||
variable: params.variable,
|
||||
loc_pattern: params.loc_pattern,
|
||||
opt_provided: params.opt_provided,
|
||||
module_id,
|
||||
|
@ -2400,15 +2421,17 @@ fn canonicalize_pending_value_def<'a>(
|
|||
}
|
||||
ImportParams {
|
||||
symbol,
|
||||
variable,
|
||||
loc_pattern,
|
||||
module_id,
|
||||
opt_provided,
|
||||
} => {
|
||||
// Insert a reference to the record so that we don't report it as unused
|
||||
// If the whole module is unused, we'll report that separately
|
||||
output
|
||||
.references
|
||||
.insert_value_lookup(symbol, QualifiedReference::Unqualified);
|
||||
output.references.insert_value_lookup(
|
||||
SymbolLookup::no_params(symbol),
|
||||
QualifiedReference::Unqualified,
|
||||
);
|
||||
|
||||
let (opt_var_record, references) = match opt_provided {
|
||||
Some(params) => {
|
||||
|
@ -2418,7 +2441,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
let references = can_output.references.clone();
|
||||
output.union(can_output);
|
||||
|
||||
(Some((var_store.fresh(), Box::new(record))), references)
|
||||
(Some((variable, Box::new(record))), references)
|
||||
}
|
||||
None => (None, References::new()),
|
||||
};
|
||||
|
@ -2725,12 +2748,11 @@ pub fn report_unused_imports(
|
|||
for (symbol, region) in &import.exposed_symbols {
|
||||
if !references.has_unqualified_type_or_value_lookup(*symbol)
|
||||
&& !scope.abilities_store.is_specialization_name(*symbol)
|
||||
&& !import.is_task(env)
|
||||
{
|
||||
env.problem(Problem::UnusedImport(*symbol, *region));
|
||||
}
|
||||
}
|
||||
} else if !import.is_task(env) {
|
||||
} else {
|
||||
env.problem(Problem::UnusedModuleImport(import.module_id, import.region));
|
||||
}
|
||||
}
|
||||
|
@ -3003,6 +3025,7 @@ struct PendingModuleImport<'a> {
|
|||
|
||||
struct PendingModuleImportParams<'a> {
|
||||
symbol: Symbol,
|
||||
variable: Variable,
|
||||
loc_pattern: Loc<Pattern>,
|
||||
opt_provided: Option<ast::Collection<'a, Loc<AssignedField<'a, ast::Expr<'a>>>>>,
|
||||
}
|
||||
|
@ -3013,16 +3036,6 @@ pub struct IntroducedImport {
|
|||
exposed_symbols: Vec<(Symbol, Region)>,
|
||||
}
|
||||
|
||||
impl IntroducedImport {
|
||||
pub fn is_task(&self, env: &Env<'_>) -> bool {
|
||||
// Temporarily needed for `!` convenience. Can be removed when Task becomes a builtin.
|
||||
match env.qualified_module_ids.get_name(self.module_id) {
|
||||
Some(name) => name.as_inner().as_str() == "Task",
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn to_pending_value_def<'a>(
|
||||
env: &mut Env<'a>,
|
||||
|
@ -3160,15 +3173,17 @@ fn to_pending_value_def<'a>(
|
|||
// We do this even if params weren't provided so that solve can report if they are missing
|
||||
let params_sym = scope.gen_unique_symbol();
|
||||
let params_region = module_import.params.map(|p| p.params.region).unwrap_or(region);
|
||||
let params_var = var_store.fresh();
|
||||
let params =
|
||||
PendingModuleImportParams {
|
||||
symbol: params_sym,
|
||||
variable: params_var,
|
||||
loc_pattern: Loc::at(params_region, Pattern::Identifier(params_sym)),
|
||||
opt_provided: module_import.params.map(|p| p.params.value),
|
||||
};
|
||||
let provided_params_sym = if module_import.params.is_some() {
|
||||
let provided_params = if module_import.params.is_some() {
|
||||
// Only add params to scope if they are provided
|
||||
Some(params_sym)
|
||||
Some((params_var, params_sym))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -3176,7 +3191,7 @@ fn to_pending_value_def<'a>(
|
|||
if let Err(existing_import) =
|
||||
scope
|
||||
.modules
|
||||
.insert(name_with_alias.clone(), module_id, provided_params_sym, region)
|
||||
.insert(name_with_alias.clone(), module_id, provided_params, region)
|
||||
{
|
||||
env.problems.push(Problem::ImportNameConflict {
|
||||
name: name_with_alias,
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,8 @@ use roc_collections::{MutMap, VecSet};
|
|||
use roc_module::ident::{Ident, ModuleName};
|
||||
use roc_module::symbol::{IdentIdsByModule, ModuleId, PQModuleName, PackageModuleIds, Symbol};
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_region::all::{LineInfo, Loc, Region};
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
/// The canonicalization environment for a particular module.
|
||||
pub struct Env<'a> {
|
||||
|
@ -38,14 +39,24 @@ pub struct Env<'a> {
|
|||
|
||||
pub top_level_symbols: VecSet<Symbol>,
|
||||
|
||||
pub home_params_record: Option<(Symbol, Variable)>,
|
||||
|
||||
pub arena: &'a Bump,
|
||||
|
||||
pub opt_shorthand: Option<&'a str>,
|
||||
|
||||
pub src: &'a str,
|
||||
|
||||
/// Lazily calculated line info. This data is only needed if the code contains calls to `dbg`,
|
||||
/// otherwise we can leave it as `None` and never pay the cost of scanning the source an extra
|
||||
/// time.
|
||||
line_info: &'a mut Option<LineInfo>,
|
||||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
src: &'a str,
|
||||
home: ModuleId,
|
||||
module_path: &'a Path,
|
||||
dep_idents: &'a IdentIdsByModule,
|
||||
|
@ -54,6 +65,7 @@ impl<'a> Env<'a> {
|
|||
) -> Env<'a> {
|
||||
Env {
|
||||
arena,
|
||||
src,
|
||||
home,
|
||||
module_path,
|
||||
dep_idents,
|
||||
|
@ -64,7 +76,9 @@ impl<'a> Env<'a> {
|
|||
qualified_type_lookups: VecSet::default(),
|
||||
tailcallable_symbol: None,
|
||||
top_level_symbols: VecSet::default(),
|
||||
home_params_record: None,
|
||||
opt_shorthand,
|
||||
line_info: arena.alloc(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,4 +229,11 @@ impl<'a> Env<'a> {
|
|||
pub fn problem(&mut self, problem: Problem) {
|
||||
self.problems.push(problem)
|
||||
}
|
||||
|
||||
pub fn line_info(&mut self) -> &LineInfo {
|
||||
if self.line_info.is_none() {
|
||||
*self.line_info = Some(LineInfo::new(self.src));
|
||||
}
|
||||
self.line_info.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::called_via::CalledVia;
|
||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_module::symbol::{IdentId, ModuleId, Symbol};
|
||||
use roc_parse::ast::{self, Defs, PrecedenceConflict, StrLiteral};
|
||||
use roc_parse::ident::Accessor;
|
||||
use roc_parse::pattern::PatternType::*;
|
||||
|
@ -111,8 +111,9 @@ pub enum Expr {
|
|||
/// Like Var, but from a module with params
|
||||
ParamsVar {
|
||||
symbol: Symbol,
|
||||
params: Symbol,
|
||||
var: Variable,
|
||||
params_symbol: Symbol,
|
||||
params_var: Variable,
|
||||
},
|
||||
AbilityMember(
|
||||
/// Actual member name
|
||||
|
@ -320,8 +321,9 @@ impl Expr {
|
|||
&Self::Var(sym, _) => Category::Lookup(sym),
|
||||
&Self::ParamsVar {
|
||||
symbol,
|
||||
params: _,
|
||||
var: _,
|
||||
params_symbol: _,
|
||||
params_var: _,
|
||||
} => Category::Lookup(symbol),
|
||||
&Self::AbilityMember(sym, _, _) => Category::Lookup(sym),
|
||||
Self::When { .. } => Category::When,
|
||||
|
@ -1207,8 +1209,20 @@ pub fn canonicalize_expr<'a>(
|
|||
output,
|
||||
)
|
||||
}
|
||||
ast::Expr::Dbg(_, _) => {
|
||||
internal_error!("Dbg should have been desugared by now")
|
||||
ast::Expr::Dbg => {
|
||||
// Dbg was not desugared as either part of an `Apply` or a `Pizza` binop, so it's
|
||||
// invalid.
|
||||
env.problem(Problem::UnappliedDbg { region });
|
||||
|
||||
let invalid_dbg_expr = crate::desugar::desugar_invalid_dbg_expr(env, scope, region);
|
||||
|
||||
let (loc_expr, output) =
|
||||
canonicalize_expr(env, var_store, scope, region, invalid_dbg_expr);
|
||||
|
||||
(loc_expr.value, output)
|
||||
}
|
||||
ast::Expr::DbgStmt(_, _) => {
|
||||
internal_error!("DbgStmt should have been desugared by now")
|
||||
}
|
||||
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
|
||||
let mut output = Output::default();
|
||||
|
@ -1554,6 +1568,8 @@ fn canonicalize_closure_body<'a>(
|
|||
&loc_body_expr.value,
|
||||
);
|
||||
|
||||
let mut references_top_level = false;
|
||||
|
||||
let mut captured_symbols: Vec<_> = new_output
|
||||
.references
|
||||
.value_lookups()
|
||||
|
@ -1564,7 +1580,11 @@ fn canonicalize_closure_body<'a>(
|
|||
.filter(|s| !new_output.references.bound_symbols().any(|x| x == s))
|
||||
.filter(|s| bound_by_argument_patterns.iter().all(|(k, _)| s != k))
|
||||
// filter out top-level symbols those will be globally available, and don't need to be captured
|
||||
.filter(|s| !env.top_level_symbols.contains(s))
|
||||
.filter(|s| {
|
||||
let is_top_level = env.top_level_symbols.contains(s);
|
||||
references_top_level = references_top_level || is_top_level;
|
||||
!is_top_level
|
||||
})
|
||||
// filter out imported symbols those will be globally available, and don't need to be captured
|
||||
.filter(|s| s.module_id() == env.home)
|
||||
// filter out functions that don't close over anything
|
||||
|
@ -1573,6 +1593,15 @@ fn canonicalize_closure_body<'a>(
|
|||
.map(|s| (s, var_store.fresh()))
|
||||
.collect();
|
||||
|
||||
if references_top_level {
|
||||
if let Some(params_record) = env.home_params_record {
|
||||
// If this module has params and the closure references top-level symbols,
|
||||
// we need to capture the whole record so we can pass it.
|
||||
// The lower_params pass will take care of removing the captures for top-level fns.
|
||||
captured_symbols.push(params_record);
|
||||
}
|
||||
}
|
||||
|
||||
output.union(new_output);
|
||||
|
||||
// Now that we've collected all the references, check to see if any of the args we defined
|
||||
|
@ -1918,7 +1947,7 @@ fn canonicalize_var_lookup(
|
|||
Ok(lookup) => {
|
||||
output
|
||||
.references
|
||||
.insert_value_lookup(lookup.symbol, QualifiedReference::Unqualified);
|
||||
.insert_value_lookup(lookup, QualifiedReference::Unqualified);
|
||||
|
||||
if scope.abilities_store.is_ability_member_name(lookup.symbol) {
|
||||
AbilityMember(
|
||||
|
@ -1927,7 +1956,7 @@ fn canonicalize_var_lookup(
|
|||
var_store.fresh(),
|
||||
)
|
||||
} else {
|
||||
lookup_to_expr(lookup, var_store.fresh())
|
||||
lookup_to_expr(var_store, lookup)
|
||||
}
|
||||
}
|
||||
Err(problem) => {
|
||||
|
@ -1943,7 +1972,7 @@ fn canonicalize_var_lookup(
|
|||
Ok(lookup) => {
|
||||
output
|
||||
.references
|
||||
.insert_value_lookup(lookup.symbol, QualifiedReference::Qualified);
|
||||
.insert_value_lookup(lookup, QualifiedReference::Qualified);
|
||||
|
||||
if scope.abilities_store.is_ability_member_name(lookup.symbol) {
|
||||
AbilityMember(
|
||||
|
@ -1952,7 +1981,7 @@ fn canonicalize_var_lookup(
|
|||
var_store.fresh(),
|
||||
)
|
||||
} else {
|
||||
lookup_to_expr(lookup, var_store.fresh())
|
||||
lookup_to_expr(var_store, lookup)
|
||||
}
|
||||
}
|
||||
Err(problem) => {
|
||||
|
@ -1971,20 +2000,21 @@ fn canonicalize_var_lookup(
|
|||
}
|
||||
|
||||
fn lookup_to_expr(
|
||||
var_store: &mut VarStore,
|
||||
SymbolLookup {
|
||||
symbol,
|
||||
module_params: params,
|
||||
module_params,
|
||||
}: SymbolLookup,
|
||||
var: Variable,
|
||||
) -> Expr {
|
||||
if let Some(params) = params {
|
||||
if let Some((params_var, params_symbol)) = module_params {
|
||||
Expr::ParamsVar {
|
||||
symbol,
|
||||
params,
|
||||
var,
|
||||
var: var_store.fresh(),
|
||||
params_symbol,
|
||||
params_var,
|
||||
}
|
||||
} else {
|
||||
Expr::Var(symbol, var)
|
||||
Expr::Var(symbol, var_store.fresh())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2470,21 +2500,28 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::Expr::AccessorFunction(_)
|
||||
| ast::Expr::RecordUpdater(_)
|
||||
| ast::Expr::Crash
|
||||
| ast::Expr::Dbg
|
||||
| ast::Expr::Underscore(_)
|
||||
| ast::Expr::MalformedIdent(_, _)
|
||||
| ast::Expr::Tag(_)
|
||||
| ast::Expr::OpaqueRef(_)
|
||||
| ast::Expr::MalformedClosure => true,
|
||||
// Newlines are disallowed inside interpolation, and these all require newlines
|
||||
ast::Expr::Dbg(_, _)
|
||||
ast::Expr::DbgStmt(_, _)
|
||||
| ast::Expr::LowLevelDbg(_, _, _)
|
||||
| ast::Expr::Defs(_, _)
|
||||
| ast::Expr::Expect(_, _)
|
||||
| ast::Expr::When(_, _)
|
||||
| ast::Expr::Backpassing(_, _, _)
|
||||
| ast::Expr::SpaceBefore(_, _)
|
||||
| ast::Expr::Str(StrLiteral::Block(_))
|
||||
| ast::Expr::SpaceAfter(_, _) => false,
|
||||
// Desugared dbg expression
|
||||
ast::Expr::Defs(_, loc_ret) => match loc_ret.value {
|
||||
ast::Expr::LowLevelDbg(_, _, continuation) => {
|
||||
is_valid_interpolation(&continuation.value)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
// These can contain subexpressions, so we need to recursively check those
|
||||
ast::Expr::Str(StrLiteral::Line(segments)) => {
|
||||
segments.iter().all(|segment| match segment {
|
||||
|
@ -2774,6 +2811,9 @@ pub struct Declarations {
|
|||
// used for ability member specializatons.
|
||||
pub specializes: VecMap<usize, Symbol>,
|
||||
|
||||
// used while lowering params.
|
||||
arity_by_name: VecMap<IdentId, usize>,
|
||||
|
||||
pub host_exposed_annotations: VecMap<usize, (Variable, crate::def::Annotation)>,
|
||||
|
||||
pub function_bodies: Vec<Loc<FunctionDef>>,
|
||||
|
@ -2802,6 +2842,7 @@ impl Declarations {
|
|||
expressions: Vec::with_capacity(capacity),
|
||||
specializes: VecMap::default(), // number of specializations is probably low
|
||||
destructs: Vec::new(), // number of destructs is probably low
|
||||
arity_by_name: VecMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2840,6 +2881,9 @@ impl Declarations {
|
|||
arguments: loc_closure_data.value.arguments,
|
||||
};
|
||||
|
||||
self.arity_by_name
|
||||
.insert(symbol.value.ident_id(), function_def.arguments.len());
|
||||
|
||||
let loc_function_def = Loc::at(loc_closure_data.region, function_def);
|
||||
|
||||
let function_def_index = Index::push_new(&mut self.function_bodies, loc_function_def);
|
||||
|
@ -2888,6 +2932,9 @@ impl Declarations {
|
|||
arguments: loc_closure_data.value.arguments,
|
||||
};
|
||||
|
||||
self.arity_by_name
|
||||
.insert(symbol.value.ident_id(), function_def.arguments.len());
|
||||
|
||||
let loc_function_def = Loc::at(loc_closure_data.region, function_def);
|
||||
|
||||
let function_def_index = Index::push_new(&mut self.function_bodies, loc_function_def);
|
||||
|
@ -2964,6 +3011,8 @@ impl Declarations {
|
|||
.insert(self.declarations.len(), annotation);
|
||||
}
|
||||
|
||||
self.arity_by_name.insert(symbol.value.ident_id(), 0);
|
||||
|
||||
self.declarations.push(DeclarationTag::Value);
|
||||
self.variables.push(expr_var);
|
||||
self.symbols.push(symbol);
|
||||
|
@ -3080,6 +3129,60 @@ impl Declarations {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a value def to a function def with the given arguments
|
||||
/// Currently used in lower_params
|
||||
pub fn convert_value_to_function(
|
||||
&mut self,
|
||||
index: usize,
|
||||
new_arguments: Vec<(Variable, AnnotatedMark, Loc<Pattern>)>,
|
||||
var_store: &mut VarStore,
|
||||
) {
|
||||
match self.declarations[index] {
|
||||
DeclarationTag::Value => {
|
||||
let new_args_len = new_arguments.len();
|
||||
|
||||
let loc_body = self.expressions[index].clone();
|
||||
let region = loc_body.region;
|
||||
|
||||
let closure_data = ClosureData {
|
||||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
name: self.symbols[index].value,
|
||||
captured_symbols: vec![],
|
||||
recursive: Recursive::NotRecursive,
|
||||
arguments: new_arguments,
|
||||
loc_body: Box::new(loc_body),
|
||||
};
|
||||
|
||||
let loc_closure_data = Loc::at(region, closure_data);
|
||||
|
||||
let function_def = FunctionDef {
|
||||
closure_type: loc_closure_data.value.closure_type,
|
||||
return_type: loc_closure_data.value.return_type,
|
||||
captured_symbols: loc_closure_data.value.captured_symbols,
|
||||
arguments: loc_closure_data.value.arguments,
|
||||
};
|
||||
|
||||
let loc_function_def = Loc::at(region, function_def);
|
||||
|
||||
let function_def_index =
|
||||
Index::push_new(&mut self.function_bodies, loc_function_def);
|
||||
|
||||
if let Some(annotation) = &mut self.annotations[index] {
|
||||
annotation.convert_to_fn(new_args_len, var_store);
|
||||
}
|
||||
|
||||
if let Some((_var, annotation)) = self.host_exposed_annotations.get_mut(&index) {
|
||||
annotation.convert_to_fn(new_args_len, var_store);
|
||||
}
|
||||
|
||||
self.declarations[index] = DeclarationTag::Function(function_def_index);
|
||||
}
|
||||
_ => internal_error!("Expected value declaration"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.declarations.len()
|
||||
}
|
||||
|
@ -3149,6 +3252,11 @@ impl Declarations {
|
|||
|
||||
collector
|
||||
}
|
||||
|
||||
pub(crate) fn take_arity_by_name(&mut self) -> VecMap<IdentId, usize> {
|
||||
// `arity_by_name` is only needed for lowering module params
|
||||
std::mem::take(&mut self.arity_by_name)
|
||||
}
|
||||
}
|
||||
|
||||
roc_error_macros::assert_sizeof_default!(DeclarationTag, 8);
|
||||
|
@ -3205,8 +3313,9 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
|||
Expr::Var(symbol, var)
|
||||
| Expr::ParamsVar {
|
||||
symbol,
|
||||
params: _,
|
||||
var,
|
||||
params_symbol: _,
|
||||
params_var: _,
|
||||
}
|
||||
| Expr::RecordUpdate {
|
||||
symbol,
|
||||
|
|
|
@ -14,7 +14,6 @@ pub mod copy;
|
|||
pub mod def;
|
||||
mod derive;
|
||||
pub mod desugar;
|
||||
pub mod effect_module;
|
||||
pub mod env;
|
||||
pub mod exhaustive;
|
||||
pub mod expected;
|
||||
|
@ -26,6 +25,7 @@ pub mod procedure;
|
|||
pub mod scope;
|
||||
pub mod string;
|
||||
pub mod suffixed;
|
||||
pub mod task_module;
|
||||
pub mod traverse;
|
||||
|
||||
pub use derive::DERIVED_REGION;
|
||||
|
|
|
@ -3,13 +3,12 @@ use std::path::Path;
|
|||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
||||
use crate::effect_module::HostedGeneratedFunctions;
|
||||
use crate::env::Env;
|
||||
use crate::expr::{
|
||||
AnnotatedMark, ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
|
||||
ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
|
||||
};
|
||||
use crate::pattern::{
|
||||
canonicalize_record_destructure, BindingsFromPattern, Pattern, PermitShadows,
|
||||
canonicalize_record_destructs, BindingsFromPattern, Pattern, PermitShadows, RecordDestruct,
|
||||
};
|
||||
use crate::procedure::References;
|
||||
use crate::scope::Scope;
|
||||
|
@ -18,14 +17,14 @@ use roc_collections::{MutMap, SendMap, VecMap, VecSet};
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::Ident;
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::{IdentIds, IdentIdsByModule, ModuleId, PackageModuleIds, Symbol};
|
||||
use roc_module::symbol::{IdentId, IdentIds, IdentIdsByModule, ModuleId, PackageModuleIds, Symbol};
|
||||
use roc_parse::ast::{Defs, TypeAnnotation};
|
||||
use roc_parse::header::{HeaderType, ModuleParams};
|
||||
use roc_parse::header::HeaderType;
|
||||
use roc_parse::pattern::PatternType;
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{ExposedTypesStorageSubs, Subs, VarStore, Variable};
|
||||
use roc_types::types::{AbilitySet, Alias, AliasKind, AliasVar, Type};
|
||||
use roc_types::types::{AbilitySet, Alias, Type};
|
||||
|
||||
/// The types of all exposed values/functions of a collection of modules
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -138,7 +137,33 @@ pub struct Module {
|
|||
pub abilities_store: PendingAbilitiesStore,
|
||||
pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
|
||||
pub loc_dbgs: VecMap<Symbol, DbgLookup>,
|
||||
pub params_pattern: Option<(Variable, AnnotatedMark, Loc<Pattern>)>,
|
||||
pub module_params: Option<ModuleParams>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ModuleParams {
|
||||
pub region: Region,
|
||||
pub whole_symbol: Symbol,
|
||||
pub whole_var: Variable,
|
||||
pub record_var: Variable,
|
||||
pub record_ext_var: Variable,
|
||||
pub destructs: Vec<Loc<RecordDestruct>>,
|
||||
// used while lowering passed functions
|
||||
pub arity_by_name: VecMap<IdentId, usize>,
|
||||
}
|
||||
|
||||
impl ModuleParams {
|
||||
pub fn pattern(&self) -> Loc<Pattern> {
|
||||
let record_pattern = Pattern::RecordDestructure {
|
||||
whole_var: self.record_var,
|
||||
ext_var: self.record_ext_var,
|
||||
destructs: self.destructs.clone(),
|
||||
};
|
||||
let loc_record_pattern = Loc::at(self.region, record_pattern);
|
||||
|
||||
let as_pattern = Pattern::As(Box::new(loc_record_pattern), self.whole_symbol);
|
||||
Loc::at(self.region, as_pattern)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -152,7 +177,7 @@ pub struct RigidVariables {
|
|||
pub struct ModuleOutput {
|
||||
pub aliases: MutMap<Symbol, Alias>,
|
||||
pub rigid_variables: RigidVariables,
|
||||
pub params_pattern: Option<(Variable, AnnotatedMark, Loc<Pattern>)>,
|
||||
pub module_params: Option<ModuleParams>,
|
||||
pub declarations: Declarations,
|
||||
pub exposed_imports: MutMap<Symbol, Region>,
|
||||
pub exposed_symbols: VecSet<Symbol>,
|
||||
|
@ -165,99 +190,6 @@ pub struct ModuleOutput {
|
|||
pub loc_dbgs: VecMap<Symbol, DbgLookup>,
|
||||
}
|
||||
|
||||
fn validate_generate_with<'a>(
|
||||
generate_with: &'a [Loc<roc_parse::header::ExposedName<'a>>],
|
||||
) -> (HostedGeneratedFunctions, Vec<Loc<Ident>>) {
|
||||
let mut functions = HostedGeneratedFunctions::default();
|
||||
let mut unknown = Vec::new();
|
||||
|
||||
for generated in generate_with {
|
||||
match generated.value.as_str() {
|
||||
"after" => functions.after = true,
|
||||
"map" => functions.map = true,
|
||||
"always" => functions.always = true,
|
||||
"loop" => functions.loop_ = true,
|
||||
"forever" => functions.forever = true,
|
||||
other => {
|
||||
// we don't know how to generate this function
|
||||
let ident = Ident::from(other);
|
||||
unknown.push(Loc::at(generated.region, ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(functions, unknown)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum GeneratedInfo {
|
||||
Hosted {
|
||||
effect_symbol: Symbol,
|
||||
generated_functions: HostedGeneratedFunctions,
|
||||
},
|
||||
Builtin,
|
||||
NotSpecial,
|
||||
}
|
||||
|
||||
impl GeneratedInfo {
|
||||
fn from_header_type(
|
||||
env: &mut Env,
|
||||
scope: &mut Scope,
|
||||
var_store: &mut VarStore,
|
||||
header_type: &HeaderType,
|
||||
) -> Self {
|
||||
match header_type {
|
||||
HeaderType::Hosted {
|
||||
generates,
|
||||
generates_with,
|
||||
name: _,
|
||||
exposes: _,
|
||||
} => {
|
||||
let name: &str = generates.into();
|
||||
let (generated_functions, unknown_generated) =
|
||||
validate_generate_with(generates_with);
|
||||
|
||||
for unknown in unknown_generated {
|
||||
env.problem(Problem::UnknownGeneratesWith(unknown));
|
||||
}
|
||||
|
||||
let effect_symbol = scope.introduce(name.into(), Region::zero()).unwrap();
|
||||
|
||||
{
|
||||
let a_var = var_store.fresh();
|
||||
|
||||
let actual =
|
||||
crate::effect_module::build_effect_actual(Type::Variable(a_var), var_store);
|
||||
|
||||
scope.add_alias(
|
||||
effect_symbol,
|
||||
Region::zero(),
|
||||
vec![Loc::at_zero(AliasVar::unbound("a".into(), a_var))],
|
||||
vec![],
|
||||
actual,
|
||||
AliasKind::Opaque,
|
||||
);
|
||||
}
|
||||
|
||||
GeneratedInfo::Hosted {
|
||||
effect_symbol,
|
||||
generated_functions,
|
||||
}
|
||||
}
|
||||
HeaderType::Builtin {
|
||||
generates_with,
|
||||
name: _,
|
||||
exposes: _,
|
||||
opt_params: _,
|
||||
} => {
|
||||
debug_assert!(generates_with.is_empty());
|
||||
GeneratedInfo::Builtin
|
||||
}
|
||||
_ => GeneratedInfo::NotSpecial,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_no_implementation(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. }) => true,
|
||||
|
@ -308,6 +240,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
src,
|
||||
home,
|
||||
arena.alloc(Path::new(module_path)),
|
||||
dep_idents,
|
||||
|
@ -326,9 +259,6 @@ pub fn canonicalize_module_defs<'a>(
|
|||
);
|
||||
}
|
||||
|
||||
let generated_info =
|
||||
GeneratedInfo::from_header_type(&mut env, &mut scope, var_store, header_type);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
|
@ -337,19 +267,11 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
|
||||
crate::desugar::desugar_defs_node_values(
|
||||
arena,
|
||||
loc_defs,
|
||||
src,
|
||||
&mut None,
|
||||
module_path,
|
||||
true,
|
||||
&mut env.problems,
|
||||
);
|
||||
crate::desugar::desugar_defs_node_values(&mut env, &mut scope, loc_defs, true);
|
||||
|
||||
let mut rigid_variables = RigidVariables::default();
|
||||
|
||||
// Iniital scope values are treated like defs that appear before any others.
|
||||
// Initial scope values are treated like defs that appear before any others.
|
||||
// They include builtin types that are automatically imported, and for a platform
|
||||
// package, the required values from the app.
|
||||
//
|
||||
|
@ -398,13 +320,13 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
let mut output = Output::default();
|
||||
|
||||
let params_pattern = header_type.get_params().as_ref().map(
|
||||
|ModuleParams {
|
||||
let module_params = header_type.get_params().as_ref().map(
|
||||
|roc_parse::header::ModuleParams {
|
||||
pattern,
|
||||
before_arrow: _,
|
||||
after_arrow: _,
|
||||
}| {
|
||||
let can_pattern = canonicalize_record_destructure(
|
||||
let (destructs, _) = canonicalize_record_destructs(
|
||||
&mut env,
|
||||
var_store,
|
||||
&mut scope,
|
||||
|
@ -415,17 +337,22 @@ pub fn canonicalize_module_defs<'a>(
|
|||
PermitShadows(false),
|
||||
);
|
||||
|
||||
let loc_pattern = Loc::at(pattern.region, can_pattern);
|
||||
let whole_symbol = scope.gen_unique_symbol();
|
||||
env.top_level_symbols.insert(whole_symbol);
|
||||
|
||||
for (symbol, _) in BindingsFromPattern::new(&loc_pattern) {
|
||||
env.top_level_symbols.insert(symbol);
|
||||
let whole_var = var_store.fresh();
|
||||
|
||||
env.home_params_record = Some((whole_symbol, whole_var));
|
||||
|
||||
ModuleParams {
|
||||
region: pattern.region,
|
||||
whole_var,
|
||||
whole_symbol,
|
||||
record_var: var_store.fresh(),
|
||||
record_ext_var: var_store.fresh(),
|
||||
destructs,
|
||||
arity_by_name: Default::default(),
|
||||
}
|
||||
|
||||
(
|
||||
var_store.fresh(),
|
||||
AnnotatedMark::new(var_store),
|
||||
loc_pattern,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -503,6 +430,11 @@ pub fn canonicalize_module_defs<'a>(
|
|||
&exposed_symbols,
|
||||
);
|
||||
|
||||
let module_params = module_params.map(|params| ModuleParams {
|
||||
arity_by_name: declarations.take_arity_by_name(),
|
||||
..params
|
||||
});
|
||||
|
||||
debug_assert!(
|
||||
output.pending_derives.is_empty(),
|
||||
"I thought pending derives are only found during def introduction"
|
||||
|
@ -542,24 +474,6 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
report_unused_imports(imports_introduced, &output.references, &mut env, &mut scope);
|
||||
|
||||
if let GeneratedInfo::Hosted {
|
||||
effect_symbol,
|
||||
generated_functions,
|
||||
} = generated_info
|
||||
{
|
||||
let mut exposed_symbols = VecSet::default();
|
||||
|
||||
// NOTE this currently builds all functions, not just the ones that the user requested
|
||||
crate::effect_module::build_effect_builtins(
|
||||
&mut scope,
|
||||
effect_symbol,
|
||||
var_store,
|
||||
&mut exposed_symbols,
|
||||
&mut declarations,
|
||||
generated_functions,
|
||||
);
|
||||
}
|
||||
|
||||
for index in 0..declarations.len() {
|
||||
use crate::expr::DeclarationTag::*;
|
||||
|
||||
|
@ -580,8 +494,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// 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)
|
||||
if has_no_implementation(&declarations.expressions[index].value) {
|
||||
match generated_info {
|
||||
GeneratedInfo::Builtin => {
|
||||
match header_type {
|
||||
HeaderType::Builtin { .. } => {
|
||||
match crate::builtins::builtin_defs_map(*symbol, var_store) {
|
||||
None => {
|
||||
internal_error!("A builtin module contains a signature without implementation for {:?}", symbol)
|
||||
|
@ -591,7 +505,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
GeneratedInfo::Hosted { effect_symbol, .. } => {
|
||||
HeaderType::Hosted { .. } => {
|
||||
let ident_id = symbol.ident_id();
|
||||
let ident = scope
|
||||
.locals
|
||||
|
@ -609,13 +523,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
aliases: Default::default(),
|
||||
};
|
||||
|
||||
let hosted_def = crate::effect_module::build_host_exposed_def(
|
||||
&mut scope,
|
||||
*symbol,
|
||||
&ident,
|
||||
effect_symbol,
|
||||
var_store,
|
||||
annotation,
|
||||
let hosted_def = crate::task_module::build_host_exposed_def(
|
||||
&mut scope, *symbol, &ident, var_store, annotation,
|
||||
);
|
||||
|
||||
declarations.update_builtin_def(index, hosted_def);
|
||||
|
@ -638,8 +547,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// 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)
|
||||
if has_no_implementation(&declarations.expressions[index].value) {
|
||||
match generated_info {
|
||||
GeneratedInfo::Builtin => {
|
||||
match header_type {
|
||||
HeaderType::Builtin { .. } => {
|
||||
match crate::builtins::builtin_defs_map(*symbol, var_store) {
|
||||
None => {
|
||||
internal_error!("A builtin module contains a signature without implementation for {:?}", symbol)
|
||||
|
@ -649,7 +558,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
GeneratedInfo::Hosted { effect_symbol, .. } => {
|
||||
HeaderType::Hosted { .. } => {
|
||||
let ident_id = symbol.ident_id();
|
||||
let ident = scope
|
||||
.locals
|
||||
|
@ -667,13 +576,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
aliases: Default::default(),
|
||||
};
|
||||
|
||||
let hosted_def = crate::effect_module::build_host_exposed_def(
|
||||
&mut scope,
|
||||
*symbol,
|
||||
&ident,
|
||||
effect_symbol,
|
||||
var_store,
|
||||
annotation,
|
||||
let hosted_def = crate::task_module::build_host_exposed_def(
|
||||
&mut scope, *symbol, &ident, var_store, annotation,
|
||||
);
|
||||
|
||||
declarations.update_builtin_def(index, hosted_def);
|
||||
|
@ -699,18 +603,6 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
let mut aliases = MutMap::default();
|
||||
|
||||
if let GeneratedInfo::Hosted { effect_symbol, .. } = generated_info {
|
||||
// Remove this from exposed_symbols,
|
||||
// so that at the end of the process,
|
||||
// we can see if there were any
|
||||
// exposed symbols which did not have
|
||||
// corresponding defs.
|
||||
exposed_but_not_defined.remove(&effect_symbol);
|
||||
|
||||
let hosted_alias = scope.lookup_alias(effect_symbol).unwrap().clone();
|
||||
aliases.insert(effect_symbol, hosted_alias);
|
||||
}
|
||||
|
||||
for (symbol, alias) in output.aliases {
|
||||
// Remove this from exposed_symbols,
|
||||
// so that at the end of the process,
|
||||
|
@ -859,7 +751,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
scope,
|
||||
aliases,
|
||||
rigid_variables,
|
||||
params_pattern,
|
||||
module_params,
|
||||
declarations,
|
||||
referenced_values,
|
||||
exposed_imports: can_exposed_imports,
|
||||
|
|
|
@ -623,16 +623,29 @@ pub fn canonicalize_pattern<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
RecordDestructure(patterns) => canonicalize_record_destructure(
|
||||
env,
|
||||
var_store,
|
||||
scope,
|
||||
output,
|
||||
pattern_type,
|
||||
patterns,
|
||||
region,
|
||||
permit_shadows,
|
||||
),
|
||||
RecordDestructure(patterns) => {
|
||||
let ext_var = var_store.fresh();
|
||||
let whole_var = var_store.fresh();
|
||||
|
||||
let (destructs, opt_erroneous) = canonicalize_record_destructs(
|
||||
env,
|
||||
var_store,
|
||||
scope,
|
||||
output,
|
||||
pattern_type,
|
||||
patterns,
|
||||
region,
|
||||
permit_shadows,
|
||||
);
|
||||
|
||||
// If we encountered an erroneous pattern (e.g. one with shadowing),
|
||||
// use the resulting RuntimeError. Otherwise, return a successful record destructure.
|
||||
opt_erroneous.unwrap_or(Pattern::RecordDestructure {
|
||||
whole_var,
|
||||
ext_var,
|
||||
destructs,
|
||||
})
|
||||
}
|
||||
|
||||
RequiredField(_name, _loc_pattern) => {
|
||||
unreachable!("should have been handled in RecordDestructure");
|
||||
|
@ -779,7 +792,7 @@ pub fn canonicalize_pattern<'a>(
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn canonicalize_record_destructure<'a>(
|
||||
pub fn canonicalize_record_destructs<'a>(
|
||||
env: &mut Env<'a>,
|
||||
var_store: &mut VarStore,
|
||||
scope: &mut Scope,
|
||||
|
@ -788,11 +801,9 @@ pub fn canonicalize_record_destructure<'a>(
|
|||
patterns: &ast::Collection<Loc<ast::Pattern<'a>>>,
|
||||
region: Region,
|
||||
permit_shadows: PermitShadows,
|
||||
) -> Pattern {
|
||||
) -> (Vec<Loc<RecordDestruct>>, Option<Pattern>) {
|
||||
use ast::Pattern::*;
|
||||
|
||||
let ext_var = var_store.fresh();
|
||||
let whole_var = var_store.fresh();
|
||||
let mut destructs = Vec::with_capacity(patterns.len());
|
||||
let mut opt_erroneous = None;
|
||||
|
||||
|
@ -907,13 +918,7 @@ pub fn canonicalize_record_destructure<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// If we encountered an erroneous pattern (e.g. one with shadowing),
|
||||
// use the resulting RuntimeError. Otherwise, return a successful record destructure.
|
||||
opt_erroneous.unwrap_or(Pattern::RecordDestructure {
|
||||
whole_var,
|
||||
ext_var,
|
||||
destructs,
|
||||
})
|
||||
(destructs, opt_erroneous)
|
||||
}
|
||||
|
||||
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::expr::Expr;
|
||||
use crate::pattern::Pattern;
|
||||
use crate::{expr::Expr, scope::SymbolLookup};
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::Variable;
|
||||
|
@ -125,8 +125,18 @@ impl References {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert_value_lookup(&mut self, symbol: Symbol, qualified: QualifiedReference) {
|
||||
self.insert(symbol, qualified.flags(ReferencesBitflags::VALUE_LOOKUP));
|
||||
pub fn insert_value_lookup(&mut self, lookup: SymbolLookup, qualified: QualifiedReference) {
|
||||
self.insert(
|
||||
lookup.symbol,
|
||||
qualified.flags(ReferencesBitflags::VALUE_LOOKUP),
|
||||
);
|
||||
|
||||
if let Some((_, params_symbol)) = lookup.module_params {
|
||||
self.insert(
|
||||
params_symbol,
|
||||
qualified.flags(ReferencesBitflags::VALUE_LOOKUP),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_type_lookup(&mut self, symbol: Symbol, qualified: QualifiedReference) {
|
||||
|
|
|
@ -466,7 +466,7 @@ impl Scope {
|
|||
self.home.register_debug_idents(&self.locals.ident_ids)
|
||||
}
|
||||
|
||||
/// Generates a unique, new symbol like "$1" or "$5",
|
||||
/// Generates a unique, new symbol like "1" or "5",
|
||||
/// using the home module as the module_id.
|
||||
///
|
||||
/// This is used, for example, during canonicalization of an Expr::Closure
|
||||
|
@ -475,6 +475,12 @@ impl Scope {
|
|||
Symbol::new(self.home, self.locals.gen_unique())
|
||||
}
|
||||
|
||||
/// Generates a unique new symbol and return the symbol's unqualified identifier name.
|
||||
pub fn gen_unique_symbol_name(&mut self) -> &str {
|
||||
let ident_id = self.locals.gen_unique();
|
||||
self.locals.ident_ids.get_name(ident_id).unwrap()
|
||||
}
|
||||
|
||||
/// Introduce a new ignored variable (variable starting with an underscore).
|
||||
/// The underscore itself should not be included in `ident`.
|
||||
pub fn introduce_ignored_local(&mut self, ident: &str, region: Region) {
|
||||
|
@ -669,7 +675,7 @@ pub struct ScopeModules {
|
|||
/// Why is this module in scope?
|
||||
sources: Vec<ScopeModuleSource>,
|
||||
/// The params of a module if any
|
||||
params: Vec<Option<Symbol>>,
|
||||
params: Vec<Option<(Variable, Symbol)>>,
|
||||
}
|
||||
|
||||
impl ScopeModules {
|
||||
|
@ -731,7 +737,7 @@ impl ScopeModules {
|
|||
&mut self,
|
||||
module_name: ModuleName,
|
||||
module_id: ModuleId,
|
||||
params_symbol: Option<Symbol>,
|
||||
params: Option<(Variable, Symbol)>,
|
||||
region: Region,
|
||||
) -> Result<(), ScopeModuleSource> {
|
||||
if let Some(index) = self.names.iter().position(|name| name == &module_name) {
|
||||
|
@ -745,7 +751,7 @@ impl ScopeModules {
|
|||
self.ids.push(module_id);
|
||||
self.names.push(module_name);
|
||||
self.sources.push(ScopeModuleSource::Import(region));
|
||||
self.params.push(params_symbol);
|
||||
self.params.push(params);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -768,14 +774,14 @@ impl ScopeModules {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SymbolLookup {
|
||||
pub symbol: Symbol,
|
||||
pub module_params: Option<Symbol>,
|
||||
pub module_params: Option<(Variable, Symbol)>,
|
||||
}
|
||||
|
||||
impl SymbolLookup {
|
||||
pub fn new(symbol: Symbol, params: Option<Symbol>) -> Self {
|
||||
pub fn new(symbol: Symbol, params: Option<(Variable, Symbol)>) -> Self {
|
||||
Self {
|
||||
symbol,
|
||||
module_params: params,
|
||||
|
@ -789,7 +795,7 @@ impl SymbolLookup {
|
|||
|
||||
pub struct ModuleLookup {
|
||||
pub id: ModuleId,
|
||||
pub params: Option<Symbol>,
|
||||
pub params: Option<(Variable, Symbol)>,
|
||||
}
|
||||
|
||||
impl ModuleLookup {
|
||||
|
|
207
crates/compiler/can/src/task_module.rs
Normal file
207
crates/compiler/can/src/task_module.rs
Normal file
|
@ -0,0 +1,207 @@
|
|||
use crate::def::Def;
|
||||
use crate::expr::{AnnotatedMark, ClosureData, Expr, Recursive};
|
||||
use crate::pattern::Pattern;
|
||||
use crate::scope::Scope;
|
||||
use roc_collections::SendMap;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{LambdaSet, OptAbleVar, Type};
|
||||
|
||||
pub fn build_host_exposed_def(
|
||||
scope: &mut Scope,
|
||||
symbol: Symbol,
|
||||
ident: &str,
|
||||
var_store: &mut VarStore,
|
||||
annotation: crate::annotation::Annotation,
|
||||
) -> Def {
|
||||
let expr_var = var_store.fresh();
|
||||
let pattern = Pattern::Identifier(symbol);
|
||||
let mut pattern_vars = SendMap::default();
|
||||
pattern_vars.insert(symbol, expr_var);
|
||||
|
||||
let mut arguments: Vec<(Variable, AnnotatedMark, Loc<Pattern>)> = Vec::new();
|
||||
let mut linked_symbol_arguments: Vec<(Variable, Expr)> = Vec::new();
|
||||
let mut captured_symbols: Vec<(Symbol, Variable)> = Vec::new();
|
||||
|
||||
let crate::annotation::Annotation {
|
||||
introduced_variables,
|
||||
typ,
|
||||
aliases,
|
||||
..
|
||||
} = annotation;
|
||||
|
||||
let def_body = {
|
||||
match typ.shallow_structural_dealias() {
|
||||
Type::Function(args, _, _) => {
|
||||
for i in 0..args.len() {
|
||||
let name = format!("closure_arg_{ident}_{i}");
|
||||
|
||||
let arg_symbol = {
|
||||
let ident = name.clone().into();
|
||||
scope.introduce(ident, Region::zero()).unwrap()
|
||||
};
|
||||
|
||||
let arg_var = var_store.fresh();
|
||||
|
||||
arguments.push((
|
||||
arg_var,
|
||||
AnnotatedMark::new(var_store),
|
||||
Loc::at_zero(Pattern::Identifier(arg_symbol)),
|
||||
));
|
||||
|
||||
captured_symbols.push((arg_symbol, arg_var));
|
||||
linked_symbol_arguments.push((arg_var, Expr::Var(arg_symbol, arg_var)));
|
||||
}
|
||||
|
||||
let foreign_symbol_name = format!("roc_fx_{ident}");
|
||||
let low_level_call = Expr::ForeignCall {
|
||||
foreign_symbol: foreign_symbol_name.into(),
|
||||
args: linked_symbol_arguments,
|
||||
ret_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
let task_closure_symbol = {
|
||||
let name = format!("task_closure_{ident}");
|
||||
|
||||
let ident = name.into();
|
||||
scope.introduce(ident, Region::zero()).unwrap()
|
||||
};
|
||||
|
||||
let task_closure = Expr::Closure(ClosureData {
|
||||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
name: task_closure_symbol,
|
||||
captured_symbols,
|
||||
recursive: Recursive::NotRecursive,
|
||||
arguments: vec![(
|
||||
var_store.fresh(),
|
||||
AnnotatedMark::new(var_store),
|
||||
Loc::at_zero(empty_record_pattern(var_store)),
|
||||
)],
|
||||
loc_body: Box::new(Loc::at_zero(low_level_call)),
|
||||
});
|
||||
|
||||
let (specialized_def_type, type_arguments, lambda_set_variables) =
|
||||
build_fresh_opaque_variables(var_store);
|
||||
let body = Expr::OpaqueRef {
|
||||
opaque_var: var_store.fresh(),
|
||||
name: Symbol::TASK_TASK,
|
||||
argument: Box::new((var_store.fresh(), Loc::at_zero(task_closure))),
|
||||
specialized_def_type,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
};
|
||||
|
||||
Expr::Closure(ClosureData {
|
||||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
name: symbol,
|
||||
captured_symbols: std::vec::Vec::new(),
|
||||
recursive: Recursive::NotRecursive,
|
||||
arguments,
|
||||
loc_body: Box::new(Loc::at_zero(body)),
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
// not a function
|
||||
|
||||
let foreign_symbol_name = format!("roc_fx_{ident}");
|
||||
let low_level_call = Expr::ForeignCall {
|
||||
foreign_symbol: foreign_symbol_name.into(),
|
||||
args: linked_symbol_arguments,
|
||||
ret_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
let task_closure_symbol = {
|
||||
let name = format!("task_closure_{ident}");
|
||||
|
||||
let ident = name.into();
|
||||
scope.introduce(ident, Region::zero()).unwrap()
|
||||
};
|
||||
|
||||
let task_closure = Expr::Closure(ClosureData {
|
||||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
name: task_closure_symbol,
|
||||
captured_symbols,
|
||||
recursive: Recursive::NotRecursive,
|
||||
arguments: vec![(
|
||||
var_store.fresh(),
|
||||
AnnotatedMark::new(var_store),
|
||||
Loc::at_zero(empty_record_pattern(var_store)),
|
||||
)],
|
||||
loc_body: Box::new(Loc::at_zero(low_level_call)),
|
||||
});
|
||||
|
||||
let (specialized_def_type, type_arguments, lambda_set_variables) =
|
||||
build_fresh_opaque_variables(var_store);
|
||||
Expr::OpaqueRef {
|
||||
opaque_var: var_store.fresh(),
|
||||
name: Symbol::TASK_TASK,
|
||||
argument: Box::new((var_store.fresh(), Loc::at_zero(task_closure))),
|
||||
specialized_def_type,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let def_annotation = crate::def::Annotation {
|
||||
signature: typ,
|
||||
introduced_variables,
|
||||
aliases,
|
||||
region: Region::zero(),
|
||||
};
|
||||
|
||||
Def {
|
||||
loc_pattern: Loc::at_zero(pattern),
|
||||
loc_expr: Loc::at_zero(def_body),
|
||||
expr_var,
|
||||
pattern_vars,
|
||||
annotation: Some(def_annotation),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_fresh_opaque_variables(
|
||||
var_store: &mut VarStore,
|
||||
) -> (Box<Type>, Vec<OptAbleVar>, Vec<LambdaSet>) {
|
||||
let closure_var = var_store.fresh();
|
||||
|
||||
let ok_var = var_store.fresh();
|
||||
let err_var = var_store.fresh();
|
||||
let result_var = var_store.fresh();
|
||||
|
||||
let actual = Type::Function(
|
||||
vec![Type::EmptyRec],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
Box::new(Type::Variable(result_var)),
|
||||
);
|
||||
|
||||
let type_arguments = vec![
|
||||
OptAbleVar {
|
||||
var: ok_var,
|
||||
opt_abilities: None,
|
||||
},
|
||||
OptAbleVar {
|
||||
var: err_var,
|
||||
opt_abilities: None,
|
||||
},
|
||||
];
|
||||
let lambda_set_variables = vec![roc_types::types::LambdaSet(Type::Variable(closure_var))];
|
||||
|
||||
(Box::new(actual), type_arguments, lambda_set_variables)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn empty_record_pattern(var_store: &mut VarStore) -> Pattern {
|
||||
Pattern::RecordDestructure {
|
||||
whole_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
destructs: vec![],
|
||||
}
|
||||
}
|
|
@ -46,6 +46,24 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
let var = var_store.fresh();
|
||||
let qualified_module_ids = PackageModuleIds::default();
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
expr_str,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
|
@ -53,21 +71,8 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(
|
||||
arena,
|
||||
&loc_expr,
|
||||
expr_str,
|
||||
&mut None,
|
||||
arena.alloc("TestPath"),
|
||||
&mut Default::default(),
|
||||
);
|
||||
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
scope.add_alias(
|
||||
Symbol::NUM_INT,
|
||||
Region::zero(),
|
||||
|
@ -80,15 +85,6 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
roc_types::types::AliasKind::Structural,
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
);
|
||||
let (loc_expr, output) = canonicalize_expr(
|
||||
&mut env,
|
||||
&mut var_store,
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
assertion_line: 463
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-26,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 1),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-26 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@15-26,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@15-26 Identifier {
|
||||
ident: "1",
|
||||
},
|
||||
@15-26 ParensAround(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@20-25,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@20-25 Identifier {
|
||||
ident: "0",
|
||||
},
|
||||
@20-25 Apply(
|
||||
@22-23 Var {
|
||||
module_name: "Num",
|
||||
ident: "add",
|
||||
},
|
||||
[
|
||||
@20-21 Num(
|
||||
"1",
|
||||
),
|
||||
@24-25 Num(
|
||||
"1",
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Plus,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@15-26 LowLevelDbg(
|
||||
(
|
||||
"test.roc:3",
|
||||
" ",
|
||||
),
|
||||
@20-25 Apply(
|
||||
@20-25 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@20-25 Var {
|
||||
module_name: "",
|
||||
ident: "0",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@20-25 Var {
|
||||
module_name: "",
|
||||
ident: "0",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-26 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
"in =\n ",
|
||||
),
|
||||
@15-26 Apply(
|
||||
@15-26 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@15-26 Var {
|
||||
module_name: "",
|
||||
ident: "1",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@15-26 Var {
|
||||
module_name: "",
|
||||
ident: "1",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
assertion_line: 473
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-51,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 1),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-51 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-40,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@11-40 Identifier {
|
||||
ident: "1",
|
||||
},
|
||||
@11-40 Apply(
|
||||
@31-38 Var {
|
||||
module_name: "Num",
|
||||
ident: "add",
|
||||
},
|
||||
[
|
||||
@11-23 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-12,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@11-12 Identifier {
|
||||
ident: "0",
|
||||
},
|
||||
@11-12 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-23 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
" ",
|
||||
),
|
||||
@11-12 Apply(
|
||||
@11-12 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "0",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "0",
|
||||
},
|
||||
),
|
||||
),
|
||||
@39-40 Num(
|
||||
"2",
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-51 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
" main =\n 1\n ",
|
||||
),
|
||||
@11-40 Apply(
|
||||
@11-40 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@11-40 Var {
|
||||
module_name: "",
|
||||
ident: "1",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@11-40 Var {
|
||||
module_name: "",
|
||||
ident: "1",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
|
@ -6,22 +6,39 @@ mod suffixed_tests {
|
|||
use bumpalo::Bump;
|
||||
use insta::assert_snapshot;
|
||||
use roc_can::desugar::desugar_defs_node_values;
|
||||
use roc_can::env::Env;
|
||||
use roc_can::scope::Scope;
|
||||
use roc_module::symbol::{IdentIds, ModuleIds, PackageModuleIds};
|
||||
use roc_parse::test_helpers::parse_defs_with;
|
||||
use std::path::Path;
|
||||
|
||||
macro_rules! run_test {
|
||||
($src:expr) => {{
|
||||
let arena = &Bump::new();
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
desugar_defs_node_values(
|
||||
arena,
|
||||
&mut defs,
|
||||
$src,
|
||||
&mut None,
|
||||
"test.roc",
|
||||
true,
|
||||
&mut Default::default(),
|
||||
let home = ModuleIds::default().get_or_insert(&"Test".into());
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let qualified_module_ids = PackageModuleIds::default();
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
$src,
|
||||
home,
|
||||
Path::new("test.roc"),
|
||||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
desugar_defs_node_values(&mut env, &mut scope, &mut defs, true);
|
||||
|
||||
let snapshot = format!("{:#?}", &defs);
|
||||
println!("{}", snapshot);
|
||||
assert_snapshot!(snapshot);
|
||||
|
@ -441,6 +458,29 @@ mod suffixed_tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dbg_expr() {
|
||||
run_test!(
|
||||
r#"
|
||||
main =
|
||||
dbg (dbg 1 + 1)
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pizza_dbg() {
|
||||
run_test!(
|
||||
r#"
|
||||
main =
|
||||
1
|
||||
|> dbg
|
||||
|> Num.add 2
|
||||
|> dbg
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_argument_single() {
|
||||
run_test!(
|
||||
|
|
231
crates/compiler/checkmate/www/package-lock.json
generated
231
crates/compiler/checkmate/www/package-lock.json
generated
|
@ -3424,21 +3424,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.18",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
|
||||
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
|
@ -4351,20 +4345,10 @@
|
|||
"@types/json-schema": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint-scope": {
|
||||
"version": "3.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
|
||||
"integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/eslint": "*",
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
|
||||
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
|
@ -4932,9 +4916,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
|
||||
"integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
|
@ -4954,9 +4938,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
|
||||
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
|
||||
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
|
@ -4977,15 +4961,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
|
||||
"integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
|
||||
"integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6"
|
||||
"@webassemblyjs/wasm-gen": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ieee754": {
|
||||
|
@ -5013,28 +4997,28 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
|
||||
"integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
|
||||
"integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-opt": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6",
|
||||
"@webassemblyjs/wast-printer": "1.11.6"
|
||||
"@webassemblyjs/helper-wasm-section": "1.12.1",
|
||||
"@webassemblyjs/wasm-gen": "1.12.1",
|
||||
"@webassemblyjs/wasm-opt": "1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "1.12.1",
|
||||
"@webassemblyjs/wast-printer": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-gen": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
|
||||
"integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
|
||||
"integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
|
@ -5042,24 +5026,24 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
|
||||
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
|
||||
"integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/wasm-gen": "1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
|
||||
"integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
|
@ -5068,12 +5052,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
|
||||
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
|
||||
"integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
|
@ -5142,10 +5126,10 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-assertions": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
|
||||
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
|
||||
"node_modules/acorn-import-attributes": {
|
||||
"version": "1.9.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
|
||||
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
|
@ -6039,9 +6023,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.21.9",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
|
||||
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
|
||||
"version": "4.23.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
|
||||
"integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -6058,10 +6042,10 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001503",
|
||||
"electron-to-chromium": "^1.4.431",
|
||||
"node-releases": "^2.0.12",
|
||||
"update-browserslist-db": "^1.0.11"
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"electron-to-chromium": "^1.5.4",
|
||||
"node-releases": "^2.0.18",
|
||||
"update-browserslist-db": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
|
@ -6178,9 +6162,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001516",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz",
|
||||
"integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==",
|
||||
"version": "1.0.30001655",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz",
|
||||
"integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -7575,9 +7559,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.461",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.461.tgz",
|
||||
"integrity": "sha512-1JkvV2sgEGTDXjdsaQCeSwYYuhLRphRpc+g6EHTFELJXEiznLt3/0pZ9JuAOQ5p2rI3YxKTbivtvajirIfhrEQ==",
|
||||
"version": "1.5.13",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
|
||||
"integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/elkjs": {
|
||||
|
@ -7622,9 +7606,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
|
||||
"integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
|
@ -7815,9 +7799,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
|
@ -13471,9 +13455,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
|
@ -13926,9 +13910,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
|
@ -17473,9 +17457,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.19.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.0.tgz",
|
||||
"integrity": "sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q==",
|
||||
"version": "5.31.6",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz",
|
||||
"integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
|
@ -17491,16 +17475,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
"version": "5.3.9",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz",
|
||||
"integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==",
|
||||
"version": "5.3.10",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
|
||||
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"@jridgewell/trace-mapping": "^0.3.20",
|
||||
"jest-worker": "^27.4.5",
|
||||
"schema-utils": "^3.1.1",
|
||||
"serialize-javascript": "^6.0.1",
|
||||
"terser": "^5.16.8"
|
||||
"terser": "^5.26.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
|
@ -17984,9 +17968,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
|
||||
"integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
|
||||
"integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -18003,8 +17987,8 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"escalade": "^3.1.1",
|
||||
"picocolors": "^1.0.0"
|
||||
"escalade": "^3.1.2",
|
||||
"picocolors": "^1.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"update-browserslist-db": "cli.js"
|
||||
|
@ -18140,9 +18124,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
|
@ -18171,34 +18155,33 @@
|
|||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.88.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz",
|
||||
"integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==",
|
||||
"version": "5.94.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
|
||||
"integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
"@webassemblyjs/ast": "^1.11.5",
|
||||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"@types/estree": "^1.0.5",
|
||||
"@webassemblyjs/ast": "^1.12.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.12.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"browserslist": "^4.14.5",
|
||||
"acorn-import-attributes": "^1.9.5",
|
||||
"browserslist": "^4.21.10",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.15.0",
|
||||
"enhanced-resolve": "^5.17.1",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.2.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.7",
|
||||
"watchpack": "^2.4.0",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"watchpack": "^2.4.1",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"bin": {
|
||||
|
|
|
@ -17,6 +17,10 @@ impl<T> VecSet<T> {
|
|||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.elements
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
self.elements.reserve(additional)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> VecSet<T> {
|
||||
|
|
|
@ -569,8 +569,8 @@ pub fn constrain_expr(
|
|||
Var(symbol, variable)
|
||||
| ParamsVar {
|
||||
symbol,
|
||||
params: _,
|
||||
var: variable,
|
||||
..
|
||||
} => {
|
||||
// Save the expectation in the variable, then lookup the symbol's type in the environment
|
||||
let expected_type = *constraints[expected].get_type_ref();
|
||||
|
|
|
@ -3,13 +3,12 @@ use crate::pattern::{constrain_pattern, PatternState};
|
|||
use roc_can::abilities::{PendingAbilitiesStore, PendingMemberType};
|
||||
use roc_can::constraint::{Constraint, Constraints, Generalizable};
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::expr::{AnnotatedMark, Declarations};
|
||||
use roc_can::expr::Declarations;
|
||||
use roc_can::module::ModuleParams;
|
||||
use roc_can::pattern::Pattern;
|
||||
use roc_collections::MutMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::Variable;
|
||||
use roc_types::types::{AnnotationSource, Category, Type, Types};
|
||||
|
||||
pub fn constrain_module(
|
||||
|
@ -18,12 +17,12 @@ pub fn constrain_module(
|
|||
symbols_from_requires: Vec<(Loc<Symbol>, Loc<Type>)>,
|
||||
abilities_store: &PendingAbilitiesStore,
|
||||
declarations: &Declarations,
|
||||
params_pattern: &Option<(Variable, AnnotatedMark, Loc<Pattern>)>,
|
||||
opt_module_params: &Option<ModuleParams>,
|
||||
home: ModuleId,
|
||||
) -> Constraint {
|
||||
let constraint = crate::expr::constrain_decls(types, constraints, home, declarations);
|
||||
|
||||
let constraint = match params_pattern {
|
||||
let constraint = match opt_module_params {
|
||||
Some(params_pattern) => {
|
||||
constrain_params(types, constraints, home, constraint, params_pattern)
|
||||
}
|
||||
|
@ -51,7 +50,7 @@ fn constrain_params(
|
|||
constraints: &mut Constraints,
|
||||
home: ModuleId,
|
||||
constraint: Constraint,
|
||||
(pattern_var, _, loc_pattern): &(Variable, AnnotatedMark, Loc<Pattern>),
|
||||
module_params: &ModuleParams,
|
||||
) -> Constraint {
|
||||
let mut env = Env {
|
||||
home,
|
||||
|
@ -59,23 +58,13 @@ fn constrain_params(
|
|||
resolutions_to_make: vec![],
|
||||
};
|
||||
|
||||
let index = constraints.push_variable(*pattern_var);
|
||||
let index = constraints.push_variable(module_params.whole_var);
|
||||
let expected_params = constraints.push_pat_expected_type(PExpected::NoExpectation(index));
|
||||
|
||||
let mut state = PatternState::default();
|
||||
|
||||
let closed_con = match loc_pattern.value {
|
||||
Pattern::RecordDestructure {
|
||||
whole_var: _,
|
||||
ext_var,
|
||||
destructs: _,
|
||||
} => {
|
||||
// Disallow record extension for module params
|
||||
let empty_rec = constraints.push_type(types, Types::EMPTY_RECORD);
|
||||
constraints.store(empty_rec, ext_var, file!(), line!())
|
||||
}
|
||||
_ => internal_error!("Only record destructures are allowed in module params. This should've been caught earlier."),
|
||||
};
|
||||
let empty_rec = constraints.push_type(types, Types::EMPTY_RECORD);
|
||||
let closed_con = constraints.store(empty_rec, module_params.record_ext_var, file!(), line!());
|
||||
|
||||
state.constraints.push(closed_con);
|
||||
|
||||
|
@ -83,8 +72,8 @@ fn constrain_params(
|
|||
types,
|
||||
constraints,
|
||||
&mut env,
|
||||
&loc_pattern.value,
|
||||
loc_pattern.region,
|
||||
&module_params.pattern().value,
|
||||
module_params.region,
|
||||
expected_params,
|
||||
&mut state,
|
||||
);
|
||||
|
@ -100,7 +89,7 @@ fn constrain_params(
|
|||
Generalizable(true),
|
||||
);
|
||||
|
||||
constraints.exists([*pattern_var], cons)
|
||||
constraints.exists([module_params.whole_var], cons)
|
||||
}
|
||||
|
||||
fn constrain_symbols_from_requires(
|
||||
|
|
|
@ -38,6 +38,7 @@ pub enum Parens {
|
|||
InFunctionType,
|
||||
InApply,
|
||||
InOperator,
|
||||
InAsPattern,
|
||||
}
|
||||
|
||||
/// In an AST node, do we show newlines around it
|
||||
|
|
|
@ -46,7 +46,8 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| MalformedClosure
|
||||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| Crash => false,
|
||||
| Crash
|
||||
| Dbg => false,
|
||||
|
||||
RecordAccess(inner, _) | TupleAccess(inner, _) | TrySuffix { expr: inner, .. } => {
|
||||
inner.is_multiline()
|
||||
|
@ -65,7 +66,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
Expect(condition, continuation) => {
|
||||
condition.is_multiline() || continuation.is_multiline()
|
||||
}
|
||||
Dbg(condition, _) => condition.is_multiline(),
|
||||
DbgStmt(condition, _) => condition.is_multiline(),
|
||||
LowLevelDbg(_, _, _) => unreachable!(
|
||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
),
|
||||
|
@ -453,8 +454,12 @@ impl<'a> Formattable for Expr<'a> {
|
|||
Expect(condition, continuation) => {
|
||||
fmt_expect(buf, condition, continuation, self.is_multiline(), indent);
|
||||
}
|
||||
Dbg(condition, continuation) => {
|
||||
fmt_dbg(buf, condition, continuation, self.is_multiline(), indent);
|
||||
Dbg => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("dbg");
|
||||
}
|
||||
DbgStmt(condition, continuation) => {
|
||||
fmt_dbg_stmt(buf, condition, continuation, self.is_multiline(), indent);
|
||||
}
|
||||
LowLevelDbg(_, _, _) => unreachable!(
|
||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
|
@ -1018,7 +1023,7 @@ fn fmt_when<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn fmt_dbg<'a>(
|
||||
fn fmt_dbg_stmt<'a>(
|
||||
buf: &mut Buf,
|
||||
condition: &'a Loc<Expr<'a>>,
|
||||
continuation: &'a Loc<Expr<'a>>,
|
||||
|
@ -1240,7 +1245,7 @@ fn fmt_closure<'a>(
|
|||
let mut it = loc_patterns.iter().peekable();
|
||||
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
loc_pattern.format(buf, indent);
|
||||
loc_pattern.format_with_options(buf, Parens::InAsPattern, Newlines::No, indent);
|
||||
|
||||
if it.peek().is_some() {
|
||||
buf.indent(indent);
|
||||
|
|
|
@ -7,11 +7,10 @@ use crate::spaces::{fmt_comments_only, fmt_default_spaces, fmt_spaces, NewlineAt
|
|||
use crate::Buf;
|
||||
use roc_parse::ast::{Collection, CommentOrNewline, Header, Spaced, Spaces, SpacesBefore};
|
||||
use roc_parse::header::{
|
||||
AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword, HostedHeader, ImportsEntry,
|
||||
ImportsKeyword, Keyword, KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader,
|
||||
PackageKeyword, PackageName, PackagesKeyword, PlatformHeader, PlatformKeyword,
|
||||
PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword, TypedIdent,
|
||||
WithKeyword,
|
||||
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword, Keyword,
|
||||
KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader, PackageKeyword,
|
||||
PackageName, PackagesKeyword, PlatformHeader, PlatformKeyword, PlatformRequires,
|
||||
ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword, TypedIdent,
|
||||
};
|
||||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
@ -63,8 +62,6 @@ macro_rules! keywords {
|
|||
keywords! {
|
||||
ExposesKeyword,
|
||||
ImportsKeyword,
|
||||
WithKeyword,
|
||||
GeneratesKeyword,
|
||||
PackageKeyword,
|
||||
PackagesKeyword,
|
||||
RequiresKeyword,
|
||||
|
@ -206,9 +203,6 @@ pub fn fmt_hosted_header<'a>(buf: &mut Buf, header: &'a HostedHeader<'a>) {
|
|||
fmt_exposes(buf, header.exposes.item, indent);
|
||||
header.imports.keyword.format(buf, indent);
|
||||
fmt_imports(buf, header.imports.item, indent);
|
||||
header.generates.format(buf, indent);
|
||||
header.generates_with.keyword.format(buf, indent);
|
||||
fmt_exposes(buf, header.generates_with.item, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_app_header<'a>(buf: &mut Buf, header: &'a AppHeader<'a>) {
|
||||
|
|
|
@ -244,9 +244,19 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
}
|
||||
|
||||
As(pattern, pattern_as) => {
|
||||
let needs_parens = parens == Parens::InAsPattern;
|
||||
|
||||
if needs_parens {
|
||||
buf.push('(');
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &pattern.value, indent, parens);
|
||||
|
||||
pattern_as.format(buf, indent + INDENT);
|
||||
|
||||
if needs_parens {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
|
||||
// Space
|
||||
|
|
|
@ -25,6 +25,7 @@ const MODULES: &[(ModuleId, &str)] = &[
|
|||
(ModuleId::DECODE, "Decode.roc"),
|
||||
(ModuleId::HASH, "Hash.roc"),
|
||||
(ModuleId::INSPECT, "Inspect.roc"),
|
||||
(ModuleId::TASK, "Task.roc"),
|
||||
];
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -256,6 +256,7 @@ fn read_cached_types() -> MutMap<ModuleId, TypeState> {
|
|||
let mod_decode = include_bytes_align_as!(u128, concat!(env!("OUT_DIR"), "/Decode.dat"));
|
||||
let mod_hash = include_bytes_align_as!(u128, concat!(env!("OUT_DIR"), "/Hash.dat"));
|
||||
let mod_inspect = include_bytes_align_as!(u128, concat!(env!("OUT_DIR"), "/Inspect.dat"));
|
||||
let mod_task = include_bytes_align_as!(u128, concat!(env!("OUT_DIR"), "/Task.dat"));
|
||||
|
||||
let mut output = MutMap::default();
|
||||
|
||||
|
@ -279,6 +280,8 @@ fn read_cached_types() -> MutMap<ModuleId, TypeState> {
|
|||
|
||||
output.insert(ModuleId::HASH, deserialize_help(mod_hash));
|
||||
output.insert(ModuleId::INSPECT, deserialize_help(mod_inspect));
|
||||
|
||||
output.insert(ModuleId::TASK, deserialize_help(mod_task));
|
||||
}
|
||||
|
||||
output
|
||||
|
|
|
@ -51,7 +51,7 @@ pub fn infer_expr(
|
|||
exposed_by_module: &Default::default(),
|
||||
derived_module,
|
||||
function_kind: FunctionKind::LambdaSet,
|
||||
params_pattern: None,
|
||||
module_params: None,
|
||||
module_params_vars: Default::default(),
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: None,
|
||||
|
@ -161,22 +161,6 @@ pub fn can_expr_with<'a>(
|
|||
// ensure the Test module is accessible in our tests
|
||||
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
// If we did this *during* canonicalization, then each time we
|
||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(
|
||||
arena,
|
||||
&loc_expr,
|
||||
expr_str,
|
||||
&mut None,
|
||||
arena.alloc("TestPath"),
|
||||
&mut Default::default(),
|
||||
);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
|
@ -187,12 +171,23 @@ pub fn can_expr_with<'a>(
|
|||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
expr_str,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
// If we did this *during* canonicalization, then each time we
|
||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||
|
||||
let (loc_expr, output) = canonicalize_expr(
|
||||
&mut env,
|
||||
&mut var_store,
|
||||
|
|
|
@ -3793,9 +3793,9 @@ mod test_reporting {
|
|||
of these?
|
||||
|
||||
Set
|
||||
Task
|
||||
List
|
||||
Dict
|
||||
Hash
|
||||
|
||||
── SYNTAX PROBLEM in /code/proj/Main.roc ───────────────────────────────────────
|
||||
|
||||
|
@ -3804,7 +3804,7 @@ mod test_reporting {
|
|||
10│ y = { Test.example & age: 3 }
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Only variables can be updated with record update syntax.
|
||||
Only variables can be updated with record update syntax.
|
||||
"
|
||||
);
|
||||
|
||||
|
@ -5760,28 +5760,6 @@ mod test_reporting {
|
|||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
dbg_without_final_expression,
|
||||
indoc!(
|
||||
r"
|
||||
dbg 42
|
||||
"
|
||||
),
|
||||
@r#"
|
||||
── INDENT ENDS AFTER EXPRESSION in tmp/dbg_without_final_expression/Test.roc ───
|
||||
|
||||
I am partway through parsing a dbg statement, but I got stuck here:
|
||||
|
||||
4│ dbg 42
|
||||
^
|
||||
|
||||
I was expecting a final expression, like so
|
||||
|
||||
dbg 42
|
||||
"done"
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
expect_without_final_expression,
|
||||
indoc!(
|
||||
|
@ -6318,16 +6296,17 @@ All branches in an `if` must have the same type!
|
|||
)
|
||||
}
|
||||
|
||||
// TODO: this test seems out of date (what is the `effects` clause?) and as such should be removed
|
||||
#[test]
|
||||
fn platform_requires_rigids() {
|
||||
report_header_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
platform "folkertdev/foo"
|
||||
requires { main : Effect {} }
|
||||
requires { main : Task {} [] }
|
||||
exposes []
|
||||
packages {}
|
||||
imports [Task]
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
effects fx.Effect
|
||||
{
|
||||
|
@ -6344,13 +6323,13 @@ All branches in an `if` must have the same type!
|
|||
I am partway through parsing a header, but I got stuck here:
|
||||
|
||||
1│ platform "folkertdev/foo"
|
||||
2│ requires { main : Effect {} }
|
||||
2│ requires { main : Task {} [] }
|
||||
^
|
||||
|
||||
I am expecting a list of type names like `{}` or `{ Model }` next. A full
|
||||
`requires` definition looks like
|
||||
|
||||
requires { Model, Msg } {main : Effect {}}
|
||||
requires { Model, Msg } {main : Task {} []}
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -8116,7 +8095,7 @@ All branches in an `if` must have the same type!
|
|||
unimported_modules_reported,
|
||||
indoc!(
|
||||
r#"
|
||||
alt : Task.Task {} []
|
||||
alt : Unimported.CustomType
|
||||
alt = "whatever man you don't even know my type"
|
||||
alt
|
||||
"#
|
||||
|
@ -8124,18 +8103,18 @@ All branches in an `if` must have the same type!
|
|||
@r"
|
||||
── MODULE NOT IMPORTED in /code/proj/Main.roc ──────────────────────────────────
|
||||
|
||||
The `Task` module is not imported:
|
||||
The `Unimported` module is not imported:
|
||||
|
||||
4│ alt : Task.Task {} []
|
||||
^^^^^^^^^^^^^^^
|
||||
4│ alt : Unimported.CustomType
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Is there an import missing? Perhaps there is a typo. Did you mean one
|
||||
of these?
|
||||
|
||||
Hash
|
||||
Encode
|
||||
Inspect
|
||||
Dict
|
||||
List
|
||||
Num
|
||||
Box
|
||||
"
|
||||
);
|
||||
|
||||
|
@ -14516,6 +14495,76 @@ All branches in an `if` must have the same type!
|
|||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
dbg_unapplied,
|
||||
indoc!(
|
||||
r"
|
||||
1 + dbg + 2
|
||||
"
|
||||
),
|
||||
@r"
|
||||
── UNAPPLIED DBG in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This `dbg` doesn't have a value given to it:
|
||||
|
||||
4│ 1 + dbg + 2
|
||||
^^^
|
||||
|
||||
`dbg` must be passed a value to print at the exact place it's used. `dbg`
|
||||
can't be used as a value that's passed around, like functions can be -
|
||||
it must be applied immediately!
|
||||
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This 2nd argument to + has an unexpected type:
|
||||
|
||||
4│ 1 + dbg + 2
|
||||
^^^
|
||||
|
||||
This value is a:
|
||||
|
||||
{}
|
||||
|
||||
But + needs its 2nd argument to be:
|
||||
|
||||
Num *
|
||||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
dbg_overapplied,
|
||||
indoc!(
|
||||
r#"
|
||||
1 + dbg "" "" + 2
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── OVERAPPLIED DBG in /code/proj/Main.roc ──────────────────────────────────────
|
||||
|
||||
This `dbg` has too many values given to it:
|
||||
|
||||
4│ 1 + dbg "" "" + 2
|
||||
^^^^^
|
||||
|
||||
`dbg` must be given exactly one value to print.
|
||||
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This 2nd argument to + has an unexpected type:
|
||||
|
||||
4│ 1 + dbg "" "" + 2
|
||||
^^^^^^^^^
|
||||
|
||||
This value is a:
|
||||
|
||||
{}
|
||||
|
||||
But + needs its 2nd argument to be:
|
||||
|
||||
Num *
|
||||
"#
|
||||
);
|
||||
|
||||
// TODO: add the following tests after built-in Tasks are added
|
||||
// https://github.com/roc-lang/roc/pull/6836
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ roc_tracing = { path = "../../tracing" }
|
|||
roc_types = { path = "../types" }
|
||||
roc_unify = { path = "../unify" }
|
||||
roc_worker = { path = "../worker" }
|
||||
roc_lower_params = { path = "../lower_params" }
|
||||
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
|
|||
use roc_can::expr::{DbgLookup, Declarations, ExpectLookup, PendingDerives};
|
||||
use roc_can::module::{
|
||||
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
|
||||
ResolvedImplementations, TypeState,
|
||||
ModuleParams, ResolvedImplementations, TypeState,
|
||||
};
|
||||
use roc_collections::{default_hasher, BumpMap, MutMap, MutSet, VecMap, VecSet};
|
||||
use roc_constrain::module::constrain_module;
|
||||
|
@ -251,6 +251,7 @@ fn start_phase<'a>(
|
|||
|
||||
let mut aliases = MutMap::default();
|
||||
let mut abilities_store = PendingAbilitiesStore::default();
|
||||
let mut imported_module_params = VecMap::default();
|
||||
|
||||
for imported in parsed.available_modules.keys() {
|
||||
match state.module_cache.aliases.get(imported) {
|
||||
|
@ -293,6 +294,10 @@ fn start_phase<'a>(
|
|||
.union(import_store.closure_from_imported(exposed_symbols));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(params) = state.module_cache.module_params.get(imported) {
|
||||
imported_module_params.insert(*imported, params.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let skip_constraint_gen = {
|
||||
|
@ -310,6 +315,8 @@ fn start_phase<'a>(
|
|||
abilities_store,
|
||||
skip_constraint_gen,
|
||||
exposed_module_ids: state.exposed_modules,
|
||||
exec_mode: state.exec_mode,
|
||||
imported_module_params,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,6 +363,7 @@ fn start_phase<'a>(
|
|||
declarations,
|
||||
state.cached_types.clone(),
|
||||
derived_module,
|
||||
state.exec_mode,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
|
@ -889,6 +897,8 @@ enum BuildTask<'a> {
|
|||
abilities_store: PendingAbilitiesStore,
|
||||
exposed_module_ids: &'a [ModuleId],
|
||||
skip_constraint_gen: bool,
|
||||
exec_mode: ExecutionMode,
|
||||
imported_module_params: VecMap<ModuleId, ModuleParams>,
|
||||
},
|
||||
Solve {
|
||||
module: Module,
|
||||
|
@ -905,6 +915,7 @@ enum BuildTask<'a> {
|
|||
dep_idents: IdentIdsByModule,
|
||||
cached_subs: CachedTypeState,
|
||||
derived_module: SharedDerivedModule,
|
||||
exec_mode: ExecutionMode,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: Option<roc_checkmate::Collector>,
|
||||
|
@ -2318,6 +2329,7 @@ fn update<'a>(
|
|||
extend_module_with_builtin_import(parsed, ModuleId::DECODE);
|
||||
extend_module_with_builtin_import(parsed, ModuleId::HASH);
|
||||
extend_module_with_builtin_import(parsed, ModuleId::INSPECT);
|
||||
extend_module_with_builtin_import(parsed, ModuleId::TASK);
|
||||
}
|
||||
|
||||
state
|
||||
|
@ -2395,11 +2407,11 @@ fn update<'a>(
|
|||
.pending_abilities
|
||||
.insert(module_id, constrained_module.module.abilities_store.clone());
|
||||
|
||||
if let Some(params_pattern) = constrained_module.module.params_pattern.clone() {
|
||||
if let Some(module_params) = constrained_module.module.module_params.clone() {
|
||||
state
|
||||
.module_cache
|
||||
.param_patterns
|
||||
.insert(module_id, params_pattern);
|
||||
.module_params
|
||||
.insert(module_id, module_params);
|
||||
}
|
||||
|
||||
state
|
||||
|
@ -3557,7 +3569,6 @@ fn load_builtin_module_help<'a>(
|
|||
header_type: HeaderType::Builtin {
|
||||
name: header::ModuleName::new(name_stem),
|
||||
exposes: unspace(arena, header.exposes.items),
|
||||
generates_with: &[],
|
||||
opt_params: header.params,
|
||||
},
|
||||
module_comments: comments,
|
||||
|
@ -3640,6 +3651,7 @@ fn load_module<'a>(
|
|||
"Decode", ModuleId::DECODE
|
||||
"Hash", ModuleId::HASH
|
||||
"Inspect", ModuleId::INSPECT
|
||||
"Task", ModuleId::TASK
|
||||
}
|
||||
|
||||
let (filename, opt_shorthand) = module_name_to_path(src_dir, &module_name, arc_shorthands);
|
||||
|
@ -3875,8 +3887,6 @@ fn parse_header<'a>(
|
|||
header_type: HeaderType::Hosted {
|
||||
name: header.name.value,
|
||||
exposes: unspace(arena, header.exposes.item.items),
|
||||
generates: header.generates.item,
|
||||
generates_with: unspace(arena, header.generates_with.item.items),
|
||||
},
|
||||
module_comments: comments,
|
||||
header_imports: Some(header.imports),
|
||||
|
@ -4311,6 +4321,7 @@ impl<'a> BuildTask<'a> {
|
|||
declarations: Declarations,
|
||||
cached_subs: CachedTypeState,
|
||||
derived_module: SharedDerivedModule,
|
||||
exec_mode: ExecutionMode,
|
||||
|
||||
#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
|
||||
) -> Self {
|
||||
|
@ -4334,6 +4345,7 @@ impl<'a> BuildTask<'a> {
|
|||
module_timing,
|
||||
cached_subs,
|
||||
derived_module,
|
||||
exec_mode,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
|
@ -4618,6 +4630,7 @@ struct SolveResult {
|
|||
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||
problems: Vec<TypeError>,
|
||||
abilities_store: AbilitiesStore,
|
||||
imported_modules_with_params: Vec<ModuleId>,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: Option<roc_checkmate::Collector>,
|
||||
|
@ -4642,7 +4655,7 @@ fn run_solve_solve(
|
|||
aliases,
|
||||
rigid_variables,
|
||||
abilities_store: pending_abilities,
|
||||
params_pattern,
|
||||
module_params,
|
||||
..
|
||||
} = module;
|
||||
|
||||
|
@ -4663,6 +4676,11 @@ fn run_solve_solve(
|
|||
&mut imported_flex_vars,
|
||||
);
|
||||
|
||||
let imported_modules_with_params = imported_param_vars
|
||||
.keys()
|
||||
.copied()
|
||||
.collect::<Vec<ModuleId>>();
|
||||
|
||||
let actual_constraint = constraints.let_import_constraint(
|
||||
imported_rigid_vars,
|
||||
imported_flex_vars,
|
||||
|
@ -4690,7 +4708,7 @@ fn run_solve_solve(
|
|||
derived_module,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
params_pattern: params_pattern.map(|(_, _, pattern)| pattern.value),
|
||||
module_params,
|
||||
module_params_vars: imported_param_vars,
|
||||
};
|
||||
|
||||
|
@ -4745,6 +4763,7 @@ fn run_solve_solve(
|
|||
exposed_vars_by_symbol,
|
||||
problems: errors,
|
||||
abilities_store: resolved_abilities_store,
|
||||
imported_modules_with_params,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
|
@ -4766,6 +4785,7 @@ fn run_solve<'a>(
|
|||
dep_idents: IdentIdsByModule,
|
||||
cached_types: CachedTypeState,
|
||||
derived_module: SharedDerivedModule,
|
||||
exec_mode: ExecutionMode,
|
||||
|
||||
#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
|
||||
) -> Msg<'a> {
|
||||
|
@ -4776,10 +4796,8 @@ fn run_solve<'a>(
|
|||
// TODO remove when we write builtins in roc
|
||||
let aliases = module.aliases.clone();
|
||||
|
||||
let opt_params_var = module
|
||||
.params_pattern
|
||||
.as_ref()
|
||||
.map(|(params_var, _, _)| *params_var);
|
||||
let opt_params_var = module.module_params.as_ref().map(|params| params.whole_var);
|
||||
let home_has_params = opt_params_var.is_some();
|
||||
|
||||
let mut module = module;
|
||||
let loc_expects = std::mem::take(&mut module.loc_expects);
|
||||
|
@ -4814,6 +4832,7 @@ fn run_solve<'a>(
|
|||
exposed_vars_by_symbol,
|
||||
problems: vec![],
|
||||
abilities_store: abilities,
|
||||
imported_modules_with_params: vec![],
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: None,
|
||||
|
@ -4841,8 +4860,9 @@ fn run_solve<'a>(
|
|||
solved: mut solved_subs,
|
||||
solved_implementations,
|
||||
exposed_vars_by_symbol,
|
||||
problems,
|
||||
mut problems,
|
||||
abilities_store,
|
||||
imported_modules_with_params,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
|
@ -4857,6 +4877,20 @@ fn run_solve<'a>(
|
|||
&abilities_store,
|
||||
);
|
||||
|
||||
match exec_mode {
|
||||
ExecutionMode::Check => {
|
||||
// Params are not lowered in check mode
|
||||
}
|
||||
ExecutionMode::Executable | ExecutionMode::ExecutableIfCheck | ExecutionMode::Test => {
|
||||
roc_lower_params::type_error::remove_module_param_arguments(
|
||||
&mut problems,
|
||||
home_has_params,
|
||||
&decls.symbols,
|
||||
imported_modules_with_params,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let solved_module = SolvedModule {
|
||||
exposed_vars_by_symbol,
|
||||
problems,
|
||||
|
@ -5006,6 +5040,8 @@ fn canonicalize_and_constrain<'a>(
|
|||
parsed: ParsedModule<'a>,
|
||||
skip_constraint_gen: bool,
|
||||
exposed_module_ids: &[ModuleId],
|
||||
exec_mode: ExecutionMode,
|
||||
imported_module_params: VecMap<ModuleId, ModuleParams>,
|
||||
) -> CanAndCon {
|
||||
let canonicalize_start = Instant::now();
|
||||
|
||||
|
@ -5032,7 +5068,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
|
||||
let mut var_store = VarStore::default();
|
||||
|
||||
let module_output = canonicalize_module_defs(
|
||||
let mut module_output = canonicalize_module_defs(
|
||||
arena,
|
||||
parsed_defs,
|
||||
&header_type,
|
||||
|
@ -5091,6 +5127,26 @@ fn canonicalize_and_constrain<'a>(
|
|||
// _before has an underscore because it's unused in --release builds
|
||||
let _before = roc_types::types::get_type_clone_count();
|
||||
|
||||
match exec_mode {
|
||||
ExecutionMode::Check => {
|
||||
// No need to lower params for `roc check` and lang server
|
||||
// If we did, we'd have to update the language server to exclude the extra arguments
|
||||
}
|
||||
ExecutionMode::Executable | ExecutionMode::ExecutableIfCheck | ExecutionMode::Test => {
|
||||
// We need to lower params only if the current module has any or imports at least one with params
|
||||
if module_output.module_params.is_some() || !imported_module_params.is_empty() {
|
||||
roc_lower_params::lower::lower(
|
||||
module_id,
|
||||
&module_output.module_params,
|
||||
imported_module_params,
|
||||
&mut module_output.declarations,
|
||||
&mut module_output.scope.locals.ident_ids,
|
||||
&mut var_store,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut constraints = Constraints::new();
|
||||
|
||||
let constraint = if skip_constraint_gen {
|
||||
|
@ -5102,7 +5158,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
module_output.symbols_from_requires,
|
||||
&module_output.scope.abilities_store,
|
||||
&module_output.declarations,
|
||||
&module_output.params_pattern,
|
||||
&module_output.module_params,
|
||||
module_id,
|
||||
)
|
||||
};
|
||||
|
@ -5140,6 +5196,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
| ModuleId::SET
|
||||
| ModuleId::HASH
|
||||
| ModuleId::INSPECT
|
||||
| ModuleId::TASK
|
||||
);
|
||||
|
||||
if !name.is_builtin() || should_include_builtin {
|
||||
|
@ -5159,7 +5216,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
abilities_store: module_output.scope.abilities_store,
|
||||
loc_expects: module_output.loc_expects,
|
||||
loc_dbgs: module_output.loc_dbgs,
|
||||
params_pattern: module_output.params_pattern,
|
||||
module_params: module_output.module_params,
|
||||
};
|
||||
|
||||
let constrained_module = ConstrainedModule {
|
||||
|
@ -6209,6 +6266,8 @@ fn run_task<'a>(
|
|||
abilities_store,
|
||||
skip_constraint_gen,
|
||||
exposed_module_ids,
|
||||
exec_mode,
|
||||
imported_module_params,
|
||||
} => {
|
||||
let can_and_con = canonicalize_and_constrain(
|
||||
arena,
|
||||
|
@ -6220,6 +6279,8 @@ fn run_task<'a>(
|
|||
parsed,
|
||||
skip_constraint_gen,
|
||||
exposed_module_ids,
|
||||
exec_mode,
|
||||
imported_module_params,
|
||||
);
|
||||
|
||||
Ok(Msg::CanonicalizedAndConstrained(can_and_con))
|
||||
|
@ -6239,6 +6300,7 @@ fn run_task<'a>(
|
|||
dep_idents,
|
||||
cached_subs,
|
||||
derived_module,
|
||||
exec_mode,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
|
@ -6257,6 +6319,7 @@ fn run_task<'a>(
|
|||
dep_idents,
|
||||
cached_subs,
|
||||
derived_module,
|
||||
exec_mode,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
|
|
|
@ -25,4 +25,5 @@ pub const BUILTIN_MODULES: &[(ModuleId, &str)] = &[
|
|||
(ModuleId::DECODE, "Decode"),
|
||||
(ModuleId::HASH, "Hash"),
|
||||
(ModuleId::INSPECT, "Inspect"),
|
||||
(ModuleId::TASK, "Task"),
|
||||
];
|
||||
|
|
|
@ -4,13 +4,13 @@ use crate::module::{
|
|||
ModuleHeader, ParsedModule, TypeCheckedModule,
|
||||
};
|
||||
use roc_can::abilities::PendingAbilitiesStore;
|
||||
use roc_can::expr::AnnotatedMark;
|
||||
use roc_can::module::ModuleParams;
|
||||
use roc_collections::{MutMap, MutSet, VecMap};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{ModuleId, PQModuleName, Symbol};
|
||||
use roc_mono::ir::ExternalSpecializations;
|
||||
use roc_problem::Severity;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_region::all::Region;
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_types::subs::Variable;
|
||||
use roc_types::types::Alias;
|
||||
|
@ -27,8 +27,7 @@ pub(crate) struct ModuleCache<'a> {
|
|||
pub(crate) aliases: MutMap<ModuleId, MutMap<Symbol, (bool, Alias)>>,
|
||||
pub(crate) pending_abilities: MutMap<ModuleId, PendingAbilitiesStore>,
|
||||
pub(crate) constrained: MutMap<ModuleId, ConstrainedModule>,
|
||||
pub(crate) param_patterns:
|
||||
MutMap<ModuleId, (Variable, AnnotatedMark, Loc<roc_can::pattern::Pattern>)>,
|
||||
pub(crate) module_params: MutMap<ModuleId, ModuleParams>,
|
||||
pub(crate) typechecked: MutMap<ModuleId, TypeCheckedModule<'a>>,
|
||||
pub(crate) checked: MutMap<ModuleId, CheckedModule>,
|
||||
pub(crate) found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
||||
|
@ -94,6 +93,7 @@ impl Default for ModuleCache<'_> {
|
|||
DECODE,
|
||||
HASH,
|
||||
INSPECT,
|
||||
TASK,
|
||||
}
|
||||
|
||||
Self {
|
||||
|
@ -103,7 +103,7 @@ impl Default for ModuleCache<'_> {
|
|||
aliases: Default::default(),
|
||||
pending_abilities: Default::default(),
|
||||
constrained: Default::default(),
|
||||
param_patterns: Default::default(),
|
||||
module_params: Default::default(),
|
||||
typechecked: Default::default(),
|
||||
checked: Default::default(),
|
||||
found_specializations: Default::default(),
|
||||
|
|
|
@ -2151,7 +2151,7 @@ fn roc_file_no_extension() {
|
|||
indoc!(
|
||||
r#"
|
||||
app "helloWorld"
|
||||
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.14.0/dC5ceT962N_4jmoyoffVdphJ_4GlW3YMhAPyGPr-nU0.tar.br" }
|
||||
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br" }
|
||||
imports [pf.Stdout]
|
||||
provides [main] to pf
|
||||
|
||||
|
|
18
crates/compiler/lower_params/Cargo.toml
Normal file
18
crates/compiler/lower_params/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "roc_lower_params"
|
||||
description = "Lowers module params by extending functions and their calls"
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
roc_can = { path = "../can" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_solve_problem = { path = "../solve_problem" }
|
||||
|
||||
bumpalo.workspace = true
|
2
crates/compiler/lower_params/src/lib.rs
Normal file
2
crates/compiler/lower_params/src/lib.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod lower;
|
||||
pub mod type_error;
|
566
crates/compiler/lower_params/src/lower.rs
Normal file
566
crates/compiler/lower_params/src/lower.rs
Normal file
|
@ -0,0 +1,566 @@
|
|||
use roc_can::{
|
||||
expr::{
|
||||
AnnotatedMark, ClosureData,
|
||||
DeclarationTag::*,
|
||||
Declarations,
|
||||
Expr::{self, *},
|
||||
},
|
||||
module::ModuleParams,
|
||||
pattern::{Pattern, RecordDestruct},
|
||||
};
|
||||
use roc_collections::VecMap;
|
||||
use roc_module::symbol::{IdentId, IdentIds, ModuleId, Symbol};
|
||||
use roc_region::all::Loc;
|
||||
use roc_types::{
|
||||
subs::{VarStore, Variable},
|
||||
types::Type,
|
||||
};
|
||||
use std::iter::once;
|
||||
|
||||
struct LowerParams<'a> {
|
||||
home_id: ModuleId,
|
||||
home_params: &'a Option<ModuleParams>,
|
||||
imported_params: VecMap<ModuleId, ModuleParams>,
|
||||
var_store: &'a mut VarStore,
|
||||
ident_ids: &'a mut IdentIds,
|
||||
top_level_idents: Vec<IdentId>,
|
||||
}
|
||||
|
||||
pub fn lower(
|
||||
home_id: ModuleId,
|
||||
home_params: &Option<ModuleParams>,
|
||||
imported_params: VecMap<ModuleId, ModuleParams>,
|
||||
decls: &mut Declarations,
|
||||
ident_ids: &mut IdentIds,
|
||||
var_store: &mut VarStore,
|
||||
) {
|
||||
let top_level_idents = decls
|
||||
.symbols
|
||||
.iter()
|
||||
.map(|symbol| symbol.value.ident_id())
|
||||
.collect();
|
||||
|
||||
let mut env = LowerParams {
|
||||
home_id,
|
||||
home_params,
|
||||
imported_params,
|
||||
ident_ids,
|
||||
var_store,
|
||||
top_level_idents,
|
||||
};
|
||||
|
||||
env.lower_decls(decls);
|
||||
}
|
||||
|
||||
impl<'a> LowerParams<'a> {
|
||||
fn lower_decls(&mut self, decls: &mut Declarations) {
|
||||
let home_param_symbols = match self.home_params {
|
||||
Some(params) => params
|
||||
.destructs
|
||||
.iter()
|
||||
.map(|destruct| destruct.value.symbol)
|
||||
.chain(once(params.whole_symbol))
|
||||
.collect::<Vec<Symbol>>(),
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
for index in 0..decls.len() {
|
||||
let tag = decls.declarations[index];
|
||||
|
||||
match tag {
|
||||
Value => {
|
||||
self.lower_expr(&mut decls.expressions[index].value);
|
||||
|
||||
if let Some(new_arg) = self.home_params_argument() {
|
||||
// This module has params, and this is a top-level value,
|
||||
// so we need to convert it into a function that takes them.
|
||||
|
||||
decls.convert_value_to_function(index, vec![new_arg], self.var_store);
|
||||
}
|
||||
}
|
||||
Function(fn_def_index) | Recursive(fn_def_index) | TailRecursive(fn_def_index) => {
|
||||
if let Some((var, mark, pattern)) = self.home_params_argument() {
|
||||
// This module has params, and this is a top-level function,
|
||||
// so we need to extend its definition to take them.
|
||||
|
||||
let function_body = &mut decls.function_bodies[fn_def_index.index()].value;
|
||||
function_body.arguments.push((var, mark, pattern));
|
||||
|
||||
// Remove home params from the captured symbols, only nested lambdas need them.
|
||||
function_body
|
||||
.captured_symbols
|
||||
.retain(|(sym, _)| !home_param_symbols.contains(sym));
|
||||
|
||||
if let Some(ann) = &mut decls.annotations[index] {
|
||||
if let Type::Function(args, _, _) = &mut ann.signature {
|
||||
args.push(Type::Variable(var));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.lower_expr(&mut decls.expressions[index].value);
|
||||
}
|
||||
|
||||
Destructure(_) | Expectation | ExpectationFx => {
|
||||
self.lower_expr(&mut decls.expressions[index].value);
|
||||
}
|
||||
MutualRecursion { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_expr(&mut self, expr: &mut Expr) {
|
||||
let mut expr_stack = vec![expr];
|
||||
|
||||
while let Some(expr) = expr_stack.pop() {
|
||||
match expr {
|
||||
// Nodes to lower
|
||||
ParamsVar {
|
||||
symbol,
|
||||
var,
|
||||
params_symbol,
|
||||
params_var,
|
||||
} => {
|
||||
// The module was imported with params, but it might not actually expect them.
|
||||
// We should only lower if it does to prevent confusing type errors.
|
||||
if let Some(arity) = self.get_imported_def_arity(symbol) {
|
||||
*expr = self.lower_naked_params_var(
|
||||
arity,
|
||||
*symbol,
|
||||
*var,
|
||||
*params_symbol,
|
||||
*params_var,
|
||||
);
|
||||
}
|
||||
}
|
||||
Var(symbol, var) => {
|
||||
if let Some((params, arity)) = self.params_extended_home_symbol(symbol) {
|
||||
*expr = self.lower_naked_params_var(
|
||||
arity,
|
||||
*symbol,
|
||||
*var,
|
||||
params.whole_symbol,
|
||||
params.whole_var,
|
||||
);
|
||||
}
|
||||
}
|
||||
Call(fun, args, _called_via) => {
|
||||
expr_stack.reserve(args.len() + 1);
|
||||
|
||||
match fun.1.value {
|
||||
ParamsVar {
|
||||
symbol,
|
||||
var,
|
||||
params_var,
|
||||
params_symbol,
|
||||
} => {
|
||||
// Calling an imported function with params
|
||||
|
||||
match self.get_imported_def_arity(&symbol) {
|
||||
Some(0) => {
|
||||
// We are calling a function but the top-level declaration has no arguments.
|
||||
// This can either be a function alias or a top-level def that returns functions
|
||||
// under multiple branches.
|
||||
// We call the value def with params, and apply the returned function to the original arguments.
|
||||
fun.1.value = self.call_value_def_with_params(
|
||||
symbol,
|
||||
var,
|
||||
params_symbol,
|
||||
params_var,
|
||||
);
|
||||
}
|
||||
Some(_) => {
|
||||
// The module expects params and they were provided, we need to extend the call.
|
||||
fun.1.value = Var(symbol, var);
|
||||
|
||||
args.push((
|
||||
params_var,
|
||||
Loc::at_zero(Var(params_symbol, params_var)),
|
||||
));
|
||||
}
|
||||
None => {
|
||||
// The module expects no params, do not extend to prevent confusing type errors.
|
||||
fun.1.value = Var(symbol, var);
|
||||
}
|
||||
}
|
||||
}
|
||||
Var(symbol, var) => {
|
||||
if let Some((params, arity)) = self.params_extended_home_symbol(&symbol)
|
||||
{
|
||||
if arity == 0 {
|
||||
// Calling the result of a top-level value def in the current module
|
||||
fun.1.value = self.call_value_def_with_params(
|
||||
symbol,
|
||||
var,
|
||||
params.whole_symbol,
|
||||
params.whole_var,
|
||||
);
|
||||
} else {
|
||||
// Calling a top-level function in the current module with params
|
||||
args.push((
|
||||
params.whole_var,
|
||||
Loc::at_zero(Var(params.whole_symbol, params.whole_var)),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => expr_stack.push(&mut fun.1.value),
|
||||
}
|
||||
|
||||
for (_, arg) in args.iter_mut() {
|
||||
expr_stack.push(&mut arg.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes to walk
|
||||
Closure(ClosureData {
|
||||
loc_body,
|
||||
captured_symbols: _,
|
||||
name: _,
|
||||
function_type: _,
|
||||
closure_type: _,
|
||||
return_type: _,
|
||||
recursive: _,
|
||||
arguments: _,
|
||||
}) => {
|
||||
expr_stack.push(&mut loc_body.value);
|
||||
}
|
||||
|
||||
LetNonRec(def, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&mut def.loc_expr.value);
|
||||
expr_stack.push(&mut cont.value);
|
||||
}
|
||||
|
||||
LetRec(defs, cont, _cycle_mark) => {
|
||||
expr_stack.reserve(defs.len() + 1);
|
||||
|
||||
for def in defs {
|
||||
expr_stack.push(&mut def.loc_expr.value);
|
||||
}
|
||||
|
||||
expr_stack.push(&mut cont.value);
|
||||
}
|
||||
When {
|
||||
loc_cond,
|
||||
branches,
|
||||
cond_var: _,
|
||||
expr_var: _,
|
||||
region: _,
|
||||
branches_cond_var: _,
|
||||
exhaustive: _,
|
||||
} => {
|
||||
expr_stack.reserve(branches.len() + 1);
|
||||
expr_stack.push(&mut loc_cond.value);
|
||||
|
||||
for branch in branches.iter_mut() {
|
||||
expr_stack.push(&mut branch.value.value);
|
||||
}
|
||||
}
|
||||
If {
|
||||
branches,
|
||||
final_else,
|
||||
cond_var: _,
|
||||
branch_var: _,
|
||||
} => {
|
||||
expr_stack.reserve(branches.len() * 2 + 1);
|
||||
|
||||
for (cond, ret) in branches.iter_mut() {
|
||||
expr_stack.push(&mut cond.value);
|
||||
expr_stack.push(&mut ret.value);
|
||||
}
|
||||
|
||||
expr_stack.push(&mut final_else.value);
|
||||
}
|
||||
RunLowLevel {
|
||||
args,
|
||||
op: _,
|
||||
ret_var: _,
|
||||
}
|
||||
| ForeignCall {
|
||||
foreign_symbol: _,
|
||||
args,
|
||||
ret_var: _,
|
||||
} => {
|
||||
expr_stack.extend(args.iter_mut().map(|(_, arg)| arg));
|
||||
}
|
||||
List {
|
||||
elem_var: _,
|
||||
loc_elems,
|
||||
} => {
|
||||
expr_stack.extend(loc_elems.iter_mut().map(|loc_elem| &mut loc_elem.value));
|
||||
}
|
||||
Record {
|
||||
record_var: _,
|
||||
fields,
|
||||
} => {
|
||||
expr_stack.extend(
|
||||
fields
|
||||
.iter_mut()
|
||||
.map(|(_, field)| &mut field.loc_expr.value),
|
||||
);
|
||||
}
|
||||
Tuple {
|
||||
tuple_var: _,
|
||||
elems,
|
||||
} => {
|
||||
expr_stack.extend(elems.iter_mut().map(|(_, elem)| &mut elem.value));
|
||||
}
|
||||
ImportParams(_, _, Some((_, params_expr))) => {
|
||||
expr_stack.push(params_expr);
|
||||
}
|
||||
Crash { msg, ret_var: _ } => {
|
||||
expr_stack.push(&mut msg.value);
|
||||
}
|
||||
RecordAccess {
|
||||
loc_expr,
|
||||
record_var: _,
|
||||
ext_var: _,
|
||||
field_var: _,
|
||||
field: _,
|
||||
} => expr_stack.push(&mut loc_expr.value),
|
||||
TupleAccess {
|
||||
loc_expr,
|
||||
tuple_var: _,
|
||||
ext_var: _,
|
||||
elem_var: _,
|
||||
index: _,
|
||||
} => expr_stack.push(&mut loc_expr.value),
|
||||
RecordUpdate {
|
||||
updates,
|
||||
record_var: _,
|
||||
ext_var: _,
|
||||
symbol: _,
|
||||
} => expr_stack.extend(
|
||||
updates
|
||||
.iter_mut()
|
||||
.map(|(_, field)| &mut field.loc_expr.value),
|
||||
),
|
||||
Tag {
|
||||
arguments,
|
||||
tag_union_var: _,
|
||||
ext_var: _,
|
||||
name: _,
|
||||
} => expr_stack.extend(arguments.iter_mut().map(|(_, arg)| &mut arg.value)),
|
||||
OpaqueRef {
|
||||
argument,
|
||||
opaque_var: _,
|
||||
name: _,
|
||||
specialized_def_type: _,
|
||||
type_arguments: _,
|
||||
lambda_set_variables: _,
|
||||
} => expr_stack.push(&mut argument.1.value),
|
||||
Expect {
|
||||
loc_condition,
|
||||
loc_continuation,
|
||||
lookups_in_cond: _,
|
||||
} => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&mut loc_condition.value);
|
||||
expr_stack.push(&mut loc_continuation.value);
|
||||
}
|
||||
ExpectFx {
|
||||
loc_condition,
|
||||
loc_continuation,
|
||||
lookups_in_cond: _,
|
||||
} => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&mut loc_condition.value);
|
||||
expr_stack.push(&mut loc_continuation.value);
|
||||
}
|
||||
Dbg {
|
||||
loc_message,
|
||||
loc_continuation,
|
||||
source_location: _,
|
||||
source: _,
|
||||
variable: _,
|
||||
symbol: _,
|
||||
} => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&mut loc_message.value);
|
||||
expr_stack.push(&mut loc_continuation.value);
|
||||
}
|
||||
RecordAccessor(_)
|
||||
| ImportParams(_, _, None)
|
||||
| ZeroArgumentTag {
|
||||
closure_name: _,
|
||||
variant_var: _,
|
||||
ext_var: _,
|
||||
name: _,
|
||||
}
|
||||
| OpaqueWrapFunction(_)
|
||||
| EmptyRecord
|
||||
| TypedHole(_)
|
||||
| RuntimeError(_)
|
||||
| Num(_, _, _, _)
|
||||
| Int(_, _, _, _, _)
|
||||
| Float(_, _, _, _, _)
|
||||
| Str(_)
|
||||
| SingleQuote(_, _, _, _)
|
||||
| IngestedFile(_, _, _)
|
||||
| AbilityMember(_, _, _) => { /* terminal */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unique_symbol(&mut self) -> Symbol {
|
||||
Symbol::new(self.home_id, self.ident_ids.gen_unique())
|
||||
}
|
||||
|
||||
fn home_params_argument(&mut self) -> Option<(Variable, AnnotatedMark, Loc<Pattern>)> {
|
||||
match &self.home_params {
|
||||
Some(module_params) => {
|
||||
let destructs: Vec<Loc<RecordDestruct>> = module_params
|
||||
.destructs
|
||||
.iter()
|
||||
.map(|destructure| {
|
||||
destructure.map(|d| RecordDestruct {
|
||||
symbol: d.symbol,
|
||||
var: self.var_store.fresh(),
|
||||
label: d.label.clone(),
|
||||
typ: d.typ.clone(),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let record_pattern = Pattern::RecordDestructure {
|
||||
whole_var: module_params.record_var,
|
||||
ext_var: module_params.record_ext_var,
|
||||
destructs,
|
||||
};
|
||||
let loc_record_pattern = Loc::at(module_params.region, record_pattern);
|
||||
let as_pattern =
|
||||
Pattern::As(Box::new(loc_record_pattern), module_params.whole_symbol);
|
||||
let loc_pattern = Loc::at(module_params.region, as_pattern);
|
||||
|
||||
Some((
|
||||
self.var_store.fresh(),
|
||||
AnnotatedMark::new(self.var_store),
|
||||
loc_pattern,
|
||||
))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn params_extended_home_symbol(&self, symbol: &Symbol) -> Option<(&ModuleParams, usize)> {
|
||||
if symbol.module_id() == self.home_id {
|
||||
self.home_params.as_ref().and_then(|params| {
|
||||
params
|
||||
.arity_by_name
|
||||
.get(&symbol.ident_id())
|
||||
.map(|arity| (params, *arity))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_imported_def_arity(&self, symbol: &Symbol) -> Option<usize> {
|
||||
self.imported_params
|
||||
.get(&symbol.module_id())
|
||||
.and_then(|params| params.arity_by_name.get(&symbol.ident_id()).copied())
|
||||
}
|
||||
|
||||
fn lower_naked_params_var(
|
||||
&mut self,
|
||||
arity: usize,
|
||||
symbol: Symbol,
|
||||
var: Variable,
|
||||
params_symbol: Symbol,
|
||||
params_var: Variable,
|
||||
) -> Expr {
|
||||
if arity == 0 {
|
||||
// We are passing a top-level value that takes params, so we need to replace the Var
|
||||
// with a call that passes the params to get the final result.
|
||||
//
|
||||
// value = \#params -> #params.x * 2
|
||||
// record = \... #params -> { doubled: value }
|
||||
// ↓
|
||||
// value #params
|
||||
self.call_value_def_with_params(symbol, var, params_symbol, params_var)
|
||||
} else {
|
||||
// We are passing a top-level function that takes params, so we need to replace
|
||||
// the Var with a closure that captures the params and passes them to the function.
|
||||
//
|
||||
// fn1 = \arg #params -> #params.x * arg
|
||||
// fn2 = \... #params -> List.map [1, 2] fn1
|
||||
// ↓
|
||||
// (\#1 -> fn1 #1 #params)
|
||||
//
|
||||
let mut arguments = Vec::with_capacity(arity);
|
||||
let mut call_arguments = Vec::with_capacity(arity + 1);
|
||||
|
||||
for _ in 0..arity {
|
||||
let sym = self.unique_symbol();
|
||||
let var = self.var_store.fresh();
|
||||
|
||||
arguments.push((
|
||||
var,
|
||||
AnnotatedMark::new(self.var_store),
|
||||
Loc::at_zero(Pattern::Identifier(sym)),
|
||||
));
|
||||
call_arguments.push((var, Loc::at_zero(Var(sym, var))));
|
||||
}
|
||||
|
||||
let params_arg = (params_var, Loc::at_zero(Var(params_symbol, params_var)));
|
||||
|
||||
call_arguments.push(params_arg);
|
||||
|
||||
let call_fn = Box::new((
|
||||
self.var_store.fresh(),
|
||||
Loc::at_zero(Var(symbol, var)),
|
||||
self.var_store.fresh(),
|
||||
self.var_store.fresh(),
|
||||
));
|
||||
|
||||
let body = Call(
|
||||
call_fn,
|
||||
call_arguments,
|
||||
roc_module::called_via::CalledVia::NakedParamsVar,
|
||||
);
|
||||
|
||||
let captured_symbols = if symbol.module_id() == self.home_id
|
||||
|| !self.top_level_idents.contains(¶ms_symbol.ident_id())
|
||||
{
|
||||
vec![(params_symbol, params_var)]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
Closure(ClosureData {
|
||||
function_type: self.var_store.fresh(),
|
||||
closure_type: self.var_store.fresh(),
|
||||
return_type: self.var_store.fresh(),
|
||||
name: self.unique_symbol(),
|
||||
captured_symbols,
|
||||
recursive: roc_can::expr::Recursive::NotRecursive,
|
||||
arguments,
|
||||
loc_body: Box::new(Loc::at_zero(body)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn call_value_def_with_params(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
var: Variable,
|
||||
params_symbol: Symbol,
|
||||
params_var: Variable,
|
||||
) -> Expr {
|
||||
let params_arg = (params_var, Loc::at_zero(Var(params_symbol, params_var)));
|
||||
|
||||
let call_fn = Box::new((
|
||||
self.var_store.fresh(),
|
||||
Loc::at_zero(Var(symbol, var)),
|
||||
self.var_store.fresh(),
|
||||
self.var_store.fresh(),
|
||||
));
|
||||
|
||||
Call(
|
||||
call_fn,
|
||||
vec![params_arg],
|
||||
roc_module::called_via::CalledVia::NakedParamsVar,
|
||||
)
|
||||
}
|
||||
}
|
208
crates/compiler/lower_params/src/type_error.rs
Normal file
208
crates/compiler/lower_params/src/type_error.rs
Normal file
|
@ -0,0 +1,208 @@
|
|||
use roc_can::{expected::Expected, pattern::Pattern};
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::Loc;
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_types::types::{ErrorType, Reason};
|
||||
|
||||
/// Removes the arguments added as a result of lowering params
|
||||
pub fn remove_module_param_arguments(
|
||||
errors: &mut Vec<TypeError>,
|
||||
home_has_params: bool,
|
||||
home_top_level_symbols: &[Loc<Symbol>],
|
||||
imported_modules_with_params: Vec<ModuleId>,
|
||||
) {
|
||||
if errors.is_empty() || (!home_has_params && imported_modules_with_params.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let home_top_level_symbols = if home_has_params {
|
||||
home_top_level_symbols
|
||||
.iter()
|
||||
.map(|loc| loc.value)
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let env = Env {
|
||||
home_top_level_symbols,
|
||||
imported_modules_with_params,
|
||||
};
|
||||
|
||||
for error in errors {
|
||||
match error {
|
||||
TypeError::BadExpr(_, _, found, Expected::ForReason(reason, expected, _)) => {
|
||||
remove_for_reason(&env, found, reason, expected);
|
||||
}
|
||||
|
||||
TypeError::BadExpr(
|
||||
_,
|
||||
_,
|
||||
found,
|
||||
Expected::FromAnnotation(
|
||||
Loc {
|
||||
value: Pattern::Identifier(name),
|
||||
region: _,
|
||||
},
|
||||
arity,
|
||||
_,
|
||||
expected,
|
||||
),
|
||||
) if env.is_extended(name) => {
|
||||
if *arity > 1 {
|
||||
*arity -= 1;
|
||||
}
|
||||
|
||||
drop_last_argument(found);
|
||||
drop_last_argument(expected);
|
||||
|
||||
if let (
|
||||
ErrorType::Function(found_args, _, _),
|
||||
ErrorType::Function(expected_args, _, _),
|
||||
) = (found, expected)
|
||||
{
|
||||
if found_args.len() > expected_args.len() {
|
||||
// If the found arity doesn't match the annotation's, the params
|
||||
// record would appear in the error, so we replace it with `?`.
|
||||
if let Some(last) = found_args.last_mut() {
|
||||
*last = ErrorType::Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypeError::BadExpr(_, _, _, Expected::FromAnnotation(_, _, _, _))
|
||||
| TypeError::BadExpr(_, _, _, Expected::NoExpectation(_)) => {}
|
||||
|
||||
// Irrelevant
|
||||
TypeError::BadPattern(_, _, _, _)
|
||||
| TypeError::CircularType(_, _, _)
|
||||
| TypeError::CircularDef(_)
|
||||
| TypeError::UnexposedLookup(_, _)
|
||||
| TypeError::UnfulfilledAbility(_)
|
||||
| TypeError::BadExprMissingAbility(_, _, _, _)
|
||||
| TypeError::BadPatternMissingAbility(_, _, _, _)
|
||||
| TypeError::Exhaustive(_)
|
||||
| TypeError::StructuralSpecialization {
|
||||
region: _,
|
||||
typ: _,
|
||||
ability: _,
|
||||
member: _,
|
||||
}
|
||||
| TypeError::WrongSpecialization {
|
||||
region: _,
|
||||
ability_member: _,
|
||||
expected_opaque: _,
|
||||
found_opaque: _,
|
||||
}
|
||||
| TypeError::IngestedFileBadUtf8(_, _)
|
||||
| TypeError::IngestedFileUnsupportedType(_, _)
|
||||
| TypeError::UnexpectedModuleParams(_, _)
|
||||
| TypeError::MissingModuleParams(_, _, _)
|
||||
| TypeError::ModuleParamsMismatch(_, _, _, _) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Env {
|
||||
home_top_level_symbols: Vec<Symbol>,
|
||||
imported_modules_with_params: Vec<ModuleId>,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
fn is_extended(&self, symbol: &Symbol) -> bool {
|
||||
self.home_top_level_symbols.contains(symbol)
|
||||
|| self
|
||||
.imported_modules_with_params
|
||||
.contains(&symbol.module_id())
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_for_reason(
|
||||
env: &Env,
|
||||
found_type: &mut ErrorType,
|
||||
reason: &mut Reason,
|
||||
expected_type: &mut ErrorType,
|
||||
) {
|
||||
match reason {
|
||||
Reason::FnCall {
|
||||
name: Some(name),
|
||||
arity,
|
||||
called_via: _,
|
||||
} if env.is_extended(name) => {
|
||||
*arity -= 1;
|
||||
debug_assert_ne!(0, *arity);
|
||||
|
||||
drop_last_argument(found_type);
|
||||
drop_last_argument(expected_type);
|
||||
}
|
||||
|
||||
Reason::FnCall { .. } => {}
|
||||
|
||||
Reason::FnArg { .. } | Reason::TypedArg { .. } => {
|
||||
// I believe these don't need to be touched because reporting only
|
||||
// shows the type of the arguments, not the whole function.
|
||||
}
|
||||
|
||||
// Irrelevant
|
||||
Reason::LowLevelOpArg {
|
||||
op: _,
|
||||
arg_index: _,
|
||||
}
|
||||
| Reason::ForeignCallArg {
|
||||
foreign_symbol: _,
|
||||
arg_index: _,
|
||||
}
|
||||
| Reason::FloatLiteral
|
||||
| Reason::IntLiteral
|
||||
| Reason::NumLiteral
|
||||
| Reason::StrInterpolation
|
||||
| Reason::WhenBranches
|
||||
| Reason::WhenBranch { index: _ }
|
||||
| Reason::WhenGuard
|
||||
| Reason::ExpectCondition
|
||||
| Reason::IfCondition
|
||||
| Reason::IfBranch {
|
||||
index: _,
|
||||
total_branches: _,
|
||||
}
|
||||
| Reason::ElemInList { index: _ }
|
||||
| Reason::RecordUpdateValue(_)
|
||||
| Reason::RecordUpdateKeys(_, _)
|
||||
| Reason::RecordDefaultField(_)
|
||||
| Reason::NumericLiteralSuffix
|
||||
| Reason::InvalidAbilityMemberSpecialization {
|
||||
member_name: _,
|
||||
def_region: _,
|
||||
unimplemented_abilities: _,
|
||||
}
|
||||
| Reason::GeneralizedAbilityMemberSpecialization {
|
||||
member_name: _,
|
||||
def_region: _,
|
||||
}
|
||||
| Reason::CrashArg
|
||||
| Reason::ImportParams(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_last_argument(err_type: &mut ErrorType) {
|
||||
match err_type {
|
||||
ErrorType::Function(arguments, _, _) => {
|
||||
arguments.pop();
|
||||
}
|
||||
// Irrelevant
|
||||
ErrorType::Infinite
|
||||
| ErrorType::Type(_, _)
|
||||
| ErrorType::FlexVar(_)
|
||||
| ErrorType::RigidVar(_)
|
||||
| ErrorType::FlexAbleVar(_, _)
|
||||
| ErrorType::RigidAbleVar(_, _)
|
||||
| ErrorType::Record(_, _)
|
||||
| ErrorType::Tuple(_, _)
|
||||
| ErrorType::TagUnion(_, _, _)
|
||||
| ErrorType::RecursiveTagUnion(_, _, _, _)
|
||||
| ErrorType::Alias(_, _, _, _)
|
||||
| ErrorType::Range(_)
|
||||
| ErrorType::Error => {}
|
||||
}
|
||||
}
|
|
@ -99,6 +99,9 @@ pub enum CalledVia {
|
|||
/// This call is the result of desugaring a Result.try from `?` syntax
|
||||
/// e.g. Dict.get? items "key" becomes Result.try (Dict.get items "key") \item -> ...
|
||||
QuestionSuffix,
|
||||
|
||||
/// This call is a result of lowering a reference to a module-params-extended def
|
||||
NakedParamsVar,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
|
|
@ -123,6 +123,10 @@ impl Symbol {
|
|||
.any(|(_, (s, _))| *s == self)
|
||||
}
|
||||
|
||||
pub fn is_generated(self, interns: &Interns) -> bool {
|
||||
self.ident_ids(interns).is_generated_id(self.ident_id())
|
||||
}
|
||||
|
||||
pub fn module_string<'a>(&self, interns: &'a Interns) -> &'a ModuleName {
|
||||
interns
|
||||
.module_ids
|
||||
|
@ -137,24 +141,15 @@ impl Symbol {
|
|||
}
|
||||
|
||||
pub fn as_str(self, interns: &Interns) -> &str {
|
||||
let ident_ids = interns
|
||||
.all_ident_ids
|
||||
.get(&self.module_id())
|
||||
self.ident_ids(interns)
|
||||
.get_name(self.ident_id())
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string could not find IdentIds for module {:?} in {:?}",
|
||||
self.module_id(),
|
||||
interns
|
||||
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
||||
self.ident_id().0,
|
||||
self.module_id()
|
||||
)
|
||||
});
|
||||
|
||||
ident_ids.get_name(self.ident_id()).unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
||||
self.ident_id().0,
|
||||
self.module_id()
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn as_u64(self) -> u64 {
|
||||
|
@ -186,6 +181,19 @@ impl Symbol {
|
|||
pub fn contains(self, needle: &str) -> bool {
|
||||
format!("{self:?}").contains(needle)
|
||||
}
|
||||
|
||||
fn ident_ids(self, interns: &Interns) -> &IdentIds {
|
||||
interns
|
||||
.all_ident_ids
|
||||
.get(&self.module_id())
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string could not find IdentIds for module {:?} in {:?}",
|
||||
self.module_id(),
|
||||
interns
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Rather than displaying as this:
|
||||
|
@ -707,6 +715,12 @@ impl IdentIds {
|
|||
IdentId(self.interner.insert_index_str() as u32)
|
||||
}
|
||||
|
||||
pub fn is_generated_id(&self, id: IdentId) -> bool {
|
||||
self.interner
|
||||
.try_get(id.0 as usize)
|
||||
.map_or(false, |str| str.starts_with(|c: char| c.is_ascii_digit()))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_id(&self, ident_name: &str) -> Option<IdentId> {
|
||||
self.interner
|
||||
|
@ -1666,6 +1680,23 @@ define_builtins! {
|
|||
32 INSPECT_TO_INSPECTOR: "toInspector"
|
||||
33 INSPECT_TO_STR: "toStr"
|
||||
}
|
||||
15 TASK: "Task" => {
|
||||
0 TASK_TASK: "Task" exposed_type=true // the Task.Task opaque type
|
||||
1 TASK_FOREVER: "forever"
|
||||
2 TASK_LOOP: "loop"
|
||||
3 TASK_OK: "ok"
|
||||
4 TASK_ERR: "err"
|
||||
5 TASK_ATTEMPT: "attempt"
|
||||
6 TASK_AWAIT: "await"
|
||||
7 TASK_ON_ERR: "onErr"
|
||||
8 TASK_MAP: "map"
|
||||
9 TASK_MAP_ERR: "mapErr"
|
||||
10 TASK_FROM_RESULT: "fromResult"
|
||||
11 TASK_BATCH: "batch"
|
||||
12 TASK_SEQUENCE: "sequence"
|
||||
13 TASK_FOR_EACH: "forEach"
|
||||
14 TASK_RESULT: "result"
|
||||
}
|
||||
|
||||
num_modules: 15 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
num_modules: 16 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
}
|
||||
|
|
|
@ -2870,7 +2870,6 @@ fn pattern_to_when(
|
|||
body: Loc<roc_can::expr::Expr>,
|
||||
) -> (Symbol, Loc<roc_can::expr::Expr>) {
|
||||
use roc_can::expr::Expr::*;
|
||||
use roc_can::expr::{WhenBranch, WhenBranchPattern};
|
||||
use roc_can::pattern::Pattern::{self, *};
|
||||
|
||||
match &pattern.value {
|
||||
|
@ -2888,7 +2887,7 @@ fn pattern_to_when(
|
|||
(*new_symbol, Loc::at_zero(RuntimeError(error)))
|
||||
}
|
||||
|
||||
As(_, _) => todo!("as bindings are not supported yet"),
|
||||
As(pattern, symbol) => pattern_to_when_help(pattern_var, pattern, body_var, body, *symbol),
|
||||
|
||||
UnsupportedPattern(region) => {
|
||||
// create the runtime error here, instead of delegating to When.
|
||||
|
@ -2915,28 +2914,7 @@ fn pattern_to_when(
|
|||
| TupleDestructure { .. }
|
||||
| UnwrappedOpaque { .. } => {
|
||||
let symbol = env.unique_symbol();
|
||||
|
||||
let wrapped_body = When {
|
||||
cond_var: pattern_var,
|
||||
expr_var: body_var,
|
||||
region: Region::zero(),
|
||||
loc_cond: Box::new(Loc::at_zero(Var(symbol, pattern_var))),
|
||||
branches: vec![WhenBranch {
|
||||
patterns: vec![WhenBranchPattern {
|
||||
pattern,
|
||||
degenerate: false,
|
||||
}],
|
||||
value: body,
|
||||
guard: None,
|
||||
// If this type-checked, it's non-redundant
|
||||
redundant: RedundantMark::known_non_redundant(),
|
||||
}],
|
||||
branches_cond_var: pattern_var,
|
||||
// If this type-checked, it's exhaustive
|
||||
exhaustive: ExhaustiveMark::known_exhaustive(),
|
||||
};
|
||||
|
||||
(symbol, Loc::at_zero(wrapped_body))
|
||||
pattern_to_when_help(pattern_var, &pattern, body_var, body, symbol)
|
||||
}
|
||||
|
||||
Pattern::List { .. } => todo!(),
|
||||
|
@ -2960,6 +2938,38 @@ fn pattern_to_when(
|
|||
}
|
||||
}
|
||||
|
||||
fn pattern_to_when_help(
|
||||
pattern_var: Variable,
|
||||
pattern: &Loc<roc_can::pattern::Pattern>,
|
||||
body_var: Variable,
|
||||
body: Loc<roc_can::expr::Expr>,
|
||||
symbol: Symbol,
|
||||
) -> (Symbol, Loc<roc_can::expr::Expr>) {
|
||||
use roc_can::expr::{Expr, WhenBranch, WhenBranchPattern};
|
||||
|
||||
let wrapped_body = Expr::When {
|
||||
cond_var: pattern_var,
|
||||
expr_var: body_var,
|
||||
region: Region::zero(),
|
||||
loc_cond: Box::new(Loc::at_zero(Expr::Var(symbol, pattern_var))),
|
||||
branches: vec![WhenBranch {
|
||||
patterns: vec![WhenBranchPattern {
|
||||
pattern: pattern.to_owned(),
|
||||
degenerate: false,
|
||||
}],
|
||||
value: body,
|
||||
guard: None,
|
||||
// If this type-checked, it's non-redundant
|
||||
redundant: RedundantMark::known_non_redundant(),
|
||||
}],
|
||||
branches_cond_var: pattern_var,
|
||||
// If this type-checked, it's exhaustive
|
||||
exhaustive: ExhaustiveMark::known_exhaustive(),
|
||||
};
|
||||
|
||||
(symbol, Loc::at_zero(wrapped_body))
|
||||
}
|
||||
|
||||
fn specialize_suspended<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
|
@ -4444,7 +4454,7 @@ pub fn with_hole<'a>(
|
|||
specialize_naked_symbol(env, variable, procs, layout_cache, assigned, hole, symbol)
|
||||
}
|
||||
ParamsVar { .. } => {
|
||||
unimplemented!("module params code generation")
|
||||
internal_error!("ParamsVar should've been lowered to Var")
|
||||
}
|
||||
ImportParams(_, _, Some((_, value))) => {
|
||||
with_hole(env, *value, variable, procs, layout_cache, assigned, hole)
|
||||
|
|
|
@ -497,7 +497,10 @@ pub enum Expr<'a> {
|
|||
|
||||
Backpassing(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
Expect(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
Dbg(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
Dbg,
|
||||
DbgStmt(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
// This form of debug is a desugared call to roc_dbg
|
||||
LowLevelDbg(&'a (&'a str, &'a str), &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
|
@ -663,9 +666,9 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::Tag(_) => false,
|
||||
Expr::OpaqueRef(_) => false,
|
||||
Expr::Backpassing(_, _, _) => false, // TODO: we might want to check this?
|
||||
Expr::Expect(a, b) | Expr::Dbg(a, b) => {
|
||||
is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value)
|
||||
}
|
||||
Expr::Expect(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::Dbg => false,
|
||||
Expr::DbgStmt(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::LowLevelDbg(_, a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::UnaryOp(a, _) => is_expr_suffixed(&a.value),
|
||||
Expr::When(cond, branches) => {
|
||||
|
@ -958,9 +961,17 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
expr_stack.push(&a.value);
|
||||
expr_stack.push(&b.value);
|
||||
}
|
||||
Expect(condition, cont)
|
||||
| Dbg(condition, cont)
|
||||
| LowLevelDbg(_, condition, cont) => {
|
||||
Expect(condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
}
|
||||
DbgStmt(condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
}
|
||||
LowLevelDbg(_, condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
|
@ -1032,6 +1043,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
| Var { .. }
|
||||
| Underscore(_)
|
||||
| Crash
|
||||
| Dbg
|
||||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| MalformedIdent(_, _)
|
||||
|
@ -2518,8 +2530,9 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Closure(args, body) => args.iter().any(|arg| arg.is_malformed()) || body.is_malformed(),
|
||||
Defs(defs, body) => defs.is_malformed() || body.is_malformed(),
|
||||
Backpassing(args, call, body) => args.iter().any(|arg| arg.is_malformed()) || call.is_malformed() || body.is_malformed(),
|
||||
Expect(condition, continuation) |
|
||||
Dbg(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Expect(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Dbg => false,
|
||||
DbgStmt(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
LowLevelDbg(_, condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()),
|
||||
BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(),
|
||||
|
|
|
@ -194,6 +194,7 @@ fn loc_term_or_underscore_or_conditional<'a>(
|
|||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(crash_kw()),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(underscore_expression()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
|
@ -215,6 +216,7 @@ fn loc_term_or_underscore<'a>(
|
|||
positive_number_literal_help()
|
||||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(underscore_expression()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
|
@ -232,6 +234,7 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EEx
|
|||
positive_number_literal_help()
|
||||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
ident_seq(),
|
||||
|
@ -541,7 +544,7 @@ fn stmt_start<'a>(
|
|||
)),
|
||||
loc(specialize_err(
|
||||
EExpr::Dbg,
|
||||
dbg_help(options, preceding_comment)
|
||||
dbg_stmt_help(options, preceding_comment)
|
||||
)),
|
||||
loc(specialize_err(EExpr::Import, map(import(), Stmt::ValueDef))),
|
||||
map(
|
||||
|
@ -2170,7 +2173,8 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::If(_, _)
|
||||
| Expr::When(_, _)
|
||||
| Expr::Expect(_, _)
|
||||
| Expr::Dbg(_, _)
|
||||
| Expr::Dbg
|
||||
| Expr::DbgStmt(_, _)
|
||||
| Expr::LowLevelDbg(_, _, _)
|
||||
| Expr::MalformedClosure
|
||||
| Expr::MalformedSuffixed(..)
|
||||
|
@ -2647,7 +2651,7 @@ fn expect_help<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn dbg_help<'a>(
|
||||
fn dbg_stmt_help<'a>(
|
||||
options: ExprParseOptions,
|
||||
preceding_comment: Region,
|
||||
) -> impl Parser<'a, Stmt<'a>, EExpect<'a>> {
|
||||
|
@ -2672,7 +2676,17 @@ fn dbg_help<'a>(
|
|||
|
||||
Ok((MadeProgress, stmt, state))
|
||||
})
|
||||
.trace("dbg_help")
|
||||
.trace("dbg_stmt_help")
|
||||
}
|
||||
|
||||
fn dbg_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
|
||||
(move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let (_, _, next_state) =
|
||||
parser::keyword(keyword::DBG, EExpect::Dbg).parse(arena, state, min_indent)?;
|
||||
|
||||
Ok((MadeProgress, Expr::Dbg, next_state))
|
||||
})
|
||||
.trace("dbg_kw")
|
||||
}
|
||||
|
||||
fn import<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>> {
|
||||
|
@ -2986,14 +3000,17 @@ fn stmts_to_expr<'a>(
|
|||
arena.alloc(e).before(space)
|
||||
}
|
||||
}
|
||||
Stmt::ValueDef(ValueDef::Dbg { .. }) => {
|
||||
return Err(EExpr::Dbg(
|
||||
EExpect::Continuation(
|
||||
arena.alloc(EExpr::IndentEnd(loc_stmt.region.end())),
|
||||
loc_stmt.region.end(),
|
||||
),
|
||||
loc_stmt.region.start(),
|
||||
));
|
||||
Stmt::ValueDef(ValueDef::Dbg { condition, .. }) => {
|
||||
// If we parse a `dbg` as the last thing in a series of statements then it's
|
||||
// actually an expression.
|
||||
Expr::Apply(
|
||||
arena.alloc(Loc {
|
||||
value: Expr::Dbg,
|
||||
region: loc_stmt.region,
|
||||
}),
|
||||
arena.alloc([condition]),
|
||||
CalledVia::Space,
|
||||
)
|
||||
}
|
||||
Stmt::ValueDef(ValueDef::Expect { .. }) => {
|
||||
return Err(EExpr::Expect(
|
||||
|
@ -3145,13 +3162,19 @@ fn stmts_to_defs<'a>(
|
|||
} = vd
|
||||
{
|
||||
if exprify_dbg {
|
||||
if i + 1 >= stmts.len() {
|
||||
return Err(EExpr::DbgContinue(sp_stmt.item.region.end()));
|
||||
}
|
||||
|
||||
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
|
||||
|
||||
let e = Expr::Dbg(arena.alloc(condition), arena.alloc(rest));
|
||||
let e = if i + 1 < stmts.len() {
|
||||
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
|
||||
Expr::DbgStmt(arena.alloc(condition), arena.alloc(rest))
|
||||
} else {
|
||||
Expr::Apply(
|
||||
arena.alloc(Loc {
|
||||
value: Expr::Dbg,
|
||||
region: sp_stmt.item.region,
|
||||
}),
|
||||
arena.alloc([condition]),
|
||||
CalledVia::Space,
|
||||
)
|
||||
};
|
||||
|
||||
let e = if sp_stmt.before.is_empty() {
|
||||
e
|
||||
|
|
|
@ -6,20 +6,20 @@ use crate::ast::{
|
|||
};
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::expr::merge_spaces;
|
||||
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
|
||||
use crate::ident::{self, lowercase_ident, unqualified_ident, UppercaseIdent};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map,
|
||||
map_with_arena, optional, reset_min_indent, skip_first, skip_second, specialize_err, succeed,
|
||||
then, two_bytes, zero_or_more, EExposes, EGenerates, EGeneratesWith, EHeader, EImports,
|
||||
EPackageEntry, EPackageName, EPackages, EParams, EProvides, ERequires, ETypedIdent, Parser,
|
||||
SourceError, SpaceProblem, SyntaxError,
|
||||
then, two_bytes, zero_or_more, EExposes, EHeader, EImports, EPackageEntry, EPackageName,
|
||||
EPackages, EParams, EProvides, ERequires, ETypedIdent, Parser, SourceError, SpaceProblem,
|
||||
SyntaxError,
|
||||
};
|
||||
use crate::pattern::record_pattern_fields;
|
||||
use crate::state::State;
|
||||
use crate::string_literal::{self, parse_str_literal};
|
||||
use crate::type_annotation;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_module::symbol::ModuleId;
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
||||
|
@ -188,8 +188,6 @@ fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
|
|||
name: loc(module_name_help(EHeader::ModuleName)),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_values_kw()),
|
||||
imports: specialize_err(EHeader::Imports, imports()),
|
||||
generates: specialize_err(EHeader::Generates, generates()),
|
||||
generates_with: specialize_err(EHeader::GeneratesWith, generates_with()),
|
||||
})
|
||||
.trace("hosted_header")
|
||||
}
|
||||
|
@ -761,43 +759,6 @@ fn packages_collection<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn generates<'a>(
|
||||
) -> impl Parser<'a, KeywordItem<'a, GeneratesKeyword, UppercaseIdent<'a>>, EGenerates> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
GeneratesKeyword,
|
||||
EGenerates::Generates,
|
||||
EGenerates::IndentGenerates,
|
||||
EGenerates::IndentTypeStart
|
||||
),
|
||||
item: specialize_err(|(), pos| EGenerates::Identifier(pos), uppercase())
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn generates_with<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, WithKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
EGeneratesWith,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
WithKeyword,
|
||||
EGeneratesWith::With,
|
||||
EGeneratesWith::IndentWith,
|
||||
EGeneratesWith::IndentListStart
|
||||
),
|
||||
item: collection_trailing_sep_e(
|
||||
byte(b'[', EGeneratesWith::ListStart),
|
||||
exposes_entry(EGeneratesWith::Identifier),
|
||||
byte(b',', EGeneratesWith::ListEnd),
|
||||
byte(b']', EGeneratesWith::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn imports<'a>() -> impl Parser<
|
||||
'a,
|
||||
|
@ -977,14 +938,11 @@ pub enum HeaderType<'a> {
|
|||
Hosted {
|
||||
name: ModuleName<'a>,
|
||||
exposes: &'a [Loc<ExposedName<'a>>],
|
||||
generates: UppercaseIdent<'a>,
|
||||
generates_with: &'a [Loc<ExposedName<'a>>],
|
||||
},
|
||||
/// Only created during canonicalization, never actually parsed from source
|
||||
Builtin {
|
||||
name: ModuleName<'a>,
|
||||
exposes: &'a [Loc<ExposedName<'a>>],
|
||||
generates_with: &'a [Symbol],
|
||||
opt_params: Option<ModuleParams<'a>>,
|
||||
},
|
||||
Package {
|
||||
|
@ -1045,7 +1003,6 @@ impl<'a> HeaderType<'a> {
|
|||
opt_params,
|
||||
name: _,
|
||||
exposes: _,
|
||||
generates_with: _,
|
||||
} => opt_params,
|
||||
Self::App {
|
||||
provides: _,
|
||||
|
@ -1059,8 +1016,6 @@ impl<'a> HeaderType<'a> {
|
|||
| Self::Hosted {
|
||||
name: _,
|
||||
exposes: _,
|
||||
generates: _,
|
||||
generates_with: _,
|
||||
}
|
||||
| Self::Platform {
|
||||
opt_app_module_id: _,
|
||||
|
@ -1083,7 +1038,6 @@ impl<'a> HeaderType<'a> {
|
|||
} if module_id.is_builtin() => HeaderType::Builtin {
|
||||
name,
|
||||
exposes,
|
||||
generates_with: &[],
|
||||
opt_params,
|
||||
},
|
||||
_ => self,
|
||||
|
@ -1202,8 +1156,6 @@ macro_rules! keywords {
|
|||
|
||||
keywords! {
|
||||
ExposesKeyword => "exposes",
|
||||
WithKeyword => "with",
|
||||
GeneratesKeyword => "generates",
|
||||
PackageKeyword => "package",
|
||||
PackagesKeyword => "packages",
|
||||
RequiresKeyword => "requires",
|
||||
|
@ -1247,10 +1199,6 @@ pub struct HostedHeader<'a> {
|
|||
pub exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
|
||||
pub imports: KeywordItem<'a, ImportsKeyword, Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>>,
|
||||
|
||||
pub generates: KeywordItem<'a, GeneratesKeyword, UppercaseIdent<'a>>,
|
||||
pub generates_with:
|
||||
KeywordItem<'a, WithKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -1329,7 +1277,7 @@ pub enum ImportsEntry<'a> {
|
|||
|
||||
/// e.g.
|
||||
///
|
||||
/// printLine : Str -> Effect {}
|
||||
/// printLine : Str -> Result {} *
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct TypedIdent<'a> {
|
||||
pub ident: Loc<&'a str>,
|
||||
|
|
|
@ -365,7 +365,7 @@ fn fast_forward_to(
|
|||
tokens.push(Loc::at(Region::between(start, state.pos()), Token::Error));
|
||||
}
|
||||
|
||||
pub const HEADER_KEYWORDS: [&str; 14] = [
|
||||
pub const HEADER_KEYWORDS: [&str; 12] = [
|
||||
"interface",
|
||||
"app",
|
||||
"package",
|
||||
|
@ -373,8 +373,6 @@ pub const HEADER_KEYWORDS: [&str; 14] = [
|
|||
"hosted",
|
||||
"exposes",
|
||||
"imports",
|
||||
"with",
|
||||
"generates",
|
||||
"package",
|
||||
"packages",
|
||||
"requires",
|
||||
|
|
905
crates/compiler/parse/src/module.rs
Normal file
905
crates/compiler/parse/src/module.rs
Normal file
|
@ -0,0 +1,905 @@
|
|||
use crate::ast::{Collection, CommentOrNewline, Defs, Header, Module, Spaced, Spaces};
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::expr::merge_spaces;
|
||||
use crate::header::{
|
||||
package_entry, package_name, AppHeader, ExposedName, ExposesKeyword, HostedHeader,
|
||||
ImportsCollection, ImportsEntry, ImportsKeyword, ImportsKeywordItem, Keyword, KeywordItem,
|
||||
ModuleHeader, ModuleName, ModuleParams, PackageEntry, PackageHeader, PackagesKeyword,
|
||||
PlatformHeader, PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword,
|
||||
TypedIdent,
|
||||
};
|
||||
use crate::ident::{self, lowercase_ident, unqualified_ident, UppercaseIdent};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map,
|
||||
map_with_arena, optional, reset_min_indent, skip_first, skip_second, specialize_err, succeed,
|
||||
two_bytes, zero_or_more, EExposes, EHeader, EImports, EPackages, EParams, EProvides, ERequires,
|
||||
ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
||||
};
|
||||
use crate::pattern::record_pattern_fields;
|
||||
use crate::state::State;
|
||||
use crate::string_literal::{self, parse_str_literal};
|
||||
use crate::type_annotation;
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
||||
|_arena, state: State<'a>, _min_indent: u32| {
|
||||
if state.has_reached_end() {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
Err((NoProgress, SyntaxError::NotEndOfFile(state.pos())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_module_defs<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
state: State<'a>,
|
||||
defs: Defs<'a>,
|
||||
) -> Result<Defs<'a>, SyntaxError<'a>> {
|
||||
let min_indent = 0;
|
||||
match crate::expr::parse_top_level_defs(arena, state.clone(), defs) {
|
||||
Ok((_, defs, state)) => match end_of_file().parse(arena, state, min_indent) {
|
||||
Ok(_) => Ok(defs),
|
||||
Err((_, fail)) => Err(fail),
|
||||
},
|
||||
Err((_, fail)) => Err(SyntaxError::Expr(fail, state.pos())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_header<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
state: State<'a>,
|
||||
) -> Result<(Module<'a>, State<'a>), SourceError<'a, EHeader<'a>>> {
|
||||
let min_indent = 0;
|
||||
match header().parse(arena, state.clone(), min_indent) {
|
||||
Ok((_, module, state)) => Ok((module, state)),
|
||||
Err((_, fail)) => Err(SourceError::new(fail, &state)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
||||
use crate::parser::keyword;
|
||||
|
||||
record!(Module {
|
||||
comments: space0_e(EHeader::IndentStart),
|
||||
header: one_of![
|
||||
map(
|
||||
skip_first(
|
||||
keyword("module", EHeader::Start),
|
||||
increment_min_indent(module_header())
|
||||
),
|
||||
Header::Module
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("interface", EHeader::Start),
|
||||
increment_min_indent(interface_header())
|
||||
),
|
||||
Header::Module
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("app", EHeader::Start),
|
||||
increment_min_indent(one_of![app_header(), old_app_header()])
|
||||
),
|
||||
Header::App
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("package", EHeader::Start),
|
||||
increment_min_indent(one_of![package_header(), old_package_header()])
|
||||
),
|
||||
Header::Package
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("platform", EHeader::Start),
|
||||
increment_min_indent(platform_header())
|
||||
),
|
||||
Header::Platform
|
||||
),
|
||||
map(
|
||||
skip_first(
|
||||
keyword("hosted", EHeader::Start),
|
||||
increment_min_indent(hosted_header())
|
||||
),
|
||||
Header::Hosted
|
||||
),
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn module_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
||||
record!(ModuleHeader {
|
||||
after_keyword: space0_e(EHeader::IndentStart),
|
||||
params: optional(specialize_err(EHeader::Params, module_params())),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_list()),
|
||||
interface_imports: succeed(None)
|
||||
})
|
||||
.trace("module_header")
|
||||
}
|
||||
|
||||
fn module_params<'a>() -> impl Parser<'a, ModuleParams<'a>, EParams<'a>> {
|
||||
record!(ModuleParams {
|
||||
params: specialize_err(EParams::Pattern, record_pattern_fields()),
|
||||
before_arrow: skip_second(
|
||||
space0_e(EParams::BeforeArrow),
|
||||
loc(two_bytes(b'-', b'>', EParams::Arrow))
|
||||
),
|
||||
after_arrow: space0_e(EParams::AfterArrow),
|
||||
})
|
||||
}
|
||||
|
||||
// TODO does this need to be a macro?
|
||||
macro_rules! merge_n_spaces {
|
||||
($arena:expr, $($slice:expr),*) => {
|
||||
{
|
||||
let mut merged = bumpalo::collections::Vec::with_capacity_in(0 $(+ $slice.len())*, $arena);
|
||||
$(merged.extend_from_slice($slice);)*
|
||||
merged.into_bump_slice()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Parse old interface headers so we can format them into module headers
|
||||
#[inline(always)]
|
||||
fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
||||
let after_keyword = map_with_arena(
|
||||
and(
|
||||
skip_second(
|
||||
space0_e(EHeader::IndentStart),
|
||||
loc(module_name_help(EHeader::ModuleName)),
|
||||
),
|
||||
specialize_err(EHeader::Exposes, exposes_kw()),
|
||||
),
|
||||
|arena: &'a bumpalo::Bump,
|
||||
(before_name, kw): (&'a [CommentOrNewline<'a>], Spaces<'a, ExposesKeyword>)| {
|
||||
merge_n_spaces!(arena, before_name, kw.before, kw.after)
|
||||
},
|
||||
);
|
||||
|
||||
record!(ModuleHeader {
|
||||
after_keyword: after_keyword,
|
||||
params: succeed(None),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_list()).trace("exposes_list"),
|
||||
interface_imports: map(
|
||||
specialize_err(EHeader::Imports, imports()),
|
||||
imports_none_if_empty
|
||||
)
|
||||
.trace("imports"),
|
||||
})
|
||||
.trace("interface_header")
|
||||
}
|
||||
|
||||
fn imports_none_if_empty(value: ImportsKeywordItem<'_>) -> Option<ImportsKeywordItem<'_>> {
|
||||
if value.item.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
|
||||
record!(HostedHeader {
|
||||
before_name: space0_e(EHeader::IndentStart),
|
||||
name: loc(module_name_help(EHeader::ModuleName)),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_values_kw()),
|
||||
imports: specialize_err(EHeader::Imports, imports()),
|
||||
})
|
||||
.trace("hosted_header")
|
||||
}
|
||||
|
||||
fn chomp_module_name(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
use encode_unicode::CharExt;
|
||||
|
||||
let mut chomped = 0;
|
||||
|
||||
if let Ok((first_letter, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if first_letter.is_uppercase() {
|
||||
chomped += width;
|
||||
} else {
|
||||
return Err(Progress::NoProgress);
|
||||
}
|
||||
}
|
||||
|
||||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
// After the first character, only these are allowed:
|
||||
//
|
||||
// * Unicode alphabetic chars - you might include `鹏` if that's clear to your readers
|
||||
// * ASCII digits - e.g. `1` but not `¾`, both of which pass .is_numeric()
|
||||
// * A '.' separating module parts
|
||||
if ch.is_alphabetic() || ch.is_ascii_digit() {
|
||||
chomped += width;
|
||||
} else if ch == '.' {
|
||||
chomped += width;
|
||||
|
||||
if let Ok((first_letter, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if first_letter.is_uppercase() {
|
||||
chomped += width;
|
||||
} else if first_letter == '{' {
|
||||
// the .{ starting a `Foo.{ bar, baz }` importing clauses
|
||||
chomped -= width;
|
||||
break;
|
||||
} else {
|
||||
return Err(Progress::MadeProgress);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we're done
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let name = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
|
||||
|_, mut state: State<'a>, _min_indent: u32| match chomp_module_name(state.bytes()) {
|
||||
Ok(name) => {
|
||||
let width = name.len();
|
||||
state = state.advance(width);
|
||||
|
||||
Ok((MadeProgress, ModuleName::new(name), state))
|
||||
}
|
||||
Err(progress) => Err((progress, ())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||
record!(AppHeader {
|
||||
before_provides: space0_e(EHeader::IndentStart),
|
||||
provides: specialize_err(EHeader::Exposes, exposes_list()),
|
||||
before_packages: space0_e(EHeader::IndentStart),
|
||||
packages: specialize_err(EHeader::Packages, loc(packages_collection())),
|
||||
old_imports: succeed(None),
|
||||
old_provides_to_new_package: succeed(None),
|
||||
})
|
||||
.trace("app_header")
|
||||
}
|
||||
|
||||
struct OldAppHeader<'a> {
|
||||
pub before_name: &'a [CommentOrNewline<'a>],
|
||||
pub packages: Option<Loc<OldAppPackages<'a>>>,
|
||||
pub imports: Option<KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>>,
|
||||
pub provides: ProvidesTo<'a>,
|
||||
}
|
||||
|
||||
type OldAppPackages<'a> =
|
||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>;
|
||||
|
||||
#[inline(always)]
|
||||
fn old_app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||
let old = record!(OldAppHeader {
|
||||
before_name: skip_second(
|
||||
space0_e(EHeader::IndentStart),
|
||||
loc(crate::parser::specialize_err(
|
||||
EHeader::AppName,
|
||||
string_literal::parse_str_literal()
|
||||
))
|
||||
),
|
||||
packages: optional(specialize_err(EHeader::Packages, loc(packages()))),
|
||||
imports: optional(specialize_err(EHeader::Imports, imports())),
|
||||
provides: specialize_err(EHeader::Provides, provides_to()),
|
||||
});
|
||||
|
||||
map_with_arena(old, |arena: &'a bumpalo::Bump, old: OldAppHeader<'a>| {
|
||||
let mut before_packages: &'a [CommentOrNewline] = &[];
|
||||
|
||||
let packages = match old.packages {
|
||||
Some(packages) => {
|
||||
before_packages = merge_spaces(
|
||||
arena,
|
||||
packages.value.keyword.before,
|
||||
packages.value.keyword.after,
|
||||
);
|
||||
|
||||
if let To::ExistingPackage(platform_shorthand) = old.provides.to.value {
|
||||
packages.map(|coll| {
|
||||
coll.item.map_items(arena, |loc_spaced_pkg| {
|
||||
if loc_spaced_pkg.value.item().shorthand == platform_shorthand {
|
||||
loc_spaced_pkg.map(|spaced_pkg| {
|
||||
spaced_pkg.map(arena, |pkg| {
|
||||
let mut new_pkg = *pkg;
|
||||
new_pkg.platform_marker = Some(merge_spaces(
|
||||
arena,
|
||||
old.provides.to_keyword.before,
|
||||
old.provides.to_keyword.after,
|
||||
));
|
||||
new_pkg
|
||||
})
|
||||
})
|
||||
} else {
|
||||
*loc_spaced_pkg
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
packages.map(|kw| kw.item)
|
||||
}
|
||||
}
|
||||
None => Loc {
|
||||
region: Region::zero(),
|
||||
value: Collection::empty(),
|
||||
},
|
||||
};
|
||||
|
||||
let provides = match old.provides.types {
|
||||
Some(types) => {
|
||||
let mut combined_items = bumpalo::collections::Vec::with_capacity_in(
|
||||
old.provides.entries.items.len() + types.items.len(),
|
||||
arena,
|
||||
);
|
||||
|
||||
combined_items.extend_from_slice(old.provides.entries.items);
|
||||
|
||||
for loc_spaced_type_ident in types.items {
|
||||
combined_items.push(loc_spaced_type_ident.map(|spaced_type_ident| {
|
||||
spaced_type_ident.map(arena, |type_ident| {
|
||||
ExposedName::new(From::from(*type_ident))
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
let value_comments = old.provides.entries.final_comments();
|
||||
let type_comments = types.final_comments();
|
||||
|
||||
let mut combined_comments = bumpalo::collections::Vec::with_capacity_in(
|
||||
value_comments.len() + type_comments.len(),
|
||||
arena,
|
||||
);
|
||||
combined_comments.extend_from_slice(value_comments);
|
||||
combined_comments.extend_from_slice(type_comments);
|
||||
|
||||
Collection::with_items_and_comments(
|
||||
arena,
|
||||
combined_items.into_bump_slice(),
|
||||
combined_comments.into_bump_slice(),
|
||||
)
|
||||
}
|
||||
None => old.provides.entries,
|
||||
};
|
||||
|
||||
AppHeader {
|
||||
before_provides: merge_spaces(
|
||||
arena,
|
||||
old.before_name,
|
||||
old.provides.provides_keyword.before,
|
||||
),
|
||||
provides,
|
||||
before_packages: merge_spaces(
|
||||
arena,
|
||||
before_packages,
|
||||
old.provides.provides_keyword.after,
|
||||
),
|
||||
packages,
|
||||
old_imports: old.imports.and_then(imports_none_if_empty),
|
||||
old_provides_to_new_package: match old.provides.to.value {
|
||||
To::NewPackage(new_pkg) => Some(new_pkg),
|
||||
To::ExistingPackage(_) => None,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||
record!(PackageHeader {
|
||||
before_exposes: space0_e(EHeader::IndentStart),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_module_collection()),
|
||||
before_packages: space0_e(EHeader::IndentStart),
|
||||
packages: specialize_err(EHeader::Packages, loc(packages_collection())),
|
||||
})
|
||||
.trace("package_header")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
struct OldPackageHeader<'a> {
|
||||
before_name: &'a [CommentOrNewline<'a>],
|
||||
exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
||||
packages:
|
||||
Loc<KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>>,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn old_package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||
map_with_arena(
|
||||
record!(OldPackageHeader {
|
||||
before_name: skip_second(
|
||||
space0_e(EHeader::IndentStart),
|
||||
specialize_err(EHeader::PackageName, package_name())
|
||||
),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||
packages: specialize_err(EHeader::Packages, loc(packages())),
|
||||
}),
|
||||
|arena: &'a bumpalo::Bump, old: OldPackageHeader<'a>| {
|
||||
let before_exposes = merge_n_spaces!(
|
||||
arena,
|
||||
old.before_name,
|
||||
old.exposes.keyword.before,
|
||||
old.exposes.keyword.after
|
||||
);
|
||||
let before_packages = merge_spaces(
|
||||
arena,
|
||||
old.packages.value.keyword.before,
|
||||
old.packages.value.keyword.after,
|
||||
);
|
||||
|
||||
PackageHeader {
|
||||
before_exposes,
|
||||
exposes: old.exposes.item,
|
||||
before_packages,
|
||||
packages: old.packages.map(|kw| kw.item),
|
||||
}
|
||||
},
|
||||
)
|
||||
.trace("old_package_header")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||
record!(PlatformHeader {
|
||||
before_name: space0_e(EHeader::IndentStart),
|
||||
name: loc(specialize_err(EHeader::PlatformName, package_name())),
|
||||
requires: specialize_err(EHeader::Requires, requires()),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||
packages: specialize_err(EHeader::Packages, packages()),
|
||||
imports: specialize_err(EHeader::Imports, imports()),
|
||||
provides: specialize_err(EHeader::Provides, provides_exposed()),
|
||||
})
|
||||
.trace("platform_header")
|
||||
}
|
||||
|
||||
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|
||||
one_of![
|
||||
specialize_err(
|
||||
|_, pos| EProvides::Identifier(pos),
|
||||
map(lowercase_ident(), To::ExistingPackage)
|
||||
),
|
||||
specialize_err(EProvides::Package, map(package_name(), To::NewPackage))
|
||||
]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> {
|
||||
record!(ProvidesTo {
|
||||
provides_keyword: spaces_around_keyword(
|
||||
ProvidesKeyword,
|
||||
EProvides::Provides,
|
||||
EProvides::IndentProvides,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
entries: collection_trailing_sep_e(
|
||||
byte(b'[', EProvides::ListStart),
|
||||
exposes_entry(EProvides::Identifier),
|
||||
byte(b',', EProvides::ListEnd),
|
||||
byte(b']', EProvides::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
),
|
||||
types: optional(backtrackable(provides_types())),
|
||||
to_keyword: spaces_around_keyword(
|
||||
ToKeyword,
|
||||
EProvides::To,
|
||||
EProvides::IndentTo,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
to: loc(provides_to_package()),
|
||||
})
|
||||
.trace("provides_to")
|
||||
}
|
||||
|
||||
fn provides_exposed<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ProvidesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
EProvides<'a>,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
ProvidesKeyword,
|
||||
EProvides::Provides,
|
||||
EProvides::IndentProvides,
|
||||
EProvides::IndentListStart
|
||||
),
|
||||
item: collection_trailing_sep_e(
|
||||
byte(b'[', EProvides::ListStart),
|
||||
exposes_entry(EProvides::Identifier),
|
||||
byte(b',', EProvides::ListEnd),
|
||||
byte(b']', EProvides::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn provides_types<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, EProvides<'a>> {
|
||||
skip_first(
|
||||
// We only support spaces here, not newlines, because this is not intended
|
||||
// to be the design forever. Someday it will hopefully work like Elm,
|
||||
// where platform authors can provide functions like Browser.sandbox which
|
||||
// present an API based on ordinary-looking type variables.
|
||||
zero_or_more(byte(
|
||||
b' ',
|
||||
// HACK: If this errors, EProvides::Provides is not an accurate reflection
|
||||
// of what went wrong. However, this is both skipped and zero_or_more,
|
||||
// so this error should never be visible to anyone in practice!
|
||||
EProvides::Provides,
|
||||
)),
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', EProvides::ListStart),
|
||||
provides_type_entry(EProvides::Identifier),
|
||||
byte(b',', EProvides::ListEnd),
|
||||
byte(b'}', EProvides::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn provides_type_entry<'a, F, E>(
|
||||
to_expectation: F,
|
||||
) -> impl Parser<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
F: Copy,
|
||||
E: 'a,
|
||||
{
|
||||
loc(map(
|
||||
specialize_err(move |_, pos| to_expectation(pos), ident::uppercase()),
|
||||
Spaced::Item,
|
||||
))
|
||||
}
|
||||
|
||||
fn exposes_entry<'a, F, E>(
|
||||
to_expectation: F,
|
||||
) -> impl Parser<'a, Loc<Spaced<'a, ExposedName<'a>>>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
F: Copy,
|
||||
E: 'a,
|
||||
{
|
||||
loc(map(
|
||||
specialize_err(move |_, pos| to_expectation(pos), unqualified_ident()),
|
||||
|n| Spaced::Item(ExposedName::new(n)),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires<'a>(
|
||||
) -> impl Parser<'a, KeywordItem<'a, RequiresKeyword, PlatformRequires<'a>>, ERequires<'a>> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
RequiresKeyword,
|
||||
ERequires::Requires,
|
||||
ERequires::IndentRequires,
|
||||
ERequires::IndentListStart
|
||||
),
|
||||
item: platform_requires(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a>> {
|
||||
record!(PlatformRequires {
|
||||
rigids: skip_second(requires_rigids(), space0_e(ERequires::ListStart)),
|
||||
signature: requires_typed_ident()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', ERequires::ListStart),
|
||||
specialize_err(
|
||||
|_, pos| ERequires::Rigid(pos),
|
||||
loc(map(ident::uppercase(), Spaced::Item)),
|
||||
),
|
||||
byte(b',', ERequires::ListEnd),
|
||||
byte(b'}', ERequires::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
|
||||
skip_first(
|
||||
byte(b'{', ERequires::ListStart),
|
||||
skip_second(
|
||||
reset_min_indent(space0_around_ee(
|
||||
specialize_err(ERequires::TypedIdent, loc(typed_ident())),
|
||||
ERequires::ListStart,
|
||||
ERequires::ListEnd,
|
||||
)),
|
||||
byte(b'}', ERequires::ListStart),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_values_kw<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
EExposes,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: exposes_kw(),
|
||||
item: exposes_list()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_kw<'a>() -> impl Parser<'a, Spaces<'a, ExposesKeyword>, EExposes> {
|
||||
spaces_around_keyword(
|
||||
ExposesKeyword,
|
||||
EExposes::Exposes,
|
||||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_list<'a>() -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>, EExposes>
|
||||
{
|
||||
collection_trailing_sep_e(
|
||||
byte(b'[', EExposes::ListStart),
|
||||
exposes_entry(EExposes::Identifier),
|
||||
byte(b',', EExposes::ListEnd),
|
||||
byte(b']', EExposes::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn spaces_around_keyword<'a, K: Keyword, E>(
|
||||
keyword_item: K,
|
||||
expectation: fn(Position) -> E,
|
||||
indent_problem1: fn(Position) -> E,
|
||||
indent_problem2: fn(Position) -> E,
|
||||
) -> impl Parser<'a, Spaces<'a, K>, E>
|
||||
where
|
||||
E: 'a + SpaceProblem,
|
||||
{
|
||||
map(
|
||||
and(
|
||||
skip_second(
|
||||
// parse any leading space before the keyword
|
||||
backtrackable(space0_e(indent_problem1)),
|
||||
// parse the keyword
|
||||
crate::parser::keyword(K::KEYWORD, expectation),
|
||||
),
|
||||
// parse the trailing space
|
||||
space0_e(indent_problem2),
|
||||
),
|
||||
move |(before, after)| Spaces {
|
||||
before,
|
||||
item: keyword_item,
|
||||
after,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_modules<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
||||
EExposes,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
ExposesKeyword,
|
||||
EExposes::Exposes,
|
||||
EExposes::IndentExposes,
|
||||
EExposes::IndentListStart
|
||||
),
|
||||
item: exposes_module_collection(),
|
||||
})
|
||||
}
|
||||
|
||||
fn exposes_module_collection<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>, EExposes> {
|
||||
collection_trailing_sep_e(
|
||||
byte(b'[', EExposes::ListStart),
|
||||
exposes_module(EExposes::Identifier),
|
||||
byte(b',', EExposes::ListEnd),
|
||||
byte(b']', EExposes::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
fn exposes_module<'a, F, E>(
|
||||
to_expectation: F,
|
||||
) -> impl Parser<'a, Loc<Spaced<'a, ModuleName<'a>>>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
F: Copy,
|
||||
E: 'a,
|
||||
{
|
||||
loc(map(
|
||||
specialize_err(move |_, pos| to_expectation(pos), module_name()),
|
||||
Spaced::Item,
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packages<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>,
|
||||
EPackages<'a>,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: packages_kw(),
|
||||
item: packages_collection()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packages_kw<'a>() -> impl Parser<'a, Spaces<'a, PackagesKeyword>, EPackages<'a>> {
|
||||
spaces_around_keyword(
|
||||
PackagesKeyword,
|
||||
EPackages::Packages,
|
||||
EPackages::IndentPackages,
|
||||
EPackages::IndentListStart,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packages_collection<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>, EPackages<'a>> {
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', EPackages::ListStart),
|
||||
specialize_err(EPackages::PackageEntry, loc(package_entry())),
|
||||
byte(b',', EPackages::ListEnd),
|
||||
byte(b'}', EPackages::ListEnd),
|
||||
Spaced::SpaceBefore,
|
||||
)
|
||||
}
|
||||
|
||||
fn imports<'a>() -> impl Parser<
|
||||
'a,
|
||||
KeywordItem<'a, ImportsKeyword, Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>>,
|
||||
EImports,
|
||||
> {
|
||||
record!(KeywordItem {
|
||||
keyword: spaces_around_keyword(
|
||||
ImportsKeyword,
|
||||
EImports::Imports,
|
||||
EImports::IndentImports,
|
||||
EImports::IndentListStart
|
||||
),
|
||||
item: collection_trailing_sep_e(
|
||||
byte(b'[', EImports::ListStart),
|
||||
loc(imports_entry()),
|
||||
byte(b',', EImports::ListEnd),
|
||||
byte(b']', EImports::ListEnd),
|
||||
Spaced::SpaceBefore
|
||||
)
|
||||
})
|
||||
.trace("imports")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<'a>> {
|
||||
// e.g.
|
||||
//
|
||||
// printLine : Str -> Task {} *
|
||||
map(
|
||||
and(
|
||||
and(
|
||||
loc(specialize_err(
|
||||
|_, pos| ETypedIdent::Identifier(pos),
|
||||
lowercase_ident(),
|
||||
)),
|
||||
space0_e(ETypedIdent::IndentHasType),
|
||||
),
|
||||
skip_first(
|
||||
byte(b':', ETypedIdent::HasType),
|
||||
space0_before_e(
|
||||
specialize_err(
|
||||
ETypedIdent::Type,
|
||||
reset_min_indent(type_annotation::located(true)),
|
||||
),
|
||||
ETypedIdent::IndentType,
|
||||
),
|
||||
),
|
||||
),
|
||||
|((ident, spaces_before_colon), ann)| {
|
||||
Spaced::Item(TypedIdent {
|
||||
ident,
|
||||
spaces_before_colon,
|
||||
ann,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn shortname<'a>() -> impl Parser<'a, &'a str, EImports> {
|
||||
specialize_err(|_, pos| EImports::Shorthand(pos), lowercase_ident())
|
||||
}
|
||||
|
||||
pub fn module_name_help<'a, F, E>(to_expectation: F) -> impl Parser<'a, ModuleName<'a>, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
F: 'a,
|
||||
{
|
||||
specialize_err(move |_, pos| to_expectation(pos), module_name())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports> {
|
||||
type Temp<'a> = (
|
||||
(Option<&'a str>, ModuleName<'a>),
|
||||
Option<Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
);
|
||||
|
||||
let spaced_import = |((opt_shortname, module_name), opt_values): Temp<'a>| {
|
||||
let exposed_values = opt_values.unwrap_or_else(Collection::empty);
|
||||
|
||||
let entry = match opt_shortname {
|
||||
Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values),
|
||||
|
||||
None => ImportsEntry::Module(module_name, exposed_values),
|
||||
};
|
||||
|
||||
Spaced::Item(entry)
|
||||
};
|
||||
|
||||
one_of!(
|
||||
map(
|
||||
and(
|
||||
and(
|
||||
// e.g. `pf.`
|
||||
optional(backtrackable(skip_second(
|
||||
shortname(),
|
||||
byte(b'.', EImports::ShorthandDot)
|
||||
))),
|
||||
// e.g. `Task`
|
||||
module_name_help(EImports::ModuleName)
|
||||
),
|
||||
// e.g. `.{ Task, after}`
|
||||
optional(skip_first(
|
||||
byte(b'.', EImports::ExposingDot),
|
||||
collection_trailing_sep_e(
|
||||
byte(b'{', EImports::SetStart),
|
||||
exposes_entry(EImports::Identifier),
|
||||
byte(b',', EImports::SetEnd),
|
||||
byte(b'}', EImports::SetEnd),
|
||||
Spaced::SpaceBefore
|
||||
)
|
||||
))
|
||||
),
|
||||
spaced_import
|
||||
)
|
||||
.trace("normal_import"),
|
||||
map(
|
||||
and(
|
||||
and(
|
||||
// e.g. "filename"
|
||||
// TODO: str literal allows for multiline strings. We probably don't want that for file names.
|
||||
specialize_err(|_, pos| EImports::StrLiteral(pos), parse_str_literal()),
|
||||
// e.g. as
|
||||
and(
|
||||
and(
|
||||
space0_e(EImports::AsKeyword),
|
||||
two_bytes(b'a', b's', EImports::AsKeyword)
|
||||
),
|
||||
space0_e(EImports::AsKeyword)
|
||||
)
|
||||
),
|
||||
// e.g. file : Str
|
||||
specialize_err(|_, pos| EImports::TypedIdent(pos), typed_ident())
|
||||
),
|
||||
|((file_name, _), typed_ident)| {
|
||||
// TODO: look at blacking block strings during parsing.
|
||||
Spaced::Item(ImportsEntry::IngestedFile(file_name, typed_ident))
|
||||
}
|
||||
)
|
||||
.trace("ingest_file_import")
|
||||
)
|
||||
.trace("imports_entry")
|
||||
}
|
|
@ -13,19 +13,18 @@ use crate::{
|
|||
TypeDef, TypeHeader, ValueDef, WhenBranch,
|
||||
},
|
||||
header::{
|
||||
AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword, HostedHeader, ImportsEntry,
|
||||
ImportsKeyword, KeywordItem, ModuleHeader, ModuleName, ModuleParams, PackageEntry,
|
||||
PackageHeader, PackageKeyword, PackageName, PackagesKeyword, PlatformHeader,
|
||||
PlatformKeyword, PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To,
|
||||
ToKeyword, TypedIdent, WithKeyword,
|
||||
AppHeader, ExposedName, ExposesKeyword, HostedHeader, ImportsEntry, ImportsKeyword,
|
||||
KeywordItem, ModuleHeader, ModuleName, ModuleParams, PackageEntry, PackageHeader,
|
||||
PackageKeyword, PackageName, PackagesKeyword, PlatformHeader, PlatformKeyword,
|
||||
PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword, TypedIdent,
|
||||
},
|
||||
ident::{BadIdent, UppercaseIdent},
|
||||
parser::{
|
||||
EAbility, EClosure, EExpect, EExposes, EExpr, EGenerates, EGeneratesWith, EHeader, EIf,
|
||||
EImport, EImportParams, EImports, EInParens, EList, EPackageEntry, EPackageName, EPackages,
|
||||
EParams, EPattern, EProvides, ERecord, ERequires, EString, EType, ETypeAbilityImpl,
|
||||
ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, ETypedIdent,
|
||||
EWhen, PInParens, PList, PRecord, SyntaxError,
|
||||
EAbility, EClosure, EExpect, EExposes, EExpr, EHeader, EIf, EImport, EImportParams,
|
||||
EImports, EInParens, EList, EPackageEntry, EPackageName, EPackages, EParams, EPattern,
|
||||
EProvides, ERecord, ERequires, EString, EType, ETypeAbilityImpl, ETypeApply, ETypeInParens,
|
||||
ETypeInlineAlias, ETypeRecord, ETypeTagUnion, ETypedIdent, EWhen, PInParens, PList,
|
||||
PRecord, SyntaxError,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -59,8 +58,6 @@ macro_rules! keywords {
|
|||
keywords! {
|
||||
ExposesKeyword,
|
||||
ImportsKeyword,
|
||||
WithKeyword,
|
||||
GeneratesKeyword,
|
||||
PackageKeyword,
|
||||
PackagesKeyword,
|
||||
RequiresKeyword,
|
||||
|
@ -179,8 +176,6 @@ impl<'a> Normalize<'a> for Header<'a> {
|
|||
name: header.name.normalize(arena),
|
||||
exposes: header.exposes.normalize(arena),
|
||||
imports: header.imports.normalize(arena),
|
||||
generates: header.generates.normalize(arena),
|
||||
generates_with: header.generates_with.normalize(arena),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -784,7 +779,8 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
Expr::Dbg(a, b) => Expr::Dbg(
|
||||
Expr::Dbg => Expr::Dbg,
|
||||
Expr::DbgStmt(a, b) => Expr::DbgStmt(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
|
@ -1587,38 +1583,6 @@ impl<'a> Normalize<'a> for EAbility<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for EGeneratesWith {
|
||||
fn normalize(&self, _arena: &'a Bump) -> Self {
|
||||
match self {
|
||||
EGeneratesWith::Open(_) => EGeneratesWith::Open(Position::zero()),
|
||||
EGeneratesWith::With(_) => EGeneratesWith::With(Position::zero()),
|
||||
EGeneratesWith::IndentWith(_) => EGeneratesWith::IndentWith(Position::zero()),
|
||||
EGeneratesWith::IndentListStart(_) => EGeneratesWith::IndentListStart(Position::zero()),
|
||||
EGeneratesWith::IndentListEnd(_) => EGeneratesWith::IndentListEnd(Position::zero()),
|
||||
EGeneratesWith::ListStart(_) => EGeneratesWith::ListStart(Position::zero()),
|
||||
EGeneratesWith::ListEnd(_) => EGeneratesWith::ListEnd(Position::zero()),
|
||||
EGeneratesWith::Identifier(_) => EGeneratesWith::Identifier(Position::zero()),
|
||||
EGeneratesWith::Space(inner_err, _) => {
|
||||
EGeneratesWith::Space(*inner_err, Position::zero())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for EGenerates {
|
||||
fn normalize(&self, _arena: &'a Bump) -> Self {
|
||||
match self {
|
||||
EGenerates::Open(_) => EGenerates::Open(Position::zero()),
|
||||
EGenerates::Generates(_) => EGenerates::Generates(Position::zero()),
|
||||
EGenerates::IndentGenerates(_) => EGenerates::IndentGenerates(Position::zero()),
|
||||
EGenerates::Identifier(_) => EGenerates::Identifier(Position::zero()),
|
||||
EGenerates::Space(inner_err, _) => EGenerates::Space(*inner_err, Position::zero()),
|
||||
EGenerates::IndentTypeStart(_) => EGenerates::IndentTypeStart(Position::zero()),
|
||||
EGenerates::IndentTypeEnd(_) => EGenerates::IndentTypeEnd(Position::zero()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Normalize<'a> for EPackages<'a> {
|
||||
fn normalize(&self, arena: &'a Bump) -> Self {
|
||||
match self {
|
||||
|
@ -1658,12 +1622,6 @@ impl<'a> Normalize<'a> for EHeader<'a> {
|
|||
EHeader::Packages(inner_err, _) => {
|
||||
EHeader::Packages(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EHeader::Generates(inner_err, _) => {
|
||||
EHeader::Generates(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EHeader::GeneratesWith(inner_err, _) => {
|
||||
EHeader::GeneratesWith(inner_err.normalize(arena), Position::zero())
|
||||
}
|
||||
EHeader::Space(inner_err, _) => EHeader::Space(*inner_err, Position::zero()),
|
||||
EHeader::Start(_) => EHeader::Start(Position::zero()),
|
||||
EHeader::ModuleName(_) => EHeader::ModuleName(Position::zero()),
|
||||
|
|
|
@ -83,8 +83,6 @@ impl_space_problem! {
|
|||
EExpect<'a>,
|
||||
EExposes,
|
||||
EExpr<'a>,
|
||||
EGenerates,
|
||||
EGeneratesWith,
|
||||
EHeader<'a>,
|
||||
EIf<'a>,
|
||||
EImport<'a>,
|
||||
|
@ -122,8 +120,6 @@ pub enum EHeader<'a> {
|
|||
Imports(EImports, Position),
|
||||
Requires(ERequires<'a>, Position),
|
||||
Packages(EPackages<'a>, Position),
|
||||
Generates(EGenerates, Position),
|
||||
GeneratesWith(EGeneratesWith, Position),
|
||||
|
||||
Space(BadInputError, Position),
|
||||
Start(Position),
|
||||
|
@ -251,30 +247,6 @@ pub enum EImports {
|
|||
StrLiteral(Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EGenerates {
|
||||
Open(Position),
|
||||
Generates(Position),
|
||||
IndentGenerates(Position),
|
||||
Identifier(Position),
|
||||
Space(BadInputError, Position),
|
||||
IndentTypeStart(Position),
|
||||
IndentTypeEnd(Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EGeneratesWith {
|
||||
Open(Position),
|
||||
With(Position),
|
||||
IndentWith(Position),
|
||||
IndentListStart(Position),
|
||||
IndentListEnd(Position),
|
||||
ListStart(Position),
|
||||
ListEnd(Position),
|
||||
Identifier(Position),
|
||||
Space(BadInputError, Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BadInputError {
|
||||
HasTab,
|
||||
|
@ -856,8 +828,7 @@ where
|
|||
}
|
||||
|
||||
// This should be enough for anyone. Right? RIGHT?
|
||||
let indent_text =
|
||||
"| ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! ";
|
||||
let indent_text = "| ; : ! ".repeat(20);
|
||||
|
||||
let cur_indent = INDENT.with(|i| *i.borrow());
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@ pub enum Problem {
|
|||
UnusedImport(Symbol, Region),
|
||||
UnusedModuleImport(ModuleId, Region),
|
||||
ExposedButNotDefined(Symbol),
|
||||
UnknownGeneratesWith(Loc<Ident>),
|
||||
ImportNameConflict {
|
||||
name: ModuleName,
|
||||
is_alias: bool,
|
||||
|
@ -221,6 +220,12 @@ pub enum Problem {
|
|||
OverAppliedCrash {
|
||||
region: Region,
|
||||
},
|
||||
UnappliedDbg {
|
||||
region: Region,
|
||||
},
|
||||
OverAppliedDbg {
|
||||
region: Region,
|
||||
},
|
||||
FileProblem {
|
||||
filename: PathBuf,
|
||||
error: io::ErrorKind,
|
||||
|
@ -260,7 +265,6 @@ impl Problem {
|
|||
Problem::ImportShadowsSymbol { .. } => RuntimeError,
|
||||
Problem::DeprecatedBackpassing(_) => Warning,
|
||||
Problem::ExposedButNotDefined(_) => RuntimeError,
|
||||
Problem::UnknownGeneratesWith(_) => RuntimeError,
|
||||
Problem::UnusedArgument(_, _, _, _) => Warning,
|
||||
Problem::UnusedBranchDef(_, _) => Warning,
|
||||
Problem::PrecedenceProblem(_) => RuntimeError,
|
||||
|
@ -315,6 +319,8 @@ impl Problem {
|
|||
// injecting a crash message
|
||||
Problem::UnappliedCrash { .. } => RuntimeError,
|
||||
Problem::OverAppliedCrash { .. } => RuntimeError,
|
||||
Problem::UnappliedDbg { .. } => RuntimeError,
|
||||
Problem::OverAppliedDbg { .. } => RuntimeError,
|
||||
Problem::DefsOnlyUsedInRecursion(_, _) => Warning,
|
||||
Problem::FileProblem { .. } => Fatal,
|
||||
}
|
||||
|
@ -343,7 +349,6 @@ impl Problem {
|
|||
| Problem::ExplicitBuiltinTypeImport(_, region)
|
||||
| Problem::ImportShadowsSymbol { region, .. }
|
||||
| Problem::DeprecatedBackpassing(region)
|
||||
| Problem::UnknownGeneratesWith(Loc { region, .. })
|
||||
| Problem::UnusedArgument(_, _, _, region)
|
||||
| Problem::UnusedBranchDef(_, region)
|
||||
| Problem::PrecedenceProblem(PrecedenceProblem::BothNonAssociative(region, _, _))
|
||||
|
@ -480,6 +485,8 @@ impl Problem {
|
|||
| Problem::UnnecessaryOutputWildcard { region }
|
||||
| Problem::OverAppliedCrash { region }
|
||||
| Problem::UnappliedCrash { region }
|
||||
| Problem::OverAppliedDbg { region }
|
||||
| Problem::UnappliedDbg { region }
|
||||
| Problem::DefsOnlyUsedInRecursion(_, region) => Some(*region),
|
||||
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
|
||||
| Problem::BadRecursion(cycle_entries) => {
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{aliases::Aliases, solve};
|
|||
use roc_can::abilities::{AbilitiesStore, ResolvedImpl};
|
||||
use roc_can::constraint::{Constraint, Constraints};
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_can::module::{ExposedByModule, ResolvedImplementations, RigidVariables};
|
||||
use roc_can::module::{ExposedByModule, ModuleParams, ResolvedImplementations, RigidVariables};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_collections::VecMap;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
|
@ -82,7 +82,7 @@ pub struct SolveConfig<'a> {
|
|||
pub checkmate: Option<roc_checkmate::Collector>,
|
||||
|
||||
/// Module params
|
||||
pub params_pattern: Option<roc_can::pattern::Pattern>,
|
||||
pub module_params: Option<ModuleParams>,
|
||||
pub module_params_vars: VecMap<ModuleId, Variable>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_types::subs::{Rank, Variable};
|
||||
|
||||
const DEFAULT_POOLS: usize = 8;
|
||||
|
@ -27,14 +28,14 @@ impl Pools {
|
|||
pub fn get_mut(&mut self, rank: Rank) -> &mut Vec<Variable> {
|
||||
match self.0.get_mut(rank.into_usize()) {
|
||||
Some(reference) => reference,
|
||||
None => panic!("Compiler bug: could not find pool at rank {rank}"),
|
||||
None => internal_error!("Compiler bug: could not find pool at rank {rank}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, rank: Rank) -> &Vec<Variable> {
|
||||
match self.0.get(rank.into_usize()) {
|
||||
Some(reference) => reference,
|
||||
None => panic!("Compiler bug: could not find pool at rank {rank}"),
|
||||
None => internal_error!("Compiler bug: could not find pool at rank {rank}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +47,7 @@ impl Pools {
|
|||
let last = self
|
||||
.0
|
||||
.pop()
|
||||
.unwrap_or_else(|| panic!("Attempted to split_last() on non-empty Pools"));
|
||||
.unwrap_or_else(|| internal_error!("Attempted to split_last() on non-empty Pools"));
|
||||
|
||||
(last, self.0)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use roc_can::abilities::{AbilitiesStore, MemberSpecializationInfo};
|
|||
use roc_can::constraint::Constraint::{self, *};
|
||||
use roc_can::constraint::{Cycle, LetConstraint, OpportunisticResolve};
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::module::ModuleParams;
|
||||
use roc_collections::VecMap;
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -130,7 +131,7 @@ fn run_help(
|
|||
exposed_by_module,
|
||||
derived_module,
|
||||
function_kind,
|
||||
params_pattern,
|
||||
module_params,
|
||||
module_params_vars,
|
||||
..
|
||||
} = config;
|
||||
|
@ -184,7 +185,7 @@ fn run_help(
|
|||
abilities_store,
|
||||
&mut obligation_cache,
|
||||
&mut awaiting_specializations,
|
||||
params_pattern,
|
||||
module_params,
|
||||
module_params_vars,
|
||||
);
|
||||
|
||||
|
@ -243,10 +244,10 @@ fn solve(
|
|||
abilities_store: &mut AbilitiesStore,
|
||||
obligation_cache: &mut ObligationCache,
|
||||
awaiting_specializations: &mut AwaitingSpecializations,
|
||||
params_pattern: Option<roc_can::pattern::Pattern>,
|
||||
module_params: Option<ModuleParams>,
|
||||
module_params_vars: VecMap<ModuleId, Variable>,
|
||||
) -> State {
|
||||
let scope = Scope::new(params_pattern);
|
||||
let scope = Scope::new(module_params);
|
||||
|
||||
let initial = Work::Constraint {
|
||||
scope: &scope.clone(),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use roc_can::module::ModuleParams;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
|
@ -9,29 +10,19 @@ pub struct Scope {
|
|||
}
|
||||
|
||||
impl Scope {
|
||||
pub fn new(params_pattern: Option<roc_can::pattern::Pattern>) -> Self {
|
||||
match params_pattern {
|
||||
Some(params_pattern) => match params_pattern {
|
||||
roc_can::pattern::Pattern::RecordDestructure {
|
||||
whole_var: _,
|
||||
ext_var: _,
|
||||
destructs,
|
||||
} => {
|
||||
let mut symbols = Vec::with_capacity(destructs.len());
|
||||
let mut variables = Vec::with_capacity(destructs.len());
|
||||
pub fn new(opt_module_params: Option<ModuleParams>) -> Self {
|
||||
match opt_module_params {
|
||||
Some(module_params) => {
|
||||
let mut symbols = Vec::with_capacity(module_params.destructs.len());
|
||||
let mut variables = Vec::with_capacity(module_params.destructs.len());
|
||||
|
||||
for destruct in destructs {
|
||||
symbols.push(destruct.value.symbol);
|
||||
variables.push(destruct.value.var);
|
||||
}
|
||||
|
||||
Self { symbols, variables }
|
||||
for destruct in module_params.destructs {
|
||||
symbols.push(destruct.value.symbol);
|
||||
variables.push(destruct.value.var);
|
||||
}
|
||||
_ => unreachable!(
|
||||
"other pattern types should have parsed: {:?}",
|
||||
params_pattern
|
||||
),
|
||||
},
|
||||
|
||||
Self { symbols, variables }
|
||||
}
|
||||
None => Self {
|
||||
symbols: Vec::default(),
|
||||
variables: Vec::default(),
|
||||
|
|
|
@ -438,7 +438,7 @@ fn check_derived_typechecks_and_golden(
|
|||
pending_derives: Default::default(),
|
||||
exposed_by_module: &exposed_for_module.exposed_by_module,
|
||||
derived_module: Default::default(),
|
||||
params_pattern: None,
|
||||
module_params: None,
|
||||
module_params_vars: imported_param_vars,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
|
@ -1885,22 +1885,22 @@ fn task_always_twice() {
|
|||
effectAfter : Effect a, (a -> Effect b) -> Effect b
|
||||
effectAfter = \(@Effect thunk), transform -> transform (thunk {})
|
||||
|
||||
Task a err : Effect (Result a err)
|
||||
MyTask a err : Effect (Result a err)
|
||||
|
||||
always : a -> Task a *
|
||||
always : a -> MyTask a *
|
||||
always = \x -> effectAlways (Ok x)
|
||||
|
||||
fail : err -> Task * err
|
||||
fail : err -> MyTask * err
|
||||
fail = \x -> effectAlways (Err x)
|
||||
|
||||
after : Task a err, (a -> Task b err) -> Task b err
|
||||
after : MyTask a err, (a -> MyTask b err) -> MyTask b err
|
||||
after = \task, transform ->
|
||||
effectAfter task \res ->
|
||||
when res is
|
||||
Ok x -> transform x
|
||||
Err e -> fail e
|
||||
|
||||
main : Task {} F64
|
||||
main : MyTask {} F64
|
||||
main = after (always "foo") (\_ -> always {})
|
||||
|
||||
"#
|
||||
|
@ -1921,17 +1921,17 @@ fn wildcard_rigid() {
|
|||
|
||||
Effect a := {} -> a
|
||||
|
||||
Task a err : Effect (Result a err)
|
||||
MyTask a err : Effect (Result a err)
|
||||
|
||||
# this failed because of the `*`, but worked with `err`
|
||||
always : a -> Task a *
|
||||
always : a -> MyTask a *
|
||||
always = \x ->
|
||||
inner = \{} -> (Ok x)
|
||||
|
||||
@Effect inner
|
||||
|
||||
|
||||
main : Task {} (Frac *)
|
||||
main : MyTask {} (Frac *)
|
||||
main = always {}
|
||||
"#
|
||||
),
|
||||
|
@ -1950,16 +1950,16 @@ fn alias_of_alias_with_type_arguments() {
|
|||
|
||||
Effect a := a
|
||||
|
||||
Task a err : Effect (Result a err)
|
||||
MyTask a err : Effect (Result a err)
|
||||
|
||||
always : a -> Task a *
|
||||
always : a -> MyTask a *
|
||||
always = \x ->
|
||||
inner = (Ok x)
|
||||
|
||||
@Effect inner
|
||||
|
||||
|
||||
main : Task {} F64
|
||||
main : MyTask {} F64
|
||||
main = always {}
|
||||
"#
|
||||
),
|
||||
|
@ -1989,24 +1989,24 @@ fn todo_bad_error_message() {
|
|||
effectAfter : Effect a, (a -> Effect b) -> Effect b
|
||||
effectAfter = \(@Effect thunk), transform -> transform (thunk {})
|
||||
|
||||
Task a err : Effect (Result a err)
|
||||
MyTask a err : Effect (Result a err)
|
||||
|
||||
always : a -> Task a (Frac *)
|
||||
always : a -> MyTask a (Frac *)
|
||||
always = \x -> effectAlways (Ok x)
|
||||
|
||||
# the problem is that this restricts to `Task {} *`
|
||||
fail : err -> Task {} err
|
||||
# the problem is that this restricts to `MyTask {} *`
|
||||
fail : err -> MyTask {} err
|
||||
fail = \x -> effectAlways (Err x)
|
||||
|
||||
after : Task a err, (a -> Task b err) -> Task b err
|
||||
after : MyTask a err, (a -> MyTask b err) -> MyTask b err
|
||||
after = \task, transform ->
|
||||
effectAfter task \res ->
|
||||
when res is
|
||||
Ok x -> transform x
|
||||
# but here it must be `forall b. Task b {}`
|
||||
# but here it must be `forall b. MyTask b {}`
|
||||
Err e -> fail e
|
||||
|
||||
main : Task {} (Frac *)
|
||||
main : MyTask {} (Frac *)
|
||||
main =
|
||||
after (always "foo") (\_ -> always {})
|
||||
"#
|
||||
|
|
31
crates/compiler/test_mono/generated/as_pattern_in_closure_arg.txt
generated
Normal file
31
crates/compiler/test_mono/generated/as_pattern_in_closure_arg.txt
generated
Normal file
|
@ -0,0 +1,31 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.282 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.282;
|
||||
|
||||
procedure Test.1 (Test.12):
|
||||
let Test.6 : I64 = StructAtIndex 0 Test.12;
|
||||
let Test.5 : I64 = StructAtIndex 1 Test.12;
|
||||
let Test.3 : I64 = StructAtIndex 2 Test.12;
|
||||
let Test.4 : I64 = StructAtIndex 3 Test.12;
|
||||
let Test.18 : I64 = CallByName Num.19 Test.3 Test.5;
|
||||
let Test.19 : I64 = CallByName Num.19 Test.4 Test.6;
|
||||
let Test.17 : {I64, I64} = Struct {Test.18, Test.19};
|
||||
ret Test.17;
|
||||
|
||||
procedure Test.2 (Test.9):
|
||||
let Test.7 : I64 = StructAtIndex 2 Test.9;
|
||||
let Test.8 : I64 = StructAtIndex 3 Test.9;
|
||||
let Test.16 : {I64, I64} = CallByName Test.1 Test.9;
|
||||
let Test.10 : I64 = StructAtIndex 0 Test.16;
|
||||
let Test.11 : I64 = StructAtIndex 1 Test.16;
|
||||
let Test.15 : {I64, I64, I64, I64} = Struct {Test.7, Test.8, Test.10, Test.11};
|
||||
ret Test.15;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.20 : I64 = 4i64;
|
||||
let Test.21 : I64 = 3i64;
|
||||
let Test.22 : I64 = 1i64;
|
||||
let Test.23 : I64 = 2i64;
|
||||
let Test.14 : {I64, I64, I64, I64} = Struct {Test.20, Test.21, Test.22, Test.23};
|
||||
let Test.13 : {I64, I64, I64, I64} = CallByName Test.2 Test.14;
|
||||
ret Test.13;
|
|
@ -38,8 +38,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Test.10 (Test.69, #Attr.12):
|
||||
let Test.72 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
let #Derived_gen.18 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.18 then
|
||||
let #Derived_gen.20 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.20 then
|
||||
free #Attr.12;
|
||||
ret Test.72;
|
||||
else
|
||||
|
@ -53,7 +53,7 @@ procedure Test.10 (Test.69, #Attr.12):
|
|||
procedure Test.14 (Test.45, #Attr.12):
|
||||
let Test.55 : {{}, []} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.54 : [<r>C {}, C *self {{}, []}] = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.19:
|
||||
joinpoint #Derived_gen.18:
|
||||
let Test.50 : {} = Struct {};
|
||||
let Test.51 : U8 = GetTagId Test.54;
|
||||
joinpoint Test.52 Test.15:
|
||||
|
@ -80,14 +80,14 @@ procedure Test.14 (Test.45, #Attr.12):
|
|||
jump Test.52 Test.53;
|
||||
|
||||
in
|
||||
let #Derived_gen.20 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.20 then
|
||||
let #Derived_gen.19 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.19 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.19;
|
||||
jump #Derived_gen.18;
|
||||
else
|
||||
inc Test.54;
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.19;
|
||||
jump #Derived_gen.18;
|
||||
|
||||
procedure Test.20 (Test.21, Test.18):
|
||||
let Test.23 : [C {}, C []] = CallByName Test.32 Test.21 Test.18;
|
||||
|
|
|
@ -47,11 +47,11 @@ procedure Str.3 (#Attr.2, #Attr.3):
|
|||
procedure Test.1 (Test.5):
|
||||
ret Test.5;
|
||||
|
||||
procedure Test.11 (#Derived_gen.10, #Derived_gen.11):
|
||||
procedure Test.11 (#Derived_gen.3, #Derived_gen.4):
|
||||
joinpoint Test.27 Test.12 #Attr.12:
|
||||
let Test.34 : Int1 = UnionAtIndex (Id 2) (Index 1) #Attr.12;
|
||||
let Test.33 : [<rnw><null>, C *self Int1, C *self Int1] = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.14:
|
||||
joinpoint #Derived_gen.12:
|
||||
joinpoint Test.31 Test.29:
|
||||
let Test.30 : U8 = GetTagId Test.33;
|
||||
switch Test.30:
|
||||
|
@ -78,16 +78,16 @@ procedure Test.11 (#Derived_gen.10, #Derived_gen.11):
|
|||
jump Test.31 Test.32;
|
||||
|
||||
in
|
||||
let #Derived_gen.15 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.15 then
|
||||
let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.13 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.14;
|
||||
jump #Derived_gen.12;
|
||||
else
|
||||
inc Test.33;
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.14;
|
||||
jump #Derived_gen.12;
|
||||
in
|
||||
jump Test.27 #Derived_gen.10 #Derived_gen.11;
|
||||
jump Test.27 #Derived_gen.3 #Derived_gen.4;
|
||||
|
||||
procedure Test.2 (Test.13):
|
||||
ret Test.13;
|
||||
|
@ -118,7 +118,7 @@ procedure Test.6 (Test.7, Test.8, Test.5):
|
|||
procedure Test.9 (Test.10, #Attr.12):
|
||||
let Test.43 : Int1 = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.42 : [<rnw><null>, C *self Int1, C *self Int1] = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.12:
|
||||
joinpoint #Derived_gen.14:
|
||||
let Test.39 : U8 = GetTagId Test.42;
|
||||
joinpoint Test.40 Test.38:
|
||||
switch Test.43:
|
||||
|
@ -146,14 +146,14 @@ procedure Test.9 (Test.10, #Attr.12):
|
|||
jump Test.40 Test.41;
|
||||
|
||||
in
|
||||
let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.13 then
|
||||
let #Derived_gen.15 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.15 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.12;
|
||||
jump #Derived_gen.14;
|
||||
else
|
||||
inc Test.42;
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.12;
|
||||
jump #Derived_gen.14;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.45 : Int1 = false;
|
||||
|
|
56
crates/compiler/test_mono/generated/dbg_expr.txt
generated
Normal file
56
crates/compiler/test_mono/generated/dbg_expr.txt
generated
Normal file
|
@ -0,0 +1,56 @@
|
|||
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||
dec Inspect.318;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.305 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.304 : Str = CallByName Inspect.64 Inspect.305;
|
||||
ret Inspect.304;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.57 (Inspect.277):
|
||||
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.320;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.281 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Num.96 (#Attr.2):
|
||||
let Num.282 : Str = lowlevel NumToStr #Attr.2;
|
||||
ret Num.282;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : I64 = 1i64;
|
||||
let Test.2 : I64 = 2i64;
|
||||
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||
dbg Test.3;
|
||||
dec Test.3;
|
||||
let Test.4 : I64 = CallByName Num.19 Test.5 Test.2;
|
||||
ret Test.4;
|
58
crates/compiler/test_mono/generated/dbg_inside_string.txt
generated
Normal file
58
crates/compiler/test_mono/generated/dbg_inside_string.txt
generated
Normal file
|
@ -0,0 +1,58 @@
|
|||
procedure Inspect.250 (Inspect.251, Inspect.249):
|
||||
let Inspect.323 : Str = "\"";
|
||||
let Inspect.322 : Str = CallByName Inspect.63 Inspect.251 Inspect.323;
|
||||
dec Inspect.323;
|
||||
let Inspect.318 : Str = CallByName Inspect.63 Inspect.322 Inspect.249;
|
||||
let Inspect.319 : Str = "\"";
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.318 Inspect.319;
|
||||
dec Inspect.319;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.305 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.304 : Str = CallByName Inspect.64 Inspect.305;
|
||||
ret Inspect.304;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.47 (Inspect.249):
|
||||
let Inspect.313 : Str = CallByName Inspect.30 Inspect.249;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : Str = CallByName Inspect.47 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.250 Inspect.308 Inspect.312;
|
||||
dec Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.321 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.321;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.238;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : Str = "Hello ";
|
||||
let Test.2 : Str = "world";
|
||||
inc Test.2;
|
||||
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||
dbg Test.3;
|
||||
dec Test.3;
|
||||
let Test.8 : Str = "!";
|
||||
let Test.6 : Str = CallByName Str.3 Test.2 Test.8;
|
||||
dec Test.8;
|
||||
let Test.4 : Str = CallByName Str.3 Test.5 Test.6;
|
||||
dec Test.6;
|
||||
ret Test.4;
|
56
crates/compiler/test_mono/generated/dbg_nested_expr.txt
generated
Normal file
56
crates/compiler/test_mono/generated/dbg_nested_expr.txt
generated
Normal file
|
@ -0,0 +1,56 @@
|
|||
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||
dec Inspect.318;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.324 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.323 : Str = CallByName Inspect.64 Inspect.324;
|
||||
ret Inspect.323;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.57 (Inspect.277):
|
||||
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.320;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Num.96 (#Attr.2):
|
||||
let Num.281 : Str = lowlevel NumToStr #Attr.2;
|
||||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 : I64 = 1i64;
|
||||
let Test.7 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.7;
|
||||
dec Test.7;
|
||||
let Test.8 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.8;
|
||||
dec Test.8;
|
||||
let Test.9 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.9;
|
||||
dec Test.9;
|
||||
ret Test.6;
|
|
@ -76,7 +76,7 @@ procedure List.8 (#Attr.2, #Attr.3):
|
|||
let List.649 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.649;
|
||||
|
||||
procedure List.95 (#Derived_gen.10, #Derived_gen.11, #Derived_gen.12, #Derived_gen.13, #Derived_gen.14):
|
||||
procedure List.95 (#Derived_gen.13, #Derived_gen.14, #Derived_gen.15, #Derived_gen.16, #Derived_gen.17):
|
||||
joinpoint List.628 List.169 List.170 List.171 List.172 List.173:
|
||||
let List.630 : Int1 = CallByName Num.22 List.172 List.173;
|
||||
if List.630 then
|
||||
|
@ -90,8 +90,8 @@ procedure List.95 (#Derived_gen.10, #Derived_gen.11, #Derived_gen.12, #Derived_g
|
|||
dec List.169;
|
||||
ret List.170;
|
||||
in
|
||||
inc #Derived_gen.10;
|
||||
jump List.628 #Derived_gen.10 #Derived_gen.11 #Derived_gen.12 #Derived_gen.13 #Derived_gen.14;
|
||||
inc #Derived_gen.13;
|
||||
jump List.628 #Derived_gen.13 #Derived_gen.14 #Derived_gen.15 #Derived_gen.16 #Derived_gen.17;
|
||||
|
||||
procedure Num.127 (#Attr.2):
|
||||
let Num.282 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -17,7 +17,7 @@ procedure Test.4 (Test.5, #Attr.12):
|
|||
let Test.16 : I64 = CallByName Num.19 Test.5 Test.17;
|
||||
ret Test.16;
|
||||
|
||||
procedure Test.0 (#Derived_gen.0):
|
||||
procedure Test.0 (#Derived_gen.2):
|
||||
joinpoint Test.7 Test.1:
|
||||
let Test.21 : I64 = 1i64;
|
||||
let Test.9 : I64 = CallByName Num.19 Test.1 Test.21;
|
||||
|
@ -33,4 +33,4 @@ procedure Test.0 (#Derived_gen.0):
|
|||
ret Test.8;
|
||||
|
||||
in
|
||||
jump Test.7 #Derived_gen.0;
|
||||
jump Test.7 #Derived_gen.2;
|
||||
|
|
|
@ -91,8 +91,8 @@ procedure Test.19 ():
|
|||
let Test.120 : [C Str, C {List U8, I64}] = TagId(0) Test.122;
|
||||
ret Test.120;
|
||||
else
|
||||
dec Test.92;
|
||||
dec Test.93;
|
||||
dec Test.92;
|
||||
let Test.128 : Str = "not a number";
|
||||
let Test.126 : [C Str, C {List U8, I64}] = TagId(0) Test.128;
|
||||
ret Test.126;
|
||||
|
|
|
@ -108,8 +108,8 @@ procedure Test.0 ():
|
|||
else
|
||||
let Test.22 : Str = "B";
|
||||
let Test.23 : Int1 = lowlevel Eq Test.22 Test.12;
|
||||
dec Test.22;
|
||||
dec Test.12;
|
||||
dec Test.22;
|
||||
if Test.23 then
|
||||
let Test.17 : [C U8, C U8, C ] = TagId(1) Test.2;
|
||||
jump Test.13 Test.17;
|
||||
|
|
18
crates/compiler/test_mono/generated/opaque_as_pattern_in_closure_arg.txt
generated
Normal file
18
crates/compiler/test_mono/generated/opaque_as_pattern_in_closure_arg.txt
generated
Normal file
|
@ -0,0 +1,18 @@
|
|||
procedure Num.21 (#Attr.2, #Attr.3):
|
||||
let Num.281 : U64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Test.2 (Test.8):
|
||||
let Test.14 : U64 = 2i64;
|
||||
let Test.13 : U64 = CallByName Num.21 Test.8 Test.14;
|
||||
ret Test.13;
|
||||
|
||||
procedure Test.3 (Test.7):
|
||||
let Test.12 : U64 = CallByName Test.2 Test.7;
|
||||
let Test.11 : {U64, U64} = Struct {Test.7, Test.12};
|
||||
ret Test.11;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.10 : U64 = 42i64;
|
||||
let Test.9 : {U64, U64} = CallByName Test.3 Test.10;
|
||||
ret Test.9;
|
|
@ -20,9 +20,9 @@ procedure Test.0 ():
|
|||
if Test.13 then
|
||||
let Test.6 : {I64, Str} = CallByName Test.1;
|
||||
let Test.5 : Int1 = CallByName Bool.11 Test.6 Test.4;
|
||||
dec Test.6;
|
||||
let #Derived_gen.0 : Str = StructAtIndex 1 Test.4;
|
||||
dec #Derived_gen.0;
|
||||
dec Test.6;
|
||||
ret Test.5;
|
||||
else
|
||||
let #Derived_gen.1 : Str = StructAtIndex 1 Test.4;
|
||||
|
|
59
crates/compiler/test_mono/generated/pizza_dbg.txt
generated
Normal file
59
crates/compiler/test_mono/generated/pizza_dbg.txt
generated
Normal file
|
@ -0,0 +1,59 @@
|
|||
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||
dec Inspect.318;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.322 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.321 : Str = CallByName Inspect.64 Inspect.322;
|
||||
ret Inspect.321;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.57 (Inspect.277):
|
||||
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.320;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.281 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Num.96 (#Attr.2):
|
||||
let Num.282 : Str = lowlevel NumToStr #Attr.2;
|
||||
ret Num.282;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : I64 = 1i64;
|
||||
let Test.5 : Str = CallByName Inspect.33 Test.4;
|
||||
dbg Test.5;
|
||||
dec Test.5;
|
||||
let Test.9 : I64 = 2i64;
|
||||
let Test.3 : I64 = CallByName Num.19 Test.4 Test.9;
|
||||
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.6;
|
||||
dec Test.6;
|
||||
ret Test.3;
|
31
crates/compiler/test_mono/generated/record_as_pattern_in_closure_arg.txt
generated
Normal file
31
crates/compiler/test_mono/generated/record_as_pattern_in_closure_arg.txt
generated
Normal file
|
@ -0,0 +1,31 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.282 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.282;
|
||||
|
||||
procedure Test.1 (Test.12):
|
||||
let Test.6 : I64 = StructAtIndex 0 Test.12;
|
||||
let Test.5 : I64 = StructAtIndex 1 Test.12;
|
||||
let Test.3 : I64 = StructAtIndex 2 Test.12;
|
||||
let Test.4 : I64 = StructAtIndex 3 Test.12;
|
||||
let Test.18 : I64 = CallByName Num.19 Test.3 Test.5;
|
||||
let Test.19 : I64 = CallByName Num.19 Test.4 Test.6;
|
||||
let Test.17 : {I64, I64} = Struct {Test.18, Test.19};
|
||||
ret Test.17;
|
||||
|
||||
procedure Test.2 (Test.9):
|
||||
let Test.7 : I64 = StructAtIndex 2 Test.9;
|
||||
let Test.8 : I64 = StructAtIndex 3 Test.9;
|
||||
let Test.16 : {I64, I64} = CallByName Test.1 Test.9;
|
||||
let Test.10 : I64 = StructAtIndex 0 Test.16;
|
||||
let Test.11 : I64 = StructAtIndex 1 Test.16;
|
||||
let Test.15 : {I64, I64, I64, I64} = Struct {Test.7, Test.8, Test.10, Test.11};
|
||||
ret Test.15;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.20 : I64 = 4i64;
|
||||
let Test.21 : I64 = 3i64;
|
||||
let Test.22 : I64 = 1i64;
|
||||
let Test.23 : I64 = 2i64;
|
||||
let Test.14 : {I64, I64, I64, I64} = Struct {Test.20, Test.21, Test.22, Test.23};
|
||||
let Test.13 : {I64, I64, I64, I64} = CallByName Test.2 Test.14;
|
||||
ret Test.13;
|
|
@ -31,7 +31,7 @@ procedure List.71 (#Attr.2, #Attr.3):
|
|||
let List.643 : List [<rnnu>C List *self] = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.643;
|
||||
|
||||
procedure List.95 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
procedure List.95 (#Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4, #Derived_gen.5):
|
||||
joinpoint List.631 List.169 List.170 List.171 List.172 List.173:
|
||||
let List.633 : Int1 = CallByName Num.22 List.172 List.173;
|
||||
if List.633 then
|
||||
|
@ -45,8 +45,8 @@ procedure List.95 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.
|
|||
dec List.169;
|
||||
ret List.170;
|
||||
in
|
||||
inc #Derived_gen.0;
|
||||
jump List.631 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
inc #Derived_gen.1;
|
||||
jump List.631 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4 #Derived_gen.5;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.282 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -10,7 +10,7 @@ procedure Num.21 (#Attr.2, #Attr.3):
|
|||
let Num.281 : U8 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Test.1 (#Derived_gen.0, #Derived_gen.1):
|
||||
procedure Test.1 (#Derived_gen.2, #Derived_gen.3):
|
||||
joinpoint Test.11 Test.2 Test.3:
|
||||
let Test.26 : U8 = 0i64;
|
||||
let Test.22 : Int1 = CallByName Bool.11 Test.2 Test.26;
|
||||
|
@ -33,9 +33,9 @@ procedure Test.1 (#Derived_gen.0, #Derived_gen.1):
|
|||
let Test.14 : [<rnu><null>, C *self U8] = TagId(0) Test.3 Test.2;
|
||||
jump Test.11 Test.13 Test.14;
|
||||
in
|
||||
jump Test.11 #Derived_gen.0 #Derived_gen.1;
|
||||
jump Test.11 #Derived_gen.2 #Derived_gen.3;
|
||||
|
||||
procedure Test.4 (#Derived_gen.2, #Derived_gen.3):
|
||||
procedure Test.4 (#Derived_gen.0, #Derived_gen.1):
|
||||
joinpoint Test.15 Test.5 #Attr.12:
|
||||
let Test.20 : U8 = UnionAtIndex (Id 0) (Index 1) #Attr.12;
|
||||
let Test.19 : [<rnu><null>, C *self U8] = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
|
@ -61,7 +61,7 @@ procedure Test.4 (#Derived_gen.2, #Derived_gen.3):
|
|||
decref #Attr.12;
|
||||
jump #Derived_gen.4;
|
||||
in
|
||||
jump Test.15 #Derived_gen.2 #Derived_gen.3;
|
||||
jump Test.15 #Derived_gen.0 #Derived_gen.1;
|
||||
|
||||
procedure Test.6 (Test.7):
|
||||
ret Test.7;
|
||||
|
|
|
@ -8,8 +8,8 @@ procedure Str.3 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Test.11 (Test.29, #Attr.12):
|
||||
let Test.32 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.9 then
|
||||
let #Derived_gen.11 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.11 then
|
||||
free #Attr.12;
|
||||
ret Test.32;
|
||||
else
|
||||
|
@ -19,11 +19,11 @@ procedure Test.11 (Test.29, #Attr.12):
|
|||
procedure Test.11 (Test.29, Test.10):
|
||||
ret Test.10;
|
||||
|
||||
procedure Test.14 (#Derived_gen.7, #Derived_gen.8):
|
||||
procedure Test.14 (#Derived_gen.0, #Derived_gen.1):
|
||||
joinpoint Test.38 Test.37 #Attr.12:
|
||||
let Test.46 : {} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.45 : I64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.10:
|
||||
joinpoint #Derived_gen.9:
|
||||
let Test.44 : {} = Struct {};
|
||||
let Test.43 : {} = CallByName Test.11 Test.44 Test.46;
|
||||
let Test.39 : [<r>C {}, C I64 {}] = CallByName Test.9 Test.43 Test.45;
|
||||
|
@ -38,15 +38,15 @@ procedure Test.14 (#Derived_gen.7, #Derived_gen.8):
|
|||
jump Test.38 Test.41 Test.39;
|
||||
|
||||
in
|
||||
let #Derived_gen.11 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.11 then
|
||||
let #Derived_gen.10 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.10 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.10;
|
||||
jump #Derived_gen.9;
|
||||
else
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.10;
|
||||
jump #Derived_gen.9;
|
||||
in
|
||||
jump Test.38 #Derived_gen.7 #Derived_gen.8;
|
||||
jump Test.38 #Derived_gen.0 #Derived_gen.1;
|
||||
|
||||
procedure Test.2 ():
|
||||
let Test.6 : Str = "Hello";
|
||||
|
|
|
@ -23,7 +23,7 @@ procedure Test.2 (Test.9, Test.10):
|
|||
let Test.29 : U64 = CallByName Test.3 Test.9;
|
||||
ret Test.29;
|
||||
else
|
||||
joinpoint #Derived_gen.4:
|
||||
joinpoint #Derived_gen.1:
|
||||
let Test.13 : Str = UnionAtIndex (Id 0) (Index 0) Test.10;
|
||||
let Test.14 : [<rnu><null>, C Str *self] = UnionAtIndex (Id 0) (Index 1) Test.10;
|
||||
let Test.33 : U64 = CallByName Test.3 Test.12;
|
||||
|
@ -36,15 +36,15 @@ procedure Test.2 (Test.9, Test.10):
|
|||
else
|
||||
ret Test.16;
|
||||
in
|
||||
let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.9;
|
||||
if #Derived_gen.5 then
|
||||
let #Derived_gen.2 : Int1 = lowlevel RefCountIsUnique Test.9;
|
||||
if #Derived_gen.2 then
|
||||
dec Test.11;
|
||||
free Test.9;
|
||||
jump #Derived_gen.4;
|
||||
jump #Derived_gen.1;
|
||||
else
|
||||
inc Test.12;
|
||||
decref Test.9;
|
||||
jump #Derived_gen.4;
|
||||
jump #Derived_gen.1;
|
||||
|
||||
procedure Test.3 (Test.17):
|
||||
let Test.26 : U8 = 1i64;
|
||||
|
@ -55,22 +55,22 @@ procedure Test.3 (Test.17):
|
|||
ret Test.22;
|
||||
else
|
||||
let Test.18 : [<rnu><null>, C Str *self] = UnionAtIndex (Id 0) (Index 1) Test.17;
|
||||
joinpoint #Derived_gen.1:
|
||||
joinpoint #Derived_gen.3:
|
||||
let Test.24 : U64 = 1i64;
|
||||
let Test.25 : U64 = CallByName Test.3 Test.18;
|
||||
let Test.23 : U64 = CallByName Num.19 Test.24 Test.25;
|
||||
ret Test.23;
|
||||
in
|
||||
let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique Test.17;
|
||||
if #Derived_gen.3 then
|
||||
let #Derived_gen.2 : Str = UnionAtIndex (Id 0) (Index 0) Test.17;
|
||||
dec #Derived_gen.2;
|
||||
let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.17;
|
||||
if #Derived_gen.5 then
|
||||
let #Derived_gen.4 : Str = UnionAtIndex (Id 0) (Index 0) Test.17;
|
||||
dec #Derived_gen.4;
|
||||
free Test.17;
|
||||
jump #Derived_gen.1;
|
||||
jump #Derived_gen.3;
|
||||
else
|
||||
inc Test.18;
|
||||
decref Test.17;
|
||||
jump #Derived_gen.1;
|
||||
jump #Derived_gen.3;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : [<rnu><null>, C Str *self] = TagId(1) ;
|
||||
|
|
|
@ -65,7 +65,7 @@ procedure List.8 (#Attr.2, #Attr.3):
|
|||
let List.649 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.649;
|
||||
|
||||
procedure List.95 (#Derived_gen.9, #Derived_gen.10, #Derived_gen.11, #Derived_gen.12, #Derived_gen.13):
|
||||
procedure List.95 (#Derived_gen.12, #Derived_gen.13, #Derived_gen.14, #Derived_gen.15, #Derived_gen.16):
|
||||
joinpoint List.628 List.169 List.170 List.171 List.172 List.173:
|
||||
let List.630 : Int1 = CallByName Num.22 List.172 List.173;
|
||||
if List.630 then
|
||||
|
@ -79,8 +79,8 @@ procedure List.95 (#Derived_gen.9, #Derived_gen.10, #Derived_gen.11, #Derived_ge
|
|||
dec List.169;
|
||||
ret List.170;
|
||||
in
|
||||
inc #Derived_gen.9;
|
||||
jump List.628 #Derived_gen.9 #Derived_gen.10 #Derived_gen.11 #Derived_gen.12 #Derived_gen.13;
|
||||
inc #Derived_gen.12;
|
||||
jump List.628 #Derived_gen.12 #Derived_gen.13 #Derived_gen.14 #Derived_gen.15 #Derived_gen.16;
|
||||
|
||||
procedure Num.127 (#Attr.2):
|
||||
let Num.282 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -141,7 +141,7 @@ procedure List.8 (#Attr.2, #Attr.3):
|
|||
let List.676 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.676;
|
||||
|
||||
procedure List.95 (#Derived_gen.26, #Derived_gen.27, #Derived_gen.28, #Derived_gen.29, #Derived_gen.30):
|
||||
procedure List.95 (#Derived_gen.35, #Derived_gen.36, #Derived_gen.37, #Derived_gen.38, #Derived_gen.39):
|
||||
joinpoint List.628 List.169 List.170 List.171 List.172 List.173:
|
||||
let List.630 : Int1 = CallByName Num.22 List.172 List.173;
|
||||
if List.630 then
|
||||
|
@ -155,10 +155,10 @@ procedure List.95 (#Derived_gen.26, #Derived_gen.27, #Derived_gen.28, #Derived_g
|
|||
dec List.169;
|
||||
ret List.170;
|
||||
in
|
||||
inc #Derived_gen.26;
|
||||
jump List.628 #Derived_gen.26 #Derived_gen.27 #Derived_gen.28 #Derived_gen.29 #Derived_gen.30;
|
||||
inc #Derived_gen.35;
|
||||
jump List.628 #Derived_gen.35 #Derived_gen.36 #Derived_gen.37 #Derived_gen.38 #Derived_gen.39;
|
||||
|
||||
procedure List.95 (#Derived_gen.34, #Derived_gen.35, #Derived_gen.36, #Derived_gen.37, #Derived_gen.38):
|
||||
procedure List.95 (#Derived_gen.49, #Derived_gen.50, #Derived_gen.51, #Derived_gen.52, #Derived_gen.53):
|
||||
joinpoint List.655 List.169 List.170 List.171 List.172 List.173:
|
||||
let List.657 : Int1 = CallByName Num.22 List.172 List.173;
|
||||
if List.657 then
|
||||
|
@ -172,8 +172,8 @@ procedure List.95 (#Derived_gen.34, #Derived_gen.35, #Derived_gen.36, #Derived_g
|
|||
dec List.169;
|
||||
ret List.170;
|
||||
in
|
||||
inc #Derived_gen.34;
|
||||
jump List.655 #Derived_gen.34 #Derived_gen.35 #Derived_gen.36 #Derived_gen.37 #Derived_gen.38;
|
||||
inc #Derived_gen.49;
|
||||
jump List.655 #Derived_gen.49 #Derived_gen.50 #Derived_gen.51 #Derived_gen.52 #Derived_gen.53;
|
||||
|
||||
procedure Num.127 (#Attr.2):
|
||||
let Num.286 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -657,6 +657,31 @@ fn record_optional_field_function_use_default() {
|
|||
"
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn record_as_pattern_in_closure_arg() {
|
||||
r"
|
||||
f = \{x, y, w, h} -> (x + w, y + h)
|
||||
|
||||
g = \({ x, y } as box) ->
|
||||
(right, bottom) = f box
|
||||
(x, y, right, bottom)
|
||||
|
||||
g { x: 1, y: 2, w: 3, h: 4 }
|
||||
"
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn opaque_as_pattern_in_closure_arg() {
|
||||
r"
|
||||
Opaque := U64
|
||||
|
||||
f = \(@Opaque x) -> x * 2
|
||||
g = \(@Opaque x as s) -> (x, f s)
|
||||
|
||||
g (@Opaque 42)
|
||||
"
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn quicksort_help() {
|
||||
// do we still need with_larger_debug_stack?
|
||||
|
@ -3243,6 +3268,45 @@ fn dbg_str_followed_by_number() {
|
|||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn dbg_expr() {
|
||||
indoc!(
|
||||
r#"
|
||||
1 + (dbg 2)
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn dbg_nested_expr() {
|
||||
indoc!(
|
||||
r#"
|
||||
dbg (dbg (dbg 1))
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn dbg_inside_string() {
|
||||
indoc!(
|
||||
r#"
|
||||
"Hello $(dbg "world")!"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn pizza_dbg() {
|
||||
indoc!(
|
||||
r#"
|
||||
1
|
||||
|> dbg
|
||||
|> Num.add 2
|
||||
|> dbg
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn linked_list_reverse() {
|
||||
indoc!(
|
||||
|
@ -3319,9 +3383,9 @@ fn capture_void_layout_task() {
|
|||
|
||||
Fx a : {} -> a
|
||||
|
||||
Task ok err : Fx (Result ok err)
|
||||
OtherTask ok err : Fx (Result ok err)
|
||||
|
||||
succeed : ok -> Task ok *
|
||||
succeed : ok -> OtherTask ok *
|
||||
succeed = \ok -> \{} -> Ok ok
|
||||
|
||||
after : Fx a, (a -> Fx b) -> Fx b
|
||||
|
@ -3333,7 +3397,7 @@ fn capture_void_layout_task() {
|
|||
|
||||
afterInner
|
||||
|
||||
await : Task a err, (a -> Task b err) -> Task b err
|
||||
await : OtherTask a err, (a -> OtherTask b err) -> OtherTask b err
|
||||
await = \fx, toNext ->
|
||||
inner = after fx \result ->
|
||||
when result is
|
||||
|
@ -3343,12 +3407,12 @@ fn capture_void_layout_task() {
|
|||
Err e -> (\{} -> Err e)
|
||||
inner
|
||||
|
||||
forEach : List a, (a -> Task {} err) -> Task {} err
|
||||
forEach : List a, (a -> OtherTask {} err) -> OtherTask {} err
|
||||
forEach = \list, fromElem ->
|
||||
List.walk list (succeed {}) \task, elem ->
|
||||
await task \{} -> fromElem elem
|
||||
|
||||
main : Task {} []
|
||||
main : OtherTask {} []
|
||||
main =
|
||||
forEach [] \_ -> succeed {}
|
||||
"#
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
\({ x, y } as point), (@Location inner as outer) ->
|
||||
crash ""
|
|
@ -0,0 +1,57 @@
|
|||
SpaceAfter(
|
||||
Closure(
|
||||
[
|
||||
@2-19 As(
|
||||
@2-10 RecordDestructure(
|
||||
[
|
||||
@4-5 Identifier {
|
||||
ident: "x",
|
||||
},
|
||||
@7-8 Identifier {
|
||||
ident: "y",
|
||||
},
|
||||
],
|
||||
),
|
||||
PatternAs {
|
||||
spaces_before: [],
|
||||
identifier: @14-19 "point",
|
||||
},
|
||||
),
|
||||
@23-47 As(
|
||||
@23-38 Apply(
|
||||
@23-32 OpaqueRef(
|
||||
"@Location",
|
||||
),
|
||||
[
|
||||
@33-38 Identifier {
|
||||
ident: "inner",
|
||||
},
|
||||
],
|
||||
),
|
||||
PatternAs {
|
||||
spaces_before: [],
|
||||
identifier: @42-47 "outer",
|
||||
},
|
||||
),
|
||||
],
|
||||
@56-64 SpaceBefore(
|
||||
Apply(
|
||||
@56-61 Crash,
|
||||
[
|
||||
@62-64 Str(
|
||||
PlainLine(
|
||||
"",
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1,2 @@
|
|||
\({ x, y } as point), (@Location inner as outer) ->
|
||||
crash ""
|
|
@ -1,3 +1 @@
|
|||
dbg 1 == 1
|
||||
|
||||
4
|
||||
dbg 1
|
|
@ -1,32 +1,12 @@
|
|||
SpaceBefore(
|
||||
SpaceAfter(
|
||||
Dbg(
|
||||
@5-11 BinOps(
|
||||
[
|
||||
(
|
||||
@5-6 Num(
|
||||
"1",
|
||||
),
|
||||
@7-9 Equals,
|
||||
),
|
||||
],
|
||||
@10-11 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
@13-14 SpaceBefore(
|
||||
Num(
|
||||
"4",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
SpaceAfter(
|
||||
Apply(
|
||||
@0-5 Dbg,
|
||||
[
|
||||
Newline,
|
||||
@4-5 Num(
|
||||
"1",
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
|
||||
dbg 1 == 1
|
||||
|
||||
4
|
||||
dbg 1
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
dbg 1 == 1
|
||||
|
||||
4
|
|
@ -0,0 +1,34 @@
|
|||
SpaceBefore(
|
||||
SpaceAfter(
|
||||
DbgStmt(
|
||||
@5-11 BinOps(
|
||||
[
|
||||
(
|
||||
@5-6 Num(
|
||||
"1",
|
||||
),
|
||||
@7-9 Equals,
|
||||
),
|
||||
],
|
||||
@10-11 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
@13-14 SpaceBefore(
|
||||
Num(
|
||||
"4",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
dbg 1 == 1
|
||||
|
||||
4
|
|
@ -1,5 +1,5 @@
|
|||
SpaceAfter(
|
||||
Dbg(
|
||||
DbgStmt(
|
||||
@4-16 Tuple(
|
||||
[
|
||||
@5-6 Num(
|
|
@ -22,24 +22,6 @@ SpacesBefore {
|
|||
},
|
||||
item: [],
|
||||
},
|
||||
generates: KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [],
|
||||
item: GeneratesKeyword,
|
||||
after: [],
|
||||
},
|
||||
item: UppercaseIdent(
|
||||
"Bar",
|
||||
),
|
||||
},
|
||||
generates_with: KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [],
|
||||
item: WithKeyword,
|
||||
after: [],
|
||||
},
|
||||
item: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
hosted Foo exposes [] imports [] generates Bar with []
|
||||
hosted Foo exposes [] imports []
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
app [main] {
|
||||
pf:
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.14.0/dC5ceT962N_4jmoyoffVdphJ_4GlW3YMhAPyGPr-nU0.tar.br",
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br",
|
||||
}
|
||||
|
||||
main =
|
||||
|
|
|
@ -20,7 +20,7 @@ Full(
|
|||
],
|
||||
platform_marker: None,
|
||||
package_name: @17-132 PackageName(
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.14.0/dC5ceT962N_4jmoyoffVdphJ_4GlW3YMhAPyGPr-nU0.tar.br",
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br",
|
||||
),
|
||||
},
|
||||
[
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
app [main] { pf:
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.14.0/dC5ceT962N_4jmoyoffVdphJ_4GlW3YMhAPyGPr-nU0.tar.br"
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br"
|
||||
}
|
||||
|
||||
main =
|
||||
|
|
|
@ -10,9 +10,3 @@ hosted Foo
|
|||
Blah,
|
||||
Baz.{ stuff, things },
|
||||
]
|
||||
generates Bar with
|
||||
[
|
||||
map,
|
||||
after,
|
||||
loop,
|
||||
]
|
||||
|
|
|
@ -95,58 +95,6 @@ SpacesBefore {
|
|||
],
|
||||
},
|
||||
},
|
||||
generates: KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [
|
||||
Newline,
|
||||
],
|
||||
item: GeneratesKeyword,
|
||||
after: [],
|
||||
},
|
||||
item: UppercaseIdent(
|
||||
"Bar",
|
||||
),
|
||||
},
|
||||
generates_with: KeywordItem {
|
||||
keyword: Spaces {
|
||||
before: [],
|
||||
item: WithKeyword,
|
||||
after: [
|
||||
Newline,
|
||||
],
|
||||
},
|
||||
item: Collection {
|
||||
items: [
|
||||
@239-242 SpaceBefore(
|
||||
ExposedName(
|
||||
"map",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@256-261 SpaceBefore(
|
||||
ExposedName(
|
||||
"after",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@275-279 SpaceBefore(
|
||||
ExposedName(
|
||||
"loop",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
final_comments: [
|
||||
Newline,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
|
|
@ -10,9 +10,3 @@ hosted Foo
|
|||
Blah,
|
||||
Baz.{ stuff, things },
|
||||
]
|
||||
generates Bar with
|
||||
[
|
||||
map,
|
||||
after,
|
||||
loop,
|
||||
]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1 |> dbg
|
|
@ -0,0 +1,16 @@
|
|||
SpaceAfter(
|
||||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-1 Num(
|
||||
"1",
|
||||
),
|
||||
@2-4 Pizza,
|
||||
),
|
||||
],
|
||||
@5-8 Dbg,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue