pragma for sfCallsite instead of name check + better semantics, test (#20464)
* pragma for sfCallsite instead of name check at every template definition Not documented because it seems to be for internal use? Should also make it possible to make comparisons and setops imports, but this doesn't have to be done. I can reuse a name like `cursor` for the pragma as well, added a new name just to be safe. * make sfCallsite recursive, add tests
This commit is contained in:
parent
81e7811e01
commit
2cca38d33c
13 changed files with 73 additions and 25 deletions
|
|
@ -1254,6 +1254,12 @@ proc skipPragmaExpr*(n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc setInfoRecursive*(n: PNode, info: TLineInfo) =
|
||||||
|
## set line info recursively
|
||||||
|
if n != nil:
|
||||||
|
for i in 0..<n.safeLen: setInfoRecursive(n[i], info)
|
||||||
|
n.info = info
|
||||||
|
|
||||||
when defined(useNodeIds):
|
when defined(useNodeIds):
|
||||||
const nodeIdToDebug* = -1 # 2322968
|
const nodeIdToDebug* = -1 # 2322968
|
||||||
var gNodeId: int
|
var gNodeId: int
|
||||||
|
|
|
||||||
|
|
@ -143,4 +143,5 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimHasTopDownInference")
|
defineSymbol("nimHasTopDownInference")
|
||||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||||
defineSymbol("nimHasCstringCase")
|
defineSymbol("nimHasCstringCase")
|
||||||
|
defineSymbol("nimHasCallsitePragma")
|
||||||
defineSymbol("nimHasAmbiguousEnumHint")
|
defineSymbol("nimHasAmbiguousEnumHint")
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ type
|
||||||
|
|
||||||
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
||||||
result = copyNode(a)
|
result = copyNode(a)
|
||||||
if ctx.instLines: result.info = b.info
|
if ctx.instLines: setInfoRecursive(result, b.info)
|
||||||
|
|
||||||
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||||
template handleParam(param) =
|
template handleParam(param) =
|
||||||
|
|
@ -204,7 +204,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||||
result = copyNode(body)
|
result = copyNode(body)
|
||||||
ctx.instLines = sfCallsite in tmpl.flags
|
ctx.instLines = sfCallsite in tmpl.flags
|
||||||
if ctx.instLines:
|
if ctx.instLines:
|
||||||
result.info = n.info
|
setInfoRecursive(result, n.info)
|
||||||
for i in 0..<body.safeLen:
|
for i in 0..<body.safeLen:
|
||||||
evalTemplateAux(body[i], args, ctx, result)
|
evalTemplateAux(body[i], args, ctx, result)
|
||||||
result.flags.incl nfFromTemplate
|
result.flags.incl nfFromTemplate
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||||
wDelegator, wExportNims, wUsed, wPragma, wRedefine}
|
wDelegator, wExportNims, wUsed, wPragma, wRedefine, wCallsite}
|
||||||
macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||||
wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore,
|
wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore,
|
||||||
wDiscardable, wGensym, wInject, wDelegator}
|
wDiscardable, wGensym, wInject, wDelegator}
|
||||||
|
|
@ -873,6 +873,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
of wRedefine:
|
of wRedefine:
|
||||||
if sym.kind == skTemplate: incl(sym.flags, sfTemplateRedefinition)
|
if sym.kind == skTemplate: incl(sym.flags, sfTemplateRedefinition)
|
||||||
else: invalidPragma(c, it)
|
else: invalidPragma(c, it)
|
||||||
|
of wCallsite:
|
||||||
|
if sym.kind == skTemplate: incl(sym.flags, sfCallsite)
|
||||||
|
else: invalidPragma(c, it)
|
||||||
of wImportCpp:
|
of wImportCpp:
|
||||||
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
of wCppNonPod:
|
of wCppNonPod:
|
||||||
|
|
|
||||||
|
|
@ -2338,11 +2338,6 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
incMod(c, n, it, result)
|
incMod(c, n, it, result)
|
||||||
|
|
||||||
proc setLine(n: PNode, info: TLineInfo) =
|
|
||||||
if n != nil:
|
|
||||||
for i in 0..<n.safeLen: setLine(n[i], info)
|
|
||||||
n.info = info
|
|
||||||
|
|
||||||
proc recursiveSetFlag(n: PNode, flag: TNodeFlag) =
|
proc recursiveSetFlag(n: PNode, flag: TNodeFlag) =
|
||||||
if n != nil:
|
if n != nil:
|
||||||
for i in 0..<n.safeLen: recursiveSetFlag(n[i], flag)
|
for i in 0..<n.safeLen: recursiveSetFlag(n[i], flag)
|
||||||
|
|
@ -2371,7 +2366,7 @@ proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||||
result.typ = n[1].typ
|
result.typ = n[1].typ
|
||||||
for i in 0..<pragmaList.len:
|
for i in 0..<pragmaList.len:
|
||||||
case whichPragma(pragmaList[i])
|
case whichPragma(pragmaList[i])
|
||||||
of wLine: setLine(result, pragmaList[i].info)
|
of wLine: setInfoRecursive(result, pragmaList[i].info)
|
||||||
of wNoRewrite: recursiveSetFlag(result, nfNoRewrite)
|
of wNoRewrite: recursiveSetFlag(result, nfNoRewrite)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -620,12 +620,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
s = semIdentVis(c, skTemplate, n[namePos], {})
|
s = semIdentVis(c, skTemplate, n[namePos], {})
|
||||||
assert s.kind == skTemplate
|
assert s.kind == skTemplate
|
||||||
|
|
||||||
if s.owner != nil:
|
|
||||||
const names = ["!=", ">=", ">", "incl", "excl", "in", "notin", "isnot"]
|
|
||||||
if sfSystemModule in s.owner.flags and s.name.s in names or
|
|
||||||
s.owner.name.s == "vm" and s.name.s == "stackTrace":
|
|
||||||
incl(s.flags, sfCallsite)
|
|
||||||
|
|
||||||
styleCheckDef(c, s)
|
styleCheckDef(c, s)
|
||||||
onDef(n[namePos].info, s)
|
onDef(n[namePos].info, s)
|
||||||
# check parameter list:
|
# check parameter list:
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,11 @@ proc stackTraceImpl(c: PCtx, tos: PStackFrame, pc: int,
|
||||||
let lineInfo = if lineInfo == TLineInfo.default: c.debug[pc] else: lineInfo
|
let lineInfo = if lineInfo == TLineInfo.default: c.debug[pc] else: lineInfo
|
||||||
liMessage(c.config, lineInfo, errGenerated, msg, action, infoOrigin)
|
liMessage(c.config, lineInfo, errGenerated, msg, action, infoOrigin)
|
||||||
|
|
||||||
|
when not defined(nimHasCallsitePragma):
|
||||||
|
{.pragma: callsite.}
|
||||||
|
|
||||||
template stackTrace(c: PCtx, tos: PStackFrame, pc: int,
|
template stackTrace(c: PCtx, tos: PStackFrame, pc: int,
|
||||||
msg: string, lineInfo: TLineInfo = TLineInfo.default) =
|
msg: string, lineInfo: TLineInfo = TLineInfo.default) {.callsite.} =
|
||||||
stackTraceImpl(c, tos, pc, msg, lineInfo, instantiationInfo(-2, fullPaths = true))
|
stackTraceImpl(c, tos, pc, msg, lineInfo, instantiationInfo(-2, fullPaths = true))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ type
|
||||||
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
||||||
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
||||||
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
|
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
|
||||||
wRedefine = "redefine",
|
wRedefine = "redefine", wCallsite = "callsite",
|
||||||
|
|
||||||
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
||||||
wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default",
|
wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default",
|
||||||
|
|
|
||||||
|
|
@ -731,13 +731,16 @@ proc contains*[U, V, W](s: HSlice[U, V], value: W): bool {.noSideEffect, inline.
|
||||||
## ```
|
## ```
|
||||||
result = s.a <= value and value <= s.b
|
result = s.a <= value and value <= s.b
|
||||||
|
|
||||||
template `in`*(x, y: untyped): untyped {.dirty.} = contains(y, x)
|
when not defined(nimHasCallsitePragma):
|
||||||
|
{.pragma: callsite.}
|
||||||
|
|
||||||
|
template `in`*(x, y: untyped): untyped {.dirty, callsite.} = contains(y, x)
|
||||||
## Sugar for `contains`.
|
## Sugar for `contains`.
|
||||||
## ```
|
## ```
|
||||||
## assert(1 in (1..3) == true)
|
## assert(1 in (1..3) == true)
|
||||||
## assert(5 in (1..3) == false)
|
## assert(5 in (1..3) == false)
|
||||||
## ```
|
## ```
|
||||||
template `notin`*(x, y: untyped): untyped {.dirty.} = not contains(y, x)
|
template `notin`*(x, y: untyped): untyped {.dirty, callsite.} = not contains(y, x)
|
||||||
## Sugar for `not contains`.
|
## Sugar for `not contains`.
|
||||||
## ```
|
## ```
|
||||||
## assert(1 notin (1..3) == false)
|
## assert(1 notin (1..3) == false)
|
||||||
|
|
@ -762,7 +765,7 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
||||||
## assert(test[int](3) == 3)
|
## assert(test[int](3) == 3)
|
||||||
## assert(test[string]("xyz") == 0)
|
## assert(test[string]("xyz") == 0)
|
||||||
## ```
|
## ```
|
||||||
template `isnot`*(x, y: untyped): untyped = not (x is y)
|
template `isnot`*(x, y: untyped): untyped {.callsite.} = not (x is y)
|
||||||
## Negated version of `is <#is,T,S>`_. Equivalent to `not(x is y)`.
|
## Negated version of `is <#is,T,S>`_. Equivalent to `not(x is y)`.
|
||||||
## ```
|
## ```
|
||||||
## assert 42 isnot float
|
## assert 42 isnot float
|
||||||
|
|
|
||||||
|
|
@ -125,15 +125,18 @@ proc `<`*[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.}
|
||||||
proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.}
|
proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.}
|
||||||
proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.}
|
proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.}
|
||||||
|
|
||||||
template `!=`*(x, y: untyped): untyped =
|
when not defined(nimHasCallsitePragma):
|
||||||
|
{.pragma: callsite.}
|
||||||
|
|
||||||
|
template `!=`*(x, y: untyped): untyped {.callsite.} =
|
||||||
## Unequals operator. This is a shorthand for `not (x == y)`.
|
## Unequals operator. This is a shorthand for `not (x == y)`.
|
||||||
not (x == y)
|
not (x == y)
|
||||||
|
|
||||||
template `>=`*(x, y: untyped): untyped =
|
template `>=`*(x, y: untyped): untyped {.callsite.} =
|
||||||
## "is greater or equals" operator. This is the same as `y <= x`.
|
## "is greater or equals" operator. This is the same as `y <= x`.
|
||||||
y <= x
|
y <= x
|
||||||
|
|
||||||
template `>`*(x, y: untyped): untyped =
|
template `>`*(x, y: untyped): untyped {.callsite.} =
|
||||||
## "is greater" operator. This is the same as `y < x`.
|
## "is greater" operator. This is the same as `y < x`.
|
||||||
y < x
|
y < x
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ func incl*[T](x: var set[T], y: T) {.magic: "Incl".} =
|
||||||
a.incl(4)
|
a.incl(4)
|
||||||
assert a == {1, 2, 3, 4, 5}
|
assert a == {1, 2, 3, 4, 5}
|
||||||
|
|
||||||
template incl*[T](x: var set[T], y: set[T]) =
|
when not defined(nimHasCallsitePragma):
|
||||||
|
{.pragma: callsite.}
|
||||||
|
|
||||||
|
template incl*[T](x: var set[T], y: set[T]) {.callsite.} =
|
||||||
## Includes the set `y` in the set `x`.
|
## Includes the set `y` in the set `x`.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var a = {1, 3, 5, 7}
|
var a = {1, 3, 5, 7}
|
||||||
|
|
@ -27,7 +30,7 @@ func excl*[T](x: var set[T], y: T) {.magic: "Excl".} =
|
||||||
b.excl(5)
|
b.excl(5)
|
||||||
assert b == {2, 3, 6, 12, 545}
|
assert b == {2, 3, 6, 12, 545}
|
||||||
|
|
||||||
template excl*[T](x: var set[T], y: set[T]) =
|
template excl*[T](x: var set[T], y: set[T]) {.callsite.} =
|
||||||
## Excludes the set `y` from the set `x`.
|
## Excludes the set `y` from the set `x`.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var a = {1, 3, 5, 7}
|
var a = {1, 3, 5, 7}
|
||||||
|
|
|
||||||
17
tests/template/tcallsitelineinfo.nim
Normal file
17
tests/template/tcallsitelineinfo.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
nimout: '''
|
||||||
|
tcallsitelineinfo.nim(17, 4) Warning: abc [User]
|
||||||
|
'''
|
||||||
|
exitcode: 1
|
||||||
|
outputsub: '''
|
||||||
|
tcallsitelineinfo.nim(17) tcallsitelineinfo
|
||||||
|
Error: unhandled exception: def [ValueError]
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
template foo(): untyped {.callsite.} =
|
||||||
|
{.warning: "abc".}
|
||||||
|
raise newException(ValueError, "def")
|
||||||
|
echo "hello"
|
||||||
|
|
||||||
|
foo()
|
||||||
20
tests/template/tcallsitelineinfo2.nim
Normal file
20
tests/template/tcallsitelineinfo2.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
discard """
|
||||||
|
nimout: '''
|
||||||
|
tcallsitelineinfo2.nim(18, 1) Warning: abc [User]
|
||||||
|
tcallsitelineinfo2.nim(19, 12) Warning: def [User]
|
||||||
|
'''
|
||||||
|
exitcode: 1
|
||||||
|
outputsub: '''
|
||||||
|
tcallsitelineinfo2.nim(20) tcallsitelineinfo2
|
||||||
|
Error: unhandled exception: ghi [ValueError]
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
template foo(a: untyped): untyped {.callsite.} =
|
||||||
|
{.warning: "abc".}
|
||||||
|
a
|
||||||
|
echo "hello"
|
||||||
|
|
||||||
|
foo: # with `{.line.}:`, the following do not keep their line information:
|
||||||
|
{.warning: "def".}
|
||||||
|
raise newException(ValueError, "ghi")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue