roc icon indicating copy to clipboard operation
roc copied to clipboard

Compiler crash with number literal in guard

Open gamebox opened this issue 1 year ago • 7 comments

Full code is here: https://github.com/gamebox/aoc-2024/blob/main/day3/puzzle2/main.roc

@Anton-4 said it was fine to not have a minimal reproduction

I get the following error when running, testing, or building:

thread '<unnamed>' panicked at crates/compiler/mono/src/ir/decision_tree.rs:777:17:
IntLiteral([44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], U8)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

gamebox avatar Dec 03 '24 15:12 gamebox

I checked into this with a little more debugging output and it has something to do with the first two match clauses here:

when (state, char, opState) is
       # ...many more clauses above
        (ExpectingX, d, s) if (d >= '0' && d <= '9') ->
            (muls, BuildingX (Num.toI64 (d - '0')), s)

        (BuildingX num, d, s) if (d >= '0' && d <= '9') && (num < 100) ->
            (muls, BuildingX ((num * 10) + (Num.toI64 (d - '0'))), s)

        (BuildingX num, 44, s) if (num < 1000) ->
            (muls, ExpectingY num, s)

      # more clauses below....

That third match clause is where the issue happens. It looks like it's trying to consider it part of the guard in the clause above. Here's what the start and end for this branch looks like printing using formatted debug (:#?):

Start

[
    (
        [
            TagIndex {
                index: 0,
                tag_id: 0,
            },
        ],
        AppliedTag {
            tag_name: 'BuildingX',
            tag_id: 6,
            arguments: [
                (
                    Identifier(
                        `#UserApp.num`,
                    ),
                    InLayout(I64),
                ),
            ],
            layout: NonRecursive(
                [
                    [],
                    [],
                    [],
                    [],
                    [],
                    [],
                    [
                        InLayout(I64),
                    ],
                    [
                        InLayout(I64),
                        InLayout(I64),
                    ],
                    [],
                    [],
                    [],
                    [],
                    [],
                    [
                        InLayout(I64),
                    ],
                    [],
                ],
            ),
            union: Union {
                alternatives: [
                    Ctor {
                        name: Tag(
                            'BuildingDoOrDontStartD',
                        ),
                        tag_id: TagId(
                            0,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingDoOrDontStartDO',
                        ),
                        tag_id: TagId(
                            1,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingDontStartDON',
                        ),
                        tag_id: TagId(
                            2,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingDontStartDONQ',
                        ),
                        tag_id: TagId(
                            3,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingMulStartM',
                        ),
                        tag_id: TagId(
                            4,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingMulStartMU',
                        ),
                        tag_id: TagId(
                            5,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingX',
                        ),
                        tag_id: TagId(
                            6,
                        ),
                        arity: 1,
                    },
                    Ctor {
                        name: Tag(
                            'BuildingY',
                        ),
                        tag_id: TagId(
                            7,
                        ),
                        arity: 2,
                    },
                    Ctor {
                        name: Tag(
                            'ExpectingDoClose',
                        ),
                        tag_id: TagId(
                            8,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'ExpectingDontClose',
                        ),
                        tag_id: TagId(
                            9,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'ExpectingDontOpen',
                        ),
                        tag_id: TagId(
                            10,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'ExpectingMulOpen',
                        ),
                        tag_id: TagId(
                            11,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'ExpectingX',
                        ),
                        tag_id: TagId(
                            12,
                        ),
                        arity: 0,
                    },
                    Ctor {
                        name: Tag(
                            'ExpectingY',
                        ),
                        tag_id: TagId(
                            13,
                        ),
                        arity: 1,
                    },
                    Ctor {
                        name: Tag(
                            'LookingForOpStart',
                        ),
                        tag_id: TagId(
                            14,
                        ),
                        arity: 0,
                    },
                ],
                render_as: Tag,
            },
        },
    ),
]

The pattern:

IntLiteral([44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], U8)

The end

[
    (
        [
            TagIndex {
                index: 2,
                tag_id: 0,
            },
        ],
        Identifier(
            `#UserApp.s`,
        ),
    ),
]

gamebox avatar Dec 03 '24 20:12 gamebox

The44 number literal in the pattern looks like the desugared version of the ',' char literal in that match clause

gamebox avatar Dec 03 '24 20:12 gamebox

I've done a lot of small syntactic tweaks and this is the only two things that fix it, remove the first guard or the second guard:

        (ExpectingX, d, s) ->
            num = numFromDigit d
            ps = BuildingX num
            (muls, ps, s)

        (BuildingX num, d, s) if (isLessThreeDigits d num) ->
            x = addDigit num d
            ps = BuildingX x
            (muls, ps, s)

        # 44 is ,
        (BuildingX num, 44, s) if (isNoMoreThanThreeDigits num) ->
            ps = ExpectingY num
            (muls, ps, s)
        (ExpectingX, d, s) if (isDigit d) ->
            num = numFromDigit d
            ps = BuildingX num
            (muls, ps, s)

        (BuildingX num, d, s) ->
            x = addDigit num d
            ps = BuildingX x
            (muls, ps, s)

        # 44 is ,
        (BuildingX num, 44, s) if (isNoMoreThanThreeDigits num) ->
            ps = ExpectingY num
            (muls, ps, s)

Having both will fail. I have no idea why...

gamebox avatar Dec 03 '24 21:12 gamebox

Note that I've extracted some guard logic out to functions for readability (and because I thought the char literals were causing issues in the guards)

gamebox avatar Dec 03 '24 21:12 gamebox

This is now fixed on main at the above link. I finally fixed this through some convoluted means of moving all literal matching out into the guards. The issue definitely still exists

gamebox avatar Dec 04 '24 03:12 gamebox

I'd say the issue comes down to a problem with certain literals appearing in patterns when there are also guards on some of the clauses in a when

gamebox avatar Dec 04 '24 03:12 gamebox

Now that I'm a collaborator (thanks Richard!), I'm going to take this on.

gamebox avatar Dec 05 '24 01:12 gamebox