Skip to content

Commit 67ad1ae

Browse files
authored
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.
1 parent cfd8f8b commit 67ad1ae

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

compiler/semcall.nim

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,8 +973,14 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
973973
# common case; check the only candidate has the right
974974
# number of generic type parameters:
975975
result = explicitGenericSym(c, n, s, errors, doError)
976-
if doError and result == nil:
977-
notFoundError(c, n, errors)
976+
if result == nil:
977+
if c.inGenericContext > 0:
978+
# same as in semOverloadedCall, make expression untyped,
979+
# may have failed match due to unresolved types
980+
result = semGenericStmt(c, n)
981+
result.typ() = makeTypeFromExpr(c, result.copyTree)
982+
elif doError:
983+
notFoundError(c, n, errors)
978984
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
979985
# choose the generic proc with the proper number of type parameters.
980986
result = newNodeI(a.kind, getCallLineInfo(n))
@@ -984,6 +990,14 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
984990
skFunc, skIterator}:
985991
let x = explicitGenericSym(c, n, candidate, errors, doError)
986992
if x != nil: result.add(x)
993+
elif c.inGenericContext > 0:
994+
# same as in semOverloadedCall, make expression untyped,
995+
# may have failed match due to unresolved types
996+
# any failing match stops building the symchoice for correctness,
997+
# can also make it untyped from the start
998+
result = semGenericStmt(c, n)
999+
result.typ() = makeTypeFromExpr(c, result.copyTree)
1000+
return
9871001
# get rid of nkClosedSymChoice if not ambiguous:
9881002
if result.len == 0:
9891003
result = nil

compiler/semexprs.nim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
18161816
# type parameters: partial generic specialization
18171817
n[0] = semSymGenericInstantiation(c, n[0], s)
18181818
result = maybeInstantiateGeneric(c, n, s, doError = afterOverloading)
1819-
if result != nil:
1819+
if result != nil and
1820+
# leave untyped generic expression alone:
1821+
(result.typ == nil or result.typ.kind != tyFromExpr):
18201822
# check newly created sym/symchoice
18211823
result = semExpr(c, result, flags)
18221824
of skMacro, skTemplate:

tests/proc/texplicitgenerics.nim

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,11 @@ block: # issue #21346
5353
b1(false) # Error: cannot instantiate K; got: <T> but expected: <T>
5454
b2(false) # Builds, on its own
5555
b3(false)
56+
57+
block: # explicit generic with unresolved generic param, https://forum.nim-lang.org/t/12579
58+
var s: seq[string] = @[]
59+
proc MyMedian[T](A: var openArray[T],myCmp : proc(x,y:T):int {.nimcall.} = cmp[T]) : T =
60+
if myCmp(A[0], A[1]) == 0: s.add("1")
61+
var x = [1, 1]
62+
discard MyMedian(x) # emits "1\n"
63+
doAssert s == @["1"]

0 commit comments

Comments
 (0)