Skip to content

Commit 05f23ff

Browse files
committed
pragmas: replace nkError-based implicit pragma culling
Summary ======= Change culling of non-applicable implicit pragmas to work without creating and discarding `nkError` nodes. Details ======= Creating an `nkError` node and then not comitting to it is unusual and will also cease to work once creating an `nkError` node means "emit diagnostic". Handling of implicit pragmas made use of `nkError` to detect and omit pragmas that are not applicable in the current context. The relevant procedures are changed such that handling an invalid (read, non- applicable) pragma is done via a callback (effect handler). Empty nodes returned from the callback are silently discarded, which implicit pragma processing uses to dismiss non-applicable pragmas. Pragma processing in other contexts stays unchanged, as it continues to turn non-applicable pragmas into errors.
1 parent d9b924c commit 05f23ff

File tree

1 file changed

+41
-27
lines changed

1 file changed

+41
-27
lines changed

compiler/sem/pragmas.nim

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ from compiler/ast/report_enums import ReportKind,
6262

6363
from compiler/ic/ic import addCompilerProc
6464

65+
type
66+
InvalidPragmaHandler = proc(c: PContext, n: PNode): PNode {.closure.}
67+
6568
const
6669
FirstCallConv* = wNimcall
6770
LastCallConv* = wTailcall
@@ -1020,7 +1023,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
10201023
else:
10211024
result = qualifiedLookUp(c, n, {checkUndeclared})
10221025

1023-
proc semCustomPragma(c: PContext, n: PNode): PNode =
1026+
proc semCustomPragma(c: PContext, n: PNode, invalid: InvalidPragmaHandler): PNode =
10241027
var callNode: PNode
10251028

10261029
case n.kind
@@ -1033,14 +1036,14 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
10331036
of nkPragmaCallKinds - {nkExprColonExpr}:
10341037
callNode = n
10351038
else:
1036-
result = invalidPragma(c, n)
1039+
result = invalid(c, n)
10371040
return
10381041

10391042
let r = c.semOverloadedCall(c, callNode, callNode, {skTemplate}, {efNoUndeclared})
10401043
if r.isError:
10411044
return r
10421045
elif r.isNil or sfCustomPragma notin r[0].sym.flags:
1043-
result = invalidPragma(c, n)
1046+
result = invalid(c, n)
10441047
return
10451048

10461049
result = r
@@ -1640,39 +1643,46 @@ proc applyStmtPragma(c: PContext, owner: PSym, it: PNode, k: TSpecialWord): PNod
16401643
# statement. Doing so would slightly change the semantics, however.
16411644

16421645
proc prepareSinglePragma(c: PContext; it: PNode, result: var seq[PNode],
1643-
validPragmas: TSpecialWords, sym: PSym) =
1646+
validPragmas: TSpecialWords, sym: PSym,
1647+
tryCustom=true,
1648+
invalid: InvalidPragmaHandler = invalidPragma) =
16441649
## Pre-processes the single pragma `it`, but doesn't apply it yet. The pre-
16451650
## processed pragma (multiple if the input pragma is a user-pragma) is
1646-
## appended to `result`.
1651+
## appended to `result`. Unknown Custom pragmas are only considered when
1652+
## `considerCustom` is 'true'; `invalid` is called for non-applicable
1653+
## pragmas.
16471654
##
16481655
## `sym` (nil is allowed) is only provided for use by error diagnostics and
16491656
## isn't mutated.
16501657
let key = it.key
16511658

1652-
proc customPragma(c: PContext, n: PNode, s: PSym): PNode =
1659+
proc customPragma(c: PContext, n: PNode, s: PSym,
1660+
invalid: InvalidPragmaHandler): PNode =
16531661
if s == nil or s.kind in allowsCustomPragma:
1654-
semCustomPragma(c, n)
1662+
semCustomPragma(c, n, invalid)
16551663
else:
16561664
illegalCustomPragma(c, n, s)
16571665

16581666
let r =
16591667
case key.kind
16601668
of nkBracketExpr:
1661-
invalidPragma(c, it)
1669+
invalid(c, it)
16621670
of nkCast:
16631671
# pass through the cast pragma. It's later going to be treated as a
16641672
# ``wCast``
16651673
it
16661674
of nkIdentKinds:
16671675
# uses normal processing
16681676
nil
1677+
elif tryCustom:
1678+
customPragma(c, it, sym, invalid)
16691679
else:
1670-
# must be either a custom pragma or an error
1671-
customPragma(c, it, sym)
1680+
invalid(c, it)
16721681

16731682
if r != nil:
16741683
# already processed
1675-
result.add r
1684+
if r.kind != nkEmpty:
1685+
result.add r
16761686
return
16771687

16781688
let (ident, error) = considerQuotedIdent(c, key)
@@ -1695,7 +1705,8 @@ proc prepareSinglePragma(c: PContext; it: PNode, result: var seq[PNode],
16951705
else:
16961706
# expand the user pragma in-place:
16971707
for it in userPragma.ast.items:
1698-
prepareSinglePragma(c, it, result, validPragmas, sym)
1708+
prepareSinglePragma(c, it, result, validPragmas, sym,
1709+
tryCustom, invalid)
16991710

17001711
dec c.instCounter
17011712
else:
@@ -1705,10 +1716,15 @@ proc prepareSinglePragma(c: PContext; it: PNode, result: var seq[PNode],
17051716
checkPragmaUse(c.config, key.info, k, ident.s)
17061717

17071718
result.add it
1719+
elif tryCustom:
1720+
# try to treat as a custom pragma
1721+
let got = customPragma(c, it, sym, invalid)
1722+
if got.kind != nkEmpty:
1723+
result.add got
17081724
else:
1709-
# try to treat as a custom pragma, which will produce an error if it's
1710-
# not a valid custom pragma
1711-
result.add customPragma(c, it, sym)
1725+
let got = invalid(c, it)
1726+
if got.kind != nkEmpty:
1727+
result.add got
17121728

17131729
proc semSinglePragmaInStmt(
17141730
c: PContext; owner: PSym, it: PNode, validPragmas: TSpecialWords, r: var seq[PNode]): TSpecialWord
@@ -1761,7 +1777,7 @@ proc semIdentPragmaInStmt(c: PContext, owner: PSym, it: PNode, r: var seq[PNode]
17611777
else:
17621778
# it might still be a custom pragma
17631779
result = wInvalid
1764-
r.add semCustomPragma(c, it)
1780+
r.add semCustomPragma(c, it, invalidPragma)
17651781

17661782
proc semSinglePragmaInStmt(
17671783
c: PContext; owner: PSym, it: PNode, validPragmas: TSpecialWords, r: var seq[PNode]): TSpecialWord =
@@ -1785,7 +1801,7 @@ proc semSinglePragmaInStmt(
17851801
of nkIdentKinds:
17861802
result = semIdentPragmaInStmt(c, owner, it, r, validPragmas)
17871803
else:
1788-
r.add semCustomPragma(c, it)
1804+
r.add semCustomPragma(c, it, invalidPragma)
17891805

17901806
proc overwriteLineInfo(n: PNode; info: TLineInfo) =
17911807
n.info = info
@@ -1864,18 +1880,16 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWo
18641880
let o = it.otherPragmas
18651881
if o != nil:
18661882
for x in o.items:
1867-
prepareSinglePragma(c, x, tmp, validPragmas, sym)
1883+
# pragmas not applicable to the symbol are silently ignored
1884+
prepareSinglePragma(c, x, tmp, validPragmas, sym,
1885+
tryCustom=(sym.kind in allowsCustomPragma),
1886+
proc(c: PContext, n: PNode): PNode = c.graph.emptyNode)
18681887

1869-
# filter the nodes. If they're erroneous, it means that the pragma
1870-
# doesn't apply to the symbol
1888+
# the pragmas' AST is going to be mutated, so create a copy
18711889
for y in tmp.items:
1872-
if not y.isError:
1873-
# we're mutating the pragma's AST, so a copy is required
1874-
let pragma = copyTree(y)
1875-
overwriteLineInfo(pragma, n.info)
1876-
result.add(pragma)
1877-
1878-
tmp.setLen(0)
1890+
let pragma = copyTree(y)
1891+
overwriteLineInfo(pragma, n.info)
1892+
result.add pragma
18791893

18801894
if result.len == 0:
18811895
# there were no applicable pragmas; restore the original

0 commit comments

Comments
 (0)