roc icon indicating copy to clipboard operation
roc copied to clipboard

Improve type mismatch error: this need to be `a` but it is `a`

Open Anton-4 opened this issue 1 year ago • 7 comments

interface Foo
    exposes [validFn]
    imports []

invalidFn : {} -> *
invalidFn = \_ -> validFn {} (\_ -> Foo)

validFn : a, (a -> [Foo]) -> a
validFn = \s, toMaybe ->
    h : a -> a
    h = \x ->
        when toMaybe x is
            Foo -> invalidFn {}

    h s

Type mismatch in question:

── TYPE MISMATCH in package/Rocon.roc ──────────────────────────────────────────

This 1st argument to toMaybe has an unexpected type:

12│          when toMaybe x is
                          ^

This x value is a:

    a

But toMaybe needs its 1st argument to be:

    a

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

It's easy to see how this mismatch can confuse users :smile:

Full output:

>   roc test Foo.roc

── TYPE MISMATCH in package/Rocon.roc ──────────────────────────────────────────

This expression is used in an unexpected way:

6│  invalidFn = \_ -> validFn {} (\_ -> Foo)
                      ^^^^^^^^^^^^^^^^^^^^^^

This validFn call produces:

    {}

But you are trying to use it as:

    *

Tip: The type annotation uses the type variable * to say that this
definition can produce any type of value. But in the body I see that
it will only produce a record value of a single specific type. Maybe
change the type annotation to be more specific? Maybe change the code
to be more general?


── TYPE MISMATCH in package/Rocon.roc ──────────────────────────────────────────

This 1st argument to toMaybe has an unexpected type:

12│          when toMaybe x is
                          ^

This x value is a:

    a

But toMaybe needs its 1st argument to be:

    a

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

2 errors and 0 warnings found in 28 ms

Anton-4 avatar Mar 18 '24 17:03 Anton-4

Due to the multiple type mismatches this example is pretty difficult so if we can get a simpler case to investigate that would be great :)

Anton-4 avatar Mar 18 '24 17:03 Anton-4

This might be simpler example:

interface Foo
    exposes [bar]
    imports []

foo : a, (a -> a) -> a
foo = \x, f -> bar x f

bar : a, (a -> a) -> a
bar = \x, f ->
    baz : a
    baz = f x

    foo x f

It fails with just the single error:

── TYPE MISMATCH in Foo.roc ────────────────────────────────────────────────────

Something is off with the body of the baz definition:

10│      baz : a
11│      baz = f x
               ^^^

This f call produces:

    a

But the type annotation on baz says it should be:

    a

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

1 error and 1 warning found in 26 ms

The error goes away after any of the following changes:

  • Remove implementation of baz
  • Remove type annotation of baz
  • Remove type annotation of bar
  • Remove implementation of foo

jwoudenberg avatar Mar 19 '24 13:03 jwoudenberg

Awesome, thanks @jwoudenberg :)

Anton-4 avatar Mar 19 '24 14:03 Anton-4

@Anton-4 are you working on a fix for this? I would like to give it a shot.

eckertliam avatar Mar 22 '24 03:03 eckertliam

No, I've now assigned you to this issue :) Thanks for your help @eckertliam!

Anton-4 avatar Mar 22 '24 10:03 Anton-4

I don't think either of these should actually be type errors. Unless I'm misunderstanding something I think the programs should compile fine. The issue is that a in the type annotation is not used in the inner annotations' a.

ayazhafiz avatar Apr 21 '24 22:04 ayazhafiz

I wonder if we could add a suggestion? maybe it would be possible to detect this somehow and provide a suggestion like "the types are different even though they are have the same name"

Or perhaps there is a way to prevent this kind of issue by making it invalid to use the same type variable in an inner annotation?

lukewilliamboswell avatar Apr 29 '24 11:04 lukewilliamboswell