mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Add load tests for apps
This commit is contained in:
parent
6c6e1d9ee3
commit
62186fdda4
14 changed files with 404 additions and 23 deletions
|
@ -12,7 +12,7 @@ use roc_constrain::module::{
|
||||||
};
|
};
|
||||||
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
||||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_parse::ast::{self, Attempting, ExposesEntry, ImportsEntry, InterfaceHeader};
|
use roc_parse::ast::{self, Attempting, ExposesEntry, ImportsEntry};
|
||||||
use roc_parse::module::module_defs;
|
use roc_parse::module::module_defs;
|
||||||
use roc_parse::parser::{Fail, Parser, State};
|
use roc_parse::parser::{Fail, Parser, State};
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
|
@ -108,6 +108,7 @@ pub enum LoadingProblem {
|
||||||
fail: Fail,
|
fail: Fail,
|
||||||
},
|
},
|
||||||
MsgChannelDied,
|
MsgChannelDied,
|
||||||
|
TriedToImportAppModule,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MaybeShared<'a, 'b, A, B> {
|
enum MaybeShared<'a, 'b, A, B> {
|
||||||
|
@ -515,13 +516,36 @@ fn load_filename(
|
||||||
#[allow(clippy::let_and_return)]
|
#[allow(clippy::let_and_return)]
|
||||||
let answer = match roc_parse::module::header().parse(&arena, state) {
|
let answer = match roc_parse::module::header().parse(&arena, state) {
|
||||||
Ok((ast::Module::Interface { header }, state)) => {
|
Ok((ast::Module::Interface { header }, state)) => {
|
||||||
let module_id = send_interface_header(header, state, module_ids, msg_tx);
|
let module_id = send_header(
|
||||||
|
header.name,
|
||||||
|
header.exposes.into_bump_slice(),
|
||||||
|
header.imports.into_bump_slice(),
|
||||||
|
state,
|
||||||
|
module_ids,
|
||||||
|
msg_tx,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(module_id)
|
Ok(module_id)
|
||||||
}
|
}
|
||||||
Ok((ast::Module::App { .. }, _)) => {
|
Ok((ast::Module::App { header }, state)) => match module_ids {
|
||||||
panic!("TODO finish loading an App module");
|
MaybeShared::Shared(_, _) => {
|
||||||
|
// If this is Shared, it means we're trying to import
|
||||||
|
// an app module which is not the root. Not alllowed!
|
||||||
|
Err(LoadingProblem::TriedToImportAppModule)
|
||||||
}
|
}
|
||||||
|
unique_modules @ MaybeShared::Unique(_, _) => {
|
||||||
|
let module_id = send_header(
|
||||||
|
header.name,
|
||||||
|
header.provides.into_bump_slice(),
|
||||||
|
header.imports.into_bump_slice(),
|
||||||
|
state,
|
||||||
|
unique_modules,
|
||||||
|
msg_tx,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(module_id)
|
||||||
|
}
|
||||||
|
},
|
||||||
Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }),
|
Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -534,36 +558,37 @@ fn load_filename(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_interface_header<'a>(
|
fn send_header<'a>(
|
||||||
header: InterfaceHeader<'a>,
|
name: Located<roc_parse::header::ModuleName<'a>>,
|
||||||
|
exposes: &'a [Located<ExposesEntry<'a>>],
|
||||||
|
imports: &'a [Located<ImportsEntry<'a>>],
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
shared_modules: SharedModules<'_, '_>,
|
shared_modules: SharedModules<'_, '_>,
|
||||||
msg_tx: MsgSender,
|
msg_tx: MsgSender,
|
||||||
) -> ModuleId {
|
) -> ModuleId {
|
||||||
use MaybeShared::*;
|
use MaybeShared::*;
|
||||||
|
|
||||||
let declared_name: ModuleName = header.name.value.as_str().into();
|
let declared_name: ModuleName = name.value.as_str().into();
|
||||||
|
|
||||||
// TODO check to see if declared_name is consistent with filename.
|
// TODO check to see if declared_name is consistent with filename.
|
||||||
// If it isn't, report a problem!
|
// If it isn't, report a problem!
|
||||||
|
|
||||||
let mut imports: Vec<(ModuleName, Vec<Ident>, Region)> =
|
let mut imported: Vec<(ModuleName, Vec<Ident>, Region)> = Vec::with_capacity(imports.len());
|
||||||
Vec::with_capacity(header.imports.len());
|
|
||||||
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
||||||
let mut scope_size = 0;
|
let mut scope_size = 0;
|
||||||
|
|
||||||
for loc_entry in header.imports {
|
for loc_entry in imports {
|
||||||
let (module_name, exposed) = exposed_from_import(&loc_entry.value);
|
let (module_name, exposed) = exposed_from_import(&loc_entry.value);
|
||||||
|
|
||||||
scope_size += exposed.len();
|
scope_size += exposed.len();
|
||||||
|
|
||||||
imports.push((module_name, exposed, loc_entry.region));
|
imported.push((module_name, exposed, loc_entry.region));
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_exposes = header.exposes.len();
|
let num_exposes = exposes.len();
|
||||||
let mut deps_by_name: MutMap<ModuleName, ModuleId> =
|
let mut deps_by_name: MutMap<ModuleName, ModuleId> =
|
||||||
HashMap::with_capacity_and_hasher(num_exposes, default_hasher());
|
HashMap::with_capacity_and_hasher(num_exposes, default_hasher());
|
||||||
let mut exposes: Vec<Symbol> = Vec::with_capacity(num_exposes);
|
let mut exposed: Vec<Symbol> = Vec::with_capacity(num_exposes);
|
||||||
|
|
||||||
// Make sure the module_ids has ModuleIds for all our deps,
|
// Make sure the module_ids has ModuleIds for all our deps,
|
||||||
// then record those ModuleIds in can_module_ids for later.
|
// then record those ModuleIds in can_module_ids for later.
|
||||||
|
@ -592,7 +617,7 @@ fn send_interface_header<'a>(
|
||||||
// For each of our imports, add an entry to deps_by_name
|
// For each of our imports, add an entry to deps_by_name
|
||||||
//
|
//
|
||||||
// e.g. for `imports [ Foo.{ bar } ]`, add `Foo` to deps_by_name
|
// e.g. for `imports [ Foo.{ bar } ]`, add `Foo` to deps_by_name
|
||||||
for (module_name, exposed, region) in imports.into_iter() {
|
for (module_name, exposed, region) in imported.into_iter() {
|
||||||
let cloned_module_name = module_name.clone();
|
let cloned_module_name = module_name.clone();
|
||||||
let module_id = module_ids.get_or_insert(&module_name.into());
|
let module_id = module_ids.get_or_insert(&module_name.into());
|
||||||
|
|
||||||
|
@ -618,7 +643,7 @@ fn send_interface_header<'a>(
|
||||||
//
|
//
|
||||||
// We must *not* add them to scope yet, or else the Defs will
|
// We must *not* add them to scope yet, or else the Defs will
|
||||||
// incorrectly think they're shadowing them!
|
// incorrectly think they're shadowing them!
|
||||||
for loc_exposed in header.exposes.iter() {
|
for loc_exposed in exposes.iter() {
|
||||||
// Use get_or_insert here because the ident_ids may already
|
// Use get_or_insert here because the ident_ids may already
|
||||||
// created an IdentId for this, when it was imported exposed
|
// created an IdentId for this, when it was imported exposed
|
||||||
// in a dependent module.
|
// in a dependent module.
|
||||||
|
@ -629,7 +654,7 @@ fn send_interface_header<'a>(
|
||||||
let ident_id = ident_ids.get_or_insert(&loc_exposed.value.as_str().into());
|
let ident_id = ident_ids.get_or_insert(&loc_exposed.value.as_str().into());
|
||||||
let symbol = Symbol::new(home, ident_id);
|
let symbol = Symbol::new(home, ident_id);
|
||||||
|
|
||||||
exposes.push(symbol);
|
exposed.push(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
|
@ -648,7 +673,7 @@ fn send_interface_header<'a>(
|
||||||
// and also add any exposed values to scope.
|
// and also add any exposed values to scope.
|
||||||
//
|
//
|
||||||
// e.g. for `imports [ Foo.{ bar } ]`, add `Foo` to deps_by_name and `bar` to scope.
|
// e.g. for `imports [ Foo.{ bar } ]`, add `Foo` to deps_by_name and `bar` to scope.
|
||||||
for (module_name, exposed, region) in imports.into_iter() {
|
for (module_name, exposed, region) in imported.into_iter() {
|
||||||
let module_id = module_ids.get_or_insert(&module_name.clone().into());
|
let module_id = module_ids.get_or_insert(&module_name.clone().into());
|
||||||
|
|
||||||
deps_by_name.insert(module_name, module_id);
|
deps_by_name.insert(module_name, module_id);
|
||||||
|
@ -672,11 +697,11 @@ fn send_interface_header<'a>(
|
||||||
//
|
//
|
||||||
// We must *not* add them to scope yet, or else the Defs will
|
// We must *not* add them to scope yet, or else the Defs will
|
||||||
// incorrectly think they're shadowing them!
|
// incorrectly think they're shadowing them!
|
||||||
for loc_exposed in header.exposes.iter() {
|
for loc_exposed in exposes.iter() {
|
||||||
let ident_id = ident_ids.add(loc_exposed.value.as_str().into());
|
let ident_id = ident_ids.add(loc_exposed.value.as_str().into());
|
||||||
let symbol = Symbol::new(home, ident_id);
|
let symbol = Symbol::new(home, ident_id);
|
||||||
|
|
||||||
exposes.push(symbol);
|
exposed.push(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
|
@ -712,7 +737,7 @@ fn send_interface_header<'a>(
|
||||||
module_name: declared_name,
|
module_name: declared_name,
|
||||||
imported_modules,
|
imported_modules,
|
||||||
deps_by_name,
|
deps_by_name,
|
||||||
exposes,
|
exposes: exposed,
|
||||||
src,
|
src,
|
||||||
exposed_imports: scope,
|
exposed_imports: scope,
|
||||||
}))
|
}))
|
||||||
|
|
111
compiler/load/tests/fixtures/build/app_with_deps/AStar.roc
vendored
Normal file
111
compiler/load/tests/fixtures/build/app_with_deps/AStar.roc
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
interface AStar
|
||||||
|
exposes [ initialModel, reconstructPath, updateCost, cheapestOpen, astar, findPath ]
|
||||||
|
imports []
|
||||||
|
|
||||||
|
|
||||||
|
# a port of https://github.com/krisajenkins/elm-astar/blob/2.1.3/src/AStar/Generalised.elm
|
||||||
|
|
||||||
|
Model position :
|
||||||
|
{ evaluated : Set position
|
||||||
|
, openSet : Set position
|
||||||
|
, costs : Map.Map position Float
|
||||||
|
, cameFrom : Map.Map position position
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initialModel : position -> Model position
|
||||||
|
initialModel = \start ->
|
||||||
|
{ evaluated : Set.empty
|
||||||
|
, openSet : Set.singleton start
|
||||||
|
, costs : Map.singleton start 0.0
|
||||||
|
, cameFrom : Map.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cheapestOpen : (position -> Float), Model position -> Result position [ KeyNotFound ]*
|
||||||
|
cheapestOpen = \costFunction, model ->
|
||||||
|
|
||||||
|
folder = \position, resSmallestSoFar ->
|
||||||
|
when Map.get model.costs position is
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
|
Ok cost ->
|
||||||
|
positionCost = costFunction position
|
||||||
|
|
||||||
|
when resSmallestSoFar is
|
||||||
|
Err _ -> Ok { position, cost: cost + positionCost }
|
||||||
|
Ok smallestSoFar ->
|
||||||
|
if positionCost + cost < smallestSoFar.cost then
|
||||||
|
Ok { position, cost: cost + positionCost }
|
||||||
|
|
||||||
|
else
|
||||||
|
Ok smallestSoFar
|
||||||
|
|
||||||
|
Set.foldl model.openSet folder (Err KeyNotFound)
|
||||||
|
|> Result.map (\x -> x.position)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
reconstructPath : Map position position, position -> List position
|
||||||
|
reconstructPath = \cameFrom, goal ->
|
||||||
|
when Map.get cameFrom goal is
|
||||||
|
Err KeyNotFound ->
|
||||||
|
[]
|
||||||
|
|
||||||
|
Ok next ->
|
||||||
|
List.push (reconstructPath cameFrom next) goal
|
||||||
|
|
||||||
|
updateCost : position, position, Model position -> Model position
|
||||||
|
updateCost = \current, neighbour, model ->
|
||||||
|
newCameFrom = Map.insert model.cameFrom neighbour current
|
||||||
|
|
||||||
|
newCosts = Map.insert model.costs neighbour distanceTo
|
||||||
|
|
||||||
|
distanceTo = reconstructPath newCameFrom neighbour
|
||||||
|
|> List.len
|
||||||
|
|> Num.toFloat
|
||||||
|
|
||||||
|
newModel = { model & costs : newCosts , cameFrom : newCameFrom }
|
||||||
|
|
||||||
|
when Map.get model.costs neighbour is
|
||||||
|
Err KeyNotFound ->
|
||||||
|
newModel
|
||||||
|
|
||||||
|
Ok previousDistance ->
|
||||||
|
if distanceTo < previousDistance then
|
||||||
|
newModel
|
||||||
|
|
||||||
|
else
|
||||||
|
model
|
||||||
|
|
||||||
|
|
||||||
|
findPath : { costFunction: (position, position -> Float), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [ KeyNotFound ]*
|
||||||
|
findPath = \{ costFunction, moveFunction, start, end } ->
|
||||||
|
astar costFunction moveFunction end (initialModel start)
|
||||||
|
|
||||||
|
|
||||||
|
astar : (position, position -> Float), (position -> Set position), position, Model position -> [ Err [ KeyNotFound ]*, Ok (List position) ]*
|
||||||
|
astar = \costFn, moveFn, goal, model ->
|
||||||
|
when cheapestOpen (\position -> costFn goal position) model is
|
||||||
|
Err _ ->
|
||||||
|
Err KeyNotFound
|
||||||
|
|
||||||
|
Ok current ->
|
||||||
|
if current == goal then
|
||||||
|
Ok (reconstructPath model.cameFrom goal)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
modelPopped = { model & openSet : Set.remove model.openSet current, evaluated : Set.insert model.evaluated current }
|
||||||
|
|
||||||
|
neighbours = moveFn current
|
||||||
|
|
||||||
|
newNeighbours = Set.diff neighbours modelPopped.evaluated
|
||||||
|
|
||||||
|
modelWithNeighbours = { modelPopped & openSet : Set.union modelPopped.openSet newNeighbours }
|
||||||
|
|
||||||
|
modelWithCosts = Set.foldl newNeighbours (\nb, md -> updateCost current nb md) modelWithNeighbours
|
||||||
|
|
||||||
|
astar costFn moveFn goal modelWithCosts
|
||||||
|
|
15
compiler/load/tests/fixtures/build/app_with_deps/Dep1.roc
vendored
Normal file
15
compiler/load/tests/fixtures/build/app_with_deps/Dep1.roc
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
interface Dep1
|
||||||
|
exposes [ three, str, Unit, Identity, one, two ]
|
||||||
|
imports [ Dep3.Blah.{ foo } ]
|
||||||
|
|
||||||
|
one = 1
|
||||||
|
|
||||||
|
two = foo
|
||||||
|
|
||||||
|
three = 3.0
|
||||||
|
|
||||||
|
str = "string!"
|
||||||
|
|
||||||
|
Unit : [ Unit ]
|
||||||
|
|
||||||
|
Identity a : [ Identity a ]
|
10
compiler/load/tests/fixtures/build/app_with_deps/Dep2.roc
vendored
Normal file
10
compiler/load/tests/fixtures/build/app_with_deps/Dep2.roc
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
interface Dep2
|
||||||
|
exposes [ one, two, blah ]
|
||||||
|
imports [ Dep3.Blah.{ foo, bar } ]
|
||||||
|
|
||||||
|
one = 1
|
||||||
|
|
||||||
|
blah = foo
|
||||||
|
|
||||||
|
two = 2.0
|
||||||
|
|
10
compiler/load/tests/fixtures/build/app_with_deps/Dep3/Blah.roc
vendored
Normal file
10
compiler/load/tests/fixtures/build/app_with_deps/Dep3/Blah.roc
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
interface Dep3.Blah
|
||||||
|
exposes [ one, two, foo, bar ]
|
||||||
|
imports []
|
||||||
|
|
||||||
|
one = 1
|
||||||
|
|
||||||
|
two = 2
|
||||||
|
|
||||||
|
foo = "foo from Dep3"
|
||||||
|
bar = "bar from Dep3"
|
7
compiler/load/tests/fixtures/build/app_with_deps/ImportAlias.roc
vendored
Normal file
7
compiler/load/tests/fixtures/build/app_with_deps/ImportAlias.roc
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
interface ImportAlias
|
||||||
|
exposes [ unit ]
|
||||||
|
imports [ Dep1 ]
|
||||||
|
|
||||||
|
unit : Dep1.Unit
|
||||||
|
unit = Unit
|
||||||
|
|
18
compiler/load/tests/fixtures/build/app_with_deps/ManualAttr.roc
vendored
Normal file
18
compiler/load/tests/fixtures/build/app_with_deps/ManualAttr.roc
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
interface ManualAttr
|
||||||
|
exposes []
|
||||||
|
imports []
|
||||||
|
|
||||||
|
# manually replicates the Attr wrapping that uniqueness inference uses, to try and find out why they are different
|
||||||
|
# It is very important that there are no signatures here! elm uses an optimization that leads to less copying when
|
||||||
|
# signatures are given.
|
||||||
|
|
||||||
|
map =
|
||||||
|
unAttr = \Attr _ foobar -> foobar
|
||||||
|
|
||||||
|
r = Attr unknown "bar"
|
||||||
|
|
||||||
|
s = Attr unknown2 { left : Attr Shared "foo" }
|
||||||
|
|
||||||
|
when True is
|
||||||
|
_ -> { y : r }
|
||||||
|
_ -> { y : (unAttr s).left }
|
5
compiler/load/tests/fixtures/build/app_with_deps/OneDep.roc
vendored
Normal file
5
compiler/load/tests/fixtures/build/app_with_deps/OneDep.roc
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
interface OneDep
|
||||||
|
exposes [ str ]
|
||||||
|
imports [ Dep3.Blah.{ foo } ]
|
||||||
|
|
||||||
|
str = foo
|
31
compiler/load/tests/fixtures/build/app_with_deps/Primary.roc
vendored
Normal file
31
compiler/load/tests/fixtures/build/app_with_deps/Primary.roc
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
app Primary
|
||||||
|
provides [ blah2, blah3, str, alwaysThree, identity, z, w, succeed, withDefault, yay ]
|
||||||
|
imports [ Dep1, Dep2.{ two, foo }, Dep3.Blah.{ bar }, Res ]
|
||||||
|
|
||||||
|
blah2 = Dep2.two
|
||||||
|
blah3 = bar
|
||||||
|
|
||||||
|
str = Dep1.str
|
||||||
|
|
||||||
|
# alwaysThree = \_ -> Dep1.three # TODO FIXME for some reason this infers as a circular type
|
||||||
|
alwaysThree = \_ -> "foo"
|
||||||
|
|
||||||
|
identity = \a -> a
|
||||||
|
|
||||||
|
z = identity (alwaysThree {})
|
||||||
|
|
||||||
|
w : Dep1.Identity {}
|
||||||
|
w = Identity {}
|
||||||
|
|
||||||
|
succeed : a -> Dep1.Identity a
|
||||||
|
succeed = \x -> Identity x
|
||||||
|
|
||||||
|
withDefault = Res.withDefault
|
||||||
|
|
||||||
|
yay : Res.Res {} err
|
||||||
|
yay =
|
||||||
|
ok = Ok "foo"
|
||||||
|
|
||||||
|
f = \_ -> {}
|
||||||
|
|
||||||
|
Res.map ok f
|
49
compiler/load/tests/fixtures/build/app_with_deps/Quicksort.roc
vendored
Normal file
49
compiler/load/tests/fixtures/build/app_with_deps/Quicksort.roc
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
app Quicksort
|
||||||
|
provides [ swap, partition, quicksort ]
|
||||||
|
imports []
|
||||||
|
|
||||||
|
quicksort : List (Num a), Int, Int -> List (Num a)
|
||||||
|
quicksort = \list, low, high ->
|
||||||
|
when partition low high list is
|
||||||
|
Pair partitionIndex partitioned ->
|
||||||
|
partitioned
|
||||||
|
|> quicksort low (partitionIndex - 1)
|
||||||
|
|> quicksort (partitionIndex + 1) high
|
||||||
|
|
||||||
|
|
||||||
|
swap : Int, Int, List a -> List a
|
||||||
|
swap = \i, j, list ->
|
||||||
|
when Pair (List.get list i) (List.get list j) is
|
||||||
|
Pair (Ok atI) (Ok atJ) ->
|
||||||
|
list
|
||||||
|
|> List.set i atJ
|
||||||
|
|> List.set j atI
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
partition : Int, Int, List (Num a) -> [ Pair Int (List (Num a)) ]
|
||||||
|
partition = \low, high, initialList ->
|
||||||
|
when List.get initialList high is
|
||||||
|
Ok pivot ->
|
||||||
|
go = \i, j, list ->
|
||||||
|
if j < high then
|
||||||
|
when List.get list j is
|
||||||
|
Ok value ->
|
||||||
|
if value <= pivot then
|
||||||
|
go (i + 1) (j + 1) (swap (i + 1) j list)
|
||||||
|
else
|
||||||
|
go i (j + 1) list
|
||||||
|
|
||||||
|
Err _ ->
|
||||||
|
Pair i list
|
||||||
|
else
|
||||||
|
Pair i list
|
||||||
|
|
||||||
|
when go (low - 1) low initialList is
|
||||||
|
Pair newI newList ->
|
||||||
|
Pair (newI + 1) (swap (newI + 1) high newList)
|
||||||
|
|
||||||
|
Err _ ->
|
||||||
|
Pair (low - 1) initialList
|
8
compiler/load/tests/fixtures/build/app_with_deps/Records.roc
vendored
Normal file
8
compiler/load/tests/fixtures/build/app_with_deps/Records.roc
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
interface Records
|
||||||
|
exposes [ intVal ]
|
||||||
|
imports []
|
||||||
|
|
||||||
|
intVal =
|
||||||
|
foo = \{ x } -> x
|
||||||
|
|
||||||
|
foo { x: 5 }
|
32
compiler/load/tests/fixtures/build/app_with_deps/Res.roc
vendored
Normal file
32
compiler/load/tests/fixtures/build/app_with_deps/Res.roc
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
interface Res
|
||||||
|
exposes [ Res, withDefault, map, andThen, ConsList ]
|
||||||
|
imports []
|
||||||
|
|
||||||
|
Res ok err : [ Ok ok, Err err ]
|
||||||
|
|
||||||
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
# TODO FIXME for some reason, exposing this causes a stack overflow
|
||||||
|
# listMap : ConsList a, (a -> b) -> ConsList b
|
||||||
|
# listMap = \list, f ->
|
||||||
|
# when list is
|
||||||
|
# Nil -> Nil
|
||||||
|
# Cons x xs -> Cons (f x) (listMap xs f)
|
||||||
|
|
||||||
|
map : Res a err, (a -> b) -> Res b err
|
||||||
|
map = \result, transform ->
|
||||||
|
when result is
|
||||||
|
Ok ok -> Ok (transform ok)
|
||||||
|
Err err -> Err err
|
||||||
|
|
||||||
|
withDefault : Res a err, a -> a
|
||||||
|
withDefault = \result, default ->
|
||||||
|
when result is
|
||||||
|
Ok ok -> ok
|
||||||
|
Err _ -> default
|
||||||
|
|
||||||
|
andThen : Res a err, (a -> Res b err) -> Res b err
|
||||||
|
andThen = \result, transform ->
|
||||||
|
when result is
|
||||||
|
Ok ok -> transform ok
|
||||||
|
Err err -> Err err
|
19
compiler/load/tests/fixtures/build/app_with_deps/WithBuiltins.roc
vendored
Normal file
19
compiler/load/tests/fixtures/build/app_with_deps/WithBuiltins.roc
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
interface WithBuiltins
|
||||||
|
exposes [ floatTest, divisionFn, divisionTest, intTest, constantNum, fromDep2, divDep1ByDep2 ]
|
||||||
|
imports [ Dep1, Dep2.{ two } ]
|
||||||
|
|
||||||
|
floatTest = Float.highest
|
||||||
|
|
||||||
|
divisionFn = Float.div
|
||||||
|
|
||||||
|
x = 5.0
|
||||||
|
|
||||||
|
divisionTest = Float.highest / x
|
||||||
|
|
||||||
|
intTest = Int.highest
|
||||||
|
|
||||||
|
constantNum = 5
|
||||||
|
|
||||||
|
fromDep2 = Dep2.two
|
||||||
|
|
||||||
|
divDep1ByDep2 = Dep1.three / fromDep2
|
|
@ -212,7 +212,7 @@ mod test_load {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_and_typecheck_quicksort() {
|
fn iface_quicksort() {
|
||||||
test_async(async {
|
test_async(async {
|
||||||
let subs_by_module = MutMap::default();
|
let subs_by_module = MutMap::default();
|
||||||
let loaded_module =
|
let loaded_module =
|
||||||
|
@ -229,6 +229,23 @@ mod test_load {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn app_quicksort() {
|
||||||
|
test_async(async {
|
||||||
|
let subs_by_module = MutMap::default();
|
||||||
|
let loaded_module = load_fixture("app_with_deps", "Quicksort", subs_by_module).await;
|
||||||
|
|
||||||
|
expect_types(
|
||||||
|
loaded_module,
|
||||||
|
hashmap! {
|
||||||
|
"swap" => "Int, Int, List a -> List a",
|
||||||
|
"partition" => "Int, Int, List (Num a) -> [ Pair Int (List (Num a)) ]",
|
||||||
|
"quicksort" => "List (Num a), Int, Int -> List (Num a)",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_astar() {
|
fn load_astar() {
|
||||||
test_async(async {
|
test_async(async {
|
||||||
|
@ -266,7 +283,7 @@ mod test_load {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_dep_types() {
|
fn iface_dep_types() {
|
||||||
test_async(async {
|
test_async(async {
|
||||||
let subs_by_module = MutMap::default();
|
let subs_by_module = MutMap::default();
|
||||||
let loaded_module =
|
let loaded_module =
|
||||||
|
@ -290,6 +307,30 @@ mod test_load {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn app_dep_types() {
|
||||||
|
test_async(async {
|
||||||
|
let subs_by_module = MutMap::default();
|
||||||
|
let loaded_module = load_fixture("app_with_deps", "Primary", subs_by_module).await;
|
||||||
|
|
||||||
|
expect_types(
|
||||||
|
loaded_module,
|
||||||
|
hashmap! {
|
||||||
|
"blah2" => "Float",
|
||||||
|
"blah3" => "Str",
|
||||||
|
"str" => "Str",
|
||||||
|
"alwaysThree" => "* -> Str",
|
||||||
|
"identity" => "a -> a",
|
||||||
|
"z" => "Str",
|
||||||
|
"w" => "Dep1.Identity {}",
|
||||||
|
"succeed" => "a -> Dep1.Identity a",
|
||||||
|
"yay" => "Res.Res {} err",
|
||||||
|
"withDefault" => "Res.Res a *, a -> a",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn imported_dep_regression() {
|
fn imported_dep_regression() {
|
||||||
test_async(async {
|
test_async(async {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue