roc-lang / roc

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

Error without "unnecessary" wildcard #6873

Closed Anton-4 closed 4 months ago

Anton-4 commented 4 months ago

If I remove my "unnecessary wildcard" my code does not work anymore :p

module [foo]

okStr : Str -> Result Str []*
okStr = \str ->
    Ok str

foo =
    Result.try (okStr "aa") \str ->
        Err (MyErr str)

This produces the warning:

$ roc check examples/helloWorld.roc 

── UNNECESSARY WILDCARD in examples/helloWorld.roc ─────────────────────────────

This type annotation has a wildcard type variable (*) that isn't
needed.

3│  okStr : Str -> Result Str []*
                                ^

Annotations for tag unions which are constants, or which are returned
from functions, work the same way with or without a * at the end. (The
* means something different when the tag union is an argument to a
function, though!)

You can safely remove this to make the code more concise without
changing what it means.

────────────────────────────────────────────────────────────────────────────────

0 errors and 1 warning found in 10 ms

If I remove the * in okStr : Str -> Result Str []* I get:

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

This 2nd argument to try has an unexpected type:

8│>      Result.try (okStr "aa") \str ->
9│>          Err (MyErr str)

The argument is an anonymous function of type:

    Str -> [
        Err [MyErr Str],
        Ok b,
    ]

But try needs its 2nd argument to be:

    Str -> Result b []

────────────────────────────────────────────────────────────────────────────────

1 error and 0 warnings found in 10 ms

It appears the Result Str [] is not inferred as Result Str []*, which would be the expected behavior.

Anton-4 commented 4 months ago

Strangely enough the signature okStr : Str -> Result Str [Hey] does not result in a type mismatch.

Anton-4 commented 4 months ago

I've got a possible fix in can/src/annotation.rs:

              /*match ext {
                  Some(_) => {
                      // just `a` does not mean the same as `[]`, so even
                      // if there are no fields, still make this a `TagUnion`,
                      // not an EmptyTagUnion
                      Type::TagUnion(
                          Default::default(),
                          TypeExtension::from_type(ext_type, is_implicit_openness),
                      )
                  }

                  None => Type::EmptyTagUnion,
              }*/

              Type::TagUnion(
                  Default::default(),
                  TypeExtension::from_type(ext_type, is_implicit_openness),
              )

I do now have a failing test tests/exhaustive/extend_uninhabited_without_opening_union.txt, but I may just need to update it, going to talk it through with Folkert tomorrow.