mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 06:18:51 +00:00
fix standalone explicit generic procs with unresolved arguments (#24404)
fixes issue described in https://forum.nim-lang.org/t/12579
In #24065 explicit generic parameter matching was made to fail matches
on arguments with unresolved types in generic contexts (the sigmatch
diff, following #24010), similar to what is done for regular calls since
#22029. However unlike regular calls, a failed match in a generic
context for a standalone explicit generic instantiation did not convert
the expression into one with `tyFromExpr` type, which means it would
error immediately given any unresolved parameter. This is now done to
fix the issue.
For explicit generic instantiations on single non-overloaded symbols, a
successful match is still instantiated. For multiple overloads (i.e.
symchoice), if any of the overloads fail the match, the entire
expression is considered untyped and any instantiations are not used, so
as to not void overloads that would match later. This means even
symchoices without unresolved arguments aren't instantiated, which may
be too restrictive, but it could also be too lenient and we might need
to make symchoice instantiations always untyped. The behavior for
symchoice is not sound anyway given it causes #9997 so this is something
to consider for a redesign.
Diff follows #24276.
(cherry picked from commit 67ad1ae159)
This commit is contained in:
@@ -973,8 +973,14 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
|
||||
# common case; check the only candidate has the right
|
||||
# number of generic type parameters:
|
||||
result = explicitGenericSym(c, n, s, errors, doError)
|
||||
if doError and result == nil:
|
||||
notFoundError(c, n, errors)
|
||||
if result == nil:
|
||||
if c.inGenericContext > 0:
|
||||
# same as in semOverloadedCall, make expression untyped,
|
||||
# may have failed match due to unresolved types
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
elif doError:
|
||||
notFoundError(c, n, errors)
|
||||
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
|
||||
# choose the generic proc with the proper number of type parameters.
|
||||
result = newNodeI(a.kind, getCallLineInfo(n))
|
||||
@@ -984,6 +990,14 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
|
||||
skFunc, skIterator}:
|
||||
let x = explicitGenericSym(c, n, candidate, errors, doError)
|
||||
if x != nil: result.add(x)
|
||||
elif c.inGenericContext > 0:
|
||||
# same as in semOverloadedCall, make expression untyped,
|
||||
# may have failed match due to unresolved types
|
||||
# any failing match stops building the symchoice for correctness,
|
||||
# can also make it untyped from the start
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
# get rid of nkClosedSymChoice if not ambiguous:
|
||||
if result.len == 0:
|
||||
result = nil
|
||||
|
||||
@@ -1816,7 +1816,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
|
||||
# type parameters: partial generic specialization
|
||||
n[0] = semSymGenericInstantiation(c, n[0], s)
|
||||
result = maybeInstantiateGeneric(c, n, s, doError = afterOverloading)
|
||||
if result != nil:
|
||||
if result != nil and
|
||||
# leave untyped generic expression alone:
|
||||
(result.typ == nil or result.typ.kind != tyFromExpr):
|
||||
# check newly created sym/symchoice
|
||||
result = semExpr(c, result, flags)
|
||||
of skMacro, skTemplate:
|
||||
|
||||
@@ -53,3 +53,11 @@ block: # issue #21346
|
||||
b1(false) # Error: cannot instantiate K; got: <T> but expected: <T>
|
||||
b2(false) # Builds, on its own
|
||||
b3(false)
|
||||
|
||||
block: # explicit generic with unresolved generic param, https://forum.nim-lang.org/t/12579
|
||||
var s: seq[string] = @[]
|
||||
proc MyMedian[T](A: var openArray[T],myCmp : proc(x,y:T):int {.nimcall.} = cmp[T]) : T =
|
||||
if myCmp(A[0], A[1]) == 0: s.add("1")
|
||||
var x = [1, 1]
|
||||
discard MyMedian(x) # emits "1\n"
|
||||
doAssert s == @["1"]
|
||||
|
||||
Reference in New Issue
Block a user