mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-29 10:01:39 +00:00
Expand hoisted default params in sem (#15270)
* Expand hoisted default params in sem
Introduce ast.newTree{I,IT}
Add test for default params in procs
* Cleanup
* Simplify hoist transformation and expand test
This commit is contained in:
@@ -1556,10 +1556,9 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
|
||||
# nodes?
|
||||
let aOrig = nOrig[0]
|
||||
result = newNode(nkCall, n.info, sons = @[setterId, a[0],
|
||||
semExprWithType(c, n[1])])
|
||||
result = newTreeI(nkCall, n.info, setterId, a[0], semExprWithType(c, n[1]))
|
||||
result.flags.incl nfDotSetter
|
||||
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
|
||||
let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1])
|
||||
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
|
||||
|
||||
if result != nil:
|
||||
@@ -2041,7 +2040,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
|
||||
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
|
||||
ids.add c.graph.emptyNode # no default value
|
||||
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids)
|
||||
|
||||
var tmpl = semTemplateDef(c, dummyTemplate)
|
||||
quotes[0] = tmpl[namePos]
|
||||
@@ -2053,10 +2052,10 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
newIdentNode(getIdent(c.cache, "newIdentNode"), n.info)
|
||||
else:
|
||||
identNodeSym.newSymNode
|
||||
quotes[1] = newNode(nkCall, n.info, @[identNode, newStrNode(nkStrLit, "result")])
|
||||
result = newNode(nkCall, n.info, @[
|
||||
quotes[1] = newTreeI(nkCall, n.info, identNode, newStrNode(nkStrLit, "result"))
|
||||
result = newTreeI(nkCall, n.info,
|
||||
createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
|
||||
newNode(nkCall, n.info, quotes)])
|
||||
newTreeI(nkCall, n.info, quotes))
|
||||
result = semExpandToAst(c, result)
|
||||
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
@@ -2579,6 +2578,43 @@ proc shouldBeBracketExpr(n: PNode): bool =
|
||||
n[0] = be
|
||||
return true
|
||||
|
||||
proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var 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 preceding 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 and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
|
||||
let paramPos = defExpr.sym.position + 1
|
||||
|
||||
if call[paramPos].kind != nkSym:
|
||||
let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.p.owner, letSection.info, c.p.owner.options)
|
||||
hoistedVarSym.typ = call[paramPos].typ
|
||||
|
||||
letSection.add newTreeI(nkIdentDefs, letSection.info,
|
||||
newSymNode(hoistedVarSym),
|
||||
newNodeI(nkEmpty, letSection.info),
|
||||
call[paramPos])
|
||||
|
||||
call[paramPos] = newSymNode(hoistedVarSym) # Refer the original arg to its hoisted sym
|
||||
|
||||
# arg we refer to is a sym, wether introduced by hoisting or not doesn't matter, we simply reuse it
|
||||
defExpr = call[paramPos]
|
||||
else:
|
||||
for i in 0..<defExpr.safeLen:
|
||||
hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
when defined(nimCompilerStackraceHints):
|
||||
setFrameMsg c.config$n.info & " " & $n.kind
|
||||
@@ -2707,6 +2743,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = semDirectOp(c, n, flags)
|
||||
else:
|
||||
result = semIndirectOp(c, n, flags)
|
||||
|
||||
if nfDefaultRefsParam in result.flags:
|
||||
result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?)
|
||||
# We've found a default value that references another param.
|
||||
# See the notes in `hoistParamsUsedInDefault` for more details.
|
||||
var hoistedParams = newNodeI(nkLetSection, result.info)
|
||||
for i in 1..<result.len:
|
||||
hoistParamsUsedInDefault(c, result, hoistedParams, result[i])
|
||||
result = newTreeIT(nkStmtListExpr, result.info, result.typ, hoistedParams, result)
|
||||
of nkWhen:
|
||||
if efWantStmt in flags:
|
||||
result = semWhen(c, n, true)
|
||||
|
||||
Reference in New Issue
Block a user