roc-lang / roc

A fast, friendly, functional language.
https://roc-lang.org
Universal Permissive License v1.0
4.17k stars 294 forks source link

Optional record fields can't be used in two different ways #6423

Open bhansconnect opened 8 months ago

bhansconnect commented 8 months ago

Simple repro, run roc check on this code:

app "helloWorld"
    packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" }
    imports [pf.Stdout]
    provides [main] to pf

add : { a : U64, b ? U64 } -> U64
add = \{ a, b ? 1} -> a + b

main =
    x = add { a : 7, b: 8 }
    y = add { a : 7 }
    Stdout.line "$(Num.toStr x),$(Num.toStr y)"

Some reason, we can use add both with/without the optional field as add { a : 7, b: 8 } and add { a : 7 }.

bhansconnect commented 8 months ago

Error message:

── TYPE MISMATCH in examples/helloWorld.roc ────────────────────────────────────

This 1st argument to add has an unexpected type:

11│      y = add { a : 7 }
                 ^^^^^^^^^

The argument is a record of type:

    { … }

But add needs its 1st argument to be:

    { b : Int Unsigned64, … }

Tip: Looks like the b field is missing.

────────────────────────────────────────────────────────────────────────────────
imclerran commented 8 months ago

In some cases, omitting optional record fields can also cause a compiler panic. Example can be found here

Panic message example:

thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x11\x00\x00\x00\x02\x00\x00\x00\xcbr?\x05\x92\xae\x19\x92"), definition of value binding ValueId(3): expected type '(((), (), ()),)', found type '((),)'', crates/compiler/gen_llvm/src/llvm/build.rs:5761:19
Anton-4 commented 7 months ago

For people looking for a workaround: You can use:

Xml : {
    declaration : [Some Str, None],
    root : Str,
}

Instead of:

Xml : {
    xmlDeclaration ? Str,
    root : Str,
}