mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Merge remote-tracking branch 'origin/main' into expect-print-values
This commit is contained in:
commit
13d0b75bc1
124 changed files with 5745 additions and 2274 deletions
|
@ -4,6 +4,8 @@ const UpdateMode = utils.UpdateMode;
|
|||
const mem = std.mem;
|
||||
const math = std.math;
|
||||
|
||||
const expect = std.testing.expect;
|
||||
|
||||
const EqFn = fn (?[*]u8, ?[*]u8) callconv(.C) bool;
|
||||
const CompareFn = fn (?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) u8;
|
||||
const Opaque = ?[*]u8;
|
||||
|
@ -770,7 +772,7 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
|
|||
// This first call must use mem.copy because the slices might overlap.
|
||||
const byte_count_a = list_a.len() * element_width;
|
||||
const byte_count_b = list_b.len() * element_width;
|
||||
mem.copy(u8, source_b[byte_count_a .. byte_count_a + byte_count_b], source_b[0..byte_count_b]);
|
||||
mem.copyBackwards(u8, source_b[byte_count_a .. byte_count_a + byte_count_b], source_b[0..byte_count_b]);
|
||||
@memcpy(source_b, source_a, byte_count_a);
|
||||
|
||||
// decrement list a.
|
||||
|
@ -854,3 +856,21 @@ pub fn listIsUnique(
|
|||
) callconv(.C) bool {
|
||||
return list.isEmpty() or list.isUnique();
|
||||
}
|
||||
|
||||
test "listConcat: non-unique with unique overlapping" {
|
||||
var nonUnique = RocList.fromSlice(u8, ([_]u8{1})[0..]);
|
||||
var bytes: [*]u8 = @ptrCast([*]u8, nonUnique.bytes);
|
||||
const ptr_width = @sizeOf(usize);
|
||||
const refcount_ptr = @ptrCast([*]isize, @alignCast(ptr_width, bytes) - ptr_width);
|
||||
utils.increfC(&refcount_ptr[0], 1);
|
||||
defer nonUnique.deinit(u8); // listConcat will dec the other refcount
|
||||
|
||||
var unique = RocList.fromSlice(u8, ([_]u8{ 2, 3, 4 })[0..]);
|
||||
defer unique.deinit(u8);
|
||||
|
||||
var concatted = listConcat(nonUnique, unique, 1, 1);
|
||||
var wanted = RocList.fromSlice(u8, ([_]u8{ 1, 2, 3, 4 })[0..]);
|
||||
defer wanted.deinit(u8);
|
||||
|
||||
try expect(concatted.eql(wanted));
|
||||
}
|
||||
|
|
|
@ -4,13 +4,18 @@ interface Dict
|
|||
empty,
|
||||
withCapacity,
|
||||
single,
|
||||
get,
|
||||
walk,
|
||||
insert,
|
||||
clear,
|
||||
capacity,
|
||||
len,
|
||||
get,
|
||||
contains,
|
||||
insert,
|
||||
remove,
|
||||
update,
|
||||
contains,
|
||||
walk,
|
||||
walkUntil,
|
||||
toList,
|
||||
fromList,
|
||||
keys,
|
||||
values,
|
||||
insertAll,
|
||||
|
@ -22,8 +27,8 @@ interface Dict
|
|||
Result.{ Result },
|
||||
List,
|
||||
Str,
|
||||
Num.{ Nat, U64, U8 },
|
||||
Hash.{ Hasher },
|
||||
Num.{ Nat, U64, U8, I8 },
|
||||
Hash.{ Hasher, Hash },
|
||||
]
|
||||
|
||||
## A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you
|
||||
|
@ -74,45 +79,103 @@ interface Dict
|
|||
## does. It removes an element and moves the most recent insertion into the
|
||||
## vacated spot.
|
||||
##
|
||||
## This move is done as a performance optimization, and it lets [Dict.remove]
|
||||
## have [constant time complexity](https://en.wikipedia.org/wiki/Time_complexity#Constant_time).
|
||||
## This move is done as a performance optimization, and it lets [remove] have
|
||||
## [constant time complexity](https://en.wikipedia.org/wiki/Time_complexity#Constant_time). ##
|
||||
##
|
||||
## ### Equality
|
||||
##
|
||||
## Two dictionaries are equal when their contents and orderings match. This
|
||||
## means that when `dict1 == dict2`, the expression `fn dict1 == fn dict2` will
|
||||
## also evaluate to `Bool.true`. The function `fn` can count on the ordering of
|
||||
## values in the dictionary to also match.
|
||||
Dict k v := List [Pair k v] has [Eq]
|
||||
## Dict is inspired by [IndexMap](https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html).
|
||||
## The internal implementation of a dictionary is similar to [absl::flat_hash_map](https://abseil.io/docs/cpp/guides/container).
|
||||
## It has a list of keys value pairs that is ordered based on insertion.
|
||||
## It uses a list of indices into the data as the backing of a hash map.
|
||||
Dict k v := {
|
||||
# TODO: Add hashflooding ordered map fall back.
|
||||
# TODO: Add Groups and SIMD h1 key comparison (initial tests where slower, but with proper SIMD should be fast).
|
||||
# TODO: As an optimization, we can make all of these lists in one allocation
|
||||
# TODO: Grow data with the rest of the hashmap. This will require creating a list of garbage data.
|
||||
# TODO: Change remove to use tombstones. Store the tombstones in a bitmap.
|
||||
# TODO: define Eq and Hash that are unordered. Only if value has hash/eq?
|
||||
metadata : List I8,
|
||||
dataIndices : List Nat,
|
||||
data : List (T k v),
|
||||
size : Nat,
|
||||
} | k has Hash & Eq
|
||||
|
||||
## Return an empty dictionary.
|
||||
empty : Dict k v
|
||||
empty = @Dict []
|
||||
empty : Dict k v | k has Hash & Eq
|
||||
empty =
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot 8,
|
||||
dataIndices: List.repeat 0 8,
|
||||
data: [],
|
||||
size: 0,
|
||||
}
|
||||
|
||||
## Returns the max number of elements the dictionary can hold before requiring a rehash.
|
||||
capacity : Dict k v -> Nat | k has Hash & Eq
|
||||
capacity = \@Dict { dataIndices } ->
|
||||
cap = List.len dataIndices
|
||||
|
||||
cap - Num.shiftRightZfBy cap 3
|
||||
|
||||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimisation if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Dict k v
|
||||
withCapacity = \n -> @Dict (List.withCapacity n)
|
||||
withCapacity : Nat -> Dict k v | k has Hash & Eq
|
||||
withCapacity = \_ ->
|
||||
# TODO: power of 2 * 8 and actual implementation
|
||||
empty
|
||||
|
||||
## Get the value for a given key. If there is a value for the specified key it
|
||||
## will return [Ok value], otherwise return [Err KeyNotFound].
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
##
|
||||
## dictionary =
|
||||
## expect
|
||||
## Dict.single "A" "B"
|
||||
## |> Bool.isEq (Dict.insert Dict.empty "A" "B")
|
||||
single : k, v -> Dict k v | k has Hash & Eq
|
||||
single = \k, v ->
|
||||
insert empty k v
|
||||
|
||||
## Returns dictionary with the keys and values specified by the input [List].
|
||||
##
|
||||
## expect
|
||||
## Dict.single 1 "One"
|
||||
## |> Dict.insert 2 "Two"
|
||||
## |> Dict.insert 3 "Three"
|
||||
## |> Dict.insert 4 "Four"
|
||||
## |> Bool.isEq (Dict.fromList [T 1 "One", T 2 "Two", T 3 "Three", T 4 "Four"])
|
||||
fromList : List (T k v) -> Dict k v | k has Hash & Eq
|
||||
fromList = \data ->
|
||||
# TODO: make this efficient. Should just set data and then set all indicies in the hashmap.
|
||||
List.walk data empty (\dict, T k v -> insert dict k v)
|
||||
|
||||
## Returns the number of values in the dictionary.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1 "Apple"
|
||||
## |> Dict.insert 2 "Orange"
|
||||
##
|
||||
## expect Dict.get dictionary 1 == Ok "Apple"
|
||||
## expect Dict.get dictionary 2000 == Err KeyNotFound
|
||||
get : Dict k v, k -> Result v [KeyNotFound] | k has Eq
|
||||
get = \@Dict list, needle ->
|
||||
when List.findFirst list (\Pair key _ -> key == needle) is
|
||||
Ok (Pair _ v) ->
|
||||
Ok v
|
||||
## |> Dict.insert "One" "A Song"
|
||||
## |> Dict.insert "Two" "Candy Canes"
|
||||
## |> Dict.insert "Three" "Boughs of Holly"
|
||||
## |> Dict.len
|
||||
## |> Bool.isEq 3
|
||||
len : Dict k v -> Nat | k has Hash & Eq
|
||||
len = \@Dict { size } ->
|
||||
size
|
||||
|
||||
Err NotFound ->
|
||||
Err KeyNotFound
|
||||
## Clears all elements from a dictionary keeping around the allocation if it isn't huge.
|
||||
clear : Dict k v -> Dict k v | k has Hash & Eq
|
||||
clear = \@Dict { metadata, dataIndices, data } ->
|
||||
cap = List.len dataIndices
|
||||
|
||||
# Only clear large allocations.
|
||||
if cap > 128 * 8 then
|
||||
empty
|
||||
else
|
||||
@Dict {
|
||||
metadata: List.map metadata (\_ -> emptySlot),
|
||||
# just leave data indicies as garbage, no need to clear.
|
||||
dataIndices,
|
||||
# use takeFirst to keep around the capacity.
|
||||
data: List.takeFirst data 0,
|
||||
size: 0,
|
||||
}
|
||||
|
||||
## Iterate through the keys and values in the dictionary and call the provided
|
||||
## function with signature `state, k, v -> state` for each value, with an
|
||||
|
@ -124,9 +187,78 @@ get = \@Dict list, needle ->
|
|||
## |> Dict.insert "Orange" 24
|
||||
## |> Dict.walk 0 (\count, _, qty -> count + qty)
|
||||
## |> Bool.isEq 36
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state
|
||||
walk = \@Dict list, initialState, transform ->
|
||||
List.walk list initialState (\state, Pair k v -> transform state k v)
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state | k has Hash & Eq
|
||||
walk = \@Dict { data }, initialState, transform ->
|
||||
List.walk data initialState (\state, T k v -> transform state k v)
|
||||
|
||||
## Same as [Dict.walk], except you can stop walking early.
|
||||
##
|
||||
## ## Performance Details
|
||||
##
|
||||
## Compared to [Dict.walk], this can potentially visit fewer elements (which can
|
||||
## improve performance) at the cost of making each step take longer.
|
||||
## However, the added cost to each step is extremely small, and can easily
|
||||
## be outweighed if it results in skipping even a small number of elements.
|
||||
##
|
||||
## As such, it is typically better for performance to use this over [Dict.walk]
|
||||
## if returning `Break` earlier than the last element is expected to be common.
|
||||
walkUntil : Dict k v, state, (state, k, v -> [Continue state, Break state]) -> state | k has Hash & Eq
|
||||
walkUntil = \@Dict { data }, initialState, transform ->
|
||||
List.walkUntil data initialState (\state, T k v -> transform state k v)
|
||||
|
||||
## Get the value for a given key. If there is a value for the specified key it
|
||||
## will return [Ok value], otherwise return [Err KeyNotFound].
|
||||
##
|
||||
## dictionary =
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1 "Apple"
|
||||
## |> Dict.insert 2 "Orange"
|
||||
##
|
||||
## expect Dict.get dictionary 1 == Ok "Apple"
|
||||
## expect Dict.get dictionary 2000 == Err KeyNotFound
|
||||
get : Dict k v, k -> Result v [KeyNotFound] | k has Hash & Eq
|
||||
get = \@Dict { metadata, dataIndices, data }, key ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
(T _ v) = listGetUnsafe data dataIndex
|
||||
|
||||
Ok v
|
||||
|
||||
Err NotFound ->
|
||||
Err KeyNotFound
|
||||
|
||||
## Check if the dictionary has a value for a specified key.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1234 "5678"
|
||||
## |> Dict.contains 1234
|
||||
## |> Bool.isEq Bool.true
|
||||
contains : Dict k v, k -> Bool | k has Hash & Eq
|
||||
contains = \@Dict { metadata, dataIndices, data }, key ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok _ ->
|
||||
Bool.true
|
||||
|
||||
Err NotFound ->
|
||||
Bool.false
|
||||
|
||||
## Insert a value into the dictionary at a specified key.
|
||||
##
|
||||
|
@ -135,29 +267,42 @@ walk = \@Dict list, initialState, transform ->
|
|||
## |> Dict.insert "Apples" 12
|
||||
## |> Dict.get "Apples"
|
||||
## |> Bool.isEq (Ok 12)
|
||||
insert : Dict k v, k, v -> Dict k v | k has Eq
|
||||
insert = \@Dict list, k, v ->
|
||||
when List.findFirstIndex list (\Pair key _ -> key == k) is
|
||||
Err NotFound ->
|
||||
insertFresh (@Dict list) k v
|
||||
insert : Dict k v, k, v -> Dict k v | k has Hash & Eq
|
||||
insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
list
|
||||
|> List.set index (Pair k v)
|
||||
|> @Dict
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
|
||||
## Returns the number of values in the dictionary.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert "One" "A Song"
|
||||
## |> Dict.insert "Two" "Candy Canes"
|
||||
## |> Dict.insert "Three" "Boughs of Holly"
|
||||
## |> Dict.len
|
||||
## |> Bool.isEq 3
|
||||
len : Dict k v -> Nat
|
||||
len = \@Dict list ->
|
||||
List.len list
|
||||
@Dict {
|
||||
metadata,
|
||||
dataIndices,
|
||||
data: List.set data dataIndex (T key value),
|
||||
size,
|
||||
}
|
||||
|
||||
Err NotFound ->
|
||||
# The dictionary has grown, it might need to rehash.
|
||||
rehashedDict =
|
||||
maybeRehash
|
||||
(
|
||||
@Dict {
|
||||
metadata,
|
||||
dataIndices,
|
||||
data,
|
||||
size: size + 1,
|
||||
}
|
||||
)
|
||||
|
||||
# Need to rescan searching for the first empty or deleted cell.
|
||||
insertNotFoundHelper rehashedDict key value h1Key h2Key
|
||||
|
||||
## Remove a value from the dictionary for a specified key.
|
||||
##
|
||||
|
@ -167,19 +312,34 @@ len = \@Dict list ->
|
|||
## |> Dict.remove "Some"
|
||||
## |> Dict.len
|
||||
## |> Bool.isEq 0
|
||||
remove : Dict k v, k -> Dict k v | k has Eq
|
||||
remove = \@Dict list, key ->
|
||||
when List.findFirstIndex list (\Pair k _ -> k == key) is
|
||||
Err NotFound ->
|
||||
@Dict list
|
||||
remove : Dict k v, k -> Dict k v | k has Hash & Eq
|
||||
remove = \@Dict { metadata, dataIndices, data, size }, key ->
|
||||
# TODO: change this from swap remove to tombstone and test is performance is still good.
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
lastIndex = List.len list - 1
|
||||
last = List.len data - 1
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
|
||||
list
|
||||
|> List.swap index lastIndex
|
||||
|> List.dropLast
|
||||
|> @Dict
|
||||
if dataIndex == last then
|
||||
@Dict {
|
||||
metadata: List.set metadata index deletedSlot,
|
||||
dataIndices,
|
||||
data: List.dropLast data,
|
||||
size: size - 1,
|
||||
}
|
||||
else
|
||||
swapAndUpdateDataIndex (@Dict { metadata, dataIndices, data, size }) index last
|
||||
|
||||
Err NotFound ->
|
||||
@Dict { metadata, dataIndices, data, size }
|
||||
|
||||
## Insert or remove a value for a specified key. This function enables a
|
||||
## performance optimisation for the use case of providing a default when a value
|
||||
|
@ -195,8 +355,9 @@ remove = \@Dict list, key ->
|
|||
## expect Dict.update Dict.empty "a" alterValue == Dict.single "a" Bool.false
|
||||
## expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true
|
||||
## expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v | k has Eq
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v | k has Hash & Eq
|
||||
update = \dict, key, alter ->
|
||||
# TODO: look into optimizing by merging substeps and reducing lookups.
|
||||
possibleValue =
|
||||
get dict key
|
||||
|> Result.map Present
|
||||
|
@ -206,46 +367,22 @@ update = \dict, key, alter ->
|
|||
Present value -> insert dict key value
|
||||
Missing -> remove dict key
|
||||
|
||||
# Internal for testing only
|
||||
alterValue : [Present Bool, Missing] -> [Present Bool, Missing]
|
||||
alterValue = \possibleValue ->
|
||||
when possibleValue is
|
||||
Missing -> Present Bool.false
|
||||
Present value -> if value then Missing else Present Bool.true
|
||||
|
||||
expect update empty "a" alterValue == single "a" Bool.false
|
||||
expect update (single "a" Bool.false) "a" alterValue == single "a" Bool.true
|
||||
expect update (single "a" Bool.true) "a" alterValue == empty
|
||||
|
||||
## Check if the dictionary has a value for a specified key.
|
||||
## Returns the keys and values of a dictionary as a [List].
|
||||
## This requires allocating a temporary list, prefer using [Dict.toList] or [Dict.walk] instead.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1234 "5678"
|
||||
## |> Dict.contains 1234
|
||||
contains : Dict k v, k -> Bool | k has Eq
|
||||
contains = \@Dict list, needle ->
|
||||
List.any list \Pair key _val -> key == needle
|
||||
|
||||
expect contains empty "a" == Bool.false
|
||||
expect contains (single "a" {}) "a" == Bool.true
|
||||
expect contains (single "b" {}) "a" == Bool.false
|
||||
expect
|
||||
Dict.empty
|
||||
|> Dict.insert 1234 "5678"
|
||||
|> Dict.contains 1234
|
||||
|> Bool.isEq Bool.true
|
||||
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
##
|
||||
## expect
|
||||
## Dict.single "A" "B"
|
||||
## |> Bool.isEq (Dict.insert Dict.empty "A" "B")
|
||||
single : k, v -> Dict k v
|
||||
single = \key, value ->
|
||||
@Dict [Pair key value]
|
||||
## Dict.single 1 "One"
|
||||
## |> Dict.insert 2 "Two"
|
||||
## |> Dict.insert 3 "Three"
|
||||
## |> Dict.insert 4 "Four"
|
||||
## |> Dict.toList
|
||||
## |> Bool.isEq [T 1 "One", T 2 "Two", T 3 "Three", T 4 "Four"]
|
||||
toList : Dict k v -> List (T k v) | k has Hash & Eq
|
||||
toList = \@Dict { data } ->
|
||||
data
|
||||
|
||||
## Returns the keys of a dictionary as a [List].
|
||||
## This requires allocating a temporary [List], prefer using [Dict.toList] or [Dict.walk] instead.
|
||||
##
|
||||
## expect
|
||||
## Dict.single 1 "One"
|
||||
|
@ -254,11 +391,12 @@ single = \key, value ->
|
|||
## |> Dict.insert 4 "Four"
|
||||
## |> Dict.keys
|
||||
## |> Bool.isEq [1,2,3,4]
|
||||
keys : Dict k v -> List k
|
||||
keys = \@Dict list ->
|
||||
List.map list (\Pair k _ -> k)
|
||||
keys : Dict k v -> List k | k has Hash & Eq
|
||||
keys = \@Dict { data } ->
|
||||
List.map data (\T k _ -> k)
|
||||
|
||||
## Returns the values of a dictionary as a [List].
|
||||
## This requires allocating a temporary [List], prefer using [Dict.toList] or [Dict.walk] instead.
|
||||
##
|
||||
## expect
|
||||
## Dict.single 1 "One"
|
||||
|
@ -267,22 +405,22 @@ keys = \@Dict list ->
|
|||
## |> Dict.insert 4 "Four"
|
||||
## |> Dict.values
|
||||
## |> Bool.isEq ["One","Two","Three","Four"]
|
||||
values : Dict k v -> List v
|
||||
values = \@Dict list ->
|
||||
List.map list (\Pair _ v -> v)
|
||||
values : Dict k v -> List v | k has Hash & Eq
|
||||
values = \@Dict { data } ->
|
||||
List.map data (\T _ v -> v)
|
||||
|
||||
## Combine two dictionaries by keeping the [union](https://en.wikipedia.org/wiki/Union_(set_theory))
|
||||
## of all the key-value pairs. This means that all the key-value pairs in
|
||||
## both dictionaries will be combined. Note that where there are pairs
|
||||
## with the same key, the value contained in the first input will be
|
||||
## retained, and the value in the second input will be removed.
|
||||
## with the same key, the value contained in the second input will be
|
||||
## retained, and the value in the first input will be removed.
|
||||
##
|
||||
## first =
|
||||
## Dict.single 1 "Keep Me"
|
||||
## Dict.single 1 "Not Me"
|
||||
## |> Dict.insert 2 "And Me"
|
||||
##
|
||||
## second =
|
||||
## Dict.single 1 "Not Me"
|
||||
## Dict.single 1 "Keep Me"
|
||||
## |> Dict.insert 3 "Me Too"
|
||||
## |> Dict.insert 4 "And Also Me"
|
||||
##
|
||||
|
@ -294,9 +432,9 @@ values = \@Dict list ->
|
|||
##
|
||||
## expect
|
||||
## Dict.insertAll first second == expected
|
||||
insertAll : Dict k v, Dict k v -> Dict k v | k has Eq
|
||||
insertAll = \xs, @Dict ys ->
|
||||
List.walk ys xs (\state, Pair k v -> Dict.insertIfVacant state k v)
|
||||
insertAll : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
insertAll = \xs, ys ->
|
||||
walk ys xs insert
|
||||
|
||||
## Combine two dictionaries by keeping the [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory))
|
||||
## of all the key-value pairs. This means that we keep only those pairs
|
||||
|
@ -315,10 +453,17 @@ insertAll = \xs, @Dict ys ->
|
|||
## |> Dict.insert 4 "Or Me"
|
||||
##
|
||||
## expect Dict.keepShared first second == first
|
||||
keepShared : Dict k v, Dict k v -> Dict k v | k has Eq
|
||||
keepShared = \@Dict xs, ys ->
|
||||
List.keepIf xs (\Pair k _ -> Dict.contains ys k)
|
||||
|> @Dict
|
||||
keepShared : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
keepShared = \xs, ys ->
|
||||
walk
|
||||
xs
|
||||
empty
|
||||
(\state, k, v ->
|
||||
if contains ys k then
|
||||
insert state k v
|
||||
else
|
||||
state
|
||||
)
|
||||
|
||||
## Remove the key-value pairs in the first input that are also in the second
|
||||
## using the [set difference](https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement)
|
||||
|
@ -339,25 +484,349 @@ keepShared = \@Dict xs, ys ->
|
|||
## |> Dict.insert 2 "And Me"
|
||||
##
|
||||
## expect Dict.removeAll first second == expected
|
||||
removeAll : Dict k v, Dict k v -> Dict k v | k has Eq
|
||||
removeAll = \xs, @Dict ys ->
|
||||
List.walk ys xs (\state, Pair k _ -> Dict.remove state k)
|
||||
removeAll : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
removeAll = \xs, ys ->
|
||||
walk ys xs (\state, k, _ -> remove state k)
|
||||
|
||||
## Internal helper function to insert a new association
|
||||
##
|
||||
## Precondition: `k` should not exist in the Dict yet.
|
||||
insertFresh : Dict k v, k, v -> Dict k v
|
||||
insertFresh = \@Dict list, k, v ->
|
||||
list
|
||||
|> List.append (Pair k v)
|
||||
|> @Dict
|
||||
swapAndUpdateDataIndex : Dict k v, Nat, Nat -> Dict k v | k has Hash & Eq
|
||||
swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data, size }, removedIndex, lastIndex ->
|
||||
(T key _) = listGetUnsafe data lastIndex
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
insertIfVacant : Dict k v, k, v -> Dict k v | k has Eq
|
||||
insertIfVacant = \dict, key, value ->
|
||||
if Dict.contains dict key then
|
||||
dict
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
dataIndex = listGetUnsafe dataIndices removedIndex
|
||||
# Swap and remove data.
|
||||
nextData =
|
||||
data
|
||||
|> List.swap dataIndex lastIndex
|
||||
|> List.dropLast
|
||||
|
||||
@Dict {
|
||||
# Set old metadata as deleted.
|
||||
metadata: List.set metadata removedIndex deletedSlot,
|
||||
# Update index of swaped element.
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data: nextData,
|
||||
size: size - 1,
|
||||
}
|
||||
|
||||
Err NotFound ->
|
||||
# This should be impossible.
|
||||
crash "unreachable state in dict swapAndUpdateDataIndex hit. Definitely a standard library bug."
|
||||
|
||||
insertNotFoundHelper : Dict k v, k, v, U64, I8 -> Dict k v
|
||||
insertNotFoundHelper = \@Dict { metadata, dataIndices, data, size }, key, value, h1Key, h2Key ->
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
index = nextEmptyOrDeletedHelper metadata probe 0
|
||||
dataIndex = List.len data
|
||||
nextData = List.append data (T key value)
|
||||
|
||||
@Dict {
|
||||
metadata: List.set metadata index h2Key,
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data: nextData,
|
||||
size,
|
||||
}
|
||||
|
||||
nextEmptyOrDeletedHelper : List I8, Probe, Nat -> Nat
|
||||
nextEmptyOrDeletedHelper = \metadata, probe, offset ->
|
||||
# For inserting, we can use deleted indices.
|
||||
index = Num.addWrap (mul8 probe.slotIndex) offset
|
||||
|
||||
md = listGetUnsafe metadata index
|
||||
|
||||
if md < 0 then
|
||||
# Empty or deleted slot, no possibility of the element.
|
||||
index
|
||||
else if offset == 7 then
|
||||
nextEmptyOrDeletedHelper metadata (nextProbe probe) 0
|
||||
else
|
||||
Dict.insert dict key value
|
||||
nextEmptyOrDeletedHelper metadata probe (Num.addWrap offset 1)
|
||||
|
||||
# TODO: investigate if this needs to be split into more specific helper functions.
|
||||
# There is a chance that returning specific sub-info like the value would be faster.
|
||||
findIndexHelper : List I8, List Nat, List (T k v), I8, k, Probe, Nat -> Result Nat [NotFound] | k has Hash & Eq
|
||||
findIndexHelper = \metadata, dataIndices, data, h2Key, key, probe, offset ->
|
||||
# For finding a value, we must search past all deleted element tombstones.
|
||||
index = Num.addWrap (mul8 probe.slotIndex) offset
|
||||
|
||||
md = listGetUnsafe metadata index
|
||||
|
||||
if md == emptySlot then
|
||||
# Empty slot, no possibility of the element.
|
||||
Err NotFound
|
||||
else if md == h2Key then
|
||||
# Potentially matching slot, check if the key is a match.
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
(T k _) = listGetUnsafe data dataIndex
|
||||
|
||||
if k == key then
|
||||
# We have a match, return its index.
|
||||
Ok index
|
||||
else if offset == 7 then
|
||||
# No match, keep checking.
|
||||
findIndexHelper metadata dataIndices data h2Key key (nextProbe probe) 0
|
||||
else
|
||||
findIndexHelper metadata dataIndices data h2Key key probe (Num.addWrap offset 1)
|
||||
else if offset == 7 then
|
||||
# Used slot, check next slot.
|
||||
findIndexHelper metadata dataIndices data h2Key key (nextProbe probe) 0
|
||||
else
|
||||
findIndexHelper metadata dataIndices data h2Key key probe (Num.addWrap offset 1)
|
||||
|
||||
# This is how we grow the container.
|
||||
# If we aren't to the load factor yet, just ignore this.
|
||||
# The container must have an updated size including any elements about to be inserted.
|
||||
maybeRehash : Dict k v -> Dict k v | k has Hash & Eq
|
||||
maybeRehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
cap = List.len dataIndices
|
||||
maxLoadCap =
|
||||
# This is 7/8 * capacity, which is the max load factor.
|
||||
cap - Num.shiftRightZfBy cap 3
|
||||
|
||||
if size > maxLoadCap then
|
||||
rehash (@Dict { metadata, dataIndices, data, size })
|
||||
else
|
||||
@Dict { metadata, dataIndices, data, size }
|
||||
|
||||
# TODO: switch rehash to iterate data and eventually clear out tombstones as well.
|
||||
rehash : Dict k v -> Dict k v | k has Hash & Eq
|
||||
rehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
newLen = 2 * List.len dataIndices
|
||||
newDict =
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot newLen,
|
||||
dataIndices: List.repeat 0 newLen,
|
||||
data,
|
||||
size,
|
||||
}
|
||||
|
||||
rehashHelper newDict metadata dataIndices data 0
|
||||
|
||||
rehashHelper : Dict k v, List I8, List Nat, List (T k v), Nat -> Dict k v | k has Hash & Eq
|
||||
rehashHelper = \dict, oldMetadata, oldDataIndices, oldData, index ->
|
||||
when List.get oldMetadata index is
|
||||
Ok md ->
|
||||
nextDict =
|
||||
if md >= 0 then
|
||||
# We have an actual element here
|
||||
dataIndex = listGetUnsafe oldDataIndices index
|
||||
(T k _) = listGetUnsafe oldData dataIndex
|
||||
|
||||
insertForRehash dict k dataIndex
|
||||
else
|
||||
# Empty or deleted data
|
||||
dict
|
||||
|
||||
rehashHelper nextDict oldMetadata oldDataIndices oldData (index + 1)
|
||||
|
||||
Err OutOfBounds ->
|
||||
# Walked entire list, complete now.
|
||||
dict
|
||||
|
||||
insertForRehash : Dict k v, k, Nat -> Dict k v | k has Hash & Eq
|
||||
insertForRehash = \@Dict { metadata, dataIndices, data, size }, key, dataIndex ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
index = nextEmptyOrDeletedHelper metadata probe 0
|
||||
|
||||
@Dict {
|
||||
metadata: List.set metadata index h2Key,
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data,
|
||||
size,
|
||||
}
|
||||
|
||||
emptySlot : I8
|
||||
emptySlot = -128
|
||||
deletedSlot : I8
|
||||
deletedSlot = -2
|
||||
|
||||
T k v : [T k v]
|
||||
|
||||
# Capacity must be a power of 2.
|
||||
# We still will use slots of 8 even though this version has no true slots.
|
||||
# We just move an element at a time.
|
||||
# Thus, the true index is slotIndex * 8 + offset.
|
||||
Probe : { slotIndex : Nat, probeI : Nat, mask : Nat }
|
||||
|
||||
newProbe : U64, Nat -> Probe
|
||||
newProbe = \h1Key, slots ->
|
||||
mask = Num.subSaturated slots 1
|
||||
slotIndex = Num.bitwiseAnd (Num.toNat h1Key) mask
|
||||
|
||||
{ slotIndex, probeI: 1, mask }
|
||||
|
||||
nextProbe : Probe -> Probe
|
||||
nextProbe = \{ slotIndex, probeI, mask } ->
|
||||
nextSlotIndex = Num.bitwiseAnd (Num.addWrap slotIndex probeI) mask
|
||||
|
||||
{ slotIndex: nextSlotIndex, probeI: Num.addWrap probeI 1, mask }
|
||||
|
||||
mul8 = \val -> Num.shiftLeftBy val 3
|
||||
div8 = \val -> Num.shiftRightZfBy val 3
|
||||
|
||||
h1 : U64 -> U64
|
||||
h1 = \hashKey ->
|
||||
Num.shiftRightZfBy hashKey 7
|
||||
|
||||
h2 : U64 -> I8
|
||||
h2 = \hashKey ->
|
||||
Num.toI8 (Num.bitwiseAnd hashKey 0b0111_1111)
|
||||
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "foo" "bar"
|
||||
|> get "foo"
|
||||
|
||||
val == Ok "bar"
|
||||
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "foo" "bar"
|
||||
|> insert "foo" "baz"
|
||||
|> get "foo"
|
||||
|
||||
val == Ok "baz"
|
||||
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "foo" "bar"
|
||||
|> get "bar"
|
||||
|
||||
val == Err KeyNotFound
|
||||
|
||||
expect
|
||||
empty
|
||||
|> insert "foo" {}
|
||||
|> contains "foo"
|
||||
|
||||
expect
|
||||
dict =
|
||||
empty
|
||||
|> insert "foo" {}
|
||||
|> insert "bar" {}
|
||||
|> insert "baz" {}
|
||||
|
||||
contains dict "baz" && Bool.not (contains dict "other")
|
||||
|
||||
expect
|
||||
dict =
|
||||
fromList [T 1u8 1u8, T 2 2, T 3 3]
|
||||
|> remove 1
|
||||
|> remove 3
|
||||
|
||||
keys dict == [2]
|
||||
|
||||
expect
|
||||
list =
|
||||
fromList [T 1u8 1u8, T 2u8 2u8, T 3 3]
|
||||
|> remove 1
|
||||
|> insert 0 0
|
||||
|> remove 3
|
||||
|> keys
|
||||
|
||||
list == [0, 2]
|
||||
|
||||
# Reach capacity, no rehash.
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|> capacity
|
||||
|
||||
val == 7
|
||||
|
||||
expect
|
||||
dict =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|
||||
(get dict "a" == Ok 0)
|
||||
&& (get dict "b" == Ok 1)
|
||||
&& (get dict "c" == Ok 2)
|
||||
&& (get dict "d" == Ok 3)
|
||||
&& (get dict "e" == Ok 4)
|
||||
&& (get dict "f" == Ok 5)
|
||||
&& (get dict "g" == Ok 6)
|
||||
|
||||
# Force rehash.
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|> insert "h" 7
|
||||
|> capacity
|
||||
|
||||
val == 14
|
||||
|
||||
expect
|
||||
dict =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|> insert "h" 7
|
||||
|
||||
(get dict "a" == Ok 0)
|
||||
&& (get dict "b" == Ok 1)
|
||||
&& (get dict "c" == Ok 2)
|
||||
&& (get dict "d" == Ok 3)
|
||||
&& (get dict "e" == Ok 4)
|
||||
&& (get dict "f" == Ok 5)
|
||||
&& (get dict "g" == Ok 6)
|
||||
&& (get dict "h" == Ok 7)
|
||||
|
||||
expect
|
||||
empty
|
||||
|> insert "Some" "Value"
|
||||
|> remove "Some"
|
||||
|> len
|
||||
|> Bool.isEq 0
|
||||
|
||||
# Makes sure a Dict with Nat keys works
|
||||
expect
|
||||
empty
|
||||
|> insert 7nat "Testing"
|
||||
|> get 7
|
||||
|> Bool.isEq (Ok "Testing")
|
||||
|
||||
# We have decided not to expose the standard roc hashing algorithm.
|
||||
# This is to avoid external dependence and the need for versioning.
|
||||
|
@ -524,10 +993,32 @@ wymix = \a, b ->
|
|||
|
||||
wymum : U64, U64 -> { lower : U64, upper : U64 }
|
||||
wymum = \a, b ->
|
||||
r = Num.toU128 a * Num.toU128 b
|
||||
lower = Num.toU64 r
|
||||
upper = Num.shiftRightZfBy r 64 |> Num.toU64
|
||||
# uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
|
||||
# uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
|
||||
# lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
|
||||
ha = Num.shiftRightZfBy a 32
|
||||
hb = Num.shiftRightZfBy b 32
|
||||
la = Num.bitwiseAnd a 0x0000_0000_FFFF_FFFF
|
||||
lb = Num.bitwiseAnd b 0x0000_0000_FFFF_FFFF
|
||||
rh = ha * hb
|
||||
rm0 = ha * lb
|
||||
rm1 = hb * la
|
||||
rl = la * lb
|
||||
t = Num.addWrap rl (Num.shiftLeftBy rm0 32)
|
||||
c = if t < rl then 1 else 0
|
||||
lower = Num.addWrap t (Num.shiftLeftBy rm1 32)
|
||||
c2 = c + (if lower < t then 1 else 0)
|
||||
upper =
|
||||
rh
|
||||
|> Num.addWrap (Num.shiftRightZfBy rm0 32)
|
||||
|> Num.addWrap (Num.shiftRightZfBy rm1 32)
|
||||
|> Num.addWrap c2
|
||||
|
||||
# TODO: switch back to this once wasm supports bit shifting a U128.
|
||||
# The above code is manually doing the 128bit multiplication.
|
||||
# r = Num.toU128 a * Num.toU128 b
|
||||
# lower = Num.toU64 r
|
||||
# upper = Num.shiftRightZfBy r 64 |> Num.toU64
|
||||
# This is the more robust form.
|
||||
# { lower: Num.bitwiseXor a lower, upper: Num.bitwiseXor b upper }
|
||||
{ lower, upper }
|
||||
|
|
|
@ -14,14 +14,16 @@ interface Hash
|
|||
hashI32,
|
||||
hashI64,
|
||||
hashI128,
|
||||
hashNat,
|
||||
complete,
|
||||
hashStrBytes,
|
||||
hashList,
|
||||
hashUnordered,
|
||||
] imports [
|
||||
Bool.{ isEq },
|
||||
List,
|
||||
Str,
|
||||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128 },
|
||||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, Nat },
|
||||
]
|
||||
|
||||
## A value that can hashed.
|
||||
|
@ -88,6 +90,21 @@ hashI64 = \hasher, n -> addU64 hasher (Num.toU64 n)
|
|||
hashI128 : a, I128 -> a | a has Hasher
|
||||
hashI128 = \hasher, n -> addU128 hasher (Num.toU128 n)
|
||||
|
||||
## Adds a single Nat to a hasher.
|
||||
hashNat : a, Nat -> a | a has Hasher
|
||||
hashNat = \hasher, n ->
|
||||
isPlatform32bit =
|
||||
x : Nat
|
||||
x = 0xffff_ffff
|
||||
y = Num.addWrap x 1
|
||||
|
||||
y == 0
|
||||
|
||||
if isPlatform32bit then
|
||||
addU32 hasher (Num.toU32 n)
|
||||
else
|
||||
addU64 hasher (Num.toU64 n)
|
||||
|
||||
## Adds a container of [Hash]able elements to a [Hasher] by hashing each element.
|
||||
## The container is iterated using the walk method passed in.
|
||||
## The order of the elements does not affect the final hash.
|
||||
|
|
|
@ -205,7 +205,7 @@ takeWhile = \list, predicate ->
|
|||
helper { taken: [], rest: list }
|
||||
|
||||
digits : List U8
|
||||
digits = List.range '0' ('9' + 1)
|
||||
digits = List.range { start: At '0', end: At '9' }
|
||||
|
||||
takeDigits = \bytes ->
|
||||
takeWhile bytes \n -> List.contains digits n
|
||||
|
|
|
@ -637,26 +637,130 @@ mapWithIndexHelp = \src, dest, func, index, length ->
|
|||
else
|
||||
dest
|
||||
|
||||
## Returns a list of all the integers between one and another,
|
||||
## including both of the given numbers.
|
||||
## Returns a list of all the integers between `start` and `end`.
|
||||
##
|
||||
## >>> List.range 2 8
|
||||
range : Int a, Int a -> List (Int a)
|
||||
range = \start, end ->
|
||||
when Num.compare start end is
|
||||
GT -> []
|
||||
EQ -> [start]
|
||||
LT ->
|
||||
length = Num.intCast (end - start)
|
||||
## To include the `start` and `end` integers themselves, use `At` like so:
|
||||
##
|
||||
## List.range { start: At 2, end: At 5 } # returns [2, 3, 4, 5]
|
||||
##
|
||||
## To exclude them, use `After` and `Before`, like so:
|
||||
##
|
||||
## List.range { start: After 2, end: Before 5 } # returns [3, 4]
|
||||
##
|
||||
## You can have the list end at a certain length rather than a certain integer:
|
||||
##
|
||||
## List.range { start: At 6, end: Length 4 } # returns [6, 7, 8, 9]
|
||||
##
|
||||
## If `step` is specified, each integer increases by that much. (`step: 1` is the default.)
|
||||
##
|
||||
## List.range { start: After 1, end: Before 10, step: 3 } # returns [2, 5, 8]
|
||||
##
|
||||
## All of these options are compatible with the others. For example, you can use `At` or `After`
|
||||
## with `start` regardless of what `end` and `step` are set to.
|
||||
# TODO: Make the type annotation work
|
||||
# range :
|
||||
# {
|
||||
# start : [At (Int a), After (Int a)],
|
||||
# end : [At (Int a), Before (Int a), Length Nat],
|
||||
# # TODO: We want this to be Int *, but that requires the ability to convert or add from Int * to Int a
|
||||
# step ? Int a
|
||||
# }
|
||||
# -> List (Int a) | a has Bool.Eq
|
||||
range = \{ start, end, step ? 0 } ->
|
||||
{ incByStep, stepIsPositive } =
|
||||
if step == 0 then
|
||||
when T start end is
|
||||
T (At x) (At y) | T (At x) (Before y) | T (After x) (At y) | T (After x) (Before y) ->
|
||||
if x < y then
|
||||
{
|
||||
incByStep: \i -> i + 1,
|
||||
stepIsPositive: Bool.true,
|
||||
}
|
||||
else
|
||||
{
|
||||
incByStep: \i -> i - 1,
|
||||
stepIsPositive: Bool.false,
|
||||
}
|
||||
|
||||
rangeHelp (List.withCapacity length) start end
|
||||
T (At _) (Length _) | T (After _) (Length _) ->
|
||||
{
|
||||
incByStep: \i -> i + 1,
|
||||
stepIsPositive: Bool.true,
|
||||
}
|
||||
else
|
||||
{
|
||||
incByStep: \i -> i + step,
|
||||
stepIsPositive: step > 0,
|
||||
}
|
||||
|
||||
rangeHelp : List (Int a), Int a, Int a -> List (Int a)
|
||||
rangeHelp = \accum, start, end ->
|
||||
if end <= start then
|
||||
inclusiveStart =
|
||||
when start is
|
||||
At x -> x
|
||||
After x -> incByStep x
|
||||
|
||||
when end is
|
||||
At at ->
|
||||
isComplete =
|
||||
if stepIsPositive then
|
||||
\i -> i > at
|
||||
else
|
||||
\i -> i < at
|
||||
|
||||
# TODO: switch to List.withCapacity
|
||||
rangeHelp [] inclusiveStart incByStep isComplete
|
||||
|
||||
Before before ->
|
||||
isComplete =
|
||||
if stepIsPositive then
|
||||
\i -> i >= before
|
||||
else
|
||||
\i -> i <= before
|
||||
|
||||
# TODO: switch to List.withCapacity
|
||||
rangeHelp [] inclusiveStart incByStep isComplete
|
||||
|
||||
Length l ->
|
||||
rangeLengthHelp (List.withCapacity l) inclusiveStart l incByStep
|
||||
|
||||
rangeHelp = \accum, i, incByStep, isComplete ->
|
||||
if isComplete i then
|
||||
accum
|
||||
else
|
||||
rangeHelp (List.appendUnsafe accum start) (start + 1) end
|
||||
# TODO: change this to List.appendUnsafe once capacity is set correctly
|
||||
rangeHelp (List.append accum i) (incByStep i) incByStep isComplete
|
||||
|
||||
rangeLengthHelp = \accum, i, remaining, incByStep ->
|
||||
if remaining == 0 then
|
||||
accum
|
||||
else
|
||||
rangeLengthHelp (List.appendUnsafe accum i) (incByStep i) (remaining - 1) incByStep
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: At 4 } == [0, 1, 2, 3, 4]
|
||||
|
||||
expect
|
||||
List.range { start: After 0, end: At 4 } == [1, 2, 3, 4]
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: At 4, step: 2 } == [0, 2, 4]
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: Before 4 } == [0, 1, 2, 3]
|
||||
|
||||
expect
|
||||
List.range { start: After 0, end: Before 4 } == [1, 2, 3]
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: Before 4, step: 2 } == [0, 2]
|
||||
|
||||
expect
|
||||
List.range { start: At 4, end: Length 5 } == [4, 5, 6, 7, 8]
|
||||
|
||||
expect
|
||||
List.range { start: At 4, end: Length 5, step: 10 } == [4, 14, 24, 34, 44]
|
||||
|
||||
expect
|
||||
List.range { start: At 4, end: Length 5, step: -3 } == [4, 1, -2, -5, -8]
|
||||
|
||||
## Sort with a custom comparison function
|
||||
sortWith : List a, (a, a -> [LT, EQ, GT]) -> List a
|
||||
|
|
|
@ -14,99 +14,192 @@ interface Set
|
|||
intersection,
|
||||
difference,
|
||||
]
|
||||
imports [List, Bool.{ Bool, Eq }, Dict.{ Dict }, Num.{ Nat }]
|
||||
imports [
|
||||
List,
|
||||
Bool.{ Bool, Eq },
|
||||
Dict.{ Dict },
|
||||
Num.{ Nat },
|
||||
Hash.{ Hash },
|
||||
]
|
||||
|
||||
Set k := Dict.Dict k {} has [Eq]
|
||||
# We should have this line above the next has.
|
||||
# It causes the formatter to fail currently.
|
||||
# | k has Hash & Eq
|
||||
Set k := Dict.Dict k {}
|
||||
has [
|
||||
Eq {
|
||||
isEq,
|
||||
},
|
||||
]
|
||||
|
||||
fromDict : Dict k {} -> Set k
|
||||
fromDict = \dict -> @Set dict
|
||||
|
||||
toDict : Set k -> Dict k {}
|
||||
toDict = \@Set dict -> dict
|
||||
isEq : Set k, Set k -> Bool | k has Hash & Eq
|
||||
isEq = \xs, ys ->
|
||||
if len xs != len ys then
|
||||
Bool.false
|
||||
else
|
||||
walkUntil xs Bool.true \_, elem ->
|
||||
if contains ys elem then
|
||||
Continue Bool.true
|
||||
else
|
||||
Break Bool.false
|
||||
|
||||
## An empty set.
|
||||
empty : Set k
|
||||
empty = fromDict Dict.empty
|
||||
empty : Set k | k has Hash & Eq
|
||||
empty = @Set Dict.empty
|
||||
|
||||
single : k -> Set k
|
||||
single : k -> Set k | k has Hash & Eq
|
||||
single = \key ->
|
||||
@Set (Dict.single key {})
|
||||
Dict.single key {} |> @Set
|
||||
|
||||
## Make sure never to insert a *NaN* to a [Set]! Because *NaN* is defined to be
|
||||
## unequal to *NaN*, adding a *NaN* results in an entry that can never be
|
||||
## retrieved or removed from the [Set].
|
||||
insert : Set k, k -> Set k | k has Eq
|
||||
insert : Set k, k -> Set k | k has Hash & Eq
|
||||
insert = \@Set dict, key ->
|
||||
dict
|
||||
|> Dict.insert key {}
|
||||
|> @Set
|
||||
Dict.insert dict key {} |> @Set
|
||||
|
||||
# Inserting a duplicate key has no effect.
|
||||
expect
|
||||
actual =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "baz"
|
||||
empty
|
||||
|> insert "foo"
|
||||
|> insert "bar"
|
||||
|> insert "foo"
|
||||
|> insert "baz"
|
||||
|
||||
expected =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "baz"
|
||||
empty
|
||||
|> insert "foo"
|
||||
|> insert "bar"
|
||||
|> insert "baz"
|
||||
|
||||
expected == actual
|
||||
|
||||
len : Set k -> Nat
|
||||
len : Set k -> Nat | k has Hash & Eq
|
||||
len = \@Set dict ->
|
||||
Dict.len dict
|
||||
|
||||
# Inserting a duplicate key has no effect on length.
|
||||
expect
|
||||
actual =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "baz"
|
||||
|> Set.len
|
||||
empty
|
||||
|> insert "foo"
|
||||
|> insert "bar"
|
||||
|> insert "foo"
|
||||
|> insert "baz"
|
||||
|> len
|
||||
|
||||
actual == 3
|
||||
|
||||
## Drops the given element from the set.
|
||||
remove : Set k, k -> Set k | k has Eq
|
||||
remove : Set k, k -> Set k | k has Hash & Eq
|
||||
remove = \@Set dict, key ->
|
||||
@Set (Dict.remove dict key)
|
||||
Dict.remove dict key |> @Set
|
||||
|
||||
contains : Set k, k -> Bool | k has Eq
|
||||
contains = \set, key ->
|
||||
set
|
||||
|> Set.toDict
|
||||
|> Dict.contains key
|
||||
contains : Set k, k -> Bool | k has Hash & Eq
|
||||
contains = \@Set dict, key ->
|
||||
Dict.contains dict key
|
||||
|
||||
toList : Set k -> List k
|
||||
toList : Set k -> List k | k has Hash & Eq
|
||||
toList = \@Set dict ->
|
||||
Dict.keys dict
|
||||
|
||||
fromList : List k -> Set k | k has Eq
|
||||
fromList : List k -> Set k | k has Hash & Eq
|
||||
fromList = \list ->
|
||||
initial = @Set (Dict.withCapacity (List.len list))
|
||||
|
||||
List.walk list initial \set, key -> Set.insert set key
|
||||
List.walk list initial insert
|
||||
|
||||
union : Set k, Set k -> Set k | k has Eq
|
||||
union : Set k, Set k -> Set k | k has Hash & Eq
|
||||
union = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.insertAll dict1 dict2)
|
||||
Dict.insertAll dict1 dict2 |> @Set
|
||||
|
||||
intersection : Set k, Set k -> Set k | k has Eq
|
||||
intersection : Set k, Set k -> Set k | k has Hash & Eq
|
||||
intersection = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.keepShared dict1 dict2)
|
||||
Dict.keepShared dict1 dict2 |> @Set
|
||||
|
||||
difference : Set k, Set k -> Set k | k has Eq
|
||||
difference : Set k, Set k -> Set k | k has Hash & Eq
|
||||
difference = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.removeAll dict1 dict2)
|
||||
Dict.removeAll dict1 dict2 |> @Set
|
||||
|
||||
walk : Set k, state, (state, k -> state) -> state
|
||||
walk = \set, state, step ->
|
||||
Dict.walk (Set.toDict set) state (\s, k, _ -> step s k)
|
||||
walk : Set k, state, (state, k -> state) -> state | k has Hash & Eq
|
||||
walk = \@Set dict, state, step ->
|
||||
Dict.walk dict state (\s, k, _ -> step s k)
|
||||
|
||||
walkUntil : Set k, state, (state, k -> [Continue state, Break state]) -> state | k has Hash & Eq
|
||||
walkUntil = \@Set dict, state, step ->
|
||||
Dict.walkUntil dict state (\s, k, _ -> step s k)
|
||||
|
||||
expect
|
||||
first =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|> insert "Remove Me"
|
||||
|
||||
second =
|
||||
single "Remove Me"
|
||||
|> insert "I do nothing..."
|
||||
|
||||
expected =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
difference first second == expected
|
||||
|
||||
expect
|
||||
first =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|> insert "Remove Me"
|
||||
|
||||
second =
|
||||
single "Remove Me"
|
||||
|> insert "I do nothing..."
|
||||
|
||||
expected =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
difference first second == expected
|
||||
|
||||
expect
|
||||
first =
|
||||
single 1
|
||||
|> insert 2
|
||||
|
||||
second =
|
||||
single 1
|
||||
|> insert 3
|
||||
|> insert 4
|
||||
|
||||
expected =
|
||||
single 1
|
||||
|> insert 2
|
||||
|> insert 3
|
||||
|> insert 4
|
||||
|
||||
union first second == expected
|
||||
|
||||
expect
|
||||
base =
|
||||
single "Remove Me"
|
||||
|> insert "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
expected =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
remove base "Remove Me" == expected
|
||||
|
||||
expect
|
||||
x =
|
||||
single 0
|
||||
|> insert 1
|
||||
|> insert 2
|
||||
|> insert 3
|
||||
|> insert 4
|
||||
|> insert 5
|
||||
|> insert 6
|
||||
|> insert 7
|
||||
|> insert 8
|
||||
|> insert 9
|
||||
|
||||
x == fromList (toList x)
|
||||
|
|
|
@ -488,17 +488,19 @@ impl Constraints {
|
|||
/// then need to find their way to the pool, and a convenient approach turned out to be to
|
||||
/// tag them onto the `Let` that we used to add the imported values.
|
||||
#[inline(always)]
|
||||
pub fn let_import_constraint<I1, I2>(
|
||||
pub fn let_import_constraint<I1, I2, I3>(
|
||||
&mut self,
|
||||
rigid_vars: I1,
|
||||
def_types: I2,
|
||||
flex_vars: I2,
|
||||
def_types: I3,
|
||||
module_constraint: Constraint,
|
||||
pool_variables: &[Variable],
|
||||
) -> Constraint
|
||||
where
|
||||
I1: IntoIterator<Item = Variable>,
|
||||
I2: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I2::IntoIter: ExactSizeIterator,
|
||||
I2: IntoIterator<Item = Variable>,
|
||||
I3: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I3::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
// defs and ret constraint are stored consequtively, so we only need to store one index
|
||||
let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
|
||||
|
@ -508,7 +510,7 @@ impl Constraints {
|
|||
|
||||
let let_contraint = LetConstraint {
|
||||
rigid_vars: self.variable_slice(rigid_vars),
|
||||
flex_vars: Slice::default(),
|
||||
flex_vars: self.variable_slice(flex_vars),
|
||||
def_types: self.def_types_slice(def_types),
|
||||
defs_and_ret_constraint,
|
||||
};
|
||||
|
|
|
@ -302,7 +302,7 @@ fn sort_type_defs_before_introduction(
|
|||
matrix
|
||||
.strongly_connected_components_all()
|
||||
.groups()
|
||||
.flat_map(|group| group.iter_ones())
|
||||
.flat_map(|(group, _)| group.iter_ones())
|
||||
.map(|index| symbols[index])
|
||||
.collect()
|
||||
}
|
||||
|
@ -1547,10 +1547,12 @@ impl DefOrdering {
|
|||
|
||||
#[inline(always)]
|
||||
pub(crate) fn sort_can_defs_new(
|
||||
env: &mut Env<'_>,
|
||||
scope: &mut Scope,
|
||||
var_store: &mut VarStore,
|
||||
defs: CanDefs,
|
||||
mut output: Output,
|
||||
exposed_symbols: &VecSet<Symbol>,
|
||||
) -> (Declarations, Output) {
|
||||
let CanDefs {
|
||||
defs,
|
||||
|
@ -1611,7 +1613,7 @@ pub(crate) fn sort_can_defs_new(
|
|||
|
||||
sccs.reorder(&mut defs);
|
||||
|
||||
for group in sccs.groups().rev() {
|
||||
for (group, is_initial) in sccs.groups().rev() {
|
||||
match group.count_ones() {
|
||||
1 => {
|
||||
// a group with a single Def, nice and simple
|
||||
|
@ -1636,6 +1638,10 @@ pub(crate) fn sort_can_defs_new(
|
|||
}
|
||||
};
|
||||
|
||||
if is_initial && !exposed_symbols.contains(&symbol) {
|
||||
env.problem(Problem::DefsOnlyUsedInRecursion(1, def.region()));
|
||||
}
|
||||
|
||||
match def.loc_expr.value {
|
||||
Closure(closure_data) => {
|
||||
declarations.push_recursive_def(
|
||||
|
@ -1720,6 +1726,9 @@ pub(crate) fn sort_can_defs_new(
|
|||
let cycle_mark = IllegalCycleMark::new(var_store);
|
||||
declarations.push_recursive_group(group_length as u16, cycle_mark);
|
||||
|
||||
let mut group_is_initial = is_initial;
|
||||
let mut whole_region = None;
|
||||
|
||||
// then push the definitions of this group
|
||||
for def in group_defs {
|
||||
let (symbol, specializes) = match def.loc_pattern.value {
|
||||
|
@ -1734,6 +1743,12 @@ pub(crate) fn sort_can_defs_new(
|
|||
}
|
||||
};
|
||||
|
||||
group_is_initial = group_is_initial && !exposed_symbols.contains(&symbol);
|
||||
whole_region = match whole_region {
|
||||
None => Some(def.region()),
|
||||
Some(r) => Some(Region::span_across(&r, &def.region())),
|
||||
};
|
||||
|
||||
match def.loc_expr.value {
|
||||
Closure(closure_data) => {
|
||||
declarations.push_recursive_def(
|
||||
|
@ -1755,6 +1770,13 @@ pub(crate) fn sort_can_defs_new(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if group_is_initial {
|
||||
env.problem(Problem::DefsOnlyUsedInRecursion(
|
||||
group_length,
|
||||
whole_region.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1803,7 +1825,7 @@ pub(crate) fn sort_can_defs(
|
|||
|
||||
let mut declarations = Vec::with_capacity(defs.len());
|
||||
|
||||
for group in sccs.groups() {
|
||||
for (group, is_initial) in sccs.groups() {
|
||||
if group.count_ones() == 1 {
|
||||
// a group with a single Def, nice and simple
|
||||
let index = group.iter_ones().next().unwrap();
|
||||
|
@ -1817,6 +1839,16 @@ pub(crate) fn sort_can_defs(
|
|||
let declaration = if def_ordering.references.get_row_col(index, index) {
|
||||
debug_assert!(!is_specialization, "Self-recursive specializations can only be determined during solving - but it was determined for {:?} now, that's a bug!", def);
|
||||
|
||||
if is_initial
|
||||
&& !def
|
||||
.pattern_vars
|
||||
.keys()
|
||||
.any(|sym| output.references.has_value_lookup(*sym))
|
||||
{
|
||||
// This defs is only used in recursion with itself.
|
||||
env.problem(Problem::DefsOnlyUsedInRecursion(1, def.region()));
|
||||
}
|
||||
|
||||
// this function calls itself, and must be typechecked as a recursive def
|
||||
Declaration::DeclareRec(vec![mark_def_recursive(def)], IllegalCycleMark::empty())
|
||||
} else {
|
||||
|
@ -1862,11 +1894,26 @@ pub(crate) fn sort_can_defs(
|
|||
|
||||
Declaration::InvalidCycle(entries)
|
||||
} else {
|
||||
let rec_defs = group
|
||||
let rec_defs: Vec<Def> = group
|
||||
.iter_ones()
|
||||
.map(|index| mark_def_recursive(take_def!(index)))
|
||||
.collect();
|
||||
|
||||
if is_initial
|
||||
&& !rec_defs.iter().any(|def| {
|
||||
def.pattern_vars
|
||||
.keys()
|
||||
.any(|sym| output.references.has_value_lookup(*sym))
|
||||
})
|
||||
{
|
||||
// These defs are only used in mutual recursion with themselves.
|
||||
let region = Region::span_across(
|
||||
&rec_defs.first().unwrap().region(),
|
||||
&rec_defs.last().unwrap().region(),
|
||||
);
|
||||
env.problem(Problem::DefsOnlyUsedInRecursion(rec_defs.len(), region));
|
||||
}
|
||||
|
||||
Declaration::DeclareRec(rec_defs, IllegalCycleMark::new(var_store))
|
||||
};
|
||||
|
||||
|
@ -2312,10 +2359,15 @@ pub fn can_defs_with_return<'a>(
|
|||
output
|
||||
.introduced_variables
|
||||
.union(&defs_output.introduced_variables);
|
||||
|
||||
// Sort the defs with the output of the return expression - we'll use this to catch unused defs
|
||||
// due only to recursion.
|
||||
let (declarations, mut output) = sort_can_defs(env, var_store, unsorted, output);
|
||||
|
||||
output.references.union_mut(&defs_output.references);
|
||||
|
||||
// Now that we've collected all the references, check to see if any of the new idents
|
||||
// we defined went unused by the return expression. If any were unused, report it.
|
||||
// we defined went unused by the return expression or any other def.
|
||||
for (symbol, region) in symbols_introduced {
|
||||
if !output.references.has_type_or_value_lookup(symbol)
|
||||
&& !scope.abilities_store.is_specialization_name(symbol)
|
||||
|
@ -2324,8 +2376,6 @@ pub fn can_defs_with_return<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let (declarations, output) = sort_can_defs(env, var_store, unsorted, output);
|
||||
|
||||
let mut loc_expr: Loc<Expr> = ret_expr;
|
||||
|
||||
for declaration in declarations.into_iter().rev() {
|
||||
|
@ -2738,12 +2788,12 @@ fn correct_mutual_recursive_type_alias<'a>(
|
|||
// this is needed.
|
||||
let scratchpad_capacity = sccs
|
||||
.groups()
|
||||
.map(|r| r.count_ones())
|
||||
.map(|(r, _)| r.count_ones())
|
||||
.max()
|
||||
.unwrap_or_default();
|
||||
let mut scratchpad = Vec::with_capacity(scratchpad_capacity);
|
||||
|
||||
for cycle in sccs.groups() {
|
||||
for (cycle, _is_initial) in sccs.groups() {
|
||||
debug_assert!(cycle.count_ones() > 0);
|
||||
|
||||
// We need to instantiate the alias with any symbols in the currrent module it
|
||||
|
|
|
@ -3003,7 +3003,7 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
|
|||
|
||||
let mut loc_expr = Loc::at(expect_region, expect);
|
||||
|
||||
for stored in stack {
|
||||
for stored in stack.into_iter().rev() {
|
||||
match stored {
|
||||
StoredDef::NonRecursive(region, boxed_def) => {
|
||||
loc_expr = Loc::at(region, Expr::LetNonRec(boxed_def, Box::new(loc_expr)));
|
||||
|
|
|
@ -376,6 +376,9 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
// See if any of the new idents we defined went unused.
|
||||
// If any were unused and also not exposed, report it.
|
||||
//
|
||||
// We'll catch symbols that are only referenced due to (mutual) recursion later,
|
||||
// when sorting the defs.
|
||||
for (symbol, region) in symbols_introduced {
|
||||
if !output.references.has_type_or_value_lookup(symbol)
|
||||
&& !exposed_symbols.contains(&symbol)
|
||||
|
@ -427,8 +430,14 @@ pub fn canonicalize_module_defs<'a>(
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let (mut declarations, mut output) =
|
||||
crate::def::sort_can_defs_new(&mut scope, var_store, defs, new_output);
|
||||
let (mut declarations, mut output) = crate::def::sort_can_defs_new(
|
||||
&mut env,
|
||||
&mut scope,
|
||||
var_store,
|
||||
defs,
|
||||
new_output,
|
||||
exposed_symbols,
|
||||
);
|
||||
|
||||
debug_assert!(
|
||||
output.pending_derives.is_empty(),
|
||||
|
|
|
@ -181,7 +181,7 @@ struct Params {
|
|||
p: Vec<u32>,
|
||||
s: Vec<u32>,
|
||||
scc: Sccs,
|
||||
scca: BitVec,
|
||||
scca: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Params {
|
||||
|
@ -200,8 +200,10 @@ impl Params {
|
|||
scc: Sccs {
|
||||
matrix: ReferenceMatrix::new(length),
|
||||
components: 0,
|
||||
not_initial: BitVec::repeat(false, length),
|
||||
},
|
||||
scca: BitVec::repeat(false, length),
|
||||
// use u32::MAX as the sentinel empty value
|
||||
scca: vec![u32::MAX; length],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +217,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) {
|
|||
params.p.push(v as u32);
|
||||
|
||||
for w in bitvec[v * length..][..length].iter_ones() {
|
||||
if !params.scca[w] {
|
||||
if params.scca[w] == u32::MAX {
|
||||
match params.preorders[w] {
|
||||
Preorder::Filled(pw) => loop {
|
||||
let index = *params.p.last().unwrap();
|
||||
|
@ -235,6 +237,8 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) {
|
|||
Preorder::Empty => recurse_onto(length, bitvec, w, params),
|
||||
Preorder::Removed => {}
|
||||
}
|
||||
} else {
|
||||
params.scc.not_initial.set(params.scca[w] as _, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,13 +250,17 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) {
|
|||
.scc
|
||||
.matrix
|
||||
.set_row_col(params.scc.components, node as usize, true);
|
||||
params.scca.set(node as usize, true);
|
||||
params.scca[node as usize] = params.scc.components as _;
|
||||
params.preorders[node as usize] = Preorder::Removed;
|
||||
if node as usize == v {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !params.s.is_empty() {
|
||||
params.scc.not_initial.set(params.scc.components, true);
|
||||
}
|
||||
|
||||
params.scc.components += 1;
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +269,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) {
|
|||
pub struct Sccs {
|
||||
components: usize,
|
||||
matrix: ReferenceMatrix,
|
||||
not_initial: BitVec,
|
||||
}
|
||||
|
||||
impl Sccs {
|
||||
|
@ -271,7 +280,7 @@ impl Sccs {
|
|||
///
|
||||
/// It is guaranteed that a group is non-empty, and that flattening the groups gives a valid
|
||||
/// topological ordering.
|
||||
pub fn groups(&self) -> std::iter::Take<bitvec::slice::ChunksExact<'_, Element, Order>> {
|
||||
pub fn groups(&self) -> impl DoubleEndedIterator<Item = (&'_ BitSlice, bool)> {
|
||||
// work around a panic when requesting a chunk size of 0
|
||||
let length = if self.matrix.length == 0 {
|
||||
// the `.take(self.components)` ensures the resulting iterator will be empty
|
||||
|
@ -286,13 +295,15 @@ impl Sccs {
|
|||
.bitvec
|
||||
.chunks_exact(length)
|
||||
.take(self.components)
|
||||
.enumerate()
|
||||
.map(|(c, slice)| (slice, !self.not_initial[c]))
|
||||
}
|
||||
|
||||
/// Reorder the input slice based on the SCCs. This produces a topological sort
|
||||
pub fn reorder<T>(&self, slice: &mut [T]) {
|
||||
debug_assert_eq!(self.matrix.length, slice.len());
|
||||
|
||||
let mut indices: Vec<_> = self.groups().flat_map(|s| s.iter_ones()).collect();
|
||||
let mut indices: Vec<_> = self.groups().flat_map(|(s, _)| s.iter_ones()).collect();
|
||||
|
||||
for i in 0..slice.len() {
|
||||
let mut index = indices[i];
|
||||
|
|
|
@ -79,6 +79,9 @@ flags! {
|
|||
/// Only use this in single-threaded mode!
|
||||
ROC_PRINT_UNIFICATIONS
|
||||
|
||||
/// Prints types whose ability impls failed to be derived.
|
||||
ROC_PRINT_UNDERIVABLE
|
||||
|
||||
/// Prints traces of unspecialized lambda set compaction
|
||||
ROC_TRACE_COMPACTION
|
||||
|
||||
|
@ -116,6 +119,9 @@ flags! {
|
|||
|
||||
// ===Mono===
|
||||
|
||||
/// Type-checks the mono IR after specialization.
|
||||
ROC_CHECK_MONO_IR
|
||||
|
||||
/// Writes a pretty-printed mono IR to stderr after function specialization.
|
||||
ROC_PRINT_IR_AFTER_SPECIALIZATION
|
||||
|
||||
|
|
|
@ -174,6 +174,9 @@ const fn num_symbol_to_hash_lambda(symbol: Symbol) -> Option<FlatHash> {
|
|||
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => {
|
||||
Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I128))
|
||||
}
|
||||
Symbol::NUM_NAT | Symbol::NUM_NATURAL => {
|
||||
Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_NAT))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,3 +11,4 @@ roc_collections = { path = "../collections" }
|
|||
roc_region = { path = "../region" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
roc_problem = { path = "../problem" }
|
||||
|
|
|
@ -7,6 +7,7 @@ use roc_module::{
|
|||
ident::{Lowercase, TagIdIntType, TagName},
|
||||
symbol::Symbol,
|
||||
};
|
||||
use roc_problem::Severity;
|
||||
use roc_region::all::Region;
|
||||
|
||||
use self::Pattern::*;
|
||||
|
@ -149,6 +150,17 @@ pub enum Error {
|
|||
},
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn severity(&self) -> Severity {
|
||||
use Severity::*;
|
||||
match self {
|
||||
Error::Incomplete(..) => RuntimeError,
|
||||
Error::Redundant { .. } => Warning,
|
||||
Error::Unmatchable { .. } => Warning,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Context {
|
||||
BadArg,
|
||||
|
|
|
@ -298,17 +298,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push('\'');
|
||||
for c in string.chars() {
|
||||
if c == '"' {
|
||||
buf.push_char_literal('"')
|
||||
} else {
|
||||
for escaped in c.escape_default() {
|
||||
buf.push_char_literal(escaped);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.push('\'');
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
&NonBase10Int {
|
||||
base,
|
||||
|
@ -438,6 +428,20 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn format_sq_literal(buf: &mut Buf, s: &str) {
|
||||
buf.push('\'');
|
||||
for c in s.chars() {
|
||||
if c == '"' {
|
||||
buf.push_char_literal('"')
|
||||
} else {
|
||||
for escaped in c.escape_default() {
|
||||
buf.push_char_literal(escaped);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.push('\'');
|
||||
}
|
||||
|
||||
fn starts_with_newline(expr: &Expr) -> bool {
|
||||
use roc_parse::ast::Expr::*;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::annotation::{Formattable, Newlines, Parens};
|
||||
use crate::expr::fmt_str_literal;
|
||||
use crate::expr::{fmt_str_literal, format_sq_literal};
|
||||
use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt};
|
||||
use crate::Buf;
|
||||
use roc_parse::ast::{Base, CommentOrNewline, Pattern};
|
||||
|
@ -155,9 +155,7 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
StrLiteral(literal) => fmt_str_literal(buf, *literal, indent),
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push('\'');
|
||||
buf.push_str(string);
|
||||
buf.push('\'');
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
Underscore(name) => {
|
||||
buf.indent(indent);
|
||||
|
|
|
@ -5673,6 +5673,18 @@ mod test_fmt {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_char_pattern() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
when x is
|
||||
' ' -> x
|
||||
'\n' -> x
|
||||
'\t' -> x
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_nested_pipeline() {
|
||||
expr_formats_same(indoc!(
|
||||
|
|
|
@ -37,6 +37,7 @@ use roc_collections::all::{ImMap, MutMap, MutSet};
|
|||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_PRINT_LLVM_FN_VERIFICATION;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc,
|
||||
|
@ -5610,3 +5611,23 @@ pub fn add_func<'ctx>(
|
|||
|
||||
fn_val
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
Loop(UnionLayout<'a>),
|
||||
}
|
||||
|
||||
impl<'a> WhenRecursive<'a> {
|
||||
pub fn unwrap_recursive_pointer(&self, layout: Layout<'a>) -> Layout<'a> {
|
||||
match layout {
|
||||
Layout::RecursivePointer => match self {
|
||||
WhenRecursive::Loop(lay) => Layout::Union(*lay),
|
||||
WhenRecursive::Unreachable => {
|
||||
internal_error!("cannot compare recursive pointers outside of a structure")
|
||||
}
|
||||
},
|
||||
_ => layout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
|
||||
use crate::llvm::build::{
|
||||
get_tag_id, tag_pointer_clear_tag_id, Env, WhenRecursive, FAST_CALL_CONV,
|
||||
};
|
||||
use crate::llvm::build_list::{list_len, load_list_ptr};
|
||||
use crate::llvm::build_str::str_equal;
|
||||
use crate::llvm::convert::basic_type_from_layout;
|
||||
|
@ -17,12 +19,6 @@ use super::build::{load_roc_value, use_roc_value};
|
|||
use super::convert::argument_type_from_union_layout;
|
||||
use super::lowlevel::dec_binop_with_unchecked;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
Loop(UnionLayout<'a>),
|
||||
}
|
||||
|
||||
pub fn generic_eq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
|
@ -406,8 +402,9 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
|||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let symbol = Symbol::LIST_EQ;
|
||||
let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout);
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, element_layout)
|
||||
.get(symbol, &element_layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
|
@ -427,7 +424,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
|||
layout_ids,
|
||||
when_recursive,
|
||||
function_value,
|
||||
element_layout,
|
||||
&element_layout,
|
||||
);
|
||||
|
||||
function_value
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::debug_info_init;
|
|||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||
use crate::llvm::build::{
|
||||
add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, use_roc_value, Env,
|
||||
FAST_CALL_CONV,
|
||||
WhenRecursive, FAST_CALL_CONV,
|
||||
};
|
||||
use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
||||
use crate::llvm::convert::{basic_type_from_layout, RocUnion};
|
||||
|
@ -399,14 +399,8 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
match builtin {
|
||||
List(element_layout) => {
|
||||
let function = modify_refcount_list(
|
||||
env,
|
||||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
layout,
|
||||
element_layout,
|
||||
);
|
||||
let function =
|
||||
modify_refcount_list(env, layout_ids, mode, when_recursive, element_layout);
|
||||
|
||||
Some(function)
|
||||
}
|
||||
|
@ -437,12 +431,6 @@ fn modify_refcount_layout<'a, 'ctx, 'env>(
|
|||
);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
Loop(UnionLayout<'a>),
|
||||
}
|
||||
|
||||
fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
|
@ -609,25 +597,26 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
|
|||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
when_recursive: &WhenRecursive<'a>,
|
||||
layout: &Layout<'a>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout);
|
||||
let list_layout = &Layout::Builtin(Builtin::List(env.arena.alloc(element_layout)));
|
||||
let (_, fn_name) = function_name_from_mode(
|
||||
layout_ids,
|
||||
&env.interns,
|
||||
"increment_list",
|
||||
"decrement_list",
|
||||
layout,
|
||||
list_layout,
|
||||
mode,
|
||||
);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let basic_type = argument_type_from_layout(env, layout);
|
||||
let basic_type = argument_type_from_layout(env, list_layout);
|
||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||
|
||||
modify_refcount_list_help(
|
||||
|
@ -635,8 +624,8 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
|
|||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
layout,
|
||||
element_layout,
|
||||
list_layout,
|
||||
&element_layout,
|
||||
function_value,
|
||||
);
|
||||
|
||||
|
|
|
@ -744,7 +744,7 @@ impl<'a> WasmBackend<'a> {
|
|||
let mut current_stmt = stmt;
|
||||
while let Stmt::Let(sym, expr, layout, following) = current_stmt {
|
||||
if DEBUG_SETTINGS.let_stmt_ir {
|
||||
print!("\nlet {:?} = {}", sym, expr.to_pretty(200));
|
||||
print!("\nlet {:?} = {}", sym, expr.to_pretty(200, true));
|
||||
}
|
||||
|
||||
let kind = match following {
|
||||
|
@ -974,7 +974,7 @@ impl<'a> WasmBackend<'a> {
|
|||
self.register_symbol_debug_names();
|
||||
println!(
|
||||
"## rc_stmt:\n{}\n{:?}",
|
||||
rc_stmt.to_pretty(self.env.layout_interner, 200),
|
||||
rc_stmt.to_pretty(self.env.layout_interner, 200, true),
|
||||
rc_stmt
|
||||
);
|
||||
}
|
||||
|
@ -1078,7 +1078,7 @@ impl<'a> WasmBackend<'a> {
|
|||
Expr::Reset { symbol: arg, .. } => self.expr_reset(*arg, sym, storage),
|
||||
|
||||
Expr::RuntimeErrorFunction(_) => {
|
||||
todo!("Expression `{}`", expr.to_pretty(100))
|
||||
todo!("Expression `{}`", expr.to_pretty(100, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ pub fn build_app_module<'a>(
|
|||
if DEBUG_SETTINGS.user_procs_ir {
|
||||
println!("## procs");
|
||||
for proc in procs.iter() {
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200));
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200, true));
|
||||
// println!("{:?}", proc);
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ pub fn build_app_module<'a>(
|
|||
if DEBUG_SETTINGS.helper_procs_ir {
|
||||
println!("## helper_procs");
|
||||
for proc in helper_procs.iter() {
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200));
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200, true));
|
||||
// println!("{:#?}", proc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,14 +101,14 @@ pub fn load_and_monomorphize_from_str<'a>(
|
|||
exposed_types: ExposedByModule,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
) -> Result<MonomorphizedModule<'a>, LoadMonomorphizedError<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_str(arena, filename, src, roc_cache_dir, src_dir)?;
|
||||
|
||||
match load(arena, load_start, exposed_types, roc_cache_dir, load_config)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
TypeChecked(module) => Err(LoadMonomorphizedError::ErrorModule(module)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use crate::docs::ModuleDocumentation;
|
||||
use bumpalo::Bump;
|
||||
use crossbeam::channel::{bounded, Sender};
|
||||
|
@ -17,8 +19,8 @@ use roc_constrain::module::constrain_module;
|
|||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::{
|
||||
ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE, ROC_PRINT_IR_AFTER_SPECIALIZATION,
|
||||
ROC_PRINT_LOAD_LOG,
|
||||
ROC_CHECK_MONO_IR, ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE,
|
||||
ROC_PRINT_IR_AFTER_SPECIALIZATION, ROC_PRINT_LOAD_LOG,
|
||||
};
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
|
@ -45,12 +47,13 @@ use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
|||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_parse::module::module_defs;
|
||||
use roc_parse::parser::{FileError, Parser, SourceError, SyntaxError};
|
||||
use roc_problem::Severity;
|
||||
use roc_region::all::{LineInfo, Loc, Region};
|
||||
use roc_reporting::report::{Annotation, Palette, RenderTarget};
|
||||
use roc_solve::module::{extract_module_owned_implementations, Solved, SolvedModule};
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{ExposedTypesStorageSubs, Subs, VarStore, Variable};
|
||||
use roc_types::subs::{CopiedImport, ExposedTypesStorageSubs, Subs, VarStore, Variable};
|
||||
use roc_types::types::{Alias, Types};
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::collections::HashMap;
|
||||
|
@ -97,20 +100,28 @@ pub struct LoadConfig {
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ExecutionMode {
|
||||
Test,
|
||||
Check,
|
||||
Executable,
|
||||
/// Like [`ExecutionMode::Executable`], but stops in the presence of type errors.
|
||||
ExecutableIfCheck,
|
||||
/// Test is like [`ExecutionMode::ExecutableIfCheck`], but rather than producing a proper
|
||||
/// executable, run tests.
|
||||
Test,
|
||||
}
|
||||
|
||||
impl ExecutionMode {
|
||||
fn goal_phase(&self) -> Phase {
|
||||
match self {
|
||||
ExecutionMode::Test | ExecutionMode::Executable => Phase::MakeSpecializations,
|
||||
ExecutionMode::Check | ExecutionMode::ExecutableIfCheck => Phase::SolveTypes,
|
||||
ExecutionMode::Executable => Phase::MakeSpecializations,
|
||||
ExecutionMode::Check | ExecutionMode::ExecutableIfCheck | ExecutionMode::Test => {
|
||||
Phase::SolveTypes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_if_checks(&self) -> bool {
|
||||
matches!(self, Self::ExecutableIfCheck | Self::Test)
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct storing various intermediate stages by their ModuleId
|
||||
|
@ -141,18 +152,22 @@ struct ModuleCache<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ModuleCache<'a> {
|
||||
pub fn total_problems(&self) -> usize {
|
||||
let mut total = 0;
|
||||
fn has_can_errors(&self) -> bool {
|
||||
self.can_problems
|
||||
.values()
|
||||
.flatten()
|
||||
.any(|problem| problem.severity() == Severity::RuntimeError)
|
||||
}
|
||||
|
||||
for problems in self.can_problems.values() {
|
||||
total += problems.len();
|
||||
}
|
||||
fn has_type_errors(&self) -> bool {
|
||||
self.type_problems
|
||||
.values()
|
||||
.flatten()
|
||||
.any(|problem| problem.severity() == Severity::RuntimeError)
|
||||
}
|
||||
|
||||
for problems in self.type_problems.values() {
|
||||
total += problems.len();
|
||||
}
|
||||
|
||||
total
|
||||
pub fn has_errors(&self) -> bool {
|
||||
self.has_can_errors() || self.has_type_errors()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -963,7 +978,6 @@ impl<'a> State<'a> {
|
|||
self.exec_mode.goal_phase()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new(
|
||||
root_id: ModuleId,
|
||||
target_info: TargetInfo,
|
||||
|
@ -1208,7 +1222,6 @@ fn enqueue_task<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn load_and_typecheck_str<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
|
@ -1495,7 +1508,6 @@ pub enum Threading {
|
|||
/// and then linking them together, and possibly caching them by the hash of their
|
||||
/// specializations, so if none of their specializations changed, we don't even need
|
||||
/// to rebuild the module and can link in the cached one directly.)
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn load<'a>(
|
||||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
|
@ -1556,7 +1568,6 @@ pub fn load<'a>(
|
|||
}
|
||||
|
||||
/// Load using only a single thread; used when compiling to webassembly
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn load_single_threaded<'a>(
|
||||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
|
@ -1821,7 +1832,6 @@ fn state_thread_step<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_multi_threaded<'a>(
|
||||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
|
@ -1997,7 +2007,6 @@ fn load_multi_threaded<'a>(
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn worker_task_step<'a>(
|
||||
worker_arena: &'a Bump,
|
||||
worker: &Worker<BuildTask<'a>>,
|
||||
|
@ -2072,7 +2081,6 @@ fn worker_task_step<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn worker_task<'a>(
|
||||
worker_arena: &'a Bump,
|
||||
worker: Worker<BuildTask<'a>>,
|
||||
|
@ -2164,7 +2172,7 @@ macro_rules! debug_print_ir {
|
|||
let procs_string = $state
|
||||
.procedures
|
||||
.values()
|
||||
.map(|proc| proc.to_pretty($interner, 200))
|
||||
.map(|proc| proc.to_pretty($interner, 200, true))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = procs_string.join("\n");
|
||||
|
@ -2174,6 +2182,27 @@ macro_rules! debug_print_ir {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_check_ir {
|
||||
($state:expr, $arena:expr, $interner:expr, $flag:path) => {
|
||||
dbg_do!($flag, {
|
||||
use roc_mono::debug::{check_procs, format_problems};
|
||||
|
||||
let interns = Interns {
|
||||
module_ids: $state.arc_modules.lock().clone().into_module_ids(),
|
||||
all_ident_ids: $state.constrained_ident_ids.clone(),
|
||||
};
|
||||
|
||||
let procedures = &$state.procedures;
|
||||
|
||||
let problems = check_procs($arena, $interner, procedures);
|
||||
if !problems.is_empty() {
|
||||
let formatted = format_problems(&interns, $interner, problems);
|
||||
eprintln!("IR PROBLEMS FOUND:\n{formatted}");
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
/// Report modules that are imported, but from which nothing is used
|
||||
fn report_unused_imported_modules<'a>(
|
||||
state: &mut State<'a>,
|
||||
|
@ -2615,7 +2644,7 @@ fn update<'a>(
|
|||
let finish_type_checking = is_host_exposed &&
|
||||
(state.goal_phase() == Phase::SolveTypes)
|
||||
// If we're running in check-and-then-build mode, only exit now there are errors.
|
||||
&& (!matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) || state.module_cache.total_problems() > 0);
|
||||
&& (!state.exec_mode.build_if_checks() || state.module_cache.has_errors());
|
||||
|
||||
if finish_type_checking {
|
||||
debug_assert!(work.is_empty());
|
||||
|
@ -2623,7 +2652,7 @@ fn update<'a>(
|
|||
|
||||
state.timings.insert(module_id, module_timing);
|
||||
|
||||
if matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) {
|
||||
if state.exec_mode.build_if_checks() {
|
||||
// We there may outstanding modules in the typecheked cache whose ident IDs
|
||||
// aren't registered; transfer all of their idents over to the state, since
|
||||
// we're now done and ready to report errors.
|
||||
|
@ -2677,9 +2706,7 @@ fn update<'a>(
|
|||
},
|
||||
);
|
||||
|
||||
if state.goal_phase() > Phase::SolveTypes
|
||||
|| matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
if state.goal_phase() > Phase::SolveTypes || state.exec_mode.build_if_checks() {
|
||||
let layout_cache = state.layout_caches.pop().unwrap_or_else(|| {
|
||||
LayoutCache::new(state.layout_interner.fork(), state.target_info)
|
||||
});
|
||||
|
@ -2703,17 +2730,12 @@ fn update<'a>(
|
|||
state.timings.insert(module_id, module_timing);
|
||||
}
|
||||
|
||||
let work = if is_host_exposed
|
||||
&& matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
let work = if is_host_exposed && state.exec_mode.build_if_checks() {
|
||||
debug_assert!(
|
||||
work.is_empty(),
|
||||
"work left over after host exposed is checked"
|
||||
);
|
||||
|
||||
// Update the goal phase to target full codegen.
|
||||
state.exec_mode = ExecutionMode::Executable;
|
||||
|
||||
// Load the find + make specializations portion of the dependency graph.
|
||||
state
|
||||
.dependencies
|
||||
|
@ -2785,7 +2807,10 @@ fn update<'a>(
|
|||
layout_cache,
|
||||
..
|
||||
} => {
|
||||
debug_assert!(state.goal_phase() == Phase::MakeSpecializations);
|
||||
debug_assert!(
|
||||
state.goal_phase() == Phase::MakeSpecializations
|
||||
|| state.exec_mode.build_if_checks()
|
||||
);
|
||||
|
||||
log!("made specializations for {:?}", module_id);
|
||||
|
||||
|
@ -2896,6 +2921,7 @@ fn update<'a>(
|
|||
log!("specializations complete from {:?}", module_id);
|
||||
|
||||
debug_print_ir!(state, &layout_interner, ROC_PRINT_IR_AFTER_SPECIALIZATION);
|
||||
debug_check_ir!(state, arena, &layout_interner, ROC_CHECK_MONO_IR);
|
||||
|
||||
let ident_ids = state.constrained_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
|
@ -3205,7 +3231,6 @@ fn finish_specialization<'a>(
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn finish(
|
||||
mut state: State,
|
||||
solved: Solved<Subs>,
|
||||
|
@ -3644,7 +3669,6 @@ fn verify_interface_matches_file_path<'a>(
|
|||
Err(problem)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn parse_header<'a>(
|
||||
arena: &'a Bump,
|
||||
read_file_duration: Duration,
|
||||
|
@ -3931,7 +3955,6 @@ fn parse_header<'a>(
|
|||
}
|
||||
|
||||
/// Load a module by its filename
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_filename<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
|
@ -3970,7 +3993,6 @@ fn load_filename<'a>(
|
|||
|
||||
/// Load a module from a str
|
||||
/// the `filename` is never read, but used for the module name
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_from_str<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
|
@ -4010,7 +4032,6 @@ struct HeaderInfo<'a> {
|
|||
extra: HeaderFor<'a>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_header<'a>(
|
||||
info: HeaderInfo<'a>,
|
||||
parse_state: roc_parse::state::State<'a>,
|
||||
|
@ -4236,7 +4257,6 @@ struct PlatformHeaderInfo<'a> {
|
|||
}
|
||||
|
||||
// TODO refactor so more logic is shared with `send_header`
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn send_header_two<'a>(
|
||||
info: PlatformHeaderInfo<'a>,
|
||||
parse_state: roc_parse::state::State<'a>,
|
||||
|
@ -4488,7 +4508,6 @@ fn send_header_two<'a>(
|
|||
|
||||
impl<'a> BuildTask<'a> {
|
||||
// TODO trim down these arguments - possibly by moving Constraint into Module
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn solve_module(
|
||||
module: Module,
|
||||
ident_ids: IdentIds,
|
||||
|
@ -4575,61 +4594,26 @@ pub fn add_imports(
|
|||
mut pending_abilities: PendingAbilitiesStore,
|
||||
exposed_for_module: &ExposedForModule,
|
||||
def_types: &mut Vec<(Symbol, Loc<TypeOrVar>)>,
|
||||
rigid_vars: &mut Vec<Variable>,
|
||||
imported_rigid_vars: &mut Vec<Variable>,
|
||||
imported_flex_vars: &mut Vec<Variable>,
|
||||
) -> (Vec<Variable>, AbilitiesStore) {
|
||||
let mut import_variables = Vec::new();
|
||||
|
||||
let mut cached_symbol_vars = VecMap::default();
|
||||
|
||||
macro_rules! import_var_for_symbol {
|
||||
($subs:expr, $exposed_by_module:expr, $symbol:ident, $break:stmt) => {
|
||||
let module_id = $symbol.module_id();
|
||||
match $exposed_by_module.get(&module_id) {
|
||||
Some(ExposedModuleTypes {
|
||||
exposed_types_storage_subs: exposed_types,
|
||||
resolved_implementations: _,
|
||||
}) => {
|
||||
let variable = match exposed_types.stored_vars_by_symbol.iter().find(|(s, _)| **s == $symbol) {
|
||||
None => {
|
||||
// Today we define builtins in each module that uses them
|
||||
// so even though they have a different module name from
|
||||
// the surrounding module, they are not technically imported
|
||||
debug_assert!($symbol.is_builtin());
|
||||
$break
|
||||
}
|
||||
Some((_, x)) => *x,
|
||||
};
|
||||
|
||||
let copied_import = exposed_types.storage_subs.export_variable_to($subs, variable);
|
||||
let copied_import_index = constraints.push_variable(copied_import.variable);
|
||||
|
||||
def_types.push((
|
||||
$symbol,
|
||||
Loc::at_zero(copied_import_index),
|
||||
));
|
||||
|
||||
// not a typo; rigids are turned into flex during type inference, but when imported we must
|
||||
// consider them rigid variables
|
||||
rigid_vars.extend(copied_import.rigid);
|
||||
rigid_vars.extend(copied_import.flex);
|
||||
|
||||
// Rigid vars bound to abilities are also treated like rigids.
|
||||
rigid_vars.extend(copied_import.rigid_able);
|
||||
rigid_vars.extend(copied_import.flex_able);
|
||||
|
||||
import_variables.extend(copied_import.registered);
|
||||
|
||||
cached_symbol_vars.insert($symbol, copied_import.variable);
|
||||
}
|
||||
None => {
|
||||
internal_error!("Imported module {:?} is not available", module_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &symbol in &exposed_for_module.imported_values {
|
||||
import_var_for_symbol!(subs, exposed_for_module.exposed_by_module, symbol, continue);
|
||||
import_variable_for_symbol(
|
||||
subs,
|
||||
constraints,
|
||||
def_types,
|
||||
&mut import_variables,
|
||||
imported_rigid_vars,
|
||||
imported_flex_vars,
|
||||
&mut cached_symbol_vars,
|
||||
&exposed_for_module.exposed_by_module,
|
||||
symbol,
|
||||
OnSymbolNotFound::AssertIsBuiltin,
|
||||
);
|
||||
}
|
||||
|
||||
// Patch used symbols from circular dependencies.
|
||||
|
@ -4656,6 +4640,9 @@ pub fn add_imports(
|
|||
struct Ctx<'a> {
|
||||
subs: &'a mut Subs,
|
||||
exposed_by_module: &'a ExposedByModule,
|
||||
imported_variables: &'a mut Vec<Variable>,
|
||||
imported_rigids: &'a mut Vec<Variable>,
|
||||
imported_flex: &'a mut Vec<Variable>,
|
||||
}
|
||||
|
||||
let abilities_store = pending_abilities.resolve_for_module(
|
||||
|
@ -4663,16 +4650,26 @@ pub fn add_imports(
|
|||
&mut Ctx {
|
||||
subs,
|
||||
exposed_by_module: &exposed_for_module.exposed_by_module,
|
||||
imported_variables: &mut import_variables,
|
||||
imported_rigids: imported_rigid_vars,
|
||||
imported_flex: imported_flex_vars,
|
||||
},
|
||||
|ctx, symbol| match cached_symbol_vars.get(&symbol).copied() {
|
||||
Some(var) => var,
|
||||
None => {
|
||||
import_var_for_symbol!(
|
||||
import_variable_for_symbol(
|
||||
ctx.subs,
|
||||
ctx.exposed_by_module,
|
||||
constraints,
|
||||
def_types,
|
||||
ctx.imported_variables,
|
||||
ctx.imported_rigids,
|
||||
ctx.imported_flex,
|
||||
&mut cached_symbol_vars,
|
||||
&exposed_for_module.exposed_by_module,
|
||||
symbol,
|
||||
internal_error!("Import ability member {:?} not available", symbol)
|
||||
OnSymbolNotFound::AbilityMemberMustBeAvailable,
|
||||
);
|
||||
|
||||
*cached_symbol_vars.get(&symbol).unwrap()
|
||||
}
|
||||
},
|
||||
|
@ -4690,7 +4687,15 @@ pub fn add_imports(
|
|||
.storage_subs
|
||||
.export_variable_to(ctx.subs, *var);
|
||||
|
||||
copied_import.variable
|
||||
#[allow(clippy::let_and_return)]
|
||||
let copied_import_var = extend_imports_data_with_copied_import(
|
||||
copied_import,
|
||||
ctx.imported_variables,
|
||||
ctx.imported_rigids,
|
||||
ctx.imported_flex,
|
||||
);
|
||||
|
||||
copied_import_var
|
||||
}
|
||||
None => internal_error!("Imported module {:?} is not available", module),
|
||||
},
|
||||
|
@ -4699,6 +4704,95 @@ pub fn add_imports(
|
|||
(import_variables, abilities_store)
|
||||
}
|
||||
|
||||
enum OnSymbolNotFound {
|
||||
AssertIsBuiltin,
|
||||
AbilityMemberMustBeAvailable,
|
||||
}
|
||||
|
||||
fn extend_imports_data_with_copied_import(
|
||||
copied_import: CopiedImport,
|
||||
imported_variables: &mut Vec<Variable>,
|
||||
imported_rigids: &mut Vec<Variable>,
|
||||
imported_flex: &mut Vec<Variable>,
|
||||
) -> Variable {
|
||||
// not a typo; rigids are turned into flex during type inference, but when imported we must
|
||||
// consider them rigid variables
|
||||
imported_rigids.extend(copied_import.rigid);
|
||||
imported_flex.extend(copied_import.flex);
|
||||
|
||||
// Rigid vars bound to abilities are also treated like rigids.
|
||||
imported_rigids.extend(copied_import.rigid_able);
|
||||
imported_flex.extend(copied_import.flex_able);
|
||||
|
||||
imported_variables.extend(copied_import.registered);
|
||||
|
||||
copied_import.variable
|
||||
}
|
||||
|
||||
fn import_variable_for_symbol(
|
||||
subs: &mut Subs,
|
||||
constraints: &mut Constraints,
|
||||
def_types: &mut Vec<(Symbol, Loc<TypeOrVar>)>,
|
||||
imported_variables: &mut Vec<Variable>,
|
||||
imported_rigids: &mut Vec<Variable>,
|
||||
imported_flex: &mut Vec<Variable>,
|
||||
cached_symbol_vars: &mut VecMap<Symbol, Variable>,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
symbol: Symbol,
|
||||
on_symbol_not_found: OnSymbolNotFound,
|
||||
) {
|
||||
let module_id = symbol.module_id();
|
||||
match exposed_by_module.get(&module_id) {
|
||||
Some(ExposedModuleTypes {
|
||||
exposed_types_storage_subs: exposed_types,
|
||||
resolved_implementations: _,
|
||||
}) => {
|
||||
let variable = match exposed_types
|
||||
.stored_vars_by_symbol
|
||||
.iter()
|
||||
.find(|(s, _)| **s == symbol)
|
||||
{
|
||||
None => {
|
||||
use OnSymbolNotFound::*;
|
||||
match on_symbol_not_found {
|
||||
AssertIsBuiltin => {
|
||||
// Today we define builtins in each module that uses them
|
||||
// so even though they have a different module name from
|
||||
// the surrounding module, they are not technically imported
|
||||
debug_assert!(symbol.is_builtin());
|
||||
return;
|
||||
}
|
||||
AbilityMemberMustBeAvailable => {
|
||||
internal_error!("Import ability member {:?} not available", symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some((_, x)) => *x,
|
||||
};
|
||||
|
||||
let copied_import = exposed_types
|
||||
.storage_subs
|
||||
.export_variable_to(subs, variable);
|
||||
|
||||
let copied_import_var = extend_imports_data_with_copied_import(
|
||||
copied_import,
|
||||
imported_variables,
|
||||
imported_rigids,
|
||||
imported_flex,
|
||||
);
|
||||
|
||||
let copied_import_index = constraints.push_variable(copied_import_var);
|
||||
|
||||
def_types.push((symbol, Loc::at_zero(copied_import_index)));
|
||||
|
||||
cached_symbol_vars.insert(symbol, copied_import_var);
|
||||
}
|
||||
None => {
|
||||
internal_error!("Imported module {:?} is not available", module_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::complexity)]
|
||||
fn run_solve_solve(
|
||||
exposed_for_module: ExposedForModule,
|
||||
|
@ -4724,7 +4818,8 @@ fn run_solve_solve(
|
|||
..
|
||||
} = module;
|
||||
|
||||
let mut rigid_vars: Vec<Variable> = Vec::new();
|
||||
let mut imported_rigid_vars: Vec<Variable> = Vec::new();
|
||||
let mut imported_flex_vars: Vec<Variable> = Vec::new();
|
||||
let mut def_types: Vec<(Symbol, Loc<TypeOrVar>)> = Vec::new();
|
||||
|
||||
let mut subs = Subs::new_from_varstore(var_store);
|
||||
|
@ -4736,11 +4831,17 @@ fn run_solve_solve(
|
|||
pending_abilities,
|
||||
&exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
&mut imported_rigid_vars,
|
||||
&mut imported_flex_vars,
|
||||
);
|
||||
|
||||
let actual_constraint =
|
||||
constraints.let_import_constraint(rigid_vars, def_types, constraint, &import_variables);
|
||||
let actual_constraint = constraints.let_import_constraint(
|
||||
imported_rigid_vars,
|
||||
imported_flex_vars,
|
||||
def_types,
|
||||
constraint,
|
||||
&import_variables,
|
||||
);
|
||||
|
||||
let mut solve_aliases = roc_solve::solve::Aliases::with_capacity(aliases.len());
|
||||
for (name, (_, alias)) in aliases.iter() {
|
||||
|
@ -4805,7 +4906,6 @@ fn run_solve_solve(
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn run_solve<'a>(
|
||||
module: Module,
|
||||
ident_ids: IdentIds,
|
||||
|
@ -4919,7 +5019,6 @@ fn unspace<'a, T: Copy>(arena: &'a Bump, items: &[Loc<Spaced<'a, T>>]) -> &'a [L
|
|||
.into_bump_slice()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn fabricate_platform_module<'a>(
|
||||
arena: &'a Bump,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
|
@ -4959,7 +5058,6 @@ fn fabricate_platform_module<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn canonicalize_and_constrain<'a>(
|
||||
arena: &'a Bump,
|
||||
|
@ -5233,7 +5331,6 @@ fn ident_from_exposed(entry: &Spaced<'_, ExposedName<'_>>) -> Ident {
|
|||
entry.extract_spaces().item.as_str().into()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn make_specializations<'a>(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
|
@ -5310,7 +5407,6 @@ fn make_specializations<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_pending_specializations<'a>(
|
||||
arena: &'a Bump,
|
||||
solved_subs: Solved<Subs>,
|
||||
|
@ -5741,7 +5837,6 @@ fn build_pending_specializations<'a>(
|
|||
/// their specializations.
|
||||
// TODO: right now, this runs sequentially, and no other modules are mono'd in parallel to the
|
||||
// derived module.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_derived_partial_procs<'a>(
|
||||
home: ModuleId,
|
||||
arena: &'a Bump,
|
||||
|
@ -5987,7 +6082,7 @@ fn run_task<'a>(
|
|||
}
|
||||
|
||||
fn to_file_problem_report(filename: &Path, error: io::ErrorKind) -> String {
|
||||
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
|
||||
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
|
||||
use ven_pretty::DocAllocator;
|
||||
|
||||
let src_lines: Vec<&str> = Vec::new();
|
||||
|
@ -6074,7 +6169,7 @@ fn to_import_cycle_report(
|
|||
filename: PathBuf,
|
||||
render: RenderTarget,
|
||||
) -> String {
|
||||
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
|
||||
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
|
||||
use ven_pretty::DocAllocator;
|
||||
|
||||
// import_cycle looks like CycleModule, Import1, ..., ImportN, CycleModule
|
||||
|
@ -6134,7 +6229,7 @@ fn to_incorrect_module_name_report<'a>(
|
|||
src: &'a [u8],
|
||||
render: RenderTarget,
|
||||
) -> String {
|
||||
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
|
||||
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
|
||||
use ven_pretty::DocAllocator;
|
||||
|
||||
let IncorrectModuleName {
|
||||
|
@ -6220,7 +6315,7 @@ fn to_parse_problem_report<'a>(
|
|||
}
|
||||
|
||||
fn to_missing_platform_report(module_id: ModuleId, other: PlatformPath) -> String {
|
||||
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
|
||||
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
|
||||
use ven_pretty::DocAllocator;
|
||||
use PlatformPath::*;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ Model position :
|
|||
}
|
||||
|
||||
|
||||
initialModel : position -> Model position
|
||||
initialModel : position -> Model position | position has Hash & Eq
|
||||
initialModel = \start ->
|
||||
{ evaluated : Set.empty
|
||||
, openSet : Set.single start
|
||||
|
@ -22,7 +22,7 @@ initialModel = \start ->
|
|||
}
|
||||
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound] | position has Eq
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
cheapestOpen = \costFunction, model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
|
@ -47,7 +47,7 @@ cheapestOpen = \costFunction, model ->
|
|||
|
||||
|
||||
|
||||
reconstructPath : Dict position position, position -> List position | position has Eq
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
|
@ -56,7 +56,7 @@ reconstructPath = \cameFrom, goal ->
|
|||
Ok next ->
|
||||
List.append (reconstructPath cameFrom next) goal
|
||||
|
||||
updateCost : position, position, Model position -> Model position | position has Eq
|
||||
updateCost : position, position, Model position -> Model position | position has Hash & Eq
|
||||
updateCost = \current, neighbour, model ->
|
||||
newCameFrom = Dict.insert model.cameFrom neighbour current
|
||||
|
||||
|
@ -80,12 +80,12 @@ updateCost = \current, neighbour, model ->
|
|||
model
|
||||
|
||||
|
||||
findPath : { costFunction: (position, position -> F64), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [KeyNotFound] | position has Eq
|
||||
findPath : { costFunction: (position, position -> F64), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [KeyNotFound] | position has Hash & Eq
|
||||
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)] | position has Eq
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Hash & Eq
|
||||
astar = \costFn, moveFn, goal, model ->
|
||||
when cheapestOpen (\position -> costFn goal position) model is
|
||||
Err _ ->
|
||||
|
|
|
@ -491,12 +491,12 @@ fn load_astar() {
|
|||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound] | position has Eq",
|
||||
"initialModel" => "position -> Model position",
|
||||
"reconstructPath" => "Dict position position, position -> List position | position has Eq",
|
||||
"updateCost" => "position, position, Model position -> Model position | position has Eq",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound] | position has Eq",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Eq",
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound] | position has Hash & Eq",
|
||||
"initialModel" => "position -> Model position | position has Hash & Eq",
|
||||
"reconstructPath" => "Dict position position, position -> List position | position has Hash & Eq",
|
||||
"updateCost" => "position, position, Model position -> Model position | position has Hash & Eq",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound] | position has Hash & Eq",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Hash & Eq",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1400,26 +1400,30 @@ define_builtins! {
|
|||
0 DICT_DICT: "Dict" exposed_type=true // the Dict.Dict type alias
|
||||
1 DICT_EMPTY: "empty"
|
||||
2 DICT_SINGLE: "single"
|
||||
3 DICT_GET: "get"
|
||||
4 DICT_GET_RESULT: "#get_result" // symbol used in the definition of Dict.get
|
||||
5 DICT_WALK: "walk"
|
||||
6 DICT_INSERT: "insert"
|
||||
7 DICT_LEN: "len"
|
||||
3 DICT_CLEAR: "clear"
|
||||
4 DICT_LEN: "len"
|
||||
5 DICT_GET: "get"
|
||||
6 DICT_GET_RESULT: "#get_result" // symbol used in the definition of Dict.get
|
||||
7 DICT_CONTAINS: "contains"
|
||||
8 DICT_INSERT: "insert"
|
||||
9 DICT_REMOVE: "remove"
|
||||
|
||||
8 DICT_REMOVE: "remove"
|
||||
9 DICT_CONTAINS: "contains"
|
||||
10 DICT_KEYS: "keys"
|
||||
11 DICT_VALUES: "values"
|
||||
10 DICT_WALK: "walk"
|
||||
11 DICT_WALK_UNTIL: "walkUntil"
|
||||
12 DICT_FROM_LIST: "fromList"
|
||||
13 DICT_TO_LIST: "toList"
|
||||
14 DICT_KEYS: "keys"
|
||||
15 DICT_VALUES: "values"
|
||||
|
||||
12 DICT_INSERT_ALL: "insertAll" // union
|
||||
13 DICT_KEEP_SHARED: "keepShared" // intersection
|
||||
14 DICT_REMOVE_ALL: "removeAll" // difference
|
||||
16 DICT_INSERT_ALL: "insertAll" // union
|
||||
17 DICT_KEEP_SHARED: "keepShared" // intersection
|
||||
18 DICT_REMOVE_ALL: "removeAll" // difference
|
||||
|
||||
15 DICT_WITH_CAPACITY: "withCapacity"
|
||||
16 DICT_CAPACITY: "capacity"
|
||||
17 DICT_UPDATE: "update"
|
||||
19 DICT_WITH_CAPACITY: "withCapacity"
|
||||
20 DICT_CAPACITY: "capacity"
|
||||
21 DICT_UPDATE: "update"
|
||||
|
||||
18 DICT_LIST_GET_UNSAFE: "listGetUnsafe"
|
||||
22 DICT_LIST_GET_UNSAFE: "listGetUnsafe"
|
||||
}
|
||||
9 SET: "Set" => {
|
||||
0 SET_SET: "Set" exposed_type=true // the Set.Set type alias
|
||||
|
@ -1434,10 +1438,11 @@ define_builtins! {
|
|||
9 SET_TO_LIST: "toList"
|
||||
10 SET_FROM_LIST: "fromList"
|
||||
11 SET_WALK: "walk"
|
||||
12 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
||||
13 SET_CONTAINS: "contains"
|
||||
14 SET_TO_DICT: "toDict"
|
||||
15 SET_CAPACITY: "capacity"
|
||||
12 SET_WALK_UNTIL: "walkUntil"
|
||||
13 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
||||
14 SET_CONTAINS: "contains"
|
||||
15 SET_TO_DICT: "toDict"
|
||||
16 SET_CAPACITY: "capacity"
|
||||
}
|
||||
10 BOX: "Box" => {
|
||||
0 BOX_BOX_TYPE: "Box" exposed_apply_type=true // the Box.Box opaque type
|
||||
|
@ -1517,10 +1522,11 @@ define_builtins! {
|
|||
11 HASH_HASH_I32: "hashI32"
|
||||
12 HASH_HASH_I64: "hashI64"
|
||||
13 HASH_HASH_I128: "hashI128"
|
||||
14 HASH_COMPLETE: "complete"
|
||||
15 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
16 HASH_HASH_LIST: "hashList"
|
||||
17 HASH_HASH_UNORDERED: "hashUnordered"
|
||||
14 HASH_HASH_NAT: "hashNat"
|
||||
15 HASH_COMPLETE: "complete"
|
||||
16 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
17 HASH_HASH_LIST: "hashList"
|
||||
18 HASH_HASH_UNORDERED: "hashUnordered"
|
||||
}
|
||||
14 JSON: "Json" => {
|
||||
0 JSON_JSON: "Json"
|
||||
|
|
|
@ -68,7 +68,7 @@ pub fn infer_borrow<'a>(
|
|||
|
||||
let sccs = matrix.strongly_connected_components_all();
|
||||
|
||||
for group in sccs.groups() {
|
||||
for (group, _) in sccs.groups() {
|
||||
// This is a fixed-point analysis
|
||||
//
|
||||
// all functions initiall own all their parameters
|
||||
|
|
5
crates/compiler/mono/src/debug.rs
Normal file
5
crates/compiler/mono/src/debug.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod checker;
|
||||
mod report;
|
||||
|
||||
pub use checker::{check_procs, Problem, Problems};
|
||||
pub use report::format_problems;
|
690
crates/compiler/mono/src/debug/checker.rs
Normal file
690
crates/compiler/mono/src/debug/checker.rs
Normal file
|
@ -0,0 +1,690 @@
|
|||
//! Type-checking of the generated [ir][crate::ir::Proc].
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::{MutMap, VecMap, VecSet};
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
use crate::{
|
||||
ir::{
|
||||
Call, CallSpecId, CallType, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
|
||||
ModifyRc, Param, Proc, ProcLayout, Stmt,
|
||||
},
|
||||
layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout},
|
||||
};
|
||||
|
||||
pub enum UseKind {
|
||||
Ret,
|
||||
TagExpr,
|
||||
TagReuse,
|
||||
TagPayloadArg,
|
||||
ListElemExpr,
|
||||
CallArg,
|
||||
JumpArg,
|
||||
CrashArg,
|
||||
SwitchCond,
|
||||
ExpectCond,
|
||||
ExpectLookup,
|
||||
}
|
||||
|
||||
pub enum ProblemKind<'a> {
|
||||
RedefinedSymbol {
|
||||
symbol: Symbol,
|
||||
old_line: usize,
|
||||
},
|
||||
NoSymbolInScope {
|
||||
symbol: Symbol,
|
||||
},
|
||||
SymbolUseMismatch {
|
||||
symbol: Symbol,
|
||||
def_layout: Layout<'a>,
|
||||
def_line: usize,
|
||||
use_layout: Layout<'a>,
|
||||
use_kind: UseKind,
|
||||
},
|
||||
SymbolDefMismatch {
|
||||
symbol: Symbol,
|
||||
def_layout: Layout<'a>,
|
||||
expr_layout: Layout<'a>,
|
||||
},
|
||||
BadSwitchConditionLayout {
|
||||
found_layout: Layout<'a>,
|
||||
},
|
||||
DuplicateSwitchBranch {},
|
||||
RedefinedJoinPoint {
|
||||
id: JoinPointId,
|
||||
old_line: usize,
|
||||
},
|
||||
NoJoinPoint {
|
||||
id: JoinPointId,
|
||||
},
|
||||
JumpArityMismatch {
|
||||
def_line: usize,
|
||||
num_needed: usize,
|
||||
num_given: usize,
|
||||
},
|
||||
CallingUndefinedProc {
|
||||
symbol: Symbol,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
similar: Vec<ProcLayout<'a>>,
|
||||
},
|
||||
DuplicateCallSpecId {
|
||||
old_call_line: usize,
|
||||
},
|
||||
StructIndexOOB {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
index: u64,
|
||||
size: usize,
|
||||
},
|
||||
NotAStruct {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
},
|
||||
IndexingTagIdNotInUnion {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
tag_id: u16,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
TagUnionStructIndexOOB {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
tag_id: u16,
|
||||
index: u64,
|
||||
size: usize,
|
||||
},
|
||||
IndexIntoNullableTag {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
tag_id: u16,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
UnboxNotABox {
|
||||
symbol: Symbol,
|
||||
def_line: usize,
|
||||
},
|
||||
CreatingTagIdNotInUnion {
|
||||
tag_id: u16,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
CreateTagPayloadMismatch {
|
||||
num_needed: usize,
|
||||
num_given: usize,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Problem<'a> {
|
||||
pub proc: &'a Proc<'a>,
|
||||
pub proc_layout: ProcLayout<'a>,
|
||||
pub line: usize,
|
||||
pub kind: ProblemKind<'a>,
|
||||
}
|
||||
|
||||
type Procs<'a> = MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>;
|
||||
pub struct Problems<'a>(pub(crate) Vec<Problem<'a>>);
|
||||
|
||||
impl<'a> Problems<'a> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_procs<'a>(
|
||||
arena: &'a Bump,
|
||||
interner: &'a STLayoutInterner<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Problems<'a> {
|
||||
let mut problems = Default::default();
|
||||
|
||||
for ((_, proc_layout), proc) in procs.iter() {
|
||||
let mut ctx = Ctx {
|
||||
arena,
|
||||
interner,
|
||||
proc,
|
||||
proc_layout: *proc_layout,
|
||||
ret_layout: proc.ret_layout,
|
||||
problems: &mut problems,
|
||||
call_spec_ids: Default::default(),
|
||||
procs,
|
||||
venv: Default::default(),
|
||||
joinpoints: Default::default(),
|
||||
line: 0,
|
||||
};
|
||||
ctx.check_proc(proc);
|
||||
}
|
||||
|
||||
Problems(problems)
|
||||
}
|
||||
|
||||
type VEnv<'a> = VecMap<Symbol, (usize, Layout<'a>)>;
|
||||
type JoinPoints<'a> = VecMap<JoinPointId, (usize, &'a [Param<'a>])>;
|
||||
type CallSpecIds = VecMap<CallSpecId, usize>;
|
||||
struct Ctx<'a, 'r> {
|
||||
arena: &'a Bump,
|
||||
interner: &'a STLayoutInterner<'a>,
|
||||
problems: &'r mut Vec<Problem<'a>>,
|
||||
proc: &'a Proc<'a>,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
procs: &'r Procs<'a>,
|
||||
call_spec_ids: CallSpecIds,
|
||||
ret_layout: Layout<'a>,
|
||||
venv: VEnv<'a>,
|
||||
joinpoints: JoinPoints<'a>,
|
||||
line: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'r> Ctx<'a, 'r> {
|
||||
fn alloc<T>(&self, v: T) -> &'a T {
|
||||
self.arena.alloc(v)
|
||||
}
|
||||
|
||||
fn problem(&mut self, problem_kind: ProblemKind<'a>) {
|
||||
self.problems.push(Problem {
|
||||
proc: self.proc,
|
||||
proc_layout: self.proc_layout,
|
||||
line: self.line,
|
||||
kind: problem_kind,
|
||||
})
|
||||
}
|
||||
|
||||
fn in_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let old_venv = self.venv.clone();
|
||||
let r = f(self);
|
||||
self.venv = old_venv;
|
||||
r
|
||||
}
|
||||
|
||||
fn resolve(&mut self, mut layout: Layout<'a>) -> Layout<'a> {
|
||||
// Note that we are more aggressive than the usual `runtime_representation`
|
||||
// here because we need strict equality, and so cannot unwrap lambda sets
|
||||
// lazily.
|
||||
loop {
|
||||
match layout {
|
||||
Layout::LambdaSet(ls) => layout = ls.runtime_representation(self.interner),
|
||||
layout => return layout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, symbol: Symbol, layout: Layout<'a>) {
|
||||
if let Some((old_line, _)) = self.venv.insert(symbol, (self.line, layout)) {
|
||||
self.problem(ProblemKind::RedefinedSymbol { symbol, old_line })
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sym_exists(&mut self, symbol: Symbol) {
|
||||
if !self.venv.contains_key(&symbol) {
|
||||
self.problem(ProblemKind::NoSymbolInScope { symbol })
|
||||
}
|
||||
}
|
||||
|
||||
fn with_sym_layout<T>(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
f: impl FnOnce(&mut Self, usize, Layout<'a>) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
if let Some(&(def_line, layout)) = self.venv.get(&symbol) {
|
||||
f(self, def_line, layout)
|
||||
} else {
|
||||
self.problem(ProblemKind::NoSymbolInScope { symbol });
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sym_layout(&mut self, symbol: Symbol, expected_layout: Layout<'a>, use_kind: UseKind) {
|
||||
if let Some(&(def_line, layout)) = self.venv.get(&symbol) {
|
||||
if self.resolve(layout) != self.resolve(expected_layout) {
|
||||
self.problem(ProblemKind::SymbolUseMismatch {
|
||||
symbol,
|
||||
def_layout: layout,
|
||||
def_line,
|
||||
use_layout: expected_layout,
|
||||
use_kind,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.problem(ProblemKind::NoSymbolInScope { symbol })
|
||||
}
|
||||
}
|
||||
|
||||
fn check_proc(&mut self, proc: &Proc<'a>) {
|
||||
for (lay, arg) in proc.args.iter() {
|
||||
self.insert(*arg, *lay);
|
||||
}
|
||||
|
||||
self.check_stmt(&proc.body)
|
||||
}
|
||||
|
||||
fn check_stmt(&mut self, body: &Stmt<'a>) {
|
||||
self.line += 1;
|
||||
|
||||
match body {
|
||||
Stmt::Let(x, e, x_layout, rest) => {
|
||||
if let Some(e_layout) = self.check_expr(e) {
|
||||
if self.resolve(e_layout) != self.resolve(*x_layout) {
|
||||
self.problem(ProblemKind::SymbolDefMismatch {
|
||||
symbol: *x,
|
||||
def_layout: *x_layout,
|
||||
expr_layout: e_layout,
|
||||
})
|
||||
}
|
||||
}
|
||||
self.insert(*x, *x_layout);
|
||||
self.check_stmt(rest);
|
||||
}
|
||||
Stmt::Switch {
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout: _,
|
||||
} => {
|
||||
self.check_sym_layout(*cond_symbol, *cond_layout, UseKind::SwitchCond);
|
||||
match self.resolve(*cond_layout) {
|
||||
Layout::Builtin(Builtin::Int(int_width)) if !int_width.is_signed() => {}
|
||||
Layout::Builtin(Builtin::Bool) => {}
|
||||
_ => self.problem(ProblemKind::BadSwitchConditionLayout {
|
||||
found_layout: *cond_layout,
|
||||
}),
|
||||
}
|
||||
|
||||
// TODO: need to adjust line numbers as we step through, and depending on whether
|
||||
// the switch is printed as true/false or a proper switch.
|
||||
let mut seen_branches = VecSet::with_capacity(branches.len());
|
||||
for (match_no, _branch_info, branch) in branches.iter() {
|
||||
if seen_branches.insert(match_no) {
|
||||
self.problem(ProblemKind::DuplicateSwitchBranch {});
|
||||
}
|
||||
self.in_scope(|ctx| ctx.check_stmt(branch));
|
||||
}
|
||||
let (_branch_info, default_branch) = default_branch;
|
||||
self.in_scope(|ctx| ctx.check_stmt(default_branch));
|
||||
}
|
||||
&Stmt::Ret(sym) => self.check_sym_layout(sym, self.ret_layout, UseKind::Ret),
|
||||
&Stmt::Refcounting(rc, rest) => {
|
||||
self.check_modify_rc(rc);
|
||||
self.check_stmt(rest);
|
||||
}
|
||||
&Stmt::Expect {
|
||||
condition,
|
||||
region: _,
|
||||
lookups,
|
||||
layouts,
|
||||
remainder,
|
||||
}
|
||||
| &Stmt::ExpectFx {
|
||||
condition,
|
||||
region: _,
|
||||
lookups,
|
||||
layouts,
|
||||
remainder,
|
||||
} => {
|
||||
self.check_sym_layout(
|
||||
condition,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
UseKind::ExpectCond,
|
||||
);
|
||||
for (sym, lay) in lookups.iter().zip(layouts) {
|
||||
self.check_sym_layout(*sym, *lay, UseKind::ExpectLookup);
|
||||
}
|
||||
self.check_stmt(remainder);
|
||||
}
|
||||
&Stmt::Join {
|
||||
id,
|
||||
parameters,
|
||||
body,
|
||||
remainder,
|
||||
} => {
|
||||
if let Some((old_line, _)) = self.joinpoints.insert(id, (self.line, parameters)) {
|
||||
self.problem(ProblemKind::RedefinedJoinPoint { id, old_line })
|
||||
}
|
||||
self.in_scope(|ctx| {
|
||||
for Param {
|
||||
symbol,
|
||||
layout,
|
||||
borrow: _,
|
||||
} in parameters
|
||||
{
|
||||
ctx.insert(*symbol, *layout);
|
||||
}
|
||||
ctx.check_stmt(body)
|
||||
});
|
||||
self.line += 1; // `in` line
|
||||
self.check_stmt(remainder);
|
||||
}
|
||||
&Stmt::Jump(id, symbols) => {
|
||||
if let Some(&(def_line, parameters)) = self.joinpoints.get(&id) {
|
||||
if symbols.len() != parameters.len() {
|
||||
self.problem(ProblemKind::JumpArityMismatch {
|
||||
def_line,
|
||||
num_needed: parameters.len(),
|
||||
num_given: symbols.len(),
|
||||
});
|
||||
}
|
||||
for (arg, param) in symbols.iter().zip(parameters.iter()) {
|
||||
let Param {
|
||||
symbol: _,
|
||||
borrow: _,
|
||||
layout,
|
||||
} = param;
|
||||
self.check_sym_layout(*arg, *layout, UseKind::JumpArg);
|
||||
}
|
||||
} else {
|
||||
self.problem(ProblemKind::NoJoinPoint { id });
|
||||
}
|
||||
}
|
||||
&Stmt::Crash(sym, _) => {
|
||||
self.check_sym_layout(sym, Layout::Builtin(Builtin::Str), UseKind::CrashArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, e: &Expr<'a>) -> Option<Layout<'a>> {
|
||||
match e {
|
||||
Expr::Literal(_) => None,
|
||||
Expr::Call(call) => self.check_call(call),
|
||||
&Expr::Tag {
|
||||
tag_layout,
|
||||
tag_id,
|
||||
arguments,
|
||||
} => {
|
||||
self.check_tag_expr(tag_layout, tag_id, arguments);
|
||||
Some(Layout::Union(tag_layout))
|
||||
}
|
||||
Expr::Struct(syms) => {
|
||||
for sym in syms.iter() {
|
||||
self.check_sym_exists(*sym);
|
||||
}
|
||||
// TODO: pass the field order hash down, so we can check this
|
||||
None
|
||||
}
|
||||
&Expr::StructAtIndex {
|
||||
index,
|
||||
// TODO: pass the field order hash down, so we can check this
|
||||
field_layouts: _,
|
||||
structure,
|
||||
} => self.check_struct_at_index(structure, index),
|
||||
Expr::GetTagId {
|
||||
structure: _,
|
||||
union_layout,
|
||||
} => Some(union_layout.tag_id_layout()),
|
||||
&Expr::UnionAtIndex {
|
||||
structure,
|
||||
tag_id,
|
||||
union_layout,
|
||||
index,
|
||||
} => self.check_union_at_index(structure, union_layout, tag_id, index),
|
||||
Expr::Array { elem_layout, elems } => {
|
||||
for elem in elems.iter() {
|
||||
match elem {
|
||||
ListLiteralElement::Literal(_) => {}
|
||||
ListLiteralElement::Symbol(sym) => {
|
||||
self.check_sym_layout(*sym, *elem_layout, UseKind::ListElemExpr)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Layout::Builtin(Builtin::List(self.alloc(*elem_layout))))
|
||||
}
|
||||
Expr::EmptyArray => {
|
||||
// TODO don't know what the element layout is
|
||||
None
|
||||
}
|
||||
&Expr::ExprBox { symbol } => self.with_sym_layout(symbol, |ctx, _def_line, layout| {
|
||||
Some(Layout::Boxed(ctx.alloc(layout)))
|
||||
}),
|
||||
&Expr::ExprUnbox { symbol } => {
|
||||
self.with_sym_layout(symbol, |ctx, def_line, layout| match ctx.resolve(layout) {
|
||||
Layout::Boxed(inner) => Some(*inner),
|
||||
_ => {
|
||||
ctx.problem(ProblemKind::UnboxNotABox { symbol, def_line });
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
&Expr::Reuse {
|
||||
symbol,
|
||||
update_tag_id: _,
|
||||
update_mode: _,
|
||||
tag_layout,
|
||||
tag_id: _,
|
||||
arguments: _,
|
||||
} => {
|
||||
self.check_sym_layout(symbol, Layout::Union(tag_layout), UseKind::TagReuse);
|
||||
// TODO also check update arguments
|
||||
Some(Layout::Union(tag_layout))
|
||||
}
|
||||
&Expr::Reset {
|
||||
symbol,
|
||||
update_mode: _,
|
||||
} => {
|
||||
self.check_sym_exists(symbol);
|
||||
None
|
||||
}
|
||||
Expr::RuntimeErrorFunction(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_struct_at_index(&mut self, structure: Symbol, index: u64) -> Option<Layout<'a>> {
|
||||
self.with_sym_layout(structure, |ctx, def_line, layout| {
|
||||
match ctx.resolve(layout) {
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
if index as usize >= field_layouts.len() {
|
||||
ctx.problem(ProblemKind::StructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
index,
|
||||
size: field_layouts.len(),
|
||||
});
|
||||
None
|
||||
} else {
|
||||
Some(field_layouts[index as usize])
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
ctx.problem(ProblemKind::NotAStruct {
|
||||
structure,
|
||||
def_line,
|
||||
});
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn check_union_at_index(
|
||||
&mut self,
|
||||
structure: Symbol,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_id: u16,
|
||||
index: u64,
|
||||
) -> Option<Layout<'a>> {
|
||||
self.with_sym_layout(structure, |ctx, def_line, _layout| {
|
||||
ctx.check_sym_layout(structure, Layout::Union(union_layout), UseKind::TagExpr);
|
||||
|
||||
match get_tag_id_payloads(union_layout, tag_id) {
|
||||
TagPayloads::IdNotInUnion => {
|
||||
ctx.problem(ProblemKind::IndexingTagIdNotInUnion {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
union_layout,
|
||||
});
|
||||
None
|
||||
}
|
||||
TagPayloads::Payloads(payloads) => {
|
||||
if index as usize >= payloads.len() {
|
||||
ctx.problem(ProblemKind::TagUnionStructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
index,
|
||||
size: payloads.len(),
|
||||
});
|
||||
return None;
|
||||
}
|
||||
let layout = resolve_recursive_layout(payloads[index as usize], union_layout);
|
||||
Some(layout)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn check_call(&mut self, call: &Call<'a>) -> Option<Layout<'a>> {
|
||||
let Call {
|
||||
call_type,
|
||||
arguments,
|
||||
} = call;
|
||||
|
||||
match call_type {
|
||||
CallType::ByName {
|
||||
name,
|
||||
ret_layout,
|
||||
arg_layouts,
|
||||
specialization_id,
|
||||
} => {
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arg_layouts,
|
||||
result: **ret_layout,
|
||||
captures_niche: name.captures_niche(),
|
||||
};
|
||||
if !self.procs.contains_key(&(name.name(), proc_layout)) {
|
||||
let similar = self
|
||||
.procs
|
||||
.keys()
|
||||
.filter(|(sym, _)| *sym == name.name())
|
||||
.map(|(_, lay)| *lay)
|
||||
.collect();
|
||||
self.problem(ProblemKind::CallingUndefinedProc {
|
||||
symbol: name.name(),
|
||||
proc_layout,
|
||||
similar,
|
||||
});
|
||||
}
|
||||
for (arg, wanted_layout) in arguments.iter().zip(arg_layouts.iter()) {
|
||||
self.check_sym_layout(*arg, *wanted_layout, UseKind::CallArg);
|
||||
}
|
||||
if let Some(old_call_line) =
|
||||
self.call_spec_ids.insert(*specialization_id, self.line)
|
||||
{
|
||||
self.problem(ProblemKind::DuplicateCallSpecId { old_call_line });
|
||||
}
|
||||
Some(**ret_layout)
|
||||
}
|
||||
CallType::HigherOrder(HigherOrderLowLevel {
|
||||
op: _,
|
||||
closure_env_layout: _,
|
||||
update_mode: _,
|
||||
passed_function: _,
|
||||
}) => {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
CallType::Foreign {
|
||||
foreign_symbol: _,
|
||||
ret_layout,
|
||||
} => Some(**ret_layout),
|
||||
CallType::LowLevel {
|
||||
op: _,
|
||||
update_mode: _,
|
||||
} => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_tag_expr(&mut self, union_layout: UnionLayout<'a>, tag_id: u16, arguments: &[Symbol]) {
|
||||
match get_tag_id_payloads(union_layout, tag_id) {
|
||||
TagPayloads::IdNotInUnion => {
|
||||
self.problem(ProblemKind::CreatingTagIdNotInUnion {
|
||||
tag_id,
|
||||
union_layout,
|
||||
});
|
||||
}
|
||||
TagPayloads::Payloads(payloads) => {
|
||||
if arguments.len() != payloads.len() {
|
||||
self.problem(ProblemKind::CreateTagPayloadMismatch {
|
||||
num_needed: payloads.len(),
|
||||
num_given: arguments.len(),
|
||||
});
|
||||
}
|
||||
for (arg, wanted_layout) in arguments.iter().zip(payloads.iter()) {
|
||||
let wanted_layout = resolve_recursive_layout(*wanted_layout, union_layout);
|
||||
self.check_sym_layout(*arg, wanted_layout, UseKind::TagPayloadArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_modify_rc(&mut self, rc: ModifyRc) {
|
||||
match rc {
|
||||
ModifyRc::Inc(sym, _) | ModifyRc::Dec(sym) | ModifyRc::DecRef(sym) => {
|
||||
// TODO: also check that sym layout needs refcounting
|
||||
self.check_sym_exists(sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_recursive_layout<'a>(layout: Layout<'a>, when_recursive: UnionLayout<'a>) -> Layout<'a> {
|
||||
// TODO check if recursive pointer not in recursive union
|
||||
match layout {
|
||||
Layout::RecursivePointer => Layout::Union(when_recursive),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
enum TagPayloads<'a> {
|
||||
IdNotInUnion,
|
||||
Payloads(&'a [Layout<'a>]),
|
||||
}
|
||||
|
||||
fn get_tag_id_payloads(union_layout: UnionLayout, tag_id: TagIdIntType) -> TagPayloads {
|
||||
macro_rules! check_tag_id_oob {
|
||||
($len:expr) => {
|
||||
if tag_id as usize >= $len {
|
||||
return TagPayloads::IdNotInUnion;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(union) => {
|
||||
check_tag_id_oob!(union.len());
|
||||
let payloads = union[tag_id as usize];
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
UnionLayout::Recursive(union) => {
|
||||
check_tag_id_oob!(union.len());
|
||||
let payloads = union[tag_id as usize];
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
UnionLayout::NonNullableUnwrapped(payloads) => {
|
||||
if tag_id != 0 {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
}
|
||||
UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags,
|
||||
} => {
|
||||
if tag_id == nullable_id {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
check_tag_id_oob!(other_tags.len());
|
||||
let payloads = other_tags[tag_id as usize];
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
}
|
||||
UnionLayout::NullableUnwrapped {
|
||||
nullable_id,
|
||||
other_fields,
|
||||
} => {
|
||||
if tag_id == nullable_id as _ {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
check_tag_id_oob!(2);
|
||||
TagPayloads::Payloads(other_fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
499
crates/compiler/mono/src/debug/report.rs
Normal file
499
crates/compiler/mono/src/debug/report.rs
Normal file
|
@ -0,0 +1,499 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use ven_pretty::{Arena, DocAllocator, DocBuilder};
|
||||
|
||||
use crate::{
|
||||
ir::{Parens, ProcLayout},
|
||||
layout::{CapturesNiche, Layout},
|
||||
};
|
||||
|
||||
use super::{
|
||||
checker::{ProblemKind, UseKind},
|
||||
Problem, Problems,
|
||||
};
|
||||
|
||||
pub fn format_problems<'a, I>(
|
||||
interns: &Interns,
|
||||
interner: &I,
|
||||
problems: Problems<'a>,
|
||||
) -> impl Display
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let Problems(problems) = problems;
|
||||
let f = Arena::new();
|
||||
let problem_docs = problems
|
||||
.into_iter()
|
||||
.map(|p| format_problem(&f, interns, interner, p));
|
||||
let all = f.intersperse(problem_docs, f.hardline());
|
||||
all.1.pretty(80).to_string()
|
||||
}
|
||||
|
||||
type Doc<'d> = DocBuilder<'d, Arena<'d>>;
|
||||
|
||||
const GUTTER_BAR: &str = "│";
|
||||
const HEADER_WIDTH: usize = 80;
|
||||
|
||||
fn format_problem<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interns: &'d Interns,
|
||||
interner: &'d I,
|
||||
problem: Problem<'a>,
|
||||
) -> Doc<'d>
|
||||
where
|
||||
'a: 'd,
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let Problem {
|
||||
proc,
|
||||
proc_layout,
|
||||
line,
|
||||
kind,
|
||||
} = problem;
|
||||
|
||||
let (title, mut docs, last_doc) = format_kind(f, interns, interner, kind);
|
||||
docs.push((line, last_doc));
|
||||
docs.sort_by_key(|(line, _)| *line);
|
||||
|
||||
let src = proc
|
||||
.to_doc(f, interner, true, Parens::NotNeeded)
|
||||
.1
|
||||
.pretty(80)
|
||||
.to_string();
|
||||
|
||||
let interpolated_docs = stack(
|
||||
f,
|
||||
docs.into_iter()
|
||||
.map(|(line, doc)| format_sourced_doc(f, line, &src, doc)),
|
||||
);
|
||||
|
||||
let header = format_header(f, title);
|
||||
let proc_loc = format_proc_spec(f, interns, interner, proc.name.name(), proc_layout);
|
||||
|
||||
stack(
|
||||
f,
|
||||
[
|
||||
header,
|
||||
f.concat([f.reflow("in "), proc_loc]),
|
||||
interpolated_docs,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
fn format_sourced_doc<'d>(f: &'d Arena<'d>, line: usize, source: &str, doc: Doc<'d>) -> Doc<'d> {
|
||||
let start_at = line.saturating_sub(1);
|
||||
let source_lines = source.lines().skip(start_at).take(3);
|
||||
let max_line_no_width = (start_at.to_string().len()).max((start_at + 3).to_string().len());
|
||||
let pretty_lines = source_lines.enumerate().map(|(i, line_src)| {
|
||||
let line_no = start_at + i;
|
||||
let line_no_s = line_no.to_string();
|
||||
let line_no_len = line_no_s.len();
|
||||
f.text(line_no_s)
|
||||
.append(f.text(" ".repeat(max_line_no_width - line_no_len)))
|
||||
.append(f.text(GUTTER_BAR))
|
||||
.append(f.text(if line_no == line { "> " } else { " " }))
|
||||
.append(f.text(line_src.to_string()))
|
||||
});
|
||||
let pretty_lines = f.intersperse(pretty_lines, f.hardline());
|
||||
stack(f, [pretty_lines, doc])
|
||||
}
|
||||
|
||||
fn format_header<'d>(f: &'d Arena<'d>, title: &str) -> Doc<'d> {
|
||||
let title_width = title.len() + 4;
|
||||
f.text(format!(
|
||||
"── {} {}",
|
||||
title,
|
||||
"─".repeat(HEADER_WIDTH - title_width)
|
||||
))
|
||||
}
|
||||
|
||||
fn format_kind<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interns: &'d Interns,
|
||||
interner: &I,
|
||||
kind: ProblemKind<'a>,
|
||||
) -> (&'static str, Vec<(usize, Doc<'d>)>, Doc<'d>)
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let title;
|
||||
let docs_before;
|
||||
let doc = match kind {
|
||||
ProblemKind::RedefinedSymbol { symbol, old_line } => {
|
||||
title = "REDEFINED SYMBOL";
|
||||
docs_before = vec![(
|
||||
old_line,
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" first defined here"),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" re-defined here"),
|
||||
])
|
||||
}
|
||||
ProblemKind::NoSymbolInScope { symbol } => {
|
||||
title = "SYMBOL NOT DEFINED";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" not found in the present scope"),
|
||||
])
|
||||
}
|
||||
ProblemKind::SymbolUseMismatch {
|
||||
symbol,
|
||||
def_layout,
|
||||
def_line,
|
||||
use_layout,
|
||||
use_kind,
|
||||
} => {
|
||||
title = "SYMBOL LAYOUT DOESN'T MATCH ITS USE";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" defined here with layout "),
|
||||
def_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" used as a "),
|
||||
f.reflow(format_use_kind(use_kind)),
|
||||
f.reflow(" here with layout "),
|
||||
use_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::SymbolDefMismatch {
|
||||
symbol,
|
||||
def_layout,
|
||||
expr_layout,
|
||||
} => {
|
||||
title = "SYMBOL INITIALIZER HAS THE WRONG LAYOUT";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" is defined as "),
|
||||
def_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
f.reflow(" but its initializer is "),
|
||||
expr_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::BadSwitchConditionLayout { found_layout } => {
|
||||
title = "BAD SWITCH CONDITION LAYOUT";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("This switch condition is a "),
|
||||
found_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::DuplicateSwitchBranch {} => {
|
||||
title = "DUPLICATE SWITCH BRANCH";
|
||||
docs_before = vec![];
|
||||
f.reflow("The match of switch branch is reached earlier")
|
||||
}
|
||||
ProblemKind::RedefinedJoinPoint { id, old_line } => {
|
||||
title = "DUPLICATE JOIN POINT";
|
||||
docs_before = vec![(
|
||||
old_line,
|
||||
f.concat([
|
||||
f.reflow("The join point "),
|
||||
f.as_string(id.0),
|
||||
f.reflow(" was previously defined here"),
|
||||
]),
|
||||
)];
|
||||
f.reflow("and is redefined here")
|
||||
}
|
||||
ProblemKind::NoJoinPoint { id } => {
|
||||
title = "JOIN POINT NOT DEFINED";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("The join point "),
|
||||
f.as_string(id.0),
|
||||
f.reflow(" was not found in the present scope"),
|
||||
])
|
||||
}
|
||||
ProblemKind::JumpArityMismatch {
|
||||
def_line,
|
||||
num_needed,
|
||||
num_given,
|
||||
} => {
|
||||
title = "WRONG NUMBER OF ARGUMENTS IN JUMP";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("This join pont needs "),
|
||||
f.as_string(num_needed),
|
||||
f.reflow(" arguments"),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but this jump only gives it "),
|
||||
f.as_string(num_given),
|
||||
])
|
||||
}
|
||||
ProblemKind::CallingUndefinedProc {
|
||||
symbol,
|
||||
proc_layout,
|
||||
similar,
|
||||
} => {
|
||||
title = "PROC SPECIALIZATION NOT DEFINED";
|
||||
docs_before = vec![];
|
||||
let no_spec_doc = stack(
|
||||
f,
|
||||
[
|
||||
f.reflow("No specialization"),
|
||||
format_proc_spec(f, interns, interner, symbol, proc_layout),
|
||||
f.reflow("was found"),
|
||||
],
|
||||
);
|
||||
let similar_doc = if similar.is_empty() {
|
||||
f.nil()
|
||||
} else {
|
||||
let similars = similar
|
||||
.into_iter()
|
||||
.map(|other| format_proc_spec(f, interns, interner, symbol, other));
|
||||
stack(
|
||||
f,
|
||||
[f.concat([
|
||||
f.reflow("The following specializations of "),
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" were built:"),
|
||||
stack(f, similars),
|
||||
])],
|
||||
)
|
||||
};
|
||||
stack(f, [no_spec_doc, similar_doc])
|
||||
}
|
||||
ProblemKind::DuplicateCallSpecId { old_call_line } => {
|
||||
title = "DUPLICATE CALL SPEC ID";
|
||||
docs_before = vec![(old_call_line, f.reflow("This call has a specialization ID"))];
|
||||
f.reflow("...that is the same as the specialization ID of the call here")
|
||||
}
|
||||
ProblemKind::StructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
index,
|
||||
size,
|
||||
} => {
|
||||
title = "STRUCT INDEX IS OUT-OF-BOUNDS";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The struct "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has "),
|
||||
f.as_string(size),
|
||||
f.reflow(" fields"),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but is being indexed into field "),
|
||||
f.as_string(index),
|
||||
])
|
||||
}
|
||||
ProblemKind::NotAStruct {
|
||||
structure,
|
||||
def_line,
|
||||
} => {
|
||||
title = "SYMBOL IS NOT A STRUCT";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The value "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here"),
|
||||
]),
|
||||
)];
|
||||
f.reflow("cannot be used as a structure here")
|
||||
}
|
||||
ProblemKind::IndexingTagIdNotInUnion {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
union_layout,
|
||||
} => {
|
||||
title = "TAG ID NOT IN UNION";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The union "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has layout "),
|
||||
Layout::Union(union_layout).to_doc(f, interner, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([f.reflow("which has no tag of id "), f.as_string(tag_id)])
|
||||
}
|
||||
ProblemKind::TagUnionStructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
index,
|
||||
size,
|
||||
} => {
|
||||
title = "UNION ID AND PAYLOAD INDEX IS OUT-OF-BOUNDS";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The union "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has "),
|
||||
f.as_string(size),
|
||||
f.reflow(" payloads at ID "),
|
||||
f.as_string(tag_id),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but is being indexed into field "),
|
||||
f.as_string(index),
|
||||
f.reflow(" here"),
|
||||
])
|
||||
}
|
||||
ProblemKind::IndexIntoNullableTag {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
union_layout,
|
||||
} => {
|
||||
title = "INDEX INTO NULLABLE TAG";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The union "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has layout "),
|
||||
Layout::Union(union_layout).to_doc(f, interner, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but is being indexed into the nullable variant "),
|
||||
f.as_string(tag_id),
|
||||
f.reflow(" here"),
|
||||
])
|
||||
}
|
||||
ProblemKind::UnboxNotABox { symbol, def_line } => {
|
||||
title = "ATTEMPTING TO UNBOX A NON-BOX";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([format_symbol(f, interns, symbol), f.reflow(" is not a box")]),
|
||||
)];
|
||||
f.reflow("but is being unboxed here")
|
||||
}
|
||||
ProblemKind::CreatingTagIdNotInUnion {
|
||||
tag_id,
|
||||
union_layout,
|
||||
} => {
|
||||
title = "NO SUCH ID FOR TAG UNION";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("The variant "),
|
||||
f.as_string(tag_id),
|
||||
f.reflow(" is outside the target union layout "),
|
||||
Layout::Union(union_layout).to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::CreateTagPayloadMismatch {
|
||||
num_needed,
|
||||
num_given,
|
||||
} => {
|
||||
title = "WRONG NUMBER OF ARGUMENTS IN TAG UNION";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("This tag union payload needs "),
|
||||
f.as_string(num_needed),
|
||||
f.reflow(" values, but is only given "),
|
||||
f.as_string(num_given),
|
||||
])
|
||||
}
|
||||
};
|
||||
(title, docs_before, doc)
|
||||
}
|
||||
|
||||
fn format_symbol<'d>(f: &'d Arena<'d>, interns: &'d Interns, symbol: Symbol) -> Doc<'d> {
|
||||
f.text(symbol.module_string(interns).to_string())
|
||||
.append(f.text("."))
|
||||
.append(f.text(symbol.as_str(interns)))
|
||||
}
|
||||
|
||||
fn format_use_kind(use_kind: UseKind) -> &'static str {
|
||||
match use_kind {
|
||||
UseKind::Ret => "return value",
|
||||
UseKind::TagExpr => "tag constructor",
|
||||
UseKind::TagReuse => "tag reuse",
|
||||
UseKind::TagPayloadArg => "tag's payload",
|
||||
UseKind::ListElemExpr => "list element",
|
||||
UseKind::CallArg => "call argument",
|
||||
UseKind::JumpArg => "jump argument",
|
||||
UseKind::CrashArg => "crash message",
|
||||
UseKind::SwitchCond => "switch condition",
|
||||
UseKind::ExpectCond => "expect condition",
|
||||
UseKind::ExpectLookup => "lookup for an expect",
|
||||
}
|
||||
}
|
||||
|
||||
fn format_proc_spec<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interns: &'d Interns,
|
||||
interner: &I,
|
||||
symbol: Symbol,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
) -> Doc<'d>
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
f.concat([
|
||||
f.as_string(symbol.as_str(interns)),
|
||||
f.reflow(" : "),
|
||||
format_proc_layout(f, interner, proc_layout),
|
||||
])
|
||||
}
|
||||
|
||||
fn format_proc_layout<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interner: &I,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
) -> Doc<'d>
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let ProcLayout {
|
||||
arguments,
|
||||
result,
|
||||
captures_niche,
|
||||
} = proc_layout;
|
||||
let args = f.intersperse(
|
||||
arguments
|
||||
.iter()
|
||||
.map(|a| a.to_doc(f, interner, Parens::InFunction)),
|
||||
f.reflow(", "),
|
||||
);
|
||||
let fun = f.concat([
|
||||
f.concat([f.reflow("("), args, f.reflow(")")]),
|
||||
f.reflow(" -> "),
|
||||
result.to_doc(f, interner, Parens::NotNeeded),
|
||||
]);
|
||||
let niche = if captures_niche == CapturesNiche::no_niche() {
|
||||
f.reflow("(no niche)")
|
||||
} else {
|
||||
f.concat([
|
||||
f.reflow("(niche {"),
|
||||
f.intersperse(
|
||||
captures_niche
|
||||
.0
|
||||
.iter()
|
||||
.map(|c| c.to_doc(f, interner, Parens::NotNeeded)),
|
||||
f.reflow(", "),
|
||||
),
|
||||
f.reflow("})"),
|
||||
])
|
||||
};
|
||||
f.concat([fun, f.space(), niche])
|
||||
}
|
||||
|
||||
fn stack<'d>(f: &'d Arena<'d>, docs: impl IntoIterator<Item = Doc<'d>>) -> Doc<'d> {
|
||||
f.intersperse(docs, f.line().append(f.line()))
|
||||
}
|
|
@ -425,6 +425,7 @@ fn flatten<'a>(
|
|||
/// variables to "how to get their value". So a pattern like (Just (x,_)) will give
|
||||
/// us something like ("x" => value.0.0)
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Match {
|
||||
Exact(Label),
|
||||
GuardOnly,
|
||||
|
@ -795,7 +796,22 @@ fn to_relevant_branch_help<'a>(
|
|||
elements,
|
||||
element_layout: _,
|
||||
} => match test {
|
||||
IsListLen { bound: _, len } if my_arity.covers_length(*len as _) => {
|
||||
IsListLen {
|
||||
bound: test_bound,
|
||||
len,
|
||||
} if my_arity.covers_length(*len as _)
|
||||
// Spread tests [_, ..] can only match spread tests, not exact-sized bounds [_].
|
||||
//
|
||||
// On the other hand, exact-sized tests [_] can match spread bounds [_, ..],
|
||||
// because each spread bound generates 0 or more exact-sized tests.
|
||||
//
|
||||
// See exhaustiveness checking of lists for more details on the tests generated
|
||||
// for spread bounds.
|
||||
&& !matches!(
|
||||
(test_bound, my_arity),
|
||||
(ListLenBound::AtLeast, ListArity::Exact(..))
|
||||
) =>
|
||||
{
|
||||
let sub_positions = elements.into_iter().enumerate().map(|(index, elem_pat)| {
|
||||
let mut new_path = path.to_vec();
|
||||
|
||||
|
|
|
@ -326,6 +326,7 @@ impl<'a> Proc<'a> {
|
|||
&'b self,
|
||||
alloc: &'b D,
|
||||
interner: &'b I,
|
||||
pretty: bool,
|
||||
_parens: Parens,
|
||||
) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
|
@ -335,7 +336,7 @@ impl<'a> Proc<'a> {
|
|||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let args_doc = self.args.iter().map(|(layout, symbol)| {
|
||||
let arg_doc = symbol_to_doc(alloc, *symbol);
|
||||
let arg_doc = symbol_to_doc(alloc, *symbol, pretty);
|
||||
if pretty_print_ir_symbols() {
|
||||
arg_doc.append(alloc.reflow(": ")).append(layout.to_doc(
|
||||
alloc,
|
||||
|
@ -350,36 +351,36 @@ impl<'a> Proc<'a> {
|
|||
if pretty_print_ir_symbols() {
|
||||
alloc
|
||||
.text("procedure : ")
|
||||
.append(symbol_to_doc(alloc, self.name.name()))
|
||||
.append(symbol_to_doc(alloc, self.name.name(), pretty))
|
||||
.append(" ")
|
||||
.append(self.ret_layout.to_doc(alloc, interner, Parens::NotNeeded))
|
||||
.append(alloc.hardline())
|
||||
.append(alloc.text("procedure = "))
|
||||
.append(symbol_to_doc(alloc, self.name.name()))
|
||||
.append(symbol_to_doc(alloc, self.name.name(), pretty))
|
||||
.append(" (")
|
||||
.append(alloc.intersperse(args_doc, ", "))
|
||||
.append("):")
|
||||
.append(alloc.hardline())
|
||||
.append(self.body.to_doc(alloc, interner).indent(4))
|
||||
.append(self.body.to_doc(alloc, interner, pretty).indent(4))
|
||||
} else {
|
||||
alloc
|
||||
.text("procedure ")
|
||||
.append(symbol_to_doc(alloc, self.name.name()))
|
||||
.append(symbol_to_doc(alloc, self.name.name(), pretty))
|
||||
.append(" (")
|
||||
.append(alloc.intersperse(args_doc, ", "))
|
||||
.append("):")
|
||||
.append(alloc.hardline())
|
||||
.append(self.body.to_doc(alloc, interner).indent(4))
|
||||
.append(self.body.to_doc(alloc, interner, pretty).indent(4))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize) -> String
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize, pretty: bool) -> String
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let allocator = BoxAllocator;
|
||||
let mut w = std::vec::Vec::new();
|
||||
self.to_doc::<_, (), _>(&allocator, interner, Parens::NotNeeded)
|
||||
self.to_doc::<_, (), _>(&allocator, interner, pretty, Parens::NotNeeded)
|
||||
.1
|
||||
.render(width, &mut w)
|
||||
.unwrap();
|
||||
|
@ -1675,35 +1676,13 @@ pub enum BranchInfo<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BranchInfo<'a> {
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, _pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
use BranchInfo::*;
|
||||
|
||||
match self {
|
||||
Constructor {
|
||||
tag_id,
|
||||
scrutinee,
|
||||
layout: _,
|
||||
} if pretty_print_ir_symbols() => alloc
|
||||
.hardline()
|
||||
.append(" BranchInfo: { scrutinee: ")
|
||||
.append(symbol_to_doc(alloc, *scrutinee))
|
||||
.append(", tag_id: ")
|
||||
.append(format!("{}", tag_id))
|
||||
.append("} "),
|
||||
|
||||
_ => {
|
||||
if pretty_print_ir_symbols() {
|
||||
alloc.text(" <no branch info>")
|
||||
} else {
|
||||
alloc.text("")
|
||||
}
|
||||
}
|
||||
}
|
||||
alloc.text("")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1724,7 +1703,7 @@ pub enum ModifyRc {
|
|||
}
|
||||
|
||||
impl ModifyRc {
|
||||
pub fn to_doc<'a, D, A>(self, alloc: &'a D) -> DocBuilder<'a, D, A>
|
||||
pub fn to_doc<'a, D, A>(self, alloc: &'a D, pretty: bool) -> DocBuilder<'a, D, A>
|
||||
where
|
||||
D: DocAllocator<'a, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -1735,20 +1714,20 @@ impl ModifyRc {
|
|||
match self {
|
||||
Inc(symbol, 1) => alloc
|
||||
.text("inc ")
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
Inc(symbol, n) => alloc
|
||||
.text("inc ")
|
||||
.append(alloc.text(format!("{} ", n)))
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
Dec(symbol) => alloc
|
||||
.text("dec ")
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
DecRef(symbol) => alloc
|
||||
.text("decref ")
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
}
|
||||
}
|
||||
|
@ -1808,7 +1787,7 @@ pub struct Call<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Call<'a> {
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -1822,19 +1801,19 @@ impl<'a> Call<'a> {
|
|||
CallType::ByName { name, .. } => {
|
||||
let it = std::iter::once(name.name())
|
||||
.chain(arguments.iter().copied())
|
||||
.map(|s| symbol_to_doc(alloc, s));
|
||||
.map(|s| symbol_to_doc(alloc, s, pretty));
|
||||
|
||||
alloc.text("CallByName ").append(alloc.intersperse(it, " "))
|
||||
}
|
||||
LowLevel { op: lowlevel, .. } => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text(format!("lowlevel {:?} ", lowlevel))
|
||||
.append(alloc.intersperse(it, " "))
|
||||
}
|
||||
HigherOrder(higher_order) => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text(format!("lowlevel {:?} ", higher_order.op))
|
||||
|
@ -1843,7 +1822,7 @@ impl<'a> Call<'a> {
|
|||
Foreign {
|
||||
ref foreign_symbol, ..
|
||||
} => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text(format!("foreign {:?} ", foreign_symbol.as_str()))
|
||||
|
@ -2034,10 +2013,10 @@ impl<'a> Literal<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_to_doc_string(symbol: Symbol) -> String {
|
||||
pub(crate) fn symbol_to_doc_string(symbol: Symbol, force_pretty: bool) -> String {
|
||||
use roc_module::ident::ModuleName;
|
||||
|
||||
if pretty_print_ir_symbols() {
|
||||
if pretty_print_ir_symbols() || force_pretty {
|
||||
format!("{:?}", symbol)
|
||||
} else {
|
||||
let text = format!("{}", symbol);
|
||||
|
@ -2051,26 +2030,30 @@ pub(crate) fn symbol_to_doc_string(symbol: Symbol) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn symbol_to_doc<'b, D, A>(alloc: &'b D, symbol: Symbol) -> DocBuilder<'b, D, A>
|
||||
fn symbol_to_doc<'b, D, A>(alloc: &'b D, symbol: Symbol, force_pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
alloc.text(symbol_to_doc_string(symbol))
|
||||
alloc.text(symbol_to_doc_string(symbol, force_pretty))
|
||||
}
|
||||
|
||||
fn join_point_to_doc<'b, D, A>(alloc: &'b D, symbol: JoinPointId) -> DocBuilder<'b, D, A>
|
||||
fn join_point_to_doc<'b, D, A>(
|
||||
alloc: &'b D,
|
||||
symbol: JoinPointId,
|
||||
pretty: bool,
|
||||
) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
symbol_to_doc(alloc, symbol.0)
|
||||
symbol_to_doc(alloc, symbol.0, pretty)
|
||||
}
|
||||
|
||||
impl<'a> Expr<'a> {
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -2081,7 +2064,7 @@ impl<'a> Expr<'a> {
|
|||
match self {
|
||||
Literal(lit) => lit.to_doc(alloc),
|
||||
|
||||
Call(call) => call.to_doc(alloc),
|
||||
Call(call) => call.to_doc(alloc, pretty),
|
||||
|
||||
Tag {
|
||||
tag_id, arguments, ..
|
||||
|
@ -2091,7 +2074,7 @@ impl<'a> Expr<'a> {
|
|||
.append(alloc.text(tag_id.to_string()))
|
||||
.append(")");
|
||||
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
doc_tag
|
||||
.append(alloc.space())
|
||||
|
@ -2109,11 +2092,11 @@ impl<'a> Expr<'a> {
|
|||
.append(alloc.text(tag_id.to_string()))
|
||||
.append(")");
|
||||
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text("Reuse ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty))
|
||||
.append(alloc.space())
|
||||
.append(format!("{:?}", update_mode))
|
||||
.append(alloc.space())
|
||||
|
@ -2130,7 +2113,7 @@ impl<'a> Expr<'a> {
|
|||
)),
|
||||
|
||||
Struct(args) => {
|
||||
let it = args.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = args.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text("Struct {")
|
||||
|
@ -2140,7 +2123,7 @@ impl<'a> Expr<'a> {
|
|||
Array { elems, .. } => {
|
||||
let it = elems.iter().map(|e| match e {
|
||||
ListLiteralElement::Literal(l) => l.to_doc(alloc),
|
||||
ListLiteralElement::Symbol(s) => symbol_to_doc(alloc, *s),
|
||||
ListLiteralElement::Symbol(s) => symbol_to_doc(alloc, *s, pretty),
|
||||
});
|
||||
|
||||
alloc
|
||||
|
@ -2154,17 +2137,21 @@ impl<'a> Expr<'a> {
|
|||
index, structure, ..
|
||||
} => alloc
|
||||
.text(format!("StructAtIndex {} ", index))
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
.append(symbol_to_doc(alloc, *structure, pretty)),
|
||||
|
||||
RuntimeErrorFunction(s) => alloc.text(format!("ErrorFunction {}", s)),
|
||||
|
||||
GetTagId { structure, .. } => alloc
|
||||
.text("GetTagId ")
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
.append(symbol_to_doc(alloc, *structure, pretty)),
|
||||
|
||||
ExprBox { symbol, .. } => alloc.text("Box ").append(symbol_to_doc(alloc, *symbol)),
|
||||
ExprBox { symbol, .. } => alloc
|
||||
.text("Box ")
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty)),
|
||||
|
||||
ExprUnbox { symbol, .. } => alloc.text("Unbox ").append(symbol_to_doc(alloc, *symbol)),
|
||||
ExprUnbox { symbol, .. } => alloc
|
||||
.text("Unbox ")
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty)),
|
||||
|
||||
UnionAtIndex {
|
||||
tag_id,
|
||||
|
@ -2173,14 +2160,14 @@ impl<'a> Expr<'a> {
|
|||
..
|
||||
} => alloc
|
||||
.text(format!("UnionAtIndex (Id {}) (Index {}) ", tag_id, index))
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
.append(symbol_to_doc(alloc, *structure, pretty)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pretty(&self, width: usize) -> String {
|
||||
pub fn to_pretty(&self, width: usize, pretty: bool) -> String {
|
||||
let allocator = BoxAllocator;
|
||||
let mut w = std::vec::Vec::new();
|
||||
self.to_doc::<_, ()>(&allocator)
|
||||
self.to_doc::<_, ()>(&allocator, pretty)
|
||||
.1
|
||||
.render(width, &mut w)
|
||||
.unwrap();
|
||||
|
@ -2200,7 +2187,12 @@ impl<'a> Stmt<'a> {
|
|||
from_can(env, var, can_expr, procs, layout_cache)
|
||||
}
|
||||
|
||||
pub fn to_doc<'b, D, A, I>(&'b self, alloc: &'b D, interner: &I) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A, I>(
|
||||
&'b self,
|
||||
alloc: &'b D,
|
||||
interner: &I,
|
||||
pretty: bool,
|
||||
) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -2212,19 +2204,19 @@ impl<'a> Stmt<'a> {
|
|||
match self {
|
||||
Let(symbol, expr, layout, cont) => alloc
|
||||
.text("let ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty))
|
||||
.append(" : ")
|
||||
.append(layout.to_doc(alloc, interner, Parens::NotNeeded))
|
||||
.append(" = ")
|
||||
.append(expr.to_doc(alloc))
|
||||
.append(expr.to_doc(alloc, pretty))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(cont.to_doc(alloc, interner)),
|
||||
.append(cont.to_doc(alloc, interner, pretty)),
|
||||
|
||||
Refcounting(modify, cont) => modify
|
||||
.to_doc(alloc)
|
||||
.to_doc(alloc, pretty)
|
||||
.append(alloc.hardline())
|
||||
.append(cont.to_doc(alloc, interner)),
|
||||
.append(cont.to_doc(alloc, interner, pretty)),
|
||||
|
||||
Expect {
|
||||
condition,
|
||||
|
@ -2232,10 +2224,10 @@ impl<'a> Stmt<'a> {
|
|||
..
|
||||
} => alloc
|
||||
.text("expect ")
|
||||
.append(symbol_to_doc(alloc, *condition))
|
||||
.append(symbol_to_doc(alloc, *condition, pretty))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(remainder.to_doc(alloc, interner)),
|
||||
.append(remainder.to_doc(alloc, interner, pretty)),
|
||||
|
||||
ExpectFx {
|
||||
condition,
|
||||
|
@ -2243,14 +2235,14 @@ impl<'a> Stmt<'a> {
|
|||
..
|
||||
} => alloc
|
||||
.text("expect-fx ")
|
||||
.append(symbol_to_doc(alloc, *condition))
|
||||
.append(symbol_to_doc(alloc, *condition, pretty))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(remainder.to_doc(alloc, interner)),
|
||||
.append(remainder.to_doc(alloc, interner, pretty)),
|
||||
|
||||
Ret(symbol) => alloc
|
||||
.text("ret ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty))
|
||||
.append(";"),
|
||||
|
||||
Switch {
|
||||
|
@ -2264,23 +2256,23 @@ impl<'a> Stmt<'a> {
|
|||
let fail = default_branch.1;
|
||||
alloc
|
||||
.text("if ")
|
||||
.append(symbol_to_doc(alloc, *cond_symbol))
|
||||
.append(symbol_to_doc(alloc, *cond_symbol, pretty))
|
||||
.append(" then")
|
||||
.append(info.to_doc(alloc))
|
||||
.append(info.to_doc(alloc, pretty))
|
||||
.append(alloc.hardline())
|
||||
.append(pass.to_doc(alloc, interner).indent(4))
|
||||
.append(pass.to_doc(alloc, interner, pretty).indent(4))
|
||||
.append(alloc.hardline())
|
||||
.append(alloc.text("else"))
|
||||
.append(default_branch.0.to_doc(alloc))
|
||||
.append(default_branch.0.to_doc(alloc, pretty))
|
||||
.append(alloc.hardline())
|
||||
.append(fail.to_doc(alloc, interner).indent(4))
|
||||
.append(fail.to_doc(alloc, interner, pretty).indent(4))
|
||||
}
|
||||
|
||||
_ => {
|
||||
let default_doc = alloc
|
||||
.text("default:")
|
||||
.append(alloc.hardline())
|
||||
.append(default_branch.1.to_doc(alloc, interner).indent(4))
|
||||
.append(default_branch.1.to_doc(alloc, interner, pretty).indent(4))
|
||||
.indent(4);
|
||||
|
||||
let branches_docs = branches
|
||||
|
@ -2289,14 +2281,14 @@ impl<'a> Stmt<'a> {
|
|||
alloc
|
||||
.text(format!("case {}:", tag))
|
||||
.append(alloc.hardline())
|
||||
.append(expr.to_doc(alloc, interner).indent(4))
|
||||
.append(expr.to_doc(alloc, interner, pretty).indent(4))
|
||||
.indent(4)
|
||||
})
|
||||
.chain(std::iter::once(default_doc));
|
||||
//
|
||||
alloc
|
||||
.text("switch ")
|
||||
.append(symbol_to_doc(alloc, *cond_symbol))
|
||||
.append(symbol_to_doc(alloc, *cond_symbol, pretty))
|
||||
.append(":")
|
||||
.append(alloc.hardline())
|
||||
.append(alloc.intersperse(
|
||||
|
@ -2308,7 +2300,9 @@ impl<'a> Stmt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Crash(s, _src) => alloc.text("Crash ").append(symbol_to_doc(alloc, *s)),
|
||||
Crash(s, _src) => alloc
|
||||
.text("Crash ")
|
||||
.append(symbol_to_doc(alloc, *s, pretty)),
|
||||
|
||||
Join {
|
||||
id,
|
||||
|
@ -2316,29 +2310,31 @@ impl<'a> Stmt<'a> {
|
|||
body: continuation,
|
||||
remainder,
|
||||
} => {
|
||||
let it = parameters.iter().map(|p| symbol_to_doc(alloc, p.symbol));
|
||||
let it = parameters
|
||||
.iter()
|
||||
.map(|p| symbol_to_doc(alloc, p.symbol, pretty));
|
||||
|
||||
alloc.intersperse(
|
||||
vec![
|
||||
alloc
|
||||
.text("joinpoint ")
|
||||
.append(join_point_to_doc(alloc, *id))
|
||||
.append(join_point_to_doc(alloc, *id, pretty))
|
||||
.append(" ".repeat(parameters.len().min(1)))
|
||||
.append(alloc.intersperse(it, alloc.space()))
|
||||
.append(":"),
|
||||
continuation.to_doc(alloc, interner).indent(4),
|
||||
continuation.to_doc(alloc, interner, pretty).indent(4),
|
||||
alloc.text("in"),
|
||||
remainder.to_doc(alloc, interner),
|
||||
remainder.to_doc(alloc, interner, pretty),
|
||||
],
|
||||
alloc.hardline(),
|
||||
)
|
||||
}
|
||||
Jump(id, arguments) => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text("jump ")
|
||||
.append(join_point_to_doc(alloc, *id))
|
||||
.append(join_point_to_doc(alloc, *id, pretty))
|
||||
.append(" ".repeat(arguments.len().min(1)))
|
||||
.append(alloc.intersperse(it, alloc.space()))
|
||||
.append(";")
|
||||
|
@ -2346,13 +2342,13 @@ impl<'a> Stmt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize) -> String
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize, pretty: bool) -> String
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let allocator = BoxAllocator;
|
||||
let mut w = std::vec::Vec::new();
|
||||
self.to_doc::<_, (), _>(&allocator, interner)
|
||||
self.to_doc::<_, (), _>(&allocator, interner, pretty)
|
||||
.1
|
||||
.render(width, &mut w)
|
||||
.unwrap();
|
||||
|
|
|
@ -1154,7 +1154,7 @@ struct SetElement<'a> {
|
|||
|
||||
impl std::fmt::Debug for SetElement<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let symbol_string = crate::ir::symbol_to_doc_string(self.symbol);
|
||||
let symbol_string = crate::ir::symbol_to_doc_string(self.symbol, false);
|
||||
|
||||
write!(f, "( {}, {:?})", symbol_string, self.layout)
|
||||
}
|
||||
|
@ -1204,7 +1204,7 @@ impl std::fmt::Debug for LambdaSet<'_> {
|
|||
///
|
||||
/// See also https://github.com/roc-lang/roc/issues/3336.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct CapturesNiche<'a>(&'a [Layout<'a>]);
|
||||
pub struct CapturesNiche<'a>(pub(crate) &'a [Layout<'a>]);
|
||||
|
||||
impl CapturesNiche<'_> {
|
||||
pub fn no_niche() -> Self {
|
||||
|
|
|
@ -21,3 +21,5 @@ pub mod tail_recursion;
|
|||
// For now, following this warning's advice will lead to nasty type inference errors.
|
||||
//#[allow(clippy::ptr_arg)]
|
||||
pub mod decision_tree;
|
||||
|
||||
pub mod debug;
|
||||
|
|
|
@ -7,6 +7,8 @@ use roc_parse::pattern::PatternType;
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::types::AliasKind;
|
||||
|
||||
use crate::Severity;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct CycleEntry {
|
||||
pub symbol: Symbol,
|
||||
|
@ -40,6 +42,7 @@ pub enum Problem {
|
|||
/// Second symbol is the name of the argument that is unused
|
||||
UnusedArgument(Symbol, bool, Symbol, Region),
|
||||
UnusedBranchDef(Symbol, Region),
|
||||
DefsOnlyUsedInRecursion(usize, Region),
|
||||
PrecedenceProblem(PrecedenceProblem),
|
||||
// Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
|
||||
UnsupportedPattern(BadPattern, Region),
|
||||
|
@ -204,6 +207,71 @@ pub enum Problem {
|
|||
}
|
||||
|
||||
impl Problem {
|
||||
pub fn severity(&self) -> Severity {
|
||||
use Severity::{RuntimeError, Warning};
|
||||
|
||||
match self {
|
||||
Problem::UnusedDef(_, _) => Warning,
|
||||
Problem::UnusedImport(_, _) => Warning,
|
||||
Problem::UnusedModuleImport(_, _) => Warning,
|
||||
Problem::ExposedButNotDefined(_) => RuntimeError,
|
||||
Problem::UnknownGeneratesWith(_) => RuntimeError,
|
||||
Problem::UnusedArgument(_, _, _, _) => Warning,
|
||||
Problem::UnusedBranchDef(_, _) => Warning,
|
||||
Problem::PrecedenceProblem(_) => RuntimeError,
|
||||
Problem::UnsupportedPattern(_, _) => RuntimeError,
|
||||
Problem::Shadowing { .. } => RuntimeError,
|
||||
Problem::CyclicAlias(..) => RuntimeError,
|
||||
Problem::BadRecursion(_) => RuntimeError,
|
||||
Problem::PhantomTypeArgument { .. } => Warning,
|
||||
Problem::UnboundTypeVariable { .. } => RuntimeError,
|
||||
Problem::DuplicateRecordFieldValue { .. } => Warning,
|
||||
Problem::DuplicateRecordFieldType { .. } => RuntimeError,
|
||||
Problem::InvalidOptionalValue { .. } => RuntimeError,
|
||||
Problem::DuplicateTag { .. } => RuntimeError,
|
||||
Problem::RuntimeError(_) => RuntimeError,
|
||||
Problem::SignatureDefMismatch { .. } => RuntimeError,
|
||||
Problem::InvalidAliasRigid { .. } => RuntimeError,
|
||||
Problem::InvalidInterpolation(_) => RuntimeError,
|
||||
Problem::InvalidHexadecimal(_) => RuntimeError,
|
||||
Problem::InvalidUnicodeCodePt(_) => RuntimeError,
|
||||
Problem::NestedDatatype { .. } => RuntimeError,
|
||||
Problem::InvalidExtensionType { .. } => RuntimeError,
|
||||
Problem::AbilityHasTypeVariables { .. } => RuntimeError,
|
||||
Problem::HasClauseIsNotAbility { .. } => RuntimeError,
|
||||
Problem::IllegalHasClause { .. } => RuntimeError,
|
||||
Problem::DuplicateHasAbility { .. } => Warning,
|
||||
Problem::AbilityMemberMissingHasClause { .. } => RuntimeError,
|
||||
Problem::AbilityMemberMultipleBoundVars { .. } => RuntimeError,
|
||||
Problem::AbilityNotOnToplevel { .. } => RuntimeError, // Ideally, could be compiled
|
||||
Problem::AbilityUsedAsType(_, _, _) => RuntimeError,
|
||||
Problem::NestedSpecialization(_, _) => RuntimeError, // Ideally, could be compiled
|
||||
Problem::IllegalDerivedAbility(_) => RuntimeError,
|
||||
Problem::ImplementationNotFound { .. } => RuntimeError,
|
||||
Problem::NotAnAbilityMember { .. } => RuntimeError,
|
||||
Problem::OptionalAbilityImpl { .. } => RuntimeError,
|
||||
Problem::QualifiedAbilityImpl { .. } => RuntimeError,
|
||||
Problem::AbilityImplNotIdent { .. } => RuntimeError,
|
||||
Problem::DuplicateImpl { .. } => Warning, // First impl is used at runtime
|
||||
Problem::NotAnAbility(_) => Warning,
|
||||
Problem::ImplementsNonRequired { .. } => Warning,
|
||||
Problem::DoesNotImplementAbility { .. } => RuntimeError,
|
||||
Problem::NotBoundInAllPatterns { .. } => RuntimeError,
|
||||
Problem::NoIdentifiersIntroduced(_) => Warning,
|
||||
Problem::OverloadedSpecialization { .. } => Warning, // Ideally, will compile
|
||||
Problem::UnnecessaryOutputWildcard { .. } => Warning,
|
||||
// TODO: sometimes this can just be a warning, e.g. if you have [1, .., .., 2] but we
|
||||
// don't catch that yet.
|
||||
Problem::MultipleListRestPattern { .. } => RuntimeError,
|
||||
Problem::BadTypeArguments { .. } => RuntimeError,
|
||||
// TODO: this can be a warning instead if we recover the program by
|
||||
// injecting a crash message
|
||||
Problem::UnappliedCrash { .. } => RuntimeError,
|
||||
Problem::OverAppliedCrash { .. } => RuntimeError,
|
||||
Problem::DefsOnlyUsedInRecursion(_, _) => Warning,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a Region value from the Problem, if possible.
|
||||
/// Some problems have more than one region; in those cases,
|
||||
/// this tries to pick the one that's closest to the original
|
||||
|
@ -333,7 +401,8 @@ impl Problem {
|
|||
| Problem::BadTypeArguments { region, .. }
|
||||
| Problem::UnnecessaryOutputWildcard { region }
|
||||
| Problem::OverAppliedCrash { region }
|
||||
| Problem::UnappliedCrash { region } => Some(*region),
|
||||
| Problem::UnappliedCrash { region }
|
||||
| Problem::DefsOnlyUsedInRecursion(_, region) => Some(*region),
|
||||
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
|
||||
| Problem::BadRecursion(cycle_entries) => {
|
||||
cycle_entries.first().map(|entry| entry.expr_region)
|
||||
|
|
|
@ -3,3 +3,15 @@
|
|||
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
pub mod can;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Severity {
|
||||
/// This will cause a runtime error if some code get srun
|
||||
/// (e.g. type mismatch, naming error)
|
||||
RuntimeError,
|
||||
|
||||
/// This will never cause the code to misbehave,
|
||||
/// but should be cleaned up
|
||||
/// (e.g. unused def, unused import)
|
||||
Warning,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_collections::{VecMap, VecSet};
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_PRINT_UNDERIVABLE;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
@ -309,12 +312,18 @@ impl ObligationCache {
|
|||
Some(Err(NotDerivable {
|
||||
var: failure_var,
|
||||
context,
|
||||
})) => Some(if failure_var == var {
|
||||
UnderivableReason::SurfaceNotDerivable(context)
|
||||
} else {
|
||||
let error_type = subs.var_to_error_type(failure_var, Polarity::OF_VALUE);
|
||||
UnderivableReason::NestedNotDerivable(error_type, context)
|
||||
}),
|
||||
})) => {
|
||||
dbg_do!(ROC_PRINT_UNDERIVABLE, {
|
||||
eprintln!("❌ derived {:?} of {:?}", ability, subs.dbg(failure_var));
|
||||
});
|
||||
|
||||
Some(if failure_var == var {
|
||||
UnderivableReason::SurfaceNotDerivable(context)
|
||||
} else {
|
||||
let error_type = subs.var_to_error_type(failure_var, Polarity::OF_VALUE);
|
||||
UnderivableReason::NestedNotDerivable(error_type, context)
|
||||
})
|
||||
}
|
||||
None => Some(UnderivableReason::NotABuiltin),
|
||||
};
|
||||
|
||||
|
@ -497,18 +506,6 @@ trait DerivableVisitor {
|
|||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_rigid_able(var: Variable, abilities: &[Symbol]) -> Result<(), NotDerivable> {
|
||||
if abilities != [Self::ABILITY] {
|
||||
Err(NotDerivable {
|
||||
var,
|
||||
context: NotDerivableContext::UnboundVar,
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_recursion(var: Variable) -> Result<Descend, NotDerivable> {
|
||||
Err(NotDerivable {
|
||||
|
@ -659,7 +656,12 @@ trait DerivableVisitor {
|
|||
subs.set_content(var, Content::FlexAbleVar(opt_name, merged_abilites));
|
||||
}
|
||||
RigidAbleVar(_, abilities) => {
|
||||
Self::visit_rigid_able(var, subs.get_subs_slice(abilities))?
|
||||
if !subs.get_subs_slice(abilities).contains(&Self::ABILITY) {
|
||||
return Err(NotDerivable {
|
||||
var,
|
||||
context: NotDerivableContext::NoContext,
|
||||
});
|
||||
}
|
||||
}
|
||||
RecursionVar {
|
||||
structure,
|
||||
|
|
|
@ -3473,7 +3473,7 @@ mod solve_expr {
|
|||
Dict.insert
|
||||
"#
|
||||
),
|
||||
"Dict k v, k, v -> Dict k v | k has Eq",
|
||||
"Dict k v, k, v -> Dict k v | k has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3734,7 +3734,7 @@ mod solve_expr {
|
|||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
reconstructPath : Dict position position, position -> List position | position has Eq
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
|
@ -3746,7 +3746,7 @@ mod solve_expr {
|
|||
reconstructPath
|
||||
"#
|
||||
),
|
||||
"Dict position position, position -> List position | position has Eq",
|
||||
"Dict position position, position -> List position | position has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3781,7 +3781,7 @@ mod solve_expr {
|
|||
|
||||
Model position : { openSet : Set position }
|
||||
|
||||
cheapestOpen : Model position -> Result position [KeyNotFound] | position has Eq
|
||||
cheapestOpen : Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
cheapestOpen = \model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
|
@ -3796,14 +3796,14 @@ mod solve_expr {
|
|||
Set.walk model.openSet (Ok { position: boom {}, cost: 0.0 }) folder
|
||||
|> Result.map (\x -> x.position)
|
||||
|
||||
astar : Model position -> Result position [KeyNotFound] | position has Eq
|
||||
astar : Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
astar = \model -> cheapestOpen model
|
||||
|
||||
main =
|
||||
astar
|
||||
"#
|
||||
),
|
||||
"Model position -> Result position [KeyNotFound] | position has Eq",
|
||||
"Model position -> Result position [KeyNotFound] | position has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4445,7 +4445,7 @@ mod solve_expr {
|
|||
|
||||
Key k : Num k
|
||||
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Eq
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelpEQGT = \targetKey, dict ->
|
||||
when dict is
|
||||
Node color key value left right ->
|
||||
|
@ -4559,7 +4559,7 @@ mod solve_expr {
|
|||
_ ->
|
||||
Empty
|
||||
|
||||
removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Eq
|
||||
removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelp = \targetKey, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
|
@ -4647,7 +4647,7 @@ mod solve_expr {
|
|||
|
||||
RBTree k v : [Node NodeColor k v (RBTree k v) (RBTree k v), Empty]
|
||||
|
||||
removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v | k has Eq
|
||||
removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v | k has Hash & Eq
|
||||
removeHelp = \targetKey, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
|
@ -4682,7 +4682,7 @@ mod solve_expr {
|
|||
|
||||
removeHelpPrepEQGT : Key k, RBTree (Key k) v, NodeColor, (Key k), v, RBTree (Key k) v, RBTree (Key k) v -> RBTree (Key k) v
|
||||
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Eq
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelpEQGT = \targetKey, dict ->
|
||||
when dict is
|
||||
Node color key value left right ->
|
||||
|
@ -8270,7 +8270,7 @@ mod solve_expr {
|
|||
r#"
|
||||
app "test" provides [top] to "./platform"
|
||||
|
||||
MDict u := (List u) | u has Eq
|
||||
MDict u := (List u) | u has Hash & Eq
|
||||
|
||||
bot : MDict k -> MDict k
|
||||
bot = \@MDict data ->
|
||||
|
@ -8281,7 +8281,7 @@ mod solve_expr {
|
|||
top = \x -> bot x
|
||||
"#
|
||||
),
|
||||
"MDict v -> MDict v | v has Eq",
|
||||
"MDict v -> MDict v | v has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8431,4 +8431,29 @@ mod solve_expr {
|
|||
@"n : Dec"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_set_eq_issue_4671() {
|
||||
infer_queries!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
s1 : Set U8
|
||||
s1 = Set.empty
|
||||
|
||||
s2 : Set Str
|
||||
s2 = Set.empty
|
||||
|
||||
Bool.isEq s1 s1 && Bool.isEq s2 s2
|
||||
# ^^^^^^^^^ ^^^^^^^^^
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
Set#Bool.isEq(17) : Set U8, Set U8 -[[Set.isEq(17)]]-> Bool
|
||||
Set#Bool.isEq(17) : Set Str, Set Str -[[Set.isEq(17)]]-> Bool
|
||||
"###
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Provides types to describe problems that can occur during solving.
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_module::{ident::Lowercase, symbol::Symbol};
|
||||
use roc_problem::can::CycleEntry;
|
||||
use roc_problem::{can::CycleEntry, Severity};
|
||||
use roc_region::all::Region;
|
||||
|
||||
use roc_types::types::{Category, ErrorType, PatternCategory};
|
||||
|
@ -31,6 +31,27 @@ pub enum TypeError {
|
|||
},
|
||||
}
|
||||
|
||||
impl TypeError {
|
||||
pub fn severity(&self) -> Severity {
|
||||
use Severity::*;
|
||||
match self {
|
||||
TypeError::BadExpr(..) => RuntimeError,
|
||||
TypeError::BadPattern(..) => RuntimeError,
|
||||
TypeError::CircularType(..) => RuntimeError,
|
||||
TypeError::CircularDef(_) => RuntimeError,
|
||||
TypeError::UnexposedLookup(_) => RuntimeError,
|
||||
TypeError::UnfulfilledAbility(_) => RuntimeError,
|
||||
TypeError::BadExprMissingAbility(_, _, _, _) => RuntimeError,
|
||||
TypeError::BadPatternMissingAbility(_, _, _, _) => RuntimeError,
|
||||
// NB: if bidirectional exhaustiveness checking is implemented, the other direction
|
||||
// is also not a runtime error.
|
||||
TypeError::Exhaustive(exhtv) => exhtv.severity(),
|
||||
TypeError::StructuralSpecialization { .. } => RuntimeError,
|
||||
TypeError::WrongSpecialization { .. } => RuntimeError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum Unfulfilled {
|
||||
/// No claimed implementation of an ability for an opaque type.
|
||||
|
|
|
@ -378,6 +378,7 @@ fn check_derived_typechecks_and_golden(
|
|||
);
|
||||
let mut def_types = Default::default();
|
||||
let mut rigid_vars = Default::default();
|
||||
let mut flex_vars = Default::default();
|
||||
let (import_variables, abilities_store) = add_imports(
|
||||
test_module,
|
||||
&mut constraints,
|
||||
|
@ -386,9 +387,15 @@ fn check_derived_typechecks_and_golden(
|
|||
&exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
&mut flex_vars,
|
||||
);
|
||||
let constr = constraints.let_import_constraint(
|
||||
rigid_vars,
|
||||
flex_vars,
|
||||
def_types,
|
||||
constr,
|
||||
&import_variables,
|
||||
);
|
||||
let constr =
|
||||
constraints.let_import_constraint(rigid_vars, def_types, constr, &import_variables);
|
||||
|
||||
// run the solver, print and fail if we have errors
|
||||
dbg_do!(
|
||||
|
|
|
@ -465,7 +465,7 @@ fn eq_rosetree() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn eq_different_rosetrees() {
|
||||
// Requires two different equality procedures for `List (Rose I64)` and `List (Rose Str)`
|
||||
// even though both appear in the mono Layout as `List(RecursivePointer)`
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#![cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#![cfg(all(
|
||||
any(feature = "gen-llvm", feature = "gen-wasm"),
|
||||
not(debug_assertions) // https://github.com/roc-lang/roc/issues/3898
|
||||
))]
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
@ -77,6 +80,7 @@ fn dict_nonempty_contains() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO figure out why this is broken with llvm wasm tests"]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn dict_empty_remove() {
|
||||
assert_evals_to!(
|
||||
|
@ -252,7 +256,11 @@ fn from_list_with_fold_reallocates() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// TODO: Re-enable this test for wasm.
|
||||
// Currently it causes "[trap] out of bounds memory access" due to the small strings.
|
||||
// I was unable to find the root cause and with llvm and valgrind it passes with no issues.
|
||||
// #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn small_str_keys() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -384,7 +392,7 @@ fn insert_all() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn insert_all_prefer_first() {
|
||||
fn insert_all_prefer_second() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -396,7 +404,7 @@ fn insert_all_prefer_first() {
|
|||
Dict.values myDict
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[100]),
|
||||
RocList::from_slice(&[200]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2808,22 +2808,6 @@ fn cleanup_because_exception() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_range() {
|
||||
assert_evals_to!(
|
||||
"List.range 0 -1",
|
||||
RocList::<i64>::from_slice(&[]),
|
||||
RocList<i64>
|
||||
);
|
||||
assert_evals_to!("List.range 0 0", RocList::from_slice(&[0]), RocList<i64>);
|
||||
assert_evals_to!(
|
||||
"List.range 0 5",
|
||||
RocList::from_slice(&[0, 1, 2, 3, 4]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_sort_with() {
|
||||
|
@ -3561,6 +3545,27 @@ fn list_walk_from_until_sum() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn concat_unique_to_nonunique_overlapping_issue_4697() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
# originalList is shared, but others is unique.
|
||||
# When we concat originalList with others, others should be re-used.
|
||||
|
||||
originalList = [1u8]
|
||||
others = [2u8, 3u8, 4u8]
|
||||
new = List.concat originalList others
|
||||
{a: originalList, b: new}
|
||||
"#,
|
||||
(
|
||||
RocList::from_slice(&[1u8]),
|
||||
RocList::from_slice(&[1u8, 2, 3, 4]),
|
||||
),
|
||||
(RocList<u8>, RocList<u8>)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_from_even_prefix_sum() {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#![cfg(feature = "gen-llvm")]
|
||||
#![cfg(all(
|
||||
any(feature = "gen-llvm"),
|
||||
not(debug_assertions) // https://github.com/roc-lang/roc/issues/3898
|
||||
))]
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
@ -62,16 +65,6 @@ fn single_to_list() {
|
|||
RocList::from_slice(&[1]),
|
||||
RocList<i64>
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Set.toList (Set.single 1.0)
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[1.0]),
|
||||
RocList<f64>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -260,6 +253,20 @@ fn from_list_void() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_list_empty() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Set.toList Set.empty
|
||||
"#
|
||||
),
|
||||
RocList::<std::convert::Infallible>::default(),
|
||||
RocList<std::convert::Infallible>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn from_list_result() {
|
||||
|
@ -280,3 +287,26 @@ fn from_list_result() {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn resolve_set_eq_issue_4671() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
s1 : Set U8
|
||||
s1 = Set.fromList [1, 2, 3]
|
||||
|
||||
s2 : Set U8
|
||||
s2 = Set.fromList [3, 2, 1]
|
||||
|
||||
s1 == s2
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use roc_build::link::llvm_module_to_dylib;
|
|||
use roc_collections::all::MutSet;
|
||||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult};
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, LoadMonomorphizedError, Threading};
|
||||
use roc_mono::ir::{CrashTag, OptLevel};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_region::all::LineInfo;
|
||||
|
@ -87,7 +87,9 @@ fn create_llvm_module<'a>(
|
|||
|
||||
let mut loaded = match loaded {
|
||||
Ok(x) => x,
|
||||
Err(roc_load::LoadingProblem::FormattedReport(report)) => {
|
||||
Err(LoadMonomorphizedError::LoadingProblem(roc_load::LoadingProblem::FormattedReport(
|
||||
report,
|
||||
))) => {
|
||||
println!("{}", report);
|
||||
panic!();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.409 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
let List.478 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.409;
|
||||
ret List.478;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.7 : {} = Struct {};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.409 : List [] = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
let List.478 : List [] = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.409;
|
||||
ret List.478;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.7 : {} = Struct {};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.2 : I64 = 41i64;
|
||||
|
|
|
@ -1,17 +1,87 @@
|
|||
procedure Dict.1 ():
|
||||
let Dict.318 : List {[], []} = Array [];
|
||||
ret Dict.318;
|
||||
let Dict.520 : List {[], []} = Array [];
|
||||
let Dict.527 : U64 = 0i64;
|
||||
let Dict.528 : U64 = 8i64;
|
||||
let Dict.521 : List U64 = CallByName List.11 Dict.527 Dict.528;
|
||||
let Dict.524 : I8 = CallByName Dict.34;
|
||||
let Dict.525 : U64 = 8i64;
|
||||
let Dict.522 : List I8 = CallByName List.11 Dict.524 Dict.525;
|
||||
let Dict.523 : U64 = 0i64;
|
||||
let Dict.519 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.520, Dict.521, Dict.522, Dict.523};
|
||||
ret Dict.519;
|
||||
|
||||
procedure Dict.7 (Dict.312):
|
||||
let Dict.317 : U64 = CallByName List.6 Dict.312;
|
||||
ret Dict.317;
|
||||
procedure Dict.34 ():
|
||||
let Dict.526 : I8 = -128i64;
|
||||
ret Dict.526;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
procedure Dict.4 (Dict.507):
|
||||
let Dict.85 : U64 = StructAtIndex 3 Dict.507;
|
||||
dec Dict.507;
|
||||
ret Dict.85;
|
||||
|
||||
procedure List.11 (List.114, List.115):
|
||||
let List.479 : List I8 = CallByName List.68 List.115;
|
||||
let List.478 : List I8 = CallByName List.80 List.114 List.115 List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.11 (List.114, List.115):
|
||||
let List.491 : List U64 = CallByName List.68 List.115;
|
||||
let List.490 : List U64 = CallByName List.80 List.114 List.115 List.491;
|
||||
ret List.490;
|
||||
|
||||
procedure List.68 (#Attr.2):
|
||||
let List.489 : List I8 = lowlevel ListWithCapacity #Attr.2;
|
||||
ret List.489;
|
||||
|
||||
procedure List.68 (#Attr.2):
|
||||
let List.501 : List U64 = lowlevel ListWithCapacity #Attr.2;
|
||||
ret List.501;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.486 : List I8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.486;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.498 : List U64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.498;
|
||||
|
||||
procedure List.80 (List.502, List.503, List.504):
|
||||
joinpoint List.480 List.116 List.117 List.118:
|
||||
let List.488 : U64 = 0i64;
|
||||
let List.482 : Int1 = CallByName Num.24 List.117 List.488;
|
||||
if List.482 then
|
||||
let List.487 : U64 = 1i64;
|
||||
let List.484 : U64 = CallByName Num.20 List.117 List.487;
|
||||
let List.485 : List I8 = CallByName List.71 List.118 List.116;
|
||||
jump List.480 List.116 List.484 List.485;
|
||||
else
|
||||
ret List.118;
|
||||
in
|
||||
jump List.480 List.502 List.503 List.504;
|
||||
|
||||
procedure List.80 (List.510, List.511, List.512):
|
||||
joinpoint List.492 List.116 List.117 List.118:
|
||||
let List.500 : U64 = 0i64;
|
||||
let List.494 : Int1 = CallByName Num.24 List.117 List.500;
|
||||
if List.494 then
|
||||
let List.499 : U64 = 1i64;
|
||||
let List.496 : U64 = CallByName Num.20 List.117 List.499;
|
||||
let List.497 : List U64 = CallByName List.71 List.118 List.116;
|
||||
jump List.492 List.116 List.496 List.497;
|
||||
else
|
||||
ret List.118;
|
||||
in
|
||||
jump List.492 List.510 List.511 List.512;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.257 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.259 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.259;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List {[], []} = CallByName Dict.1;
|
||||
let Test.1 : U64 = CallByName Dict.7 Test.2;
|
||||
dec Test.2;
|
||||
let Test.2 : {List {[], []}, List U64, List I8, U64} = CallByName Dict.1;
|
||||
let Test.1 : U64 = CallByName Dict.4 Test.2;
|
||||
ret Test.1;
|
||||
|
|
|
@ -2,25 +2,25 @@ procedure Bool.1 ():
|
|||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
|
||||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : {} = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C {}] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : {} = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C {}] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C {}] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C {}] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List U8 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List U8 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.481 : U64 = 1i64;
|
||||
let List.479 : List U8 = CallByName List.70 List.106 List.481;
|
||||
let List.478 : List U8 = CallByName List.71 List.479 List.107;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.411 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
let List.480 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
|
||||
procedure Test.23 (Test.24, Test.35, Test.22):
|
||||
let Test.37 : List U8 = CallByName List.4 Test.24 Test.22;
|
||||
|
|
|
@ -66,237 +66,237 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.432 : I64 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.125 Json.432;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.111;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.115, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.111 Json.407 Json.408;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.117 Json.404;
|
||||
ret Json.403;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.470 : I64 = 123i64;
|
||||
let Json.469 : U8 = CallByName Num.125 Json.470;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.469;
|
||||
let Json.468 : U64 = CallByName List.6 Json.111;
|
||||
let Json.445 : {List U8, U64} = Struct {Json.115, Json.468};
|
||||
let Json.446 : {} = Struct {};
|
||||
let Json.444 : {List U8, U64} = CallByName List.18 Json.111 Json.445 Json.446;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.472 : I64 = 123i64;
|
||||
let Json.471 : U8 = CallByName Num.125 Json.472;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.471;
|
||||
let Json.470 : U64 = CallByName List.6 Json.111;
|
||||
let Json.447 : {List U8, U64} = Struct {Json.115, Json.470};
|
||||
let Json.448 : {} = Struct {};
|
||||
let Json.446 : {List U8, U64} = CallByName List.18 Json.111 Json.447 Json.448;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.444;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.446;
|
||||
inc Json.117;
|
||||
dec Json.444;
|
||||
let Json.443 : I64 = 125i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.117 Json.442;
|
||||
ret Json.441;
|
||||
dec Json.446;
|
||||
let Json.445 : I64 = 125i64;
|
||||
let Json.444 : U8 = CallByName Num.125 Json.445;
|
||||
let Json.443 : List U8 = CallByName List.4 Json.117 Json.444;
|
||||
ret Json.443;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I64 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.125 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.118 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I64 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.418 Json.121 Json.419;
|
||||
joinpoint Json.413 Json.123:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.119 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.123, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.119 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.122 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.411 Json.122;
|
||||
jump Json.413 Json.122;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.467 : I64 = 34i64;
|
||||
let Json.466 : U8 = CallByName Num.125 Json.467;
|
||||
let Json.464 : List U8 = CallByName List.4 Json.118 Json.466;
|
||||
let Json.465 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.461 : List U8 = CallByName List.8 Json.464 Json.465;
|
||||
let Json.463 : I64 = 34i64;
|
||||
let Json.462 : U8 = CallByName Num.125 Json.463;
|
||||
let Json.458 : List U8 = CallByName List.4 Json.461 Json.462;
|
||||
let Json.460 : I64 = 58i64;
|
||||
let Json.459 : U8 = CallByName Num.125 Json.460;
|
||||
let Json.456 : List U8 = CallByName List.4 Json.458 Json.459;
|
||||
let Json.457 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.456 Json.121 Json.457;
|
||||
joinpoint Json.451 Json.123:
|
||||
let Json.449 : U64 = 1i64;
|
||||
let Json.448 : U64 = CallByName Num.20 Json.119 Json.449;
|
||||
let Json.447 : {List U8, U64} = Struct {Json.123, Json.448};
|
||||
ret Json.447;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.469 : I64 = 34i64;
|
||||
let Json.468 : U8 = CallByName Num.125 Json.469;
|
||||
let Json.466 : List U8 = CallByName List.4 Json.118 Json.468;
|
||||
let Json.467 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.463 : List U8 = CallByName List.8 Json.466 Json.467;
|
||||
let Json.465 : I64 = 34i64;
|
||||
let Json.464 : U8 = CallByName Num.125 Json.465;
|
||||
let Json.460 : List U8 = CallByName List.4 Json.463 Json.464;
|
||||
let Json.462 : I64 = 58i64;
|
||||
let Json.461 : U8 = CallByName Num.125 Json.462;
|
||||
let Json.458 : List U8 = CallByName List.4 Json.460 Json.461;
|
||||
let Json.459 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.458 Json.121 Json.459;
|
||||
joinpoint Json.453 Json.123:
|
||||
let Json.451 : U64 = 1i64;
|
||||
let Json.450 : U64 = CallByName Num.20 Json.119 Json.451;
|
||||
let Json.449 : {List U8, U64} = Struct {Json.123, Json.450};
|
||||
ret Json.449;
|
||||
in
|
||||
let Json.455 : U64 = 1i64;
|
||||
let Json.452 : Int1 = CallByName Num.24 Json.119 Json.455;
|
||||
if Json.452 then
|
||||
let Json.454 : I64 = 44i64;
|
||||
let Json.453 : U8 = CallByName Num.125 Json.454;
|
||||
let Json.450 : List U8 = CallByName List.4 Json.122 Json.453;
|
||||
jump Json.451 Json.450;
|
||||
let Json.457 : U64 = 1i64;
|
||||
let Json.454 : Int1 = CallByName Num.24 Json.119 Json.457;
|
||||
if Json.454 then
|
||||
let Json.456 : I64 = 44i64;
|
||||
let Json.455 : U8 = CallByName Num.125 Json.456;
|
||||
let Json.452 : List U8 = CallByName List.4 Json.122 Json.455;
|
||||
jump Json.453 Json.452;
|
||||
else
|
||||
jump Json.451 Json.122;
|
||||
jump Json.453 Json.122;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.471 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.471;
|
||||
let Json.473 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.473;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.437 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.437;
|
||||
let Json.439 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.439;
|
||||
|
||||
procedure Json.96 (Json.97, Json.473, Json.95):
|
||||
let Json.482 : I64 = 34i64;
|
||||
let Json.481 : U8 = CallByName Num.125 Json.482;
|
||||
let Json.479 : List U8 = CallByName List.4 Json.97 Json.481;
|
||||
let Json.480 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.476 : List U8 = CallByName List.8 Json.479 Json.480;
|
||||
let Json.478 : I64 = 34i64;
|
||||
let Json.477 : U8 = CallByName Num.125 Json.478;
|
||||
let Json.475 : List U8 = CallByName List.4 Json.476 Json.477;
|
||||
ret Json.475;
|
||||
procedure Json.96 (Json.97, Json.475, Json.95):
|
||||
let Json.484 : I64 = 34i64;
|
||||
let Json.483 : U8 = CallByName Num.125 Json.484;
|
||||
let Json.481 : List U8 = CallByName List.4 Json.97 Json.483;
|
||||
let Json.482 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.478 : List U8 = CallByName List.8 Json.481 Json.482;
|
||||
let Json.480 : I64 = 34i64;
|
||||
let Json.479 : U8 = CallByName Num.125 Json.480;
|
||||
let Json.477 : List U8 = CallByName List.4 Json.478 Json.479;
|
||||
ret Json.477;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.450 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.450;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.519 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.519;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.523 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.523;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.592 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.592;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.431 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.431;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.500 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.500;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.504 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.504;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.573 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.573;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.503 : U64 = 1i64;
|
||||
let List.502 : List U8 = CallByName List.70 List.105 List.503;
|
||||
let List.501 : List U8 = CallByName List.71 List.502 List.106;
|
||||
ret List.501;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.572 : U64 = 1i64;
|
||||
let List.571 : List U8 = CallByName List.70 List.106 List.572;
|
||||
let List.570 : List U8 = CallByName List.71 List.571 List.107;
|
||||
ret List.570;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.452 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.452;
|
||||
let List.521 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.521;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.526 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.526;
|
||||
let List.595 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.595;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.447 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.447;
|
||||
let List.516 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.516;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.520 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.520;
|
||||
let List.589 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.589;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.482 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
let List.551 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.551;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.480 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
let List.549 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.549;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.525 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.525;
|
||||
let List.594 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.594;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.435 : U64 = 0i64;
|
||||
let List.436 : U64 = CallByName List.6 List.385;
|
||||
let List.434 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.435 List.436;
|
||||
ret List.434;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.504 : U64 = 0i64;
|
||||
let List.505 : U64 = CallByName List.6 List.426;
|
||||
let List.503 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.504 List.505;
|
||||
ret List.503;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.508 : U64 = 0i64;
|
||||
let List.509 : U64 = CallByName List.6 List.385;
|
||||
let List.507 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.508 List.509;
|
||||
ret List.507;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.577 : U64 = 0i64;
|
||||
let List.578 : U64 = CallByName List.6 List.426;
|
||||
let List.576 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.577 List.578;
|
||||
ret List.576;
|
||||
|
||||
procedure List.90 (List.462, List.463, List.464, List.465, List.466):
|
||||
joinpoint List.437 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.439 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.439 then
|
||||
let List.446 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.440 : {List U8, U64} = CallByName List.137 List.389 List.446 List.390;
|
||||
let List.443 : U64 = 1i64;
|
||||
let List.442 : U64 = CallByName Num.19 List.391 List.443;
|
||||
jump List.437 List.388 List.440 List.390 List.442 List.392;
|
||||
procedure List.91 (List.531, List.532, List.533, List.534, List.535):
|
||||
joinpoint List.506 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.508 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.508 then
|
||||
let List.515 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.509 : {List U8, U64} = CallByName List.138 List.430 List.515 List.431;
|
||||
let List.512 : U64 = 1i64;
|
||||
let List.511 : U64 = CallByName Num.19 List.432 List.512;
|
||||
jump List.506 List.429 List.509 List.431 List.511 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.437 List.462 List.463 List.464 List.465 List.466;
|
||||
jump List.506 List.531 List.532 List.533 List.534 List.535;
|
||||
|
||||
procedure List.90 (List.536, List.537, List.538, List.539, List.540):
|
||||
joinpoint List.510 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.512 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.512 then
|
||||
let List.519 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.513 : {List U8, U64} = CallByName List.137 List.389 List.519 List.390;
|
||||
let List.516 : U64 = 1i64;
|
||||
let List.515 : U64 = CallByName Num.19 List.391 List.516;
|
||||
jump List.510 List.388 List.513 List.390 List.515 List.392;
|
||||
procedure List.91 (List.605, List.606, List.607, List.608, List.609):
|
||||
joinpoint List.579 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.581 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.581 then
|
||||
let List.588 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.582 : {List U8, U64} = CallByName List.138 List.430 List.588 List.431;
|
||||
let List.585 : U64 = 1i64;
|
||||
let List.584 : U64 = CallByName Num.19 List.432 List.585;
|
||||
jump List.579 List.429 List.582 List.431 List.584 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.510 List.536 List.537 List.538 List.539 List.540;
|
||||
jump List.579 List.605 List.606 List.607 List.608 List.609;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.282 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -39,141 +39,141 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.432 : I64 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.125 Json.432;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.111;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.115, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.111 Json.407 Json.408;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.117 Json.404;
|
||||
ret Json.403;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I64 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.125 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.118 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I64 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.418 Json.121 Json.419;
|
||||
joinpoint Json.413 Json.123:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.119 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.123, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.119 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.122 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.411 Json.122;
|
||||
jump Json.413 Json.122;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.431 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.431;
|
||||
let Json.433 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.433;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.433, Json.95):
|
||||
let Json.442 : I64 = 34i64;
|
||||
let Json.441 : U8 = CallByName Num.125 Json.442;
|
||||
let Json.439 : List U8 = CallByName List.4 Json.97 Json.441;
|
||||
let Json.440 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.436 : List U8 = CallByName List.8 Json.439 Json.440;
|
||||
let Json.438 : I64 = 34i64;
|
||||
let Json.437 : U8 = CallByName Num.125 Json.438;
|
||||
let Json.435 : List U8 = CallByName List.4 Json.436 Json.437;
|
||||
ret Json.435;
|
||||
procedure Json.96 (Json.97, Json.435, Json.95):
|
||||
let Json.444 : I64 = 34i64;
|
||||
let Json.443 : U8 = CallByName Num.125 Json.444;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.97 Json.443;
|
||||
let Json.442 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.438 : List U8 = CallByName List.8 Json.441 Json.442;
|
||||
let Json.440 : I64 = 34i64;
|
||||
let Json.439 : U8 = CallByName Num.125 Json.440;
|
||||
let Json.437 : List U8 = CallByName List.4 Json.438 Json.439;
|
||||
ret Json.437;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.456 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.456;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.525 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.525;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.437 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.437;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.506 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.506;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.436 : U64 = 1i64;
|
||||
let List.435 : List U8 = CallByName List.70 List.105 List.436;
|
||||
let List.434 : List U8 = CallByName List.71 List.435 List.106;
|
||||
ret List.434;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.505 : U64 = 1i64;
|
||||
let List.504 : List U8 = CallByName List.70 List.106 List.505;
|
||||
let List.503 : List U8 = CallByName List.71 List.504 List.107;
|
||||
ret List.503;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.459 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.459;
|
||||
let List.528 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.528;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.453 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.453;
|
||||
let List.522 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.522;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.458 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.458;
|
||||
let List.527 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.527;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.441 : U64 = 0i64;
|
||||
let List.442 : U64 = CallByName List.6 List.385;
|
||||
let List.440 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.441 List.442;
|
||||
ret List.440;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.510 : U64 = 0i64;
|
||||
let List.511 : U64 = CallByName List.6 List.426;
|
||||
let List.509 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.510 List.511;
|
||||
ret List.509;
|
||||
|
||||
procedure List.90 (List.469, List.470, List.471, List.472, List.473):
|
||||
joinpoint List.443 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.445 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.445 then
|
||||
let List.452 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.446 : {List U8, U64} = CallByName List.137 List.389 List.452 List.390;
|
||||
let List.449 : U64 = 1i64;
|
||||
let List.448 : U64 = CallByName Num.19 List.391 List.449;
|
||||
jump List.443 List.388 List.446 List.390 List.448 List.392;
|
||||
procedure List.91 (List.538, List.539, List.540, List.541, List.542):
|
||||
joinpoint List.512 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.514 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.514 then
|
||||
let List.521 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.515 : {List U8, U64} = CallByName List.138 List.430 List.521 List.431;
|
||||
let List.518 : U64 = 1i64;
|
||||
let List.517 : U64 = CallByName Num.19 List.432 List.518;
|
||||
jump List.512 List.429 List.515 List.431 List.517 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.443 List.469 List.470 List.471 List.472 List.473;
|
||||
jump List.512 List.538 List.539 List.540 List.541 List.542;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.263 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -47,141 +47,141 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.432 : I64 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.125 Json.432;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.111;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.115, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.111 Json.407 Json.408;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.117 Json.404;
|
||||
ret Json.403;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I64 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.125 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.118 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I64 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.418 Json.121 Json.419;
|
||||
joinpoint Json.413 Json.123:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.119 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.123, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.119 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.122 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.411 Json.122;
|
||||
jump Json.413 Json.122;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.443 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.443;
|
||||
let Json.445 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.445;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.433, Json.95):
|
||||
let Json.442 : I64 = 34i64;
|
||||
let Json.441 : U8 = CallByName Num.125 Json.442;
|
||||
let Json.439 : List U8 = CallByName List.4 Json.97 Json.441;
|
||||
let Json.440 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.436 : List U8 = CallByName List.8 Json.439 Json.440;
|
||||
let Json.438 : I64 = 34i64;
|
||||
let Json.437 : U8 = CallByName Num.125 Json.438;
|
||||
let Json.435 : List U8 = CallByName List.4 Json.436 Json.437;
|
||||
ret Json.435;
|
||||
procedure Json.96 (Json.97, Json.435, Json.95):
|
||||
let Json.444 : I64 = 34i64;
|
||||
let Json.443 : U8 = CallByName Num.125 Json.444;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.97 Json.443;
|
||||
let Json.442 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.438 : List U8 = CallByName List.8 Json.441 Json.442;
|
||||
let Json.440 : I64 = 34i64;
|
||||
let Json.439 : U8 = CallByName Num.125 Json.440;
|
||||
let Json.437 : List U8 = CallByName List.4 Json.438 Json.439;
|
||||
ret Json.437;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.456 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.456;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.525 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.525;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.437 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.437;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.506 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.506;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.436 : U64 = 1i64;
|
||||
let List.435 : List U8 = CallByName List.70 List.105 List.436;
|
||||
let List.434 : List U8 = CallByName List.71 List.435 List.106;
|
||||
ret List.434;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.505 : U64 = 1i64;
|
||||
let List.504 : List U8 = CallByName List.70 List.106 List.505;
|
||||
let List.503 : List U8 = CallByName List.71 List.504 List.107;
|
||||
ret List.503;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.459 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.459;
|
||||
let List.528 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.528;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.453 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.453;
|
||||
let List.522 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.522;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.458 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.458;
|
||||
let List.527 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.527;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.441 : U64 = 0i64;
|
||||
let List.442 : U64 = CallByName List.6 List.385;
|
||||
let List.440 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.441 List.442;
|
||||
ret List.440;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.510 : U64 = 0i64;
|
||||
let List.511 : U64 = CallByName List.6 List.426;
|
||||
let List.509 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.510 List.511;
|
||||
ret List.509;
|
||||
|
||||
procedure List.90 (List.469, List.470, List.471, List.472, List.473):
|
||||
joinpoint List.443 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.445 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.445 then
|
||||
let List.452 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.446 : {List U8, U64} = CallByName List.137 List.389 List.452 List.390;
|
||||
let List.449 : U64 = 1i64;
|
||||
let List.448 : U64 = CallByName Num.19 List.391 List.449;
|
||||
jump List.443 List.388 List.446 List.390 List.448 List.392;
|
||||
procedure List.91 (List.538, List.539, List.540, List.541, List.542):
|
||||
joinpoint List.512 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.514 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.514 then
|
||||
let List.521 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.515 : {List U8, U64} = CallByName List.138 List.430 List.521 List.431;
|
||||
let List.518 : U64 = 1i64;
|
||||
let List.517 : U64 = CallByName Num.19 List.432 List.518;
|
||||
jump List.512 List.429 List.515 List.431 List.517 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.443 List.469 List.470 List.471 List.472 List.473;
|
||||
jump List.512 List.538 List.539 List.540 List.541 List.542;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.263 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -12,45 +12,45 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.395 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.395;
|
||||
let Json.397 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.397, Json.95):
|
||||
let Json.406 : I64 = 34i64;
|
||||
let Json.405 : U8 = CallByName Num.125 Json.406;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.97 Json.405;
|
||||
let Json.404 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.400 : List U8 = CallByName List.8 Json.403 Json.404;
|
||||
let Json.402 : I64 = 34i64;
|
||||
let Json.401 : U8 = CallByName Num.125 Json.402;
|
||||
let Json.399 : List U8 = CallByName List.4 Json.400 Json.401;
|
||||
ret Json.399;
|
||||
procedure Json.96 (Json.97, Json.399, Json.95):
|
||||
let Json.408 : I64 = 34i64;
|
||||
let Json.407 : U8 = CallByName Num.125 Json.408;
|
||||
let Json.405 : List U8 = CallByName List.4 Json.97 Json.407;
|
||||
let Json.406 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.402 : List U8 = CallByName List.8 Json.405 Json.406;
|
||||
let Json.404 : I64 = 34i64;
|
||||
let Json.403 : U8 = CallByName Num.125 Json.404;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.402 Json.403;
|
||||
ret Json.401;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.418 : U64 = 1i64;
|
||||
let List.417 : List U8 = CallByName List.70 List.105 List.418;
|
||||
let List.416 : List U8 = CallByName List.71 List.417 List.106;
|
||||
ret List.416;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.487 : U64 = 1i64;
|
||||
let List.486 : List U8 = CallByName List.70 List.106 List.487;
|
||||
let List.485 : List U8 = CallByName List.71 List.486 List.107;
|
||||
ret List.485;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.419 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.419;
|
||||
let List.488 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.488;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.257 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -41,148 +41,148 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.126 (Json.127, Json.397, #Attr.12):
|
||||
procedure Json.126 (Json.127, Json.399, #Attr.12):
|
||||
let Json.125 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.125;
|
||||
let Json.124 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.124;
|
||||
dec #Attr.12;
|
||||
let Json.435 : I64 = 123i64;
|
||||
let Json.437 : I64 = 123i64;
|
||||
let Json.436 : U8 = CallByName Num.125 Json.437;
|
||||
let Json.433 : List U8 = CallByName List.4 Json.127 Json.436;
|
||||
let Json.435 : I64 = 34i64;
|
||||
let Json.434 : U8 = CallByName Num.125 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.127 Json.434;
|
||||
let Json.433 : I64 = 34i64;
|
||||
let Json.432 : U8 = CallByName Num.125 Json.433;
|
||||
let Json.429 : List U8 = CallByName List.4 Json.431 Json.432;
|
||||
let Json.430 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.426 : List U8 = CallByName List.8 Json.429 Json.430;
|
||||
let Json.428 : I64 = 34i64;
|
||||
let Json.427 : U8 = CallByName Num.125 Json.428;
|
||||
let Json.423 : List U8 = CallByName List.4 Json.426 Json.427;
|
||||
let Json.425 : I64 = 58i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 91i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : U64 = CallByName List.6 Json.125;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.129, Json.419};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.125 Json.407 Json.408;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.433 Json.434;
|
||||
let Json.432 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.428 : List U8 = CallByName List.8 Json.431 Json.432;
|
||||
let Json.430 : I64 = 34i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.425 : List U8 = CallByName List.4 Json.428 Json.429;
|
||||
let Json.427 : I64 = 58i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.422 : List U8 = CallByName List.4 Json.425 Json.426;
|
||||
let Json.424 : I64 = 91i64;
|
||||
let Json.423 : U8 = CallByName Num.125 Json.424;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.422 Json.423;
|
||||
let Json.421 : U64 = CallByName List.6 Json.125;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.129, Json.421};
|
||||
let Json.410 : {} = Struct {};
|
||||
let Json.408 : {List U8, U64} = CallByName List.18 Json.125 Json.409 Json.410;
|
||||
dec Json.125;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.406;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.408;
|
||||
inc Json.131;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 93i64;
|
||||
dec Json.408;
|
||||
let Json.407 : I64 = 93i64;
|
||||
let Json.406 : U8 = CallByName Num.125 Json.407;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.131 Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.131 Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.400 : List U8 = CallByName List.4 Json.401 Json.402;
|
||||
ret Json.400;
|
||||
let Json.402 : List U8 = CallByName List.4 Json.403 Json.404;
|
||||
ret Json.402;
|
||||
|
||||
procedure Json.128 (Json.399, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.399;
|
||||
procedure Json.128 (Json.401, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.132;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.418 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.418;
|
||||
joinpoint Json.413 Json.136:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.133 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.136, Json.410};
|
||||
ret Json.409;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.420 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.420;
|
||||
joinpoint Json.415 Json.136:
|
||||
let Json.413 : U64 = 1i64;
|
||||
let Json.412 : U64 = CallByName Num.20 Json.133 Json.413;
|
||||
let Json.411 : {List U8, U64} = Struct {Json.136, Json.412};
|
||||
ret Json.411;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.133 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.135 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.419 : U64 = 1i64;
|
||||
let Json.416 : Int1 = CallByName Num.24 Json.133 Json.419;
|
||||
if Json.416 then
|
||||
let Json.418 : I64 = 44i64;
|
||||
let Json.417 : U8 = CallByName Num.125 Json.418;
|
||||
let Json.414 : List U8 = CallByName List.4 Json.135 Json.417;
|
||||
jump Json.415 Json.414;
|
||||
else
|
||||
jump Json.413 Json.135;
|
||||
jump Json.415 Json.135;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.436 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.436;
|
||||
let Json.438 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.438;
|
||||
|
||||
procedure Json.21 (Json.124, Json.125):
|
||||
let Json.396 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.395 : {Str, List Str} = CallByName Encode.22 Json.396;
|
||||
ret Json.395;
|
||||
let Json.398 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.397 : {Str, List Str} = CallByName Encode.22 Json.398;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.438, Json.95):
|
||||
let Json.447 : I64 = 34i64;
|
||||
let Json.446 : U8 = CallByName Num.125 Json.447;
|
||||
let Json.444 : List U8 = CallByName List.4 Json.97 Json.446;
|
||||
let Json.445 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.441 : List U8 = CallByName List.8 Json.444 Json.445;
|
||||
let Json.443 : I64 = 34i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.440 : List U8 = CallByName List.4 Json.441 Json.442;
|
||||
ret Json.440;
|
||||
procedure Json.96 (Json.97, Json.440, Json.95):
|
||||
let Json.449 : I64 = 34i64;
|
||||
let Json.448 : U8 = CallByName Num.125 Json.449;
|
||||
let Json.446 : List U8 = CallByName List.4 Json.97 Json.448;
|
||||
let Json.447 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.443 : List U8 = CallByName List.8 Json.446 Json.447;
|
||||
let Json.445 : I64 = 34i64;
|
||||
let Json.444 : U8 = CallByName Num.125 Json.445;
|
||||
let Json.442 : List U8 = CallByName List.4 Json.443 Json.444;
|
||||
ret Json.442;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.462 : {List U8, U64} = CallByName Json.128 List.138 List.139;
|
||||
ret List.462;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.531 : {List U8, U64} = CallByName Json.128 List.139 List.140;
|
||||
ret List.531;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.443 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.443;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.512 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.512;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.442 : U64 = 1i64;
|
||||
let List.441 : List U8 = CallByName List.70 List.105 List.442;
|
||||
let List.440 : List U8 = CallByName List.71 List.441 List.106;
|
||||
ret List.440;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.511 : U64 = 1i64;
|
||||
let List.510 : List U8 = CallByName List.70 List.106 List.511;
|
||||
let List.509 : List U8 = CallByName List.71 List.510 List.107;
|
||||
ret List.509;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.463 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.463;
|
||||
let List.532 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.532;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.459 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.459;
|
||||
let List.528 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.528;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.465 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.465;
|
||||
let List.534 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.534;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.447 : U64 = 0i64;
|
||||
let List.448 : U64 = CallByName List.6 List.385;
|
||||
let List.446 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.447 List.448;
|
||||
ret List.446;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.516 : U64 = 0i64;
|
||||
let List.517 : U64 = CallByName List.6 List.426;
|
||||
let List.515 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.516 List.517;
|
||||
ret List.515;
|
||||
|
||||
procedure List.90 (List.475, List.476, List.477, List.478, List.479):
|
||||
joinpoint List.449 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.451 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.451 then
|
||||
let List.458 : Str = CallByName List.66 List.388 List.391;
|
||||
let List.452 : {List U8, U64} = CallByName List.137 List.389 List.458 List.390;
|
||||
let List.455 : U64 = 1i64;
|
||||
let List.454 : U64 = CallByName Num.19 List.391 List.455;
|
||||
jump List.449 List.388 List.452 List.390 List.454 List.392;
|
||||
procedure List.91 (List.544, List.545, List.546, List.547, List.548):
|
||||
joinpoint List.518 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.520 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.520 then
|
||||
let List.527 : Str = CallByName List.66 List.429 List.432;
|
||||
let List.521 : {List U8, U64} = CallByName List.138 List.430 List.527 List.431;
|
||||
let List.524 : U64 = 1i64;
|
||||
let List.523 : U64 = CallByName Num.19 List.432 List.524;
|
||||
jump List.518 List.429 List.521 List.431 List.523 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.449 List.475 List.476 List.477 List.478 List.479;
|
||||
jump List.518 List.544 List.545 List.546 List.547 List.548;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.265 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -47,148 +47,148 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.126 (Json.127, Json.397, #Attr.12):
|
||||
procedure Json.126 (Json.127, Json.399, #Attr.12):
|
||||
let Json.125 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.125;
|
||||
let Json.124 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.124;
|
||||
dec #Attr.12;
|
||||
let Json.435 : I64 = 123i64;
|
||||
let Json.437 : I64 = 123i64;
|
||||
let Json.436 : U8 = CallByName Num.125 Json.437;
|
||||
let Json.433 : List U8 = CallByName List.4 Json.127 Json.436;
|
||||
let Json.435 : I64 = 34i64;
|
||||
let Json.434 : U8 = CallByName Num.125 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.127 Json.434;
|
||||
let Json.433 : I64 = 34i64;
|
||||
let Json.432 : U8 = CallByName Num.125 Json.433;
|
||||
let Json.429 : List U8 = CallByName List.4 Json.431 Json.432;
|
||||
let Json.430 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.426 : List U8 = CallByName List.8 Json.429 Json.430;
|
||||
let Json.428 : I64 = 34i64;
|
||||
let Json.427 : U8 = CallByName Num.125 Json.428;
|
||||
let Json.423 : List U8 = CallByName List.4 Json.426 Json.427;
|
||||
let Json.425 : I64 = 58i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 91i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : U64 = CallByName List.6 Json.125;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.129, Json.419};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.125 Json.407 Json.408;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.433 Json.434;
|
||||
let Json.432 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.428 : List U8 = CallByName List.8 Json.431 Json.432;
|
||||
let Json.430 : I64 = 34i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.425 : List U8 = CallByName List.4 Json.428 Json.429;
|
||||
let Json.427 : I64 = 58i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.422 : List U8 = CallByName List.4 Json.425 Json.426;
|
||||
let Json.424 : I64 = 91i64;
|
||||
let Json.423 : U8 = CallByName Num.125 Json.424;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.422 Json.423;
|
||||
let Json.421 : U64 = CallByName List.6 Json.125;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.129, Json.421};
|
||||
let Json.410 : {} = Struct {};
|
||||
let Json.408 : {List U8, U64} = CallByName List.18 Json.125 Json.409 Json.410;
|
||||
dec Json.125;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.406;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.408;
|
||||
inc Json.131;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 93i64;
|
||||
dec Json.408;
|
||||
let Json.407 : I64 = 93i64;
|
||||
let Json.406 : U8 = CallByName Num.125 Json.407;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.131 Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.131 Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.400 : List U8 = CallByName List.4 Json.401 Json.402;
|
||||
ret Json.400;
|
||||
let Json.402 : List U8 = CallByName List.4 Json.403 Json.404;
|
||||
ret Json.402;
|
||||
|
||||
procedure Json.128 (Json.399, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.399;
|
||||
procedure Json.128 (Json.401, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.132;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.418 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.418;
|
||||
joinpoint Json.413 Json.136:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.133 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.136, Json.410};
|
||||
ret Json.409;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.420 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.420;
|
||||
joinpoint Json.415 Json.136:
|
||||
let Json.413 : U64 = 1i64;
|
||||
let Json.412 : U64 = CallByName Num.20 Json.133 Json.413;
|
||||
let Json.411 : {List U8, U64} = Struct {Json.136, Json.412};
|
||||
ret Json.411;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.133 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.135 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.419 : U64 = 1i64;
|
||||
let Json.416 : Int1 = CallByName Num.24 Json.133 Json.419;
|
||||
if Json.416 then
|
||||
let Json.418 : I64 = 44i64;
|
||||
let Json.417 : U8 = CallByName Num.125 Json.418;
|
||||
let Json.414 : List U8 = CallByName List.4 Json.135 Json.417;
|
||||
jump Json.415 Json.414;
|
||||
else
|
||||
jump Json.413 Json.135;
|
||||
jump Json.415 Json.135;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.448 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.448;
|
||||
let Json.450 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.450;
|
||||
|
||||
procedure Json.21 (Json.124, Json.125):
|
||||
let Json.396 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.395 : {Str, List Str} = CallByName Encode.22 Json.396;
|
||||
ret Json.395;
|
||||
let Json.398 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.397 : {Str, List Str} = CallByName Encode.22 Json.398;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.438, Json.95):
|
||||
let Json.447 : I64 = 34i64;
|
||||
let Json.446 : U8 = CallByName Num.125 Json.447;
|
||||
let Json.444 : List U8 = CallByName List.4 Json.97 Json.446;
|
||||
let Json.445 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.441 : List U8 = CallByName List.8 Json.444 Json.445;
|
||||
let Json.443 : I64 = 34i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.440 : List U8 = CallByName List.4 Json.441 Json.442;
|
||||
ret Json.440;
|
||||
procedure Json.96 (Json.97, Json.440, Json.95):
|
||||
let Json.449 : I64 = 34i64;
|
||||
let Json.448 : U8 = CallByName Num.125 Json.449;
|
||||
let Json.446 : List U8 = CallByName List.4 Json.97 Json.448;
|
||||
let Json.447 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.443 : List U8 = CallByName List.8 Json.446 Json.447;
|
||||
let Json.445 : I64 = 34i64;
|
||||
let Json.444 : U8 = CallByName Num.125 Json.445;
|
||||
let Json.442 : List U8 = CallByName List.4 Json.443 Json.444;
|
||||
ret Json.442;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.462 : {List U8, U64} = CallByName Json.128 List.138 List.139;
|
||||
ret List.462;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.531 : {List U8, U64} = CallByName Json.128 List.139 List.140;
|
||||
ret List.531;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.443 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.443;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.512 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.512;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.442 : U64 = 1i64;
|
||||
let List.441 : List U8 = CallByName List.70 List.105 List.442;
|
||||
let List.440 : List U8 = CallByName List.71 List.441 List.106;
|
||||
ret List.440;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.511 : U64 = 1i64;
|
||||
let List.510 : List U8 = CallByName List.70 List.106 List.511;
|
||||
let List.509 : List U8 = CallByName List.71 List.510 List.107;
|
||||
ret List.509;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.463 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.463;
|
||||
let List.532 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.532;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.459 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.459;
|
||||
let List.528 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.528;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.465 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.465;
|
||||
let List.534 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.534;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.447 : U64 = 0i64;
|
||||
let List.448 : U64 = CallByName List.6 List.385;
|
||||
let List.446 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.447 List.448;
|
||||
ret List.446;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.516 : U64 = 0i64;
|
||||
let List.517 : U64 = CallByName List.6 List.426;
|
||||
let List.515 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.516 List.517;
|
||||
ret List.515;
|
||||
|
||||
procedure List.90 (List.475, List.476, List.477, List.478, List.479):
|
||||
joinpoint List.449 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.451 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.451 then
|
||||
let List.458 : Str = CallByName List.66 List.388 List.391;
|
||||
let List.452 : {List U8, U64} = CallByName List.137 List.389 List.458 List.390;
|
||||
let List.455 : U64 = 1i64;
|
||||
let List.454 : U64 = CallByName Num.19 List.391 List.455;
|
||||
jump List.449 List.388 List.452 List.390 List.454 List.392;
|
||||
procedure List.91 (List.544, List.545, List.546, List.547, List.548):
|
||||
joinpoint List.518 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.520 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.520 then
|
||||
let List.527 : Str = CallByName List.66 List.429 List.432;
|
||||
let List.521 : {List U8, U64} = CallByName List.138 List.430 List.527 List.431;
|
||||
let List.524 : U64 = 1i64;
|
||||
let List.523 : U64 = CallByName Num.19 List.432 List.524;
|
||||
jump List.518 List.429 List.521 List.431 List.523 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.449 List.475 List.476 List.477 List.478 List.479;
|
||||
jump List.518 List.544 List.545 List.546 List.547 List.548;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.265 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.258 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -6,40 +6,40 @@ procedure Bool.2 ():
|
|||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
|
||||
procedure List.2 (List.94, List.95):
|
||||
let List.423 : U64 = CallByName List.6 List.94;
|
||||
let List.419 : Int1 = CallByName Num.22 List.95 List.423;
|
||||
if List.419 then
|
||||
let List.421 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.420 : [C {}, C I64] = TagId(1) List.421;
|
||||
ret List.420;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.492 : U64 = CallByName List.6 List.95;
|
||||
let List.488 : Int1 = CallByName Num.22 List.96 List.492;
|
||||
if List.488 then
|
||||
let List.490 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.489 : [C {}, C I64] = TagId(1) List.490;
|
||||
ret List.489;
|
||||
else
|
||||
let List.418 : {} = Struct {};
|
||||
let List.417 : [C {}, C I64] = TagId(0) List.418;
|
||||
ret List.417;
|
||||
let List.487 : {} = Struct {};
|
||||
let List.486 : [C {}, C I64] = TagId(0) List.487;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.424 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.424;
|
||||
let List.493 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.493;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.422 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.422;
|
||||
let List.491 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.491;
|
||||
|
||||
procedure List.9 (List.242):
|
||||
let List.416 : U64 = 0i64;
|
||||
let List.409 : [C {}, C I64] = CallByName List.2 List.242 List.416;
|
||||
let List.413 : U8 = 1i64;
|
||||
let List.414 : U8 = GetTagId List.409;
|
||||
let List.415 : Int1 = lowlevel Eq List.413 List.414;
|
||||
if List.415 then
|
||||
let List.243 : I64 = UnionAtIndex (Id 1) (Index 0) List.409;
|
||||
let List.410 : [C Int1, C I64] = TagId(1) List.243;
|
||||
ret List.410;
|
||||
procedure List.9 (List.283):
|
||||
let List.485 : U64 = 0i64;
|
||||
let List.478 : [C {}, C I64] = CallByName List.2 List.283 List.485;
|
||||
let List.482 : U8 = 1i64;
|
||||
let List.483 : U8 = GetTagId List.478;
|
||||
let List.484 : Int1 = lowlevel Eq List.482 List.483;
|
||||
if List.484 then
|
||||
let List.284 : I64 = UnionAtIndex (Id 1) (Index 0) List.478;
|
||||
let List.479 : [C Int1, C I64] = TagId(1) List.284;
|
||||
ret List.479;
|
||||
else
|
||||
let List.412 : Int1 = true;
|
||||
let List.411 : [C Int1, C I64] = TagId(0) List.412;
|
||||
ret List.411;
|
||||
let List.481 : Int1 = true;
|
||||
let List.480 : [C Int1, C I64] = TagId(0) List.481;
|
||||
ret List.480;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
14
crates/compiler/test_mono/generated/issue_4705.txt
Normal file
14
crates/compiler/test_mono/generated/issue_4705.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Test.0 (Test.4):
|
||||
let Test.7 : Int1 = CallByName Bool.2;
|
||||
ret Test.7;
|
||||
|
||||
procedure Test.3 ():
|
||||
let Test.1 : {} = Struct {};
|
||||
let Test.2 : Int1 = CallByName Test.0 Test.1;
|
||||
expect Test.2;
|
||||
let Test.5 : {} = Struct {};
|
||||
ret Test.5;
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List I64 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List I64 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.481 : U64 = 1i64;
|
||||
let List.479 : List I64 = CallByName List.70 List.106 List.481;
|
||||
let List.478 : List I64 = CallByName List.71 List.479 List.107;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.413 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.411 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
let List.480 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List I64 = Array [1i64];
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List I64 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List I64 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.481 : U64 = 1i64;
|
||||
let List.479 : List I64 = CallByName List.70 List.106 List.481;
|
||||
let List.478 : List I64 = CallByName List.71 List.479 List.107;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.413 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.411 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
let List.480 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.6 : I64 = 42i64;
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.412 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.411 : List I64 = StructAtIndex 0 List.412;
|
||||
inc List.411;
|
||||
dec List.412;
|
||||
ret List.411;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.481 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.480 : List I64 = StructAtIndex 0 List.481;
|
||||
inc List.480;
|
||||
dec List.481;
|
||||
ret List.480;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.410 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.410;
|
||||
let List.479 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.479;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.417 : U64 = CallByName List.6 List.99;
|
||||
let List.414 : Int1 = CallByName Num.22 List.100 List.417;
|
||||
if List.414 then
|
||||
let List.415 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.415;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.486 : U64 = CallByName List.6 List.100;
|
||||
let List.483 : Int1 = CallByName Num.22 List.101 List.486;
|
||||
if List.483 then
|
||||
let List.484 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.484;
|
||||
else
|
||||
let List.413 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.413;
|
||||
let List.482 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.482;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.416 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.416;
|
||||
let List.485 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.485;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.256 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C I64] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C I64] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C I64] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C I64] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.410 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.410;
|
||||
let List.479 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.479;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.256 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : Str = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C Str] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : Str = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C Str] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C Str] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C Str] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.417 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
ret List.417;
|
||||
let List.486 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : Str = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C Str] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : Str = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C Str] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C Str] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C Str] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.417 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
let List.486 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.417;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
procedure Test.0 ():
|
||||
let Test.6 : Str = "";
|
||||
let Test.1 : List Str = Array [Test.6];
|
||||
let Test.5 : U64 = lowlevel ListLen Test.1;
|
||||
dec Test.1;
|
||||
switch Test.5:
|
||||
case 0:
|
||||
let Test.2 : Str = "A";
|
||||
ret Test.2;
|
||||
|
||||
case 1:
|
||||
let Test.3 : Str = "B";
|
||||
ret Test.3;
|
||||
|
||||
default:
|
||||
let Test.4 : Str = "C";
|
||||
ret Test.4;
|
||||
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.410 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.409 : List I64 = StructAtIndex 0 List.410;
|
||||
inc List.409;
|
||||
dec List.410;
|
||||
ret List.409;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.479 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.478 : List I64 = StructAtIndex 0 List.479;
|
||||
inc List.478;
|
||||
dec List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.415 : U64 = CallByName List.6 List.99;
|
||||
let List.412 : Int1 = CallByName Num.22 List.100 List.415;
|
||||
if List.412 then
|
||||
let List.413 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.413;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.484 : U64 = CallByName List.6 List.100;
|
||||
let List.481 : Int1 = CallByName Num.22 List.101 List.484;
|
||||
if List.481 then
|
||||
let List.482 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.482;
|
||||
else
|
||||
let List.411 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.411;
|
||||
let List.480 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.480;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.414 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.414;
|
||||
let List.483 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.28 (#Attr.2, #Attr.3):
|
||||
let List.411 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let List.480 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let #Derived_gen.0 : Int1 = lowlevel ListIsUnique #Attr.2;
|
||||
if #Derived_gen.0 then
|
||||
ret List.411;
|
||||
ret List.480;
|
||||
else
|
||||
decref #Attr.2;
|
||||
ret List.411;
|
||||
ret List.480;
|
||||
|
||||
procedure List.59 (List.237):
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : List I64 = CallByName List.28 List.237 List.410;
|
||||
ret List.409;
|
||||
procedure List.59 (List.278):
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : List I64 = CallByName List.28 List.278 List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure Num.46 (#Attr.2, #Attr.3):
|
||||
let Num.256 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,52 +1,49 @@
|
|||
procedure Test.0 ():
|
||||
let Test.36 : Int1 = false;
|
||||
let Test.37 : Int1 = true;
|
||||
let Test.1 : List Int1 = Array [Test.36, Test.37];
|
||||
joinpoint Test.10:
|
||||
let Test.31 : Int1 = false;
|
||||
let Test.32 : Int1 = true;
|
||||
let Test.1 : List Int1 = Array [Test.31, Test.32];
|
||||
joinpoint Test.9:
|
||||
let Test.8 : Str = "E";
|
||||
ret Test.8;
|
||||
in
|
||||
joinpoint Test.9:
|
||||
let Test.5 : Str = "B";
|
||||
ret Test.5;
|
||||
in
|
||||
let Test.33 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.34 : U64 = 0i64;
|
||||
let Test.35 : Int1 = lowlevel Eq Test.33 Test.34;
|
||||
if Test.35 then
|
||||
let Test.28 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.29 : U64 = 0i64;
|
||||
let Test.30 : Int1 = lowlevel Eq Test.28 Test.29;
|
||||
if Test.30 then
|
||||
dec Test.1;
|
||||
let Test.4 : Str = "A";
|
||||
ret Test.4;
|
||||
else
|
||||
let Test.30 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.31 : U64 = 1i64;
|
||||
let Test.32 : Int1 = lowlevel Eq Test.30 Test.31;
|
||||
if Test.32 then
|
||||
let Test.11 : U64 = 0i64;
|
||||
let Test.12 : Int1 = lowlevel ListGetUnsafe Test.1 Test.11;
|
||||
let Test.25 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.26 : U64 = 1i64;
|
||||
let Test.27 : Int1 = lowlevel Eq Test.25 Test.26;
|
||||
if Test.27 then
|
||||
let Test.10 : U64 = 0i64;
|
||||
let Test.11 : Int1 = lowlevel ListGetUnsafe Test.1 Test.10;
|
||||
dec Test.1;
|
||||
let Test.13 : Int1 = false;
|
||||
let Test.14 : Int1 = lowlevel Eq Test.13 Test.12;
|
||||
if Test.14 then
|
||||
jump Test.9;
|
||||
let Test.12 : Int1 = false;
|
||||
let Test.13 : Int1 = lowlevel Eq Test.12 Test.11;
|
||||
if Test.13 then
|
||||
let Test.5 : Str = "B";
|
||||
ret Test.5;
|
||||
else
|
||||
jump Test.10;
|
||||
jump Test.9;
|
||||
else
|
||||
let Test.27 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.28 : U64 = 2i64;
|
||||
let Test.29 : Int1 = lowlevel NumGte Test.27 Test.28;
|
||||
if Test.29 then
|
||||
let Test.19 : U64 = 0i64;
|
||||
let Test.20 : Int1 = lowlevel ListGetUnsafe Test.1 Test.19;
|
||||
let Test.21 : Int1 = false;
|
||||
let Test.22 : Int1 = lowlevel Eq Test.21 Test.20;
|
||||
if Test.22 then
|
||||
let Test.15 : U64 = 1i64;
|
||||
let Test.16 : Int1 = lowlevel ListGetUnsafe Test.1 Test.15;
|
||||
let Test.22 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.23 : U64 = 2i64;
|
||||
let Test.24 : Int1 = lowlevel NumGte Test.22 Test.23;
|
||||
if Test.24 then
|
||||
let Test.18 : U64 = 0i64;
|
||||
let Test.19 : Int1 = lowlevel ListGetUnsafe Test.1 Test.18;
|
||||
let Test.20 : Int1 = false;
|
||||
let Test.21 : Int1 = lowlevel Eq Test.20 Test.19;
|
||||
if Test.21 then
|
||||
let Test.14 : U64 = 1i64;
|
||||
let Test.15 : Int1 = lowlevel ListGetUnsafe Test.1 Test.14;
|
||||
dec Test.1;
|
||||
let Test.17 : Int1 = false;
|
||||
let Test.18 : Int1 = lowlevel Eq Test.17 Test.16;
|
||||
if Test.18 then
|
||||
let Test.16 : Int1 = false;
|
||||
let Test.17 : Int1 = lowlevel Eq Test.16 Test.15;
|
||||
if Test.17 then
|
||||
let Test.6 : Str = "C";
|
||||
ret Test.6;
|
||||
else
|
||||
|
@ -54,14 +51,7 @@ procedure Test.0 ():
|
|||
ret Test.7;
|
||||
else
|
||||
dec Test.1;
|
||||
jump Test.10;
|
||||
else
|
||||
let Test.23 : U64 = 0i64;
|
||||
let Test.24 : Int1 = lowlevel ListGetUnsafe Test.1 Test.23;
|
||||
dec Test.1;
|
||||
let Test.25 : Int1 = false;
|
||||
let Test.26 : Int1 = lowlevel Eq Test.25 Test.24;
|
||||
if Test.26 then
|
||||
jump Test.9;
|
||||
else
|
||||
jump Test.10;
|
||||
else
|
||||
dec Test.1;
|
||||
jump Test.9;
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.431 : U64 = CallByName List.6 List.94;
|
||||
let List.428 : Int1 = CallByName Num.22 List.95 List.431;
|
||||
if List.428 then
|
||||
let List.430 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.429 : [C {}, C I64] = TagId(1) List.430;
|
||||
ret List.429;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.500 : U64 = CallByName List.6 List.95;
|
||||
let List.497 : Int1 = CallByName Num.22 List.96 List.500;
|
||||
if List.497 then
|
||||
let List.499 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.498 : [C {}, C I64] = TagId(1) List.499;
|
||||
ret List.498;
|
||||
else
|
||||
let List.427 : {} = Struct {};
|
||||
let List.426 : [C {}, C I64] = TagId(0) List.427;
|
||||
ret List.426;
|
||||
let List.496 : {} = Struct {};
|
||||
let List.495 : [C {}, C I64] = TagId(0) List.496;
|
||||
ret List.495;
|
||||
|
||||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.418 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.417 : List I64 = StructAtIndex 0 List.418;
|
||||
inc List.417;
|
||||
dec List.418;
|
||||
ret List.417;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.487 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.486 : List I64 = StructAtIndex 0 List.487;
|
||||
inc List.486;
|
||||
dec List.487;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.415 : U64 = CallByName List.6 List.99;
|
||||
let List.412 : Int1 = CallByName Num.22 List.100 List.415;
|
||||
if List.412 then
|
||||
let List.413 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.413;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.484 : U64 = CallByName List.6 List.100;
|
||||
let List.481 : Int1 = CallByName Num.22 List.101 List.484;
|
||||
if List.481 then
|
||||
let List.482 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.482;
|
||||
else
|
||||
let List.411 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.411;
|
||||
let List.480 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.480;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.424 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.424;
|
||||
let List.493 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.493;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.414 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.414;
|
||||
let List.483 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.258 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.431 : U64 = CallByName List.6 List.94;
|
||||
let List.428 : Int1 = CallByName Num.22 List.95 List.431;
|
||||
if List.428 then
|
||||
let List.430 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.429 : [C {}, C I64] = TagId(1) List.430;
|
||||
ret List.429;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.500 : U64 = CallByName List.6 List.95;
|
||||
let List.497 : Int1 = CallByName Num.22 List.96 List.500;
|
||||
if List.497 then
|
||||
let List.499 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.498 : [C {}, C I64] = TagId(1) List.499;
|
||||
ret List.498;
|
||||
else
|
||||
let List.427 : {} = Struct {};
|
||||
let List.426 : [C {}, C I64] = TagId(0) List.427;
|
||||
ret List.426;
|
||||
let List.496 : {} = Struct {};
|
||||
let List.495 : [C {}, C I64] = TagId(0) List.496;
|
||||
ret List.495;
|
||||
|
||||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.418 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.417 : List I64 = StructAtIndex 0 List.418;
|
||||
inc List.417;
|
||||
dec List.418;
|
||||
ret List.417;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.487 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.486 : List I64 = StructAtIndex 0 List.487;
|
||||
inc List.486;
|
||||
dec List.487;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.415 : U64 = CallByName List.6 List.99;
|
||||
let List.412 : Int1 = CallByName Num.22 List.100 List.415;
|
||||
if List.412 then
|
||||
let List.413 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.413;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.484 : U64 = CallByName List.6 List.100;
|
||||
let List.481 : Int1 = CallByName Num.22 List.101 List.484;
|
||||
if List.481 then
|
||||
let List.482 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.482;
|
||||
else
|
||||
let List.411 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.411;
|
||||
let List.480 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.480;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.424 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.424;
|
||||
let List.493 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.493;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.414 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.414;
|
||||
let List.483 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.258 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -13,10 +13,13 @@ extern crate indoc;
|
|||
#[allow(dead_code)]
|
||||
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_load::ExecutionMode;
|
||||
use roc_load::LoadConfig;
|
||||
use roc_load::LoadMonomorphizedError;
|
||||
use roc_load::Threading;
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::Proc;
|
||||
use roc_mono::ir::ProcLayout;
|
||||
|
@ -73,11 +76,16 @@ fn promote_expr_to_module(src: &str) -> String {
|
|||
buffer
|
||||
}
|
||||
|
||||
fn compiles_to_ir(test_name: &str, src: &str) {
|
||||
use bumpalo::Bump;
|
||||
fn compiles_to_ir(test_name: &str, src: &str, mode: &str, no_check: bool) {
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let exec_mode = match mode {
|
||||
"exec" => ExecutionMode::Executable,
|
||||
"test" => ExecutionMode::Test,
|
||||
_ => panic!("Invalid test_mono exec mode {mode}"),
|
||||
};
|
||||
|
||||
let arena = &Bump::new();
|
||||
|
||||
let filename = PathBuf::from("Test.roc");
|
||||
|
@ -85,7 +93,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
|
||||
let module_src;
|
||||
let temp;
|
||||
if src.starts_with("app") {
|
||||
if src.starts_with("app") || src.starts_with("interface") {
|
||||
// this is already a module
|
||||
module_src = src;
|
||||
} else {
|
||||
|
@ -99,7 +107,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
threading: Threading::Single,
|
||||
render: roc_reporting::report::RenderTarget::Generic,
|
||||
palette: roc_reporting::report::DEFAULT_PALETTE,
|
||||
exec_mode: ExecutionMode::Executable,
|
||||
exec_mode,
|
||||
};
|
||||
let loaded = roc_load::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
|
@ -113,7 +121,9 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
|
||||
let mut loaded = match loaded {
|
||||
Ok(x) => x,
|
||||
Err(roc_load::LoadingProblem::FormattedReport(report)) => {
|
||||
Err(LoadMonomorphizedError::LoadingProblem(roc_load::LoadingProblem::FormattedReport(
|
||||
report,
|
||||
))) => {
|
||||
println!("{}", report);
|
||||
panic!();
|
||||
}
|
||||
|
@ -126,6 +136,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
procedures,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
interns,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
|
@ -138,33 +149,54 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
|
||||
assert!(type_problems.is_empty());
|
||||
|
||||
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||
let main_fn_symbol = exposed_to_host.values.keys().copied().next();
|
||||
|
||||
let main_fn_symbol = exposed_to_host.values.keys().copied().next().unwrap();
|
||||
if !no_check {
|
||||
check_procedures(arena, &interns, &layout_interner, &procedures);
|
||||
}
|
||||
|
||||
verify_procedures(test_name, layout_interner, procedures, main_fn_symbol);
|
||||
}
|
||||
|
||||
fn check_procedures<'a>(
|
||||
arena: &'a Bump,
|
||||
interns: &Interns,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
procedures: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) {
|
||||
use roc_mono::debug::{check_procs, format_problems};
|
||||
let problems = check_procs(arena, interner, procedures);
|
||||
if problems.is_empty() {
|
||||
return;
|
||||
}
|
||||
let formatted = format_problems(interns, interner, problems);
|
||||
panic!("IR problems found:\n{formatted}");
|
||||
}
|
||||
|
||||
fn verify_procedures<'a>(
|
||||
test_name: &str,
|
||||
interner: STLayoutInterner<'a>,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
main_fn_symbol: Symbol,
|
||||
opt_main_fn_symbol: Option<Symbol>,
|
||||
) {
|
||||
let index = procedures
|
||||
.keys()
|
||||
.position(|(s, _)| *s == main_fn_symbol)
|
||||
.unwrap();
|
||||
|
||||
let mut procs_string = procedures
|
||||
.values()
|
||||
.map(|proc| proc.to_pretty(&interner, 200))
|
||||
.map(|proc| proc.to_pretty(&interner, 200, false))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let main_fn = procs_string.swap_remove(index);
|
||||
let opt_main_fn = opt_main_fn_symbol.map(|main_fn_symbol| {
|
||||
let index = procedures
|
||||
.keys()
|
||||
.position(|(s, _)| *s == main_fn_symbol)
|
||||
.unwrap();
|
||||
procs_string.swap_remove(index)
|
||||
});
|
||||
|
||||
procs_string.sort();
|
||||
procs_string.push(main_fn);
|
||||
|
||||
if let Some(main_fn) = opt_main_fn {
|
||||
procs_string.push(main_fn);
|
||||
}
|
||||
|
||||
let result = procs_string.join("\n");
|
||||
|
||||
|
@ -561,7 +593,7 @@ fn record_optional_field_function_use_default() {
|
|||
"#
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[mono_test(no_check)]
|
||||
fn quicksort_help() {
|
||||
// do we still need with_larger_debug_stack?
|
||||
r#"
|
||||
|
@ -1279,7 +1311,7 @@ fn issue_2583_specialize_errors_behind_unified_branches() {
|
|||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[mono_test(no_check)]
|
||||
fn issue_2810() {
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -2096,3 +2128,34 @@ fn toplevel_accessor_fn_thunk() {
|
|||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn list_one_vs_one_spread_issue_4685() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main = when [""] is
|
||||
[] -> "A"
|
||||
[_] -> "B"
|
||||
[_, ..] -> "C"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test(mode = "test")]
|
||||
fn issue_4705() {
|
||||
indoc!(
|
||||
r###"
|
||||
interface Test exposes [] imports []
|
||||
|
||||
go : {} -> Bool
|
||||
go = \{} -> Bool.true
|
||||
|
||||
expect
|
||||
input = {}
|
||||
x = go input
|
||||
x
|
||||
"###
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,26 @@ use proc_macro::TokenStream;
|
|||
use quote::quote;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn mono_test(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pub fn mono_test(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let mut no_check = false;
|
||||
let mut mode = "exec".to_owned();
|
||||
for arg in syn::parse_macro_input!(args as syn::AttributeArgs) {
|
||||
use syn::{Lit, Meta, MetaNameValue, NestedMeta};
|
||||
if matches!(&arg, NestedMeta::Meta(Meta::Path(p)) if p.is_ident("no_check")) {
|
||||
no_check = true;
|
||||
}
|
||||
if let NestedMeta::Meta(Meta::NameValue(MetaNameValue {
|
||||
path,
|
||||
eq_token: _,
|
||||
lit: Lit::Str(s),
|
||||
})) = arg
|
||||
{
|
||||
if path.is_ident("mode") {
|
||||
mode = s.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let task_fn = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
|
||||
let args = task_fn.sig.inputs.clone();
|
||||
|
@ -21,7 +40,7 @@ pub fn mono_test(_args: TokenStream, item: TokenStream) -> TokenStream {
|
|||
#[test]
|
||||
#(#attributes)*
|
||||
#visibility fn #name(#args) {
|
||||
compiles_to_ir(#name_str, #body);
|
||||
compiles_to_ir(#name_str, #body, &#mode, #no_check);
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4339,8 +4339,12 @@ impl StorageSubs {
|
|||
match content {
|
||||
FlexVar(opt_name) => FlexVar(*opt_name),
|
||||
RigidVar(name) => RigidVar(*name),
|
||||
FlexAbleVar(opt_name, ability) => FlexAbleVar(*opt_name, *ability),
|
||||
RigidAbleVar(name, ability) => RigidAbleVar(*name, *ability),
|
||||
FlexAbleVar(opt_name, abilities) => {
|
||||
FlexAbleVar(*opt_name, Self::offset_ability_slice(offsets, *abilities))
|
||||
}
|
||||
RigidAbleVar(name, abilities) => {
|
||||
RigidAbleVar(*name, Self::offset_ability_slice(offsets, *abilities))
|
||||
}
|
||||
RecursionVar {
|
||||
structure,
|
||||
opt_name,
|
||||
|
@ -4387,6 +4391,15 @@ impl StorageSubs {
|
|||
union_tags
|
||||
}
|
||||
|
||||
fn offset_ability_slice(
|
||||
offsets: &StorageSubsOffsets,
|
||||
mut ability_names: SubsSlice<Symbol>,
|
||||
) -> SubsSlice<Symbol> {
|
||||
ability_names.start += offsets.symbol_names;
|
||||
|
||||
ability_names
|
||||
}
|
||||
|
||||
fn offset_lambda_set(
|
||||
offsets: &StorageSubsOffsets,
|
||||
mut union_lambdas: UnionLambdas,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue