elm / compiler

Compiler for Elm, a functional language for reliable webapps.
https://elm-lang.org/
BSD 3-Clause "New" or "Revised" License
7.57k stars 662 forks source link

fails to preduce error message on certain extended record `type alias` argument types #2200

Open lue-bird opened 3 years ago

lue-bird commented 3 years ago

note: Incomplete. These are just some findings while experimenting

When a {type used in an extensible record| ... }

the printed elm error message is interrupted by a haskell error.

Note: https://github.com/elm/compiler/issues/1684 is a meta-issue from 2018 for the lack of kind checking on inference

normal behavior

any : { a | a : () }
any =
    { a = () }

Something is off with the body of the any definition:

    { a = () }
    ^^^^^^^^^^

The body is a record of type:

{ a : () }

But the type annotation on any says it should be:

{ a | a : () }

type argument mismatches

type ExtendedRecord record
    = ExtendedRecord { record | a : () }

number : ExtendedRecord number
number =
    ExtendedRecord { a = () }

unit : ExtendedRecord ()
unit =
    ExtendedRecord { a = () }

also error as expected:

Something is off with the body of the definition:

19|     ExtendedRecord { a = () }
        ^^^^^^^^^^^^^^^^^^^^^^^^^

This ExtendedRecord call produces:

ExtendedRecord {}

But the type annotation says it should be:

ExtendedRec ()

mismatches between record type alias and non-record

type alias ExtendedRecord record =
    { record | field : () }

number : ExtendedRecord number
number =
    ()

unit : ExtendedRecord ()
unit =
    ()

also error as expected:

Something is off with the body of the definition:

10|     ()
        ^^

The body is a unit value:

()

But the type annotation says it should be:

ExtendedRecord number/()

behavior with constrained variables

number : { number | field : () }
number =
    ()

Something is off with the body of the number definition:

11|     ()
        ^^

The body is a unit value:

elm: Used toErrorType on a type that is not well-formed CallStack (from HasCallStack): error, called at compiler/src/Type/Type.hs:541:21 in main:Type.Type

This happens for all constrained variable types (compappend, appendable, comparable, number).

behavior with inferred variables

When using a and { a | field : a } in one function type, calling that function with bad typed arguments leads to elm running into an error trying to produce an error message.

changeNothing : a -> { a | a : a } -> { a | a : a }
changeNothing _ a =
    a

breaks =
    changeNothing () {}

The code in breaks is incorrect but when elm tries to tell us, it fails with

elm: Used toErrorType on a type that is not well-formed CallStack (from HasCallStack): error, called at compiler/src/Type/Type.hs:541:21 in main:Type.Type

a seems to be inferred as a : (), breaking the extensible record type.

behavior with type and type alias

type alias

Problematic is the following:

unit : ExtendedRecord ()
unit =
    {}

where the value is any record and the ExtendedRecord argument is constrained, inferred to or any non-record type. This sub-issue is covered in

type arguments

type ExtendedRecord number =
    ExtendedRecord { number | a : () }

number : ExtendedRecord number
number =
    ExtendedRecord ()

The 1st argument to ExtendedRecord is not what I expect:

10|     ExtendedRecord ()
                       ^^

This argument is a unit value:

elm: Used toErrorType on a type that is not well-formed CallStack (from HasCallStack): error, called at compiler/src/Type/Type.hs:541:21 in main:Type.Type

additional details

github-actions[bot] commented 3 years ago

Thanks for reporting this! To set expectations:

Finally, please be patient with the core team. They are trying their best with limited resources.