allow referencing other parameters in default parameter values
fix #7756 fix #1201 fix #7000 fix #3002 fix #1046
This commit is contained in:
parent
e719f211c6
commit
31651ecd61
10 changed files with 244 additions and 31 deletions
|
|
@ -780,6 +780,43 @@ proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
|
|||
else:
|
||||
result = n
|
||||
|
||||
proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNode =
|
||||
# This takes care of complicated signatures such as:
|
||||
# proc foo(a: int, b = a)
|
||||
# proc bar(a: int, b: int, c = a + b)
|
||||
#
|
||||
# The recursion may confuse you. It performs two duties:
|
||||
#
|
||||
# 1) extracting all referenced params from default expressions
|
||||
# into a let section preceeding the call
|
||||
#
|
||||
# 2) replacing the "references" within the default expression
|
||||
# with these extracted skLet symbols.
|
||||
#
|
||||
# The first duty is carried out directly in the code here, while the second
|
||||
# duty is activated by returning a non-nil value. The caller is responsible
|
||||
# for replacing the input to the function with the returned non-nil value.
|
||||
# (which is the hoisted symbol)
|
||||
if defExpr.kind == nkSym:
|
||||
if defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
|
||||
let paramPos = defExpr.sym.position + 1
|
||||
|
||||
if call[paramPos].kind == nkSym and sfHoisted in call[paramPos].sym.flags:
|
||||
# Already hoisted, we still need to return it in order to replace the
|
||||
# placeholder expression in the default value.
|
||||
return call[paramPos]
|
||||
|
||||
let hoistedVarSym = hoistExpr(letSection,
|
||||
call[paramPos],
|
||||
getIdent(c.graph.cache, genPrefix),
|
||||
c.transCon.owner).newSymNode
|
||||
call[paramPos] = hoistedVarSym
|
||||
return hoistedVarSym
|
||||
else:
|
||||
for i in 0..<defExpr.safeLen:
|
||||
let hoisted = hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
|
||||
if hoisted != nil: defExpr[i] = hoisted
|
||||
|
||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
when false:
|
||||
var oldDeferAnchor: PNode
|
||||
|
|
@ -849,6 +886,15 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
of nkBreakStmt: result = transformBreak(c, n)
|
||||
of nkCallKinds:
|
||||
result = transformCall(c, n)
|
||||
var call = result.PNode
|
||||
if nfDefaultRefsParam in call.flags:
|
||||
# We've found a default value that references another param.
|
||||
# See the notes in `hoistParamsUsedInDefault` for more details.
|
||||
var hoistedParams = newNodeI(nkLetSection, call.info, 0)
|
||||
for i in 1 ..< call.len:
|
||||
let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
|
||||
if hoisted != nil: call[i] = hoisted
|
||||
result = newTree(nkStmtListExpr, hoistedParams, call).PTransNode
|
||||
of nkAddr, nkHiddenAddr:
|
||||
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue