Compile Panic While Building
While doing advent of code day 4 I ran into a case where the code typechecks, but compiling/running it results in a lengthy panic.
I'm sorry for the lenth of the example, but I do not know enough about the error to be able to properly reduce it.
Code
app "problem4"
packages { pf: "../roc/examples/cli/cli-platform/main.roc" }
imports [pf.Stdout, pf.Stderr, pf.Path.{ Path }, pf.Program, pf.File, pf.Task.{ Task, await }, Helpers]
provides [main] to pf
updateDict : Dict k v, k, (v -> v) -> Dict k v | k has Eq
updateDict = \dict, key, updateFn ->
dict
|> Dict.get key
|> Result.map (\value -> Dict.insert dict key (updateFn value))
|> Result.withDefault dict
boardSize = 5
Board : Dict U8 { row : Nat, col : Nat }
DrawnNumbers : List U8
parseBoard : Str -> Result Board [InvalidBoard Str]*
parseBoard = \boardStr ->
lines =
boardStr
|> Str.split "\n"
numbers <- lines
|> List.mapTry
(\line ->
line
|> Str.split " "
|> List.dropIf (\elem -> elem == "")
|> List.mapTry Str.toU8
)
|> Result.mapErr (\InvalidNumStr -> InvalidBoard boardStr)
|> Result.try
numbers
|> List.mapWithIndex
(\list, row ->
list
|> List.mapWithIndex
(\value, col ->
{ row, col, value })
)
|> List.join
|> List.walk
Dict.empty
(\dict, { row, col, value } ->
dict
|> Dict.insert value { row, col }
)
|> Ok
playBoard : Board, DrawnNumbers -> Result Nat [BoardDidNotFinish]*
playBoard = \board, drawnNumbers ->
emptyCoords =
List.range 1 boardSize
|> List.walk Dict.empty (\state, index -> Dict.insert state index 0)
initialState = {
cols: emptyCoords,
rows: emptyCoords,
round: 0,
won: Bool.false
}
finalState = drawnNumbers
|> List.walkUntil
initialState
(\state, number ->
newState =
when Dict.get board number is
Ok { row, col } ->
{ state &
cols: updateDict state.cols col (\val -> val + 1),
rows: updateDict state.rows row (\val -> val + 1),
round: state.round + 1,
}
Err _ ->
{ state & round: state.round + 1 }
maxLength =
List.join [Dict.values newState.rows, Dict.values newState.cols]
|> List.max
|> Result.withDefault 0
if maxLength == boardSize then
Break { newState & won: Bool.true }
else
Continue newState
)
if finalState.won then
Ok finalState.round
else
Err BoardDidNotFinish
boardScore : Board, DrawnNumbers -> U16
boardScore = \board, drawnNumbers ->
unchecked =
board
|> Dict.keys
|> List.keepIf (\number -> !(List.contains drawnNumbers number))
|> List.map Num.toU16
|> List.sum
lastDrawn =
List.last drawnNumbers
|> Result.withDefault 0
|> Num.toU16
unchecked * lastDrawn
getResults : List Board, DrawnNumbers -> List {board: Board, turns: Nat}
getResults = \boards, drawnNumbers ->
boards
|> List.keepOks (\board ->
board
|> playBoard drawnNumbers
|> Result.map (\turns -> { board, turns})
)
|> List.sortWith
(\left, right ->
Num.compare left.turns right.turns
)
getWinner : List Board, DrawnNumbers -> Result {board: Board, turns: Nat} [NoBoardsFinished]*
getWinner = \boards, drawnNumbers ->
getResults boards drawnNumbers
|> List.first
|> Result.mapErr (\ListWasEmpty -> NoBoardsFinished)
getLoser : List Board, DrawnNumbers -> Result {board: Board, turns: Nat} [NoBoardsFinished]*
getLoser = \boards, drawnNumbers ->
getResults boards drawnNumbers
|> List.last
|> Result.mapErr (\ListWasEmpty -> NoBoardsFinished)
parseFile : Str -> Result { drawnNumbers : DrawnNumbers, boards : List Board } [InvalidBoard Str, InvalidDrawnNumbers Str, NoDrawnNumbers]*
parseFile = \fileContent ->
blocks =
fileContent
|> Str.split "\n\n"
firstLine <- List.get blocks 0
|> Result.mapErr (\OutOfBounds -> NoDrawnNumbers)
|> Result.try
drawnNumbers <-
Str.split firstLine ","
|> List.mapTry Str.toU8
|> Result.mapErr (\InvalidNumStr -> InvalidDrawnNumbers firstLine)
|> Result.try
boards <-
List.dropFirst blocks
|> List.mapTry parseBoard
|> Result.try
Ok { drawnNumbers, boards }
main =
path = Path.fromStr "./problem4.input"
getWinnerScore = \boards, drawnNumbers ->
{board: winner, turns} <- Result.try (getWinner boards drawnNumbers)
numbers = drawnNumbers
|> List.sublist {start: 0, len: turns}
Ok (boardScore winner numbers)
getLoserScore = \boards, drawnNumbers ->
{board: winner, turns} <- Result.try (getLoser boards drawnNumbers)
numbers = drawnNumbers
|> List.sublist {start: 0, len: turns}
Ok (boardScore winner numbers)
mainTask =
fileContents <- await (File.readUtf8 path)
{boards, drawnNumbers} <- parseFile fileContents
|> Helpers.resultToTask
|> await
winnerScore <- getWinnerScore boards drawnNumbers
|> Result.map Num.toStr
|> Helpers.resultToTask
|> await
loserScore <- getLoserScore boards drawnNumbers
|> Result.map Num.toStr
|> Helpers.resultToTask
|> await
Stdout.line "Winner: \(winnerScore), Loser: \(loserScore)"
errorHandling =
result <- Task.attempt mainTask
when result is
Ok {} ->
Task.succeed {}
Err (InvalidBoard boardStr) ->
Stderr.line "Could not read board:\n\(boardStr)"
Err (InvalidDrawnNumbers numberStr) ->
Stderr.line "Could not read drawn numbers:\n\(numberStr)"
Err NoDrawnNumbers ->
Stderr.line "You need to draw numbers for anyone to win"
Err NoBoardsFinished ->
Stderr.line "No boards finished the bingo"
Err (FileReadErr _ _) | Err (FileReadUtf8Err _ _) ->
Stderr.line "Could not read file"
Program.quick errorHandling
Error
thread 'main' panicked at 'internal error: entered unreachable code: symbol/layout `16.IdentId(53)` ProcLayout {
arguments: [
Struct {
field_order_hash: FieldOrderHash(
11715282875446243786,
),
field_layouts: [
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
I64,
),
),
],
},
),
),
Builtin(
Int(
I64,
),
),
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
I64,
),
),
],
},
),
),
Builtin(
Bool,
),
],
},
Builtin(
Int(
U8,
),
),
LambdaSet(
LambdaSet {
set: [
( 16.53, [Builtin(List(Struct { field_order_hash: FieldOrderHash(1), field_layouts: [Struct { field_order_hash: FieldOrderHash(12820037997967260529), field_layouts: [Builtin(Int(U64)), Builtin(Int(U64))] }, Builtin(Int(U8))] }))]),
],
representation: Interned(
21,
PhantomData,
),
},
),
],
result: Union(
NonRecursive(
[
[
Struct {
field_order_hash: FieldOrderHash(
11715282875446243786,
),
field_layouts: [
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
I64,
),
),
],
},
),
),
Builtin(
Int(
I64,
),
),
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
I64,
),
),
],
},
),
),
Builtin(
Bool,
),
],
},
],
[
Struct {
field_order_hash: FieldOrderHash(
11715282875446243786,
),
field_layouts: [
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
I64,
),
),
],
},
),
),
Builtin(
Int(
I64,
),
),
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
I64,
),
),
],
},
),
),
Builtin(
Bool,
),
],
},
],
],
),
),
captures_niche: CapturesNiche(
[
Builtin(
List(
Struct {
field_order_hash: FieldOrderHash(
1,
),
field_layouts: [
Struct {
field_order_hash: FieldOrderHash(
12820037997967260529,
),
field_layouts: [
Builtin(
Int(
U64,
),
),
Builtin(
Int(
U64,
),
),
],
},
Builtin(
Int(
U8,
),
),
],
},
),
),
],
),
} combo must be in DeclarationToIndex', crates/compiler/mono/src/borrow.rs:165:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Side note: the | k has Eq is a new addition that I had to add after I downloaded the latest nightly, so that's probably not the culprit.
Let's cut this down to a minimal reproduction before attempting to fix the compiler.
@peacememories do you have the source code to Helpers.roc? I think we need that to reproduce this.
Or, if possible, could you check if this still panics on the latest roc?
Candidate for closing because not able to reproduce and no minimal failure case?
Closing as unable to reproduce without Helpers.roc.