erg-lang / erg

A statically typed language compatible with Python
http://erg-lang.org
Apache License 2.0
2.65k stars 55 forks source link

Narrowing down type errors #286

Open mtshiba opened 1 year ago

mtshiba commented 1 year ago

The following code will cause a type error.

f x: (Int, Str, Bool) = None

f((1, "a", "a"))
Error[#1249]: File test.er, line 3, <module>

3 | f((1, "a", "a"))
  :   -------------
  :               |- expected: Tuple([Int, Str, Bool])
  :               `- but found: Tuple([{Nat(1), }, {"a", }, {"a", }])

the type of f::x (the 1st argument) is mismatched

However, it is not often the case that all of the element types of a tuple are wrong, but most often only one or two are wrong. In such cases, the location and wording of the error can be further fleshed out.

like this:

3 | f((1, "a", "a"))
  :            ---
  :               |- expected: Bool
  :               `- but found: {"a", }

the type of f::x.2 (the 3rd element of the 1st argument) is mismatched

This technique can be used for polymorphic types in general, including Record types and subroutine types.

mtshiba commented 5 months ago

For records, detailed hints can now be output. It should be easy to implement similarly for tuples.

>>> r x: { a = Int; b = Str } = None
>>> r { a = 1; b = 2 }

Error[#2193]: File <stdin>, line 1, <module>

1 │ r { a = 1; b = 2 }
  ·   ----------------
  ·                  │─ expected: {::b = Str; ::a = Int}
  ·                  │─ but found: {::b = {2}; ::a = {1}}
  ·                  ╰─ ::b: Str but found {2}

TypeError: the type of r::x (the 1st argument) is mismatched
mtshiba commented 5 months ago

In the above comment I said we should rewrite the entire error message, but now I think it's better to add it as a hint. Like this:

f x: (Int, Str, Bool) = None

f((1, "a", "a"))
Error[#1249]: File test.er, line 3, <module>

3 | f((1, "a", "a"))
  :   -------------
  :               |- expected: Tuple([Int, Str, Bool])
  :               |- but found: Tuple([{1, }, {"a", }, {"a", }])
  :               `- the 3rd elem is type of Bool but found {"a", }

the type of f::x (the 1st argument) is mismatched