mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 10:52:14 +00:00
Merge branch 'devel' into pr-remove-encode-overload
This commit is contained in:
@@ -1254,6 +1254,12 @@ proc skipPragmaExpr*(n: PNode): PNode =
|
||||
else:
|
||||
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):
|
||||
const nodeIdToDebug* = -1 # 2322968
|
||||
var gNodeId: int
|
||||
|
||||
@@ -143,4 +143,5 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasTopDownInference")
|
||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||
defineSymbol("nimHasCstringCase")
|
||||
defineSymbol("nimHasCallsitePragma")
|
||||
defineSymbol("nimHasAmbiguousEnumHint")
|
||||
|
||||
@@ -26,7 +26,7 @@ type
|
||||
|
||||
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
||||
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) =
|
||||
template handleParam(param) =
|
||||
@@ -204,7 +204,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||
result = copyNode(body)
|
||||
ctx.instLines = sfCallsite in tmpl.flags
|
||||
if ctx.instLines:
|
||||
result.info = n.info
|
||||
setInfoRecursive(result, n.info)
|
||||
for i in 0..<body.safeLen:
|
||||
evalTemplateAux(body[i], args, ctx, result)
|
||||
result.flags.incl nfFromTemplate
|
||||
|
||||
@@ -77,7 +77,7 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||
proc nestedScope(parent: var Scope; body: PNode): Scope =
|
||||
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode
|
||||
|
||||
when false:
|
||||
@@ -508,14 +508,14 @@ proc processScope(c: var Con; s: var Scope; ret: PNode): PNode =
|
||||
|
||||
if s.parent != nil: s.parent[].needsTry = s.parent[].needsTry or s.needsTry
|
||||
|
||||
template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped): PNode =
|
||||
template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped, tmpFlags: TSymFlags): PNode =
|
||||
assert not ret.typ.isEmptyType
|
||||
var result = newNodeIT(nkStmtListExpr, ret.info, ret.typ)
|
||||
# There is a possibility to do this check: s.wasMoved.len > 0 or s.final.len > 0
|
||||
# later and use it to eliminate the temporary when theres no need for it, but its
|
||||
# tricky because you would have to intercept moveOrCopy at a certain point
|
||||
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
|
||||
tmp.sym.flags.incl sfSingleUsedTemp
|
||||
tmp.sym.flags = tmpFlags
|
||||
let cpy = if hasDestructor(c, ret.typ):
|
||||
s.parent[].final.add c.genDestroy(tmp)
|
||||
moveOrCopy(tmp, ret, c, s, isDecl = true)
|
||||
@@ -542,7 +542,8 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
|
||||
|
||||
result
|
||||
|
||||
template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
|
||||
tmpFlags = {sfSingleUsedTemp}) =
|
||||
template maybeVoid(child, s): untyped =
|
||||
if isEmptyType(child.typ): p(child, c, s, normal)
|
||||
else: processCall(child, s)
|
||||
@@ -570,7 +571,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt:
|
||||
processScope(c, ofScope, maybeVoid(it[^1], ofScope))
|
||||
else:
|
||||
processScopeExpr(c, ofScope, it[^1], processCall)
|
||||
processScopeExpr(c, ofScope, it[^1], processCall, tmpFlags)
|
||||
result.add branch
|
||||
|
||||
of nkWhileStmt:
|
||||
@@ -603,7 +604,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
result.add if n[1].typ.isEmptyType or willProduceStmt:
|
||||
processScope(c, bodyScope, processCall(n[1], bodyScope))
|
||||
else:
|
||||
processScopeExpr(c, bodyScope, n[1], processCall)
|
||||
processScopeExpr(c, bodyScope, n[1], processCall, tmpFlags)
|
||||
|
||||
of nkIfStmt, nkIfExpr:
|
||||
result = copyNode(n)
|
||||
@@ -618,7 +619,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt:
|
||||
processScope(c, branchScope, maybeVoid(it[^1], branchScope))
|
||||
else:
|
||||
processScopeExpr(c, branchScope, it[^1], processCall)
|
||||
processScopeExpr(c, branchScope, it[^1], processCall, tmpFlags)
|
||||
result.add branch
|
||||
|
||||
of nkTryStmt:
|
||||
@@ -627,7 +628,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
result.add if n[0].typ.isEmptyType or willProduceStmt:
|
||||
processScope(c, tryScope, maybeVoid(n[0], tryScope))
|
||||
else:
|
||||
processScopeExpr(c, tryScope, n[0], maybeVoid)
|
||||
processScopeExpr(c, tryScope, n[0], maybeVoid, tmpFlags)
|
||||
|
||||
for i in 1..<n.len:
|
||||
let it = n[i]
|
||||
@@ -637,7 +638,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
processScope(c, branchScope, if it.kind == nkFinally: p(it[^1], c, branchScope, normal)
|
||||
else: maybeVoid(it[^1], branchScope))
|
||||
else:
|
||||
processScopeExpr(c, branchScope, it[^1], processCall)
|
||||
processScopeExpr(c, branchScope, it[^1], processCall, tmpFlags)
|
||||
result.add branch
|
||||
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
@@ -670,11 +671,11 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
result.add copyNode(n[0])
|
||||
s.needsTry = true
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
|
||||
template process(child, s): untyped = p(child, c, s, mode)
|
||||
handleNestedTempl(n, process)
|
||||
handleNestedTempl(n, process, tmpFlags = tmpFlags)
|
||||
elif mode == sinkArg:
|
||||
if n.containsConstSeq:
|
||||
# const sequences are not mutable and so we need to pass a copy to the
|
||||
@@ -825,7 +826,11 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..<it.len-1:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(it[^1], c, s, normal)
|
||||
var flags = {sfSingleUsedTemp}
|
||||
if it.kind == nkIdentDefs and it.len == 3 and it[0].kind == nkSym and
|
||||
sfGlobal in it[0].sym.flags:
|
||||
flags.incl sfGlobal
|
||||
itCopy.add p(it[^1], c, s, normal, tmpFlags = flags)
|
||||
v.add itCopy
|
||||
result.add v
|
||||
of nkAsgn, nkFastAsgn:
|
||||
|
||||
@@ -38,7 +38,7 @@ const
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
wDelegator, wExportNims, wUsed, wPragma, wRedefine}
|
||||
wDelegator, wExportNims, wUsed, wPragma, wRedefine, wCallsite}
|
||||
macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore,
|
||||
wDiscardable, wGensym, wInject, wDelegator}
|
||||
@@ -873,6 +873,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wRedefine:
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfTemplateRedefinition)
|
||||
else: invalidPragma(c, it)
|
||||
of wCallsite:
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfCallsite)
|
||||
else: invalidPragma(c, it)
|
||||
of wImportCpp:
|
||||
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wCppNonPod:
|
||||
|
||||
@@ -2338,11 +2338,6 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
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) =
|
||||
if n != nil:
|
||||
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
|
||||
for i in 0..<pragmaList.len:
|
||||
case whichPragma(pragmaList[i])
|
||||
of wLine: setLine(result, pragmaList[i].info)
|
||||
of wLine: setInfoRecursive(result, pragmaList[i].info)
|
||||
of wNoRewrite: recursiveSetFlag(result, nfNoRewrite)
|
||||
else: discard
|
||||
|
||||
|
||||
@@ -620,12 +620,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
s = semIdentVis(c, skTemplate, n[namePos], {})
|
||||
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)
|
||||
onDef(n[namePos].info, s)
|
||||
# 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
|
||||
liMessage(c.config, lineInfo, errGenerated, msg, action, infoOrigin)
|
||||
|
||||
when not defined(nimHasCallsitePragma):
|
||||
{.pragma: callsite.}
|
||||
|
||||
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))
|
||||
return
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ type
|
||||
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
||||
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
||||
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
|
||||
wRedefine = "redefine",
|
||||
wRedefine = "redefine", wCallsite = "callsite",
|
||||
|
||||
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
||||
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
|
||||
|
||||
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`.
|
||||
## ```
|
||||
## assert(1 in (1..3) == true)
|
||||
## 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`.
|
||||
## ```
|
||||
## 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[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)`.
|
||||
## ```
|
||||
## 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 `<`*(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)`.
|
||||
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`.
|
||||
y <= x
|
||||
|
||||
template `>`*(x, y: untyped): untyped =
|
||||
template `>`*(x, y: untyped): untyped {.callsite.} =
|
||||
## "is greater" operator. This is the same as `y < x`.
|
||||
y < x
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@ func incl*[T](x: var set[T], y: T) {.magic: "Incl".} =
|
||||
a.incl(4)
|
||||
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`.
|
||||
runnableExamples:
|
||||
var a = {1, 3, 5, 7}
|
||||
@@ -27,7 +30,7 @@ func excl*[T](x: var set[T], y: T) {.magic: "Excl".} =
|
||||
b.excl(5)
|
||||
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`.
|
||||
runnableExamples:
|
||||
var a = {1, 3, 5, 7}
|
||||
|
||||
18
tests/arc/t18645.nim
Normal file
18
tests/arc/t18645.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
matrix: "--gc:arc; --gc:refc"
|
||||
output: '''
|
||||
1
|
||||
2
|
||||
3
|
||||
'''
|
||||
"""
|
||||
|
||||
proc bitTypeIdUnion() =
|
||||
var bitId {.global.} = block:
|
||||
0
|
||||
inc bitId
|
||||
echo bitId
|
||||
|
||||
bitTypeIdUnion()
|
||||
bitTypeIdUnion()
|
||||
bitTypeIdUnion()
|
||||
@@ -423,6 +423,31 @@ when false:
|
||||
|
||||
doAssert hasMyAttr(TObj)
|
||||
|
||||
|
||||
# bug #11415
|
||||
template noserialize() {.pragma.}
|
||||
|
||||
type
|
||||
Point[T] = object
|
||||
x, y: T
|
||||
|
||||
ReplayEventKind = enum
|
||||
FoodAppeared, FoodEaten, DirectionChanged
|
||||
|
||||
ReplayEvent = object
|
||||
case kind: ReplayEventKind
|
||||
of FoodEaten, FoodAppeared: # foodPos is in multiple branches
|
||||
foodPos {.noserialize.}: Point[float]
|
||||
of DirectionChanged:
|
||||
playerPos: float
|
||||
let ev = ReplayEvent(
|
||||
kind: FoodEaten,
|
||||
foodPos: Point[float](x: 5.0, y: 1.0)
|
||||
)
|
||||
|
||||
doAssert ev.foodPos.hasCustomPragma(noserialize)
|
||||
|
||||
|
||||
when false:
|
||||
# misc
|
||||
{.pragma: haha.}
|
||||
|
||||
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")
|
||||
Reference in New Issue
Block a user