allow untyped arguments to fail to compile in overload mismatch error (#23984)

fixes #8697, fixes #9620, fixes #23265

When matching a `template` with an `untyped` argument fails because of a
mismatching typed argument, `presentFailedCandidates` tries to sem every
single argument to show their types, but trying to type the `untyped`
argument can fail if it's supposed to use an injected symbol, so we get
an unrelated error message like "undeclared identifier".

Instead we use `tryExpr` as the comment suggests, setting the type to
`untyped` if it fails to compile. We could also maybe check if an
`untyped` argument is expected in its place and not try to compile the
expression if it is but this would require a bit of reorganizing the
code here and IMO it's better to have the information of what type it
would be if it can be typed.

(cherry picked from commit 34719cad9d)
This commit is contained in:
metagn
2024-08-20 12:43:11 +03:00
committed by narimiran
parent a78834c26c
commit 7d2fe8086f
2 changed files with 54 additions and 6 deletions

View File

@@ -329,16 +329,27 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
result.add renderTree(n[i][0])
result.add ": "
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
# XXX we really need to 'tryExpr' here!
arg = c.semOperand(c, n[i][1])
n[i].typ = arg.typ
n[i][1] = arg
arg = c.semTryExpr(c, n[i][1])
if arg == nil:
arg = n[i][1]
arg.typ = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
n[i].typ = arg.typ
n[i][1] = arg
else:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
nkOfBranch, nkElifBranch,
nkExceptBranch}:
arg = c.semOperand(c, n[i])
n[i] = arg
arg = c.semTryExpr(c, n[i])
if arg == nil:
arg = n[i]
arg.typ = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
n[i] = arg
if arg.typ != nil and arg.typ.kind == tyError: return
result.add argTypeToString(arg, prefer)

View File

@@ -0,0 +1,37 @@
discard """
cmd: "nim check $file"
"""
block:
template foo(x: var int, y: untyped) = discard
var a: float
foo(a, undeclared) #[tt.Error
^ type mismatch: got <float, untyped>]# # `untyped` is arbitary
# previous error: undeclared identifier: 'undeclared'
block: # issue #8697
type
Fruit = enum
apple
banana
orange
macro hello(x, y: untyped) = discard
hello(apple, banana, orange) #[tt.Error
^ type mismatch: got <Fruit, Fruit, Fruit>]#
block: # issue #23265
template declareFoo(fooName: untyped, value: uint16) =
const `fooName Value` {.inject.} = value
declareFoo(FOO, 0xFFFF)
declareFoo(BAR, 0xFFFFF) #[tt.Error
^ type mismatch: got <untyped, int literal(1048575)>]#
block: # issue #9620
template forLoop(index: untyped, length: int{lvalue}, body: untyped) =
for `index`{.inject.} in 0 ..< length:
body
var x = newSeq[int](10)
forLoop(i, x.len): #[tt.Error
^ type mismatch: got <untyped, int, void>]#
x[i] = i