There's often macros in packages that affect common things like the division operator or dot operator, and they will completely the had the actual error. I've found this to be a common and tricky problem to deal with as a beginner.
I wonder if in the case of base types such as int32, int64, float32, etc., it should also check for the more generic int and float also when reporting errors?
Here's an example:
import std/monotimes
from times import inNanoseconds
import vmath
let t1 = getMonotime()
let result = 1 + 2
let t2 = getMonotime()
echo "Elapsed: ", (t2 - t1).inNanoseconds / 1_000
In this case the vmath package is implementing vector division, and by default only the first 3-4 signature will be display, so I get:
macroissue.nim(10, 43) Error: type mismatch: got <int64, int literal(1000)>
but expected one of:
proc `/`[T](a`gensym155: T; b`gensym155: GVec2[T]): GVec2[T]
first type mismatch at position: 2
required type for b`gensym155: GVec2[/.T]
but expression '1000' is of type: int literal(1000)
proc `/`[T](a`gensym155: T; b`gensym155: GVec3[T]): GVec3[T]
first type mismatch at position: 2
required type for b`gensym155: GVec3[/.T]
but expression '1000' is of type: int literal(1000)
proc `/`[T](a`gensym155: T; b`gensym155: GVec4[T]): GVec4[T]
first type mismatch at position: 2
required type for b`gensym155: GVec4[/.T]
but expression '1000' is of type: int literal(1000)
9 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
The actual relevant implementations when used --showAllMismatches:no are:
proc `/`(x, y: float): float
first type mismatch at position: 1
required type for x: float
but expression 'inNanoseconds(t2 - t1)' is of type: int64
proc `/`(x, y: float32): float32
first type mismatch at position: 1
required type for x: float32
but expression 'inNanoseconds(t2 - t1)' is of type: int64
proc `/`(x, y: int): float
first type mismatch at position: 1
required type for x: int
but expression 'inNanoseconds(t2 - t1)' is of type: int64
inNanoseconds is returned an int64 instead of an int, so we we're not getting any signature matches which I guess result in it just showing the last 3, which are from the vmath package.
If I force the conversion to int with a float mismatch of 1_000.0:
"Elapsed: ", (t2 - t1).inNanoseconds.int / 1_000.0
we get the relevant (x, y: int): float first followed by the vmath implementations:
proc `/`(x, y: int): float
first type mismatch at position: 2
required type for y: int
but expression '1000.0' is of type: float64
@araq Sorry, I guess it's just a template that overloads / as defined below:
template genOp(op: untyped) =
proc op*[T](a: T, b: GVec4[T]): GVec4[T] =
gvec4[T](
op(a, b[0]),
op(a, b[1]),
op(a, b[2]),
op(a, b[3])
)
# ... others removed for brevity
genOp(`/`)
@planetis std/lenientops That's useful to know about, thanks!
I wasn't really concerned so much with specific example though as the particular sorting of the overload signatures due to the mismatch between int64 and the default available definition that uses int without importing std/lenientops.
I was just wondering if it might be beginner friendly to look for an int definition if int64 is the actual type, for the purpose of error messages.
Because "instantiated from" error messages are not a thing?
><(((°>
The problem IMO is that this error message is bloated and shouldn't be truncated by default.
1/4 lines are "but expression '1000' is of type: int literal(1000)". We already know this from the first line. Another 1/4 are "required type for b`gensym155: GVec2[/.T]" which we know from the signature. Another 1/4 are "first type mismatch at position: 2", which is good information but such a small number doesn't need its own line.
The problem IMO is that this error message is bloated and shouldn't be truncated by default.
Correct.
Good point. What if it looked something like this instead?
...\macroissue\macroissue.nim(10, 43)
Error: type mismatch: got <int64, int literal(1000)>
int64: inNanoseconds(t2 - t1)
int literal(1000): 1000
Expected one of (mismatch at position [#]):
[1] proc `/`[T](a`gensym155, b`gensym155: GVec2[T]): GVec2[T]
[1] proc `/`[T](a`gensym155, b`gensym155: GVec3[T]): GVec3[T]
[1] proc `/`[T](a`gensym155, b`gensym155: GVec4[T]): GVec4[T]
[1] proc `/`[T](a`gensym155: GVec2[T]; b`gensym155: T): GVec2[T]
[1] proc `/`[T](a`gensym155: GVec3[T]; b`gensym155: T): GVec3[T]
[1] proc `/`[T](a`gensym155: GVec4[T]; b`gensym155: T): GVec4[T]
[2] proc `/`[T](a`gensym155: T; b`gensym155: GVec2[T]): GVec2[T]
[2] proc `/`[T](a`gensym155: T; b`gensym155: GVec3[T]): GVec3[T]
[2] proc `/`[T](a`gensym155: T; b`gensym155: GVec4[T]): GVec4[T]
[1] proc `/`(x, y: float): float
[1] proc `/`(x, y: float32): float32
[1] proc `/`(x, y: int): float
All 12 fit into the same space as 4 under the current formatting. Awesome!
I was able to make some local changes to that pull request so that the types of the expression parts that were problematic are included also:
...\overloaderrors.nim(9, 43) Error: type mismatch:
Expression: inNanoseconds(t2 - t1) / 1000
[1] int64 : inNanoseconds(t2 - t1)
[2] int literal(1000) : 1000
Expected one of (mismatch at position [#]):
[1] GVec2[/.T] : proc `/`[T](a`gensym156, b`gensym156: GVec2[T]): GVec2[T]
[1] GVec2[/.T] : proc `/`[T](a`gensym156: GVec2[T]; b`gensym156: T): GVec2[T]
[1] GVec3[/.T] : proc `/`[T](a`gensym156, b`gensym156: GVec3[T]): GVec3[T]
[1] GVec3[/.T] : proc `/`[T](a`gensym156: GVec3[T]; b`gensym156: T): GVec3[T]
[1] GVec4[/.T] : proc `/`[T](a`gensym156, b`gensym156: GVec4[T]): GVec4[T]
[1] GVec4[/.T] : proc `/`[T](a`gensym156: GVec4[T]; b`gensym156: T): GVec4[T]
[1] float : proc `/`(x, y: float): float
[1] float32 : proc `/`(x, y: float32): float32
[1] int : proc `/`(x, y: int): float
[2] GVec2[/.T] : proc `/`[T](a`gensym156: T; b`gensym156: GVec2[T]): GVec2[T]
[2] GVec3[/.T] : proc `/`[T](a`gensym156: T; b`gensym156: GVec3[T]): GVec3[T]
[2] GVec4[/.T] : proc `/`[T](a`gensym156: T; b`gensym156: GVec4[T]): GVec4[T]
So the visual exercise becomes pairing up the [1] or [2]. The mismatched type has been pulled out to immediately follow the [#] which prevents the mental parsing of the type signature, but may be unnecessarily verbose.
Thoughts?
There seems to be support for styled output in .\compiler\msgs.nim, but it's a bit magical and may need some refactoring to use over in .\compiler\semcall.nim. It's currently called through msgs.nim::globalError and ultimately msgs.nim::liMessage, but it's a bit entangled with the core concept of an error I think in terms of the calling conventions.
Anyone have insights?