mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
moved all crates into seperate folder + related path fixes
This commit is contained in:
parent
12ef03bb86
commit
eee85fa45d
1063 changed files with 92 additions and 93 deletions
111
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/AStar.roc
vendored
Normal file
111
crates/compiler/load_internal/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 F64
|
||||
, cameFrom : Map.Map position position
|
||||
}
|
||||
|
||||
|
||||
initialModel : position -> Model position
|
||||
initialModel = \start ->
|
||||
{ evaluated : Set.empty
|
||||
, openSet : Set.single start
|
||||
, costs : Dict.single start 0.0
|
||||
, cameFrom : Map.empty
|
||||
}
|
||||
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound]*
|
||||
cheapestOpen = \costFunction, model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
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.walk model.openSet (Err KeyNotFound) folder
|
||||
|> 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.append (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.toFrac
|
||||
|
||||
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 -> F64), 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 -> F64), (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.difference neighbours modelPopped.evaluated
|
||||
|
||||
modelWithNeighbours = { modelPopped & openSet : Set.union modelPopped.openSet newNeighbours }
|
||||
|
||||
modelWithCosts = Set.walk newNeighbours modelWithNeighbours (\md, nb -> updateCost current nb md)
|
||||
|
||||
astar costFn moveFn goal modelWithCosts
|
||||
|
15
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Dep1.roc
vendored
Normal file
15
crates/compiler/load_internal/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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Dep2.roc
vendored
Normal file
10
crates/compiler/load_internal/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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Dep3/Blah.roc
vendored
Normal file
10
crates/compiler/load_internal/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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/ImportAlias.roc
vendored
Normal file
7
crates/compiler/load_internal/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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/ManualAttr.roc
vendored
Normal file
18
crates/compiler/load_internal/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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/OneDep.roc
vendored
Normal file
5
crates/compiler/load_internal/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
|
30
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Primary.roc
vendored
Normal file
30
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Primary.roc
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
interface Primary
|
||||
exposes [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
|
||||
|
||||
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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Quicksort.roc
vendored
Normal file
49
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Quicksort.roc
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
app "quicksort" provides [swap, partition, partitionHelp, quicksort] to "./platform"
|
||||
|
||||
quicksort : List (Num a), Nat, Nat -> 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 : Nat, Nat, 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 : Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
when partitionHelp (low - 1) low initialList high pivot is
|
||||
Pair newI newList ->
|
||||
Pair (newI + 1) (swap (newI + 1) high newList)
|
||||
|
||||
Err _ ->
|
||||
Pair (low - 1) initialList
|
||||
|
||||
|
||||
partitionHelp : Nat, Nat, List (Num a), Nat, (Num a) -> [Pair Nat (List (Num a))]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
Ok value ->
|
||||
if value <= pivot then
|
||||
partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot
|
||||
else
|
||||
partitionHelp i (j + 1) list high pivot
|
||||
|
||||
Err _ ->
|
||||
Pair i list
|
||||
else
|
||||
Pair i list
|
57
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/QuicksortOneDef.roc
vendored
Normal file
57
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/QuicksortOneDef.roc
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
app "quicksort" provides [quicksort] to "./platform"
|
||||
|
||||
quicksort = \originalList ->
|
||||
quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
|
||||
quicksortHelp = \list, low, high ->
|
||||
if low < high then
|
||||
when partition low high list is
|
||||
Pair partitionIndex partitioned ->
|
||||
partitioned
|
||||
|> quicksortHelp low (partitionIndex - 1)
|
||||
|> quicksortHelp (partitionIndex + 1) high
|
||||
else
|
||||
list
|
||||
|
||||
|
||||
swap : Nat, Nat, 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 : Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
when partitionHelp (low - 1) low initialList high pivot is
|
||||
Pair newI newList ->
|
||||
Pair (newI + 1) (swap (newI + 1) high newList)
|
||||
|
||||
Err _ ->
|
||||
Pair (low - 1) initialList
|
||||
|
||||
|
||||
partitionHelp : Nat, Nat, List (Num a), Nat, (Num a) -> [Pair Nat (List (Num a))]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
Ok value ->
|
||||
if value <= pivot then
|
||||
partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot
|
||||
else
|
||||
partitionHelp i (j + 1) list high pivot
|
||||
|
||||
Err _ ->
|
||||
Pair i list
|
||||
else
|
||||
Pair i list
|
||||
|
||||
|
||||
|
||||
n = List.len originalList
|
||||
quicksortHelp originalList 0 (n - 1)
|
8
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Records.roc
vendored
Normal file
8
crates/compiler/load_internal/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 }
|
31
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Res.roc
vendored
Normal file
31
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Res.roc
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
interface Res
|
||||
exposes [Res, withDefault, map, andThen, ConsList]
|
||||
imports []
|
||||
|
||||
Res ok err : [Ok ok, Err err]
|
||||
|
||||
ConsList a : [Cons a (ConsList a), Nil]
|
||||
|
||||
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
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/WithBuiltins.roc
vendored
Normal file
19
crates/compiler/load_internal/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 = Num.maxF64
|
||||
|
||||
divisionFn = Num.div
|
||||
|
||||
x = 5.0
|
||||
|
||||
divisionTest = Num.maxF64 / x
|
||||
|
||||
intTest = Num.maxI64
|
||||
|
||||
constantNum = 5
|
||||
|
||||
fromDep2 = Dep2.two
|
||||
|
||||
divDep1ByDep2 = Dep1.three / fromDep2
|
111
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/AStar.roc
vendored
Normal file
111
crates/compiler/load_internal/tests/fixtures/build/interface_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 : Dict.Dict position F64
|
||||
, cameFrom : Dict.Dict position position
|
||||
}
|
||||
|
||||
|
||||
initialModel : position -> Model position
|
||||
initialModel = \start ->
|
||||
{ evaluated : Set.empty
|
||||
, openSet : Set.single start
|
||||
, costs : Dict.single start 0.0
|
||||
, cameFrom : Dict.empty
|
||||
}
|
||||
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound]*
|
||||
cheapestOpen = \costFunction, model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
when Dict.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.walk model.openSet (Err KeyNotFound) folder
|
||||
|> Result.map (\x -> x.position)
|
||||
|
||||
|
||||
|
||||
reconstructPath : Dict position position, position -> List position
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
[]
|
||||
|
||||
Ok next ->
|
||||
List.append (reconstructPath cameFrom next) goal
|
||||
|
||||
updateCost : position, position, Model position -> Model position
|
||||
updateCost = \current, neighbour, model ->
|
||||
newCameFrom = Dict.insert model.cameFrom neighbour current
|
||||
|
||||
newCosts = Dict.insert model.costs neighbour distanceTo
|
||||
|
||||
distanceTo = reconstructPath newCameFrom neighbour
|
||||
|> List.len
|
||||
|> Num.toFrac
|
||||
|
||||
newModel = { model & costs : newCosts , cameFrom : newCameFrom }
|
||||
|
||||
when Dict.get model.costs neighbour is
|
||||
Err KeyNotFound ->
|
||||
newModel
|
||||
|
||||
Ok previousDistance ->
|
||||
if distanceTo < previousDistance then
|
||||
newModel
|
||||
|
||||
else
|
||||
model
|
||||
|
||||
|
||||
findPath : { costFunction: (position, position -> F64), 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 -> F64), (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.difference neighbours modelPopped.evaluated
|
||||
|
||||
modelWithNeighbours = { modelPopped & openSet : Set.union modelPopped.openSet newNeighbours }
|
||||
|
||||
modelWithCosts = Set.walk newNeighbours modelWithNeighbours (\md, nb -> updateCost current nb md)
|
||||
|
||||
astar costFn moveFn goal modelWithCosts
|
||||
|
15
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Dep1.roc
vendored
Normal file
15
crates/compiler/load_internal/tests/fixtures/build/interface_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
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Dep2.roc
vendored
Normal file
10
crates/compiler/load_internal/tests/fixtures/build/interface_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
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Dep3/Blah.roc
vendored
Normal file
10
crates/compiler/load_internal/tests/fixtures/build/interface_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
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/ImportAlias.roc
vendored
Normal file
7
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/ImportAlias.roc
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
interface ImportAlias
|
||||
exposes [unit]
|
||||
imports [Dep1]
|
||||
|
||||
unit : Dep1.Unit
|
||||
unit = Unit
|
||||
|
18
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/ManualAttr.roc
vendored
Normal file
18
crates/compiler/load_internal/tests/fixtures/build/interface_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
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/OneDep.roc
vendored
Normal file
5
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/OneDep.roc
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
interface OneDep
|
||||
exposes [str]
|
||||
imports [Dep3.Blah.{ foo }]
|
||||
|
||||
str = foo
|
30
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Primary.roc
vendored
Normal file
30
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Primary.roc
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
interface Primary
|
||||
exposes [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
|
||||
|
||||
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
|
51
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Quicksort.roc
vendored
Normal file
51
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Quicksort.roc
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
interface Quicksort
|
||||
exposes [swap, partition, quicksort]
|
||||
imports []
|
||||
|
||||
quicksort : List (Num a), Nat, Nat -> 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 : Nat, Nat, 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 : Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
when partitionHelp (low - 1) low initialList high pivot is
|
||||
Pair newI newList ->
|
||||
Pair (newI + 1) (swap (newI + 1) high newList)
|
||||
|
||||
Err _ ->
|
||||
Pair (low - 1) initialList
|
||||
|
||||
|
||||
partitionHelp : Nat, Nat, List (Num a), Nat, (Num a) -> [Pair Nat (List (Num a))]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
Ok value ->
|
||||
if value <= pivot then
|
||||
partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot
|
||||
else
|
||||
partitionHelp i (j + 1) list high pivot
|
||||
|
||||
Err _ ->
|
||||
Pair i list
|
||||
else
|
||||
Pair i list
|
8
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Records.roc
vendored
Normal file
8
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Records.roc
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
interface Records
|
||||
exposes [intVal]
|
||||
imports []
|
||||
|
||||
intVal =
|
||||
foo = \{ x } -> x
|
||||
|
||||
foo { x: 5 }
|
31
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Res.roc
vendored
Normal file
31
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/Res.roc
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
interface Res
|
||||
exposes [Res, withDefault, map, listMap, andThen, ConsList]
|
||||
imports []
|
||||
|
||||
Res ok err : [Ok ok, Err err]
|
||||
|
||||
ConsList a : [Cons a (ConsList a), Nil]
|
||||
|
||||
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
crates/compiler/load_internal/tests/fixtures/build/interface_with_deps/WithBuiltins.roc
vendored
Normal file
19
crates/compiler/load_internal/tests/fixtures/build/interface_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 = Num.maxF64
|
||||
|
||||
divisionFn = Num.div
|
||||
|
||||
x = 5.0
|
||||
|
||||
divisionTest = Num.maxF64 / x
|
||||
|
||||
intTest = Num.maxI64
|
||||
|
||||
constantNum = 5
|
||||
|
||||
fromDep2 = Dep2.two
|
||||
|
||||
divDep1ByDep2 = Dep1.three / fromDep2
|
8
crates/compiler/load_internal/tests/fixtures/build/no_deps/MissingDep.roc
vendored
Normal file
8
crates/compiler/load_internal/tests/fixtures/build/no_deps/MissingDep.roc
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
interface MissingDep
|
||||
exposes [unit]
|
||||
imports [ThisFileIsMissing]
|
||||
|
||||
Unit : [Unit]
|
||||
|
||||
unit : Unit
|
||||
unit = Unit
|
7
crates/compiler/load_internal/tests/fixtures/build/no_deps/Principal.roc
vendored
Normal file
7
crates/compiler/load_internal/tests/fixtures/build/no_deps/Principal.roc
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
interface Principal
|
||||
exposes [identity, intVal]
|
||||
imports []
|
||||
|
||||
identity = \a -> a
|
||||
|
||||
intVal = identity "hi"
|
8
crates/compiler/load_internal/tests/fixtures/build/no_deps/Unit.roc
vendored
Normal file
8
crates/compiler/load_internal/tests/fixtures/build/no_deps/Unit.roc
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
interface Unit
|
||||
exposes [unit]
|
||||
imports []
|
||||
|
||||
Unit : [Unit]
|
||||
|
||||
unit : Unit
|
||||
unit = Unit
|
7
crates/compiler/load_internal/tests/helpers/mod.rs
Normal file
7
crates/compiler/load_internal/tests/helpers/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
extern crate bumpalo;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn fixtures_dir() -> PathBuf {
|
||||
Path::new("tests").join("fixtures").join("build")
|
||||
}
|
887
crates/compiler/load_internal/tests/test_load.rs
Normal file
887
crates/compiler/load_internal/tests/test_load.rs
Normal file
|
@ -0,0 +1,887 @@
|
|||
#![cfg(test)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate indoc;
|
||||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
#[macro_use]
|
||||
extern crate maplit;
|
||||
|
||||
extern crate bumpalo;
|
||||
extern crate roc_collections;
|
||||
extern crate roc_load_internal;
|
||||
extern crate roc_module;
|
||||
|
||||
mod helpers;
|
||||
|
||||
use crate::helpers::fixtures_dir;
|
||||
use bumpalo::Bump;
|
||||
use roc_can::module::ExposedByModule;
|
||||
use roc_load_internal::file::Threading;
|
||||
use roc_load_internal::file::{LoadResult, LoadStart, LoadedModule, LoadingProblem, Phase};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::can_problem;
|
||||
use roc_reporting::report::RenderTarget;
|
||||
use roc_reporting::report::RocDocAllocator;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::pretty_print::name_and_print_var;
|
||||
use roc_types::pretty_print::DebugPrint;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn load_and_typecheck<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename, RenderTarget::Generic)?;
|
||||
|
||||
match roc_load_internal::file::load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::SolveTypes,
|
||||
target_info,
|
||||
Default::default(), // these tests will re-compile the builtins
|
||||
RenderTarget::Generic,
|
||||
Threading::Single,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
TypeChecked(module) => Ok(module),
|
||||
}
|
||||
}
|
||||
|
||||
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
// HELPERS
|
||||
|
||||
fn format_can_problems(
|
||||
problems: Vec<Problem>,
|
||||
home: ModuleId,
|
||||
interns: &Interns,
|
||||
filename: PathBuf,
|
||||
src: &str,
|
||||
) -> String {
|
||||
use ven_pretty::DocAllocator;
|
||||
|
||||
let src_lines: Vec<&str> = src.split('\n').collect();
|
||||
let lines = LineInfo::new(src);
|
||||
let alloc = RocDocAllocator::new(&src_lines, home, interns);
|
||||
let reports = problems
|
||||
.into_iter()
|
||||
.map(|problem| can_problem(&alloc, &lines, filename.clone(), problem).pretty(&alloc));
|
||||
|
||||
let mut buf = String::new();
|
||||
alloc
|
||||
.stack(reports)
|
||||
.append(alloc.line())
|
||||
.1
|
||||
.render_raw(70, &mut roc_reporting::report::CiWrite::new(&mut buf))
|
||||
.unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
fn multiple_modules(subdir: &str, files: Vec<(&str, &str)>) -> Result<LoadedModule, String> {
|
||||
let arena = Bump::new();
|
||||
let arena = &arena;
|
||||
|
||||
match multiple_modules_help(subdir, arena, files) {
|
||||
Err(io_error) => panic!("IO trouble: {:?}", io_error),
|
||||
Ok(Err(LoadingProblem::FormattedReport(buf))) => Err(buf),
|
||||
Ok(Err(loading_problem)) => Err(format!("{:?}", loading_problem)),
|
||||
Ok(Ok(mut loaded_module)) => {
|
||||
let home = loaded_module.module_id;
|
||||
let (filepath, src) = loaded_module.sources.get(&home).unwrap();
|
||||
|
||||
let can_problems = loaded_module.can_problems.remove(&home).unwrap_or_default();
|
||||
if !can_problems.is_empty() {
|
||||
return Err(format_can_problems(
|
||||
can_problems,
|
||||
home,
|
||||
&loaded_module.interns,
|
||||
filepath.clone(),
|
||||
src,
|
||||
));
|
||||
}
|
||||
|
||||
assert!(loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default()
|
||||
.is_empty(),);
|
||||
|
||||
Ok(loaded_module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn multiple_modules_help<'a>(
|
||||
subdir: &str,
|
||||
arena: &'a Bump,
|
||||
mut files: Vec<(&str, &str)>,
|
||||
) -> Result<Result<LoadedModule, roc_load_internal::file::LoadingProblem<'a>>, std::io::Error> {
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
|
||||
let mut file_handles: Vec<_> = Vec::new();
|
||||
|
||||
// Use a deterministic temporary directory.
|
||||
// We can't have all tests use "tmp" because tests run in parallel,
|
||||
// so append the test name to the tmp path.
|
||||
let tmp = format!("tmp/{}", subdir);
|
||||
let dir = roc_test_utils::TmpDir::new(&tmp);
|
||||
|
||||
let app_module = files.pop().unwrap();
|
||||
|
||||
for (name, source) in files {
|
||||
let mut filename = PathBuf::from(name);
|
||||
filename.set_extension("roc");
|
||||
let file_path = dir.path().join(filename.clone());
|
||||
|
||||
// Create any necessary intermediate directories (e.g. /platform)
|
||||
fs::create_dir_all(file_path.parent().unwrap())?;
|
||||
|
||||
let mut file = File::create(file_path)?;
|
||||
writeln!(file, "{}", source)?;
|
||||
file_handles.push(file);
|
||||
}
|
||||
|
||||
let result = {
|
||||
let (name, source) = app_module;
|
||||
|
||||
let filename = PathBuf::from(name);
|
||||
let file_path = dir.path().join(filename);
|
||||
let full_file_path = file_path.clone();
|
||||
let mut file = File::create(file_path)?;
|
||||
writeln!(file, "{}", source)?;
|
||||
file_handles.push(file);
|
||||
|
||||
load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
dir.path(),
|
||||
Default::default(),
|
||||
TARGET_INFO,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn load_fixture(
|
||||
dir_name: &str,
|
||||
module_name: &str,
|
||||
subs_by_module: ExposedByModule,
|
||||
) -> LoadedModule {
|
||||
let src_dir = fixtures_dir().join(dir_name);
|
||||
let filename = src_dir.join(format!("{}.roc", module_name));
|
||||
let arena = Bump::new();
|
||||
let loaded = load_and_typecheck(
|
||||
&arena,
|
||||
filename,
|
||||
src_dir.as_path(),
|
||||
subs_by_module,
|
||||
TARGET_INFO,
|
||||
);
|
||||
let mut loaded_module = match loaded {
|
||||
Ok(x) => x,
|
||||
Err(roc_load_internal::file::LoadingProblem::FormattedReport(report)) => {
|
||||
println!("{}", report);
|
||||
panic!("{}", report);
|
||||
}
|
||||
Err(e) => panic!("{:?}", e),
|
||||
};
|
||||
|
||||
let home = loaded_module.module_id;
|
||||
|
||||
assert_eq!(
|
||||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||
Vec::new()
|
||||
);
|
||||
assert!(loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default()
|
||||
.is_empty());
|
||||
|
||||
let expected_name = loaded_module
|
||||
.interns
|
||||
.module_ids
|
||||
.get_name(loaded_module.module_id)
|
||||
.expect("Test ModuleID not found in module_ids");
|
||||
|
||||
// App module names are hardcoded and not based on anything user-specified
|
||||
if expected_name.as_str() != ModuleName::APP {
|
||||
assert_eq!(&expected_name.as_str(), &module_name);
|
||||
}
|
||||
|
||||
loaded_module
|
||||
}
|
||||
|
||||
fn expect_types(mut loaded_module: LoadedModule, mut expected_types: HashMap<&str, &str>) {
|
||||
let home = loaded_module.module_id;
|
||||
let mut subs = loaded_module.solved.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||
Vec::new()
|
||||
);
|
||||
assert!(loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default()
|
||||
.is_empty());
|
||||
|
||||
let debug_print = DebugPrint {
|
||||
print_lambda_sets: false,
|
||||
print_only_under_alias: false,
|
||||
};
|
||||
|
||||
let interns = &loaded_module.interns;
|
||||
let declarations = loaded_module.declarations_by_id.remove(&home).unwrap();
|
||||
for index in 0..declarations.len() {
|
||||
use roc_can::expr::DeclarationTag::*;
|
||||
|
||||
match declarations.declarations[index] {
|
||||
Value | Function(_) | Recursive(_) | TailRecursive(_) => {
|
||||
let symbol = declarations.symbols[index].value;
|
||||
let expr_var = declarations.variables[index];
|
||||
|
||||
let actual_str =
|
||||
name_and_print_var(expr_var, &mut subs, home, interns, debug_print);
|
||||
let fully_qualified = symbol.fully_qualified(interns, home).to_string();
|
||||
let expected_type = expected_types
|
||||
.remove(fully_qualified.as_str())
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Defs included an unexpected symbol: {:?}", fully_qualified)
|
||||
});
|
||||
|
||||
assert_eq!((&symbol, expected_type), (&symbol, actual_str.as_str()));
|
||||
}
|
||||
Destructure(d_index) => {
|
||||
let pattern_vars = &declarations.destructs[d_index.index()].pattern_vars;
|
||||
for (symbol, expr_var) in pattern_vars.iter() {
|
||||
let actual_str =
|
||||
name_and_print_var(*expr_var, &mut subs, home, interns, debug_print);
|
||||
|
||||
let fully_qualified = symbol.fully_qualified(interns, home).to_string();
|
||||
let expected_type = expected_types
|
||||
.remove(fully_qualified.as_str())
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Defs included an unexpected symbol: {:?}", fully_qualified)
|
||||
});
|
||||
|
||||
assert_eq!((&symbol, expected_type), (&symbol, actual_str.as_str()));
|
||||
}
|
||||
}
|
||||
MutualRecursion { cycle_mark, .. } => {
|
||||
assert!(!cycle_mark.is_illegal(&subs));
|
||||
}
|
||||
Expectation => {
|
||||
// at least at the moment this does not happen
|
||||
panic!("Unexpected expectation in module declarations");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
expected_types,
|
||||
HashMap::default(),
|
||||
"Some expected types were not found in the defs"
|
||||
);
|
||||
}
|
||||
|
||||
// TESTS
|
||||
|
||||
#[test]
|
||||
fn import_transitive_alias() {
|
||||
// this had a bug where NodeColor was HostExposed, and it's `actual_var` conflicted
|
||||
// with variables in the importee
|
||||
let modules = vec![
|
||||
(
|
||||
"RBTree",
|
||||
indoc!(
|
||||
r#"
|
||||
interface RBTree exposes [RedBlackTree, empty] imports []
|
||||
|
||||
# The color of a node. Leaves are considered Black.
|
||||
NodeColor : [Red, Black]
|
||||
|
||||
RedBlackTree k v : [Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty]
|
||||
|
||||
# Create an empty dictionary.
|
||||
empty : RedBlackTree k v
|
||||
empty =
|
||||
Empty
|
||||
"#
|
||||
),
|
||||
),
|
||||
(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
interface Other exposes [empty] imports [RBTree]
|
||||
|
||||
empty : RBTree.RedBlackTree I64 I64
|
||||
empty = RBTree.empty
|
||||
"#
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
assert!(multiple_modules("import_transitive_alias", modules).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interface_with_deps() {
|
||||
let subs_by_module = Default::default();
|
||||
let src_dir = fixtures_dir().join("interface_with_deps");
|
||||
let filename = src_dir.join("Primary.roc");
|
||||
let arena = Bump::new();
|
||||
let loaded = load_and_typecheck(
|
||||
&arena,
|
||||
filename,
|
||||
src_dir.as_path(),
|
||||
subs_by_module,
|
||||
TARGET_INFO,
|
||||
);
|
||||
|
||||
let mut loaded_module = loaded.expect("Test module failed to load");
|
||||
let home = loaded_module.module_id;
|
||||
|
||||
assert_eq!(
|
||||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||
Vec::new()
|
||||
);
|
||||
assert!(loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default()
|
||||
.is_empty(),);
|
||||
|
||||
let mut def_count = 0;
|
||||
let declarations = loaded_module.declarations_by_id.remove(&home).unwrap();
|
||||
for index in 0..declarations.len() {
|
||||
use roc_can::expr::DeclarationTag::*;
|
||||
|
||||
match declarations.declarations[index] {
|
||||
Value | Function(_) | Recursive(_) | TailRecursive(_) => {
|
||||
def_count += 1;
|
||||
}
|
||||
Destructure(_) => {
|
||||
def_count += 1;
|
||||
}
|
||||
MutualRecursion { .. } => { /* do nothing, not a def */ }
|
||||
Expectation => { /* do nothing, not a def */ }
|
||||
}
|
||||
}
|
||||
|
||||
let expected_name = loaded_module
|
||||
.interns
|
||||
.module_ids
|
||||
.get_name(loaded_module.module_id)
|
||||
.expect("Test ModuleID not found in module_ids");
|
||||
|
||||
assert_eq!(expected_name.as_str(), "Primary");
|
||||
assert_eq!(def_count, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_unit() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("no_deps", "Unit", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"unit" => "Unit",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_alias() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "ImportAlias", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"unit" => "Dep1.Unit",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_and_typecheck() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "WithBuiltins", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"floatTest" => "F64",
|
||||
"divisionFn" => "Float a, Float a -> Float a",
|
||||
"x" => "Float *",
|
||||
"divisionTest" => "F64",
|
||||
"intTest" => "I64",
|
||||
"constantNum" => "Num *",
|
||||
"divisionTest" => "F64",
|
||||
"divDep1ByDep2" => "Float *",
|
||||
"fromDep2" => "Float *",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iface_quicksort() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "Quicksort", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"swap" => "Nat, Nat, List a -> List a",
|
||||
"partition" => "Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]",
|
||||
"partitionHelp" => "Nat, Nat, List (Num a), Nat, Num a -> [Pair Nat (List (Num a))]",
|
||||
"quicksort" => "List (Num a), Nat, Nat -> List (Num a)",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quicksort_one_def() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("app_with_deps", "QuicksortOneDef", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"quicksort" => "List (Num a) -> List (Num a)",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn app_quicksort() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("app_with_deps", "Quicksort", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"swap" => "Nat, Nat, List a -> List a",
|
||||
"partition" => "Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]",
|
||||
"partitionHelp" => "Nat, Nat, List (Num a), Nat, Num a -> [Pair Nat (List (Num a))]",
|
||||
"quicksort" => "List (Num a), Nat, Nat -> List (Num a)",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_astar() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "AStar", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound]*",
|
||||
"initialModel" => "position -> Model position",
|
||||
"reconstructPath" => "Dict position position, position -> List position",
|
||||
"updateCost" => "position, position, Model position -> Model position",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound]*",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound]*, Ok (List position)]*",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_principal_types() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("no_deps", "Principal", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"intVal" => "Str",
|
||||
"identity" => "a -> a",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iface_dep_types() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "Primary", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"blah2" => "Float *",
|
||||
"blah3" => "Str",
|
||||
"str" => "Str",
|
||||
"alwaysThree" => "* -> Float *",
|
||||
"identity" => "a -> a",
|
||||
"z" => "Float *",
|
||||
"w" => "Dep1.Identity {}",
|
||||
"succeed" => "a -> Dep1.Identity a",
|
||||
"yay" => "Res.Res {} err",
|
||||
"withDefault" => "Res.Res a err, a -> a",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn app_dep_types() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("app_with_deps", "Primary", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"blah2" => "Float *",
|
||||
"blah3" => "Str",
|
||||
"str" => "Str",
|
||||
"alwaysThree" => "* -> Float *",
|
||||
"identity" => "a -> a",
|
||||
"z" => "Float *",
|
||||
"w" => "Dep1.Identity {}",
|
||||
"succeed" => "a -> Dep1.Identity a",
|
||||
"yay" => "Res.Res {} err",
|
||||
"withDefault" => "Res.Res a err, a -> a",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imported_dep_regression() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "OneDep", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"str" => "Str",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_problem() {
|
||||
let modules = vec![(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
interface Main exposes [main] imports []
|
||||
|
||||
main = [
|
||||
"#
|
||||
),
|
||||
)];
|
||||
|
||||
match multiple_modules("parse_problem", modules) {
|
||||
Err(report) => assert_eq!(
|
||||
report,
|
||||
indoc!(
|
||||
"
|
||||
── UNFINISHED LIST ──────────────────────────────────── tmp/parse_problem/Main ─
|
||||
|
||||
I cannot find the end of this list:
|
||||
|
||||
3│ main = [
|
||||
^
|
||||
|
||||
You could change it to something like [1, 2, 3] or even just [].
|
||||
Anything where there is an open and a close square bracket, and where
|
||||
the elements of the list are separated by commas.
|
||||
|
||||
Note: I may be confused by indentation"
|
||||
)
|
||||
),
|
||||
Ok(_) => unreachable!("we expect failure here"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "FILE NOT FOUND")]
|
||||
fn file_not_found() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("interface_with_deps", "invalid$name", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"str" => "Str",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "FILE NOT FOUND")]
|
||||
fn imported_file_not_found() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("no_deps", "MissingDep", subs_by_module);
|
||||
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"str" => "Str",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_does_not_exist() {
|
||||
let modules = vec![(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
app "example"
|
||||
packages { pf: "./zzz-does-not-exist/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = ""
|
||||
"#
|
||||
),
|
||||
)];
|
||||
|
||||
match multiple_modules("platform_does_not_exist", modules) {
|
||||
Err(report) => {
|
||||
assert!(report.contains("FILE NOT FOUND"), "report=({})", report);
|
||||
assert!(
|
||||
report.contains("zzz-does-not-exist/main.roc"),
|
||||
"report=({})",
|
||||
report
|
||||
);
|
||||
}
|
||||
Ok(_) => unreachable!("we expect failure here"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_parse_error() {
|
||||
let modules = vec![
|
||||
(
|
||||
"platform/main.roc",
|
||||
indoc!(
|
||||
r#"
|
||||
platform "hello-c"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
blah 1 2 3 # causing a parse error on purpose
|
||||
|
||||
mainForHost : Str
|
||||
"#
|
||||
),
|
||||
),
|
||||
(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
app "hello-world"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
||||
"#
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
match multiple_modules("platform_parse_error", modules) {
|
||||
Err(report) => {
|
||||
assert!(report.contains("NOT END OF FILE"));
|
||||
assert!(report.contains("blah 1 2 3 # causing a parse error on purpose"));
|
||||
}
|
||||
Ok(_) => unreachable!("we expect failure here"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
// See https://github.com/rtfeldman/roc/issues/2413
|
||||
fn platform_exposes_main_return_by_pointer_issue() {
|
||||
let modules = vec![
|
||||
(
|
||||
"platform/main.roc",
|
||||
indoc!(
|
||||
r#"
|
||||
platform "hello-world"
|
||||
requires {} { main : { content: Str, other: Str } }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : { content: Str, other: Str }
|
||||
mainForHost = main
|
||||
"#
|
||||
),
|
||||
),
|
||||
(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
app "hello-world"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = { content: "Hello, World!\n", other: "" }
|
||||
"#
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
assert!(multiple_modules("platform_exposes_main_return_by_pointer_issue", modules).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opaque_wrapped_unwrapped_outside_defining_module() {
|
||||
let modules = vec![
|
||||
(
|
||||
"Age",
|
||||
indoc!(
|
||||
r#"
|
||||
interface Age exposes [Age] imports []
|
||||
|
||||
Age := U32
|
||||
"#
|
||||
),
|
||||
),
|
||||
(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
|
||||
twenty = @Age 20
|
||||
|
||||
readAge = \@Age n -> n
|
||||
"#
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
let err =
|
||||
multiple_modules("opaque_wrapped_unwrapped_outside_defining_module", modules).unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
indoc!(
|
||||
r#"
|
||||
── OPAQUE TYPE DECLARED OUTSIDE SCOPE ─ ...rapped_outside_defining_module/Main ─
|
||||
|
||||
The unwrapped opaque type Age referenced here:
|
||||
|
||||
3│ twenty = @Age 20
|
||||
^^^^
|
||||
|
||||
is imported from another module:
|
||||
|
||||
1│ interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
^^^^^^^^^^^
|
||||
|
||||
Note: Opaque types can only be wrapped and unwrapped in the module they are defined in!
|
||||
|
||||
── OPAQUE TYPE DECLARED OUTSIDE SCOPE ─ ...rapped_outside_defining_module/Main ─
|
||||
|
||||
The unwrapped opaque type Age referenced here:
|
||||
|
||||
5│ readAge = \@Age n -> n
|
||||
^^^^
|
||||
|
||||
is imported from another module:
|
||||
|
||||
1│ interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
^^^^^^^^^^^
|
||||
|
||||
Note: Opaque types can only be wrapped and unwrapped in the module they are defined in!
|
||||
|
||||
── UNUSED IMPORT ─── tmp/opaque_wrapped_unwrapped_outside_defining_module/Main ─
|
||||
|
||||
Nothing from Age is used in this module.
|
||||
|
||||
1│ interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
^^^^^^^^^^^
|
||||
|
||||
Since Age isn't used, you don't need to import it.
|
||||
"#
|
||||
),
|
||||
"\n{}",
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_2863_module_type_does_not_exist() {
|
||||
let modules = vec![
|
||||
(
|
||||
"platform/main.roc",
|
||||
indoc!(
|
||||
r#"
|
||||
platform "testplatform"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
||||
"#
|
||||
),
|
||||
),
|
||||
(
|
||||
"Main",
|
||||
indoc!(
|
||||
r#"
|
||||
app "test"
|
||||
packages { pf: "platform/main.roc" }
|
||||
provides [main] to pf
|
||||
|
||||
main : DoesNotExist
|
||||
main = 1
|
||||
"#
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
match multiple_modules("issue_2863_module_type_does_not_exist", modules) {
|
||||
Err(report) => {
|
||||
assert_eq!(
|
||||
report,
|
||||
indoc!(
|
||||
"
|
||||
── UNRECOGNIZED NAME ────────── tmp/issue_2863_module_type_does_not_exist/Main ─
|
||||
|
||||
Nothing is named `DoesNotExist` in this scope.
|
||||
|
||||
5│ main : DoesNotExist
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Did you mean one of these?
|
||||
|
||||
Dict
|
||||
Result
|
||||
List
|
||||
Box
|
||||
"
|
||||
)
|
||||
)
|
||||
}
|
||||
Ok(_) => unreachable!("we expect failure here"),
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue