Skip to content

Commit

Permalink
don't transform typed bracket exprs to [] calls in templates (nim-l…
Browse files Browse the repository at this point in the history
…ang#23175)

fixes nim-lang#22775

It's pre-existing that [`prepareOperand` doesn't typecheck expressions
which have
types](https://github.com/nim-lang/Nim/blob/a4f3bf374238df96f0982b7106e3702da6b485b1/compiler/sigmatch.nim#L2444).
Templates can take typed subscript expressions, transform them into
calls to `[]`, and then have this `[]` not be resolved later if the
expression is nested inside of a call argument, which leaks an untyped
expression past semantic analysis. To prevent this, don't transform any
typed subscript expressions into calls to `[]` in templates. Ditto for
curly subscripts (with `{}`) and assignments to subscripts and curly
subscripts (with `[]=` and `{}=`).
  • Loading branch information
metagn authored Jan 7, 2024
1 parent a4f3bf3 commit 62d8ca4
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
39 changes: 25 additions & 14 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if x.kind == nkExprColonExpr:
x[1] = semTemplBody(c, x[1])
of nkBracketExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
if n.typ == nil:
# if a[b] is nested inside a typed expression, don't convert it
# back to `[]`(a, b), prepareOperand will not typecheck it again
# and so `[]` will not be resolved
# checking if a[b] is typed should be enough to cover this case
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
if n.typ == nil:
# see nkBracketExpr case for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn, nkSinkAsgn:
checkSonsLen(n, 2, c.c.config)
Expand All @@ -524,17 +531,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let k = a.kind
case k
of nkBracketExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
let a0 = semTemplBody(c, a[0])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
result = semTemplBodySons(c, result)
else:
result = semTemplBodySons(c, n)
Expand Down
38 changes: 38 additions & 0 deletions tests/template/tnested.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
block: # issue #22775
proc h(c: int) = discard
template k(v: int) =
template p() = v.h()
p()
let a = @[0]
k(0 and not a[0])

block: # issue #22775 case 2
proc h(c: int, q: int) = discard
template k(v: int) =
template p() = h(v, v)
p()
let a = [0]
k(0 and not a[0])

block: # issue #22775 minimal cases
proc h(c: int) = discard
template k(v: int) =
template p() = h(v)
p()
let a = [0]
k(not a[0])
block:
k(-a[0])
block:
proc f(x: int): int = x
k(f a[0])

block: # bracket assignment case of above tests
proc h(c: int) = discard
template k(v: int) =
template p() = h(v)
p()
var a = [0]
k(not (block:
a[0] = 1
1))

0 comments on commit 62d8ca4

Please sign in to comment.