mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 19:03:42 +00:00
Compare commits
14 Commits
pr_when_ty
...
pr_disable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af5bf7f87f | ||
|
|
7813bd8b92 | ||
|
|
645e131739 | ||
|
|
7d2f28b046 | ||
|
|
f4dd00c4cc | ||
|
|
3e2cea21ed | ||
|
|
cfa769fefc | ||
|
|
db00f2d2d8 | ||
|
|
8771451701 | ||
|
|
43ac102ca8 | ||
|
|
393d27b57d | ||
|
|
9f5c193c1d | ||
|
|
4f6b727d9e | ||
|
|
7b03b8a618 |
@@ -81,6 +81,9 @@ parameter and result types, not just their source-level shape. Use
|
||||
- `std/re` and `std/nre` are deprecated as PCRE library is obsolete.
|
||||
Use https://github.com/nitely/nim-regex or `std/nre2`.
|
||||
See: https://github.com/nim-lang/Nim/issues/23668.
|
||||
- `std/pegs` now correctly lexes UTF-8 bytes inside bare identifier-style
|
||||
terminals, so case-insensitive matching of non-ASCII terms (e.g. ``\i café``)
|
||||
works without single-quoting.
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
@@ -2816,9 +2816,9 @@ proc genWasMoved(p: BProc; n: PNode) =
|
||||
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
|
||||
|
||||
proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
var a: TLoc = initLocExpr(p, n[1].skipAddr, {lfEnforceDeref, lfPrepareForMutation})
|
||||
if n.len == 4:
|
||||
# generated by liftdestructors:
|
||||
var a: TLoc = initLocExpr(p, n[1].skipAddr, {lfEnforceDeref, lfPrepareForMutation})
|
||||
var src: TLoc = initLocExpr(p, n[2])
|
||||
let destVal = rdLoc(a)
|
||||
let srcVal = rdLoc(src)
|
||||
@@ -2838,29 +2838,16 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
else:
|
||||
if d.k == locNone: d = getTemp(p, n.typ)
|
||||
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}:
|
||||
genAssignment(p, d, a, {})
|
||||
var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved)
|
||||
if op == nil:
|
||||
if op == nil or sfOverridden notin op.flags:
|
||||
var a: TLoc = initLocExpr(p, n[1].skipAddr, {lfEnforceDeref, lfPrepareForMutation})
|
||||
genAssignment(p, d, a, {})
|
||||
resetLoc(p, a)
|
||||
else:
|
||||
var b = initLocExpr(p, newSymNode(op))
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs: # todo fixme generated `wasMoved` hooks for
|
||||
# openarrays, but it probably shouldn't?
|
||||
let ra = rdLoc(a)
|
||||
var s: string
|
||||
if reifiedOpenArray(a.lode):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
s = derefField(ra, "Field0") & cArgumentSeparator & derefField(ra, "Field1")
|
||||
else:
|
||||
s = dotField(ra, "Field0") & cArgumentSeparator & dotField(ra, "Field1")
|
||||
else:
|
||||
s = ra & cArgumentSeparator & ra & "Len_0"
|
||||
p.s(cpsStmts).addCallStmt(rdLoc(b), s)
|
||||
else:
|
||||
let val = if p.module.compileToCpp: rdLoc(a) else: byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(rdLoc(b), val)
|
||||
n[1] = makeAddr(n[1], p.module.idgen)
|
||||
genCall(p, n, d)
|
||||
else:
|
||||
var a: TLoc = initLocExpr(p, n[1].skipAddr, {lfEnforceDeref, lfPrepareForMutation})
|
||||
genAssignment(p, d, a, {})
|
||||
resetLoc(p, a)
|
||||
|
||||
|
||||
@@ -341,9 +341,9 @@ proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): Snippet =
|
||||
call[i][0]
|
||||
else:
|
||||
call[i]
|
||||
if param.kind != nkBracketExpr or param.typ.kind in
|
||||
if not param.typ.isCompileTimeOnly and (param.kind != nkBracketExpr or param.typ.kind in
|
||||
{tyRef, tyPtr, tyUncheckedArray, tyArray, tyOpenArray,
|
||||
tyVarargs, tySequence, tyString, tyCstring, tyTuple}:
|
||||
tyVarargs, tySequence, tyString, tyCstring, tyTuple}):
|
||||
let tempLoc = initLocExprSingleUse(p, param)
|
||||
didGenTemp = didGenTemp or tempLoc.k == locTemp
|
||||
genOtherArg(p, call, i, typ, res, argBuilder)
|
||||
@@ -1237,6 +1237,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
else:
|
||||
scope = initScope(p.s(cpsStmts))
|
||||
# we handled the error:
|
||||
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||
expr(p, t[i][0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
endBlockWith(p):
|
||||
|
||||
@@ -46,7 +46,7 @@ proc isLocation(n: PNode): bool = not n.isValue
|
||||
|
||||
proc isLet(n: PNode): bool =
|
||||
if n.kind == nkSym:
|
||||
if n.sym.kind in {skLet, skTemp, skForVar}:
|
||||
if n.sym.kind in {skLet, skConst, skTemp, skForVar}: # guard immutable variables
|
||||
result = true
|
||||
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
||||
abstractInst).kind notin {tyVar}:
|
||||
|
||||
@@ -454,26 +454,6 @@ proc resetSemFlag(n: PNode) =
|
||||
for i in 0..<n.safeLen:
|
||||
resetSemFlag(n[i])
|
||||
|
||||
proc normalizeTypedescMacroResult(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
if result.kind == nkStmtList:
|
||||
result.transitionSonsKind(nkStmtListType)
|
||||
|
||||
const maxTypedescMacroNormalizationPasses = 32
|
||||
# Resolve surviving compile-time branches so later passes don't walk
|
||||
# unevaluated type AST for a typedesc expression.
|
||||
for _ in 0..<maxTypedescMacroNormalizationPasses:
|
||||
if result.kind == nkWhenStmt:
|
||||
result = semWhen(c, result, false)
|
||||
if result.kind == nkStmtList:
|
||||
result.transitionSonsKind(nkStmtListType)
|
||||
elif result.kind == nkStmtListType and result.len > 0 and result[^1].kind == nkWhenStmt:
|
||||
result[^1] = semWhen(c, result[^1], false)
|
||||
if result[^1].kind == nkStmtList:
|
||||
result[^1].transitionSonsKind(nkStmtListType)
|
||||
else:
|
||||
break
|
||||
|
||||
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||
## Semantically check the output of a macro.
|
||||
@@ -504,7 +484,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
# More restrictive version.
|
||||
result = semExprWithType(c, result, flags, expectedType)
|
||||
of tyTypeDesc:
|
||||
result = normalizeTypedescMacroResult(c, result)
|
||||
if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType)
|
||||
var typ = semTypeNode(c, result, nil)
|
||||
if typ == nil:
|
||||
localError(c.config, result.info, "expression has no type: " &
|
||||
@@ -512,7 +492,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
result = newSymNode(errorSym(c, result))
|
||||
else:
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
else:
|
||||
if s.ast[genericParamsPos] != nil and retType.isMetaType:
|
||||
# The return type may depend on the Macro arguments
|
||||
|
||||
@@ -1208,6 +1208,7 @@ type
|
||||
enforcedGcSafety, enforceNoSideEffects: bool
|
||||
oldExc, oldTags, oldForbids: int
|
||||
exc, tags, forbids: PNode
|
||||
excSource, tagsSource, forbidsSource: PNode
|
||||
|
||||
proc createBlockContext(tracked: PEffects): PragmaBlockContext =
|
||||
var oldForbidsLen = 0
|
||||
@@ -1230,17 +1231,18 @@ proc unapplyBlockContext(tracked: PEffects; bc: PragmaBlockContext) =
|
||||
# anything about 'raises' in the 'cast' at all. Same applies for 'tags'.
|
||||
setLen(tracked.exc.sons, bc.oldExc)
|
||||
for e in bc.exc:
|
||||
addRaiseEffect(tracked, e, e)
|
||||
addRaiseEffect(tracked, e, if bc.excSource != nil: bc.excSource else: e)
|
||||
if bc.tags != nil:
|
||||
setLen(tracked.tags.sons, bc.oldTags)
|
||||
for t in bc.tags:
|
||||
addTag(tracked, t, t)
|
||||
addTag(tracked, t, if bc.tagsSource != nil: bc.tagsSource else: t)
|
||||
if bc.forbids != nil:
|
||||
setLen(tracked.forbids.sons, bc.oldForbids)
|
||||
for t in bc.forbids:
|
||||
addNotTag(tracked, t, t)
|
||||
addNotTag(tracked, t, if bc.forbidsSource != nil: bc.forbidsSource else: t)
|
||||
|
||||
proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
|
||||
proc castBlock(tracked: PEffects, castPragma: PNode, bc: var PragmaBlockContext) =
|
||||
let pragma = castPragma[1]
|
||||
case whichPragma(pragma)
|
||||
of wGcSafe:
|
||||
bc.enforcedGcSafety = true
|
||||
@@ -1253,6 +1255,7 @@ proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
|
||||
else:
|
||||
bc.tags = newNodeI(nkArgList, pragma.info)
|
||||
bc.tags.add n
|
||||
bc.tagsSource = castPragma
|
||||
of wForbids:
|
||||
let n = pragma[1]
|
||||
if n.kind in {nkCurly, nkBracket}:
|
||||
@@ -1260,6 +1263,7 @@ proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
|
||||
else:
|
||||
bc.forbids = newNodeI(nkArgList, pragma.info)
|
||||
bc.forbids.add n
|
||||
bc.forbidsSource = castPragma
|
||||
of wRaises:
|
||||
let n = pragma[1]
|
||||
if n.kind in {nkCurly, nkBracket}:
|
||||
@@ -1267,6 +1271,7 @@ proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
|
||||
else:
|
||||
bc.exc = newNodeI(nkArgList, pragma.info)
|
||||
bc.exc.add n
|
||||
bc.excSource = castPragma
|
||||
of wUncheckedAssign:
|
||||
discard "handled in sempass1"
|
||||
else:
|
||||
@@ -1520,7 +1525,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
of wNoSideEffect:
|
||||
bc.enforceNoSideEffects = true
|
||||
of wCast:
|
||||
castBlock(tracked, pragmaList[i][1], bc)
|
||||
castBlock(tracked, pragmaList[i], bc)
|
||||
else:
|
||||
discard
|
||||
applyBlockContext(tracked, bc)
|
||||
|
||||
@@ -791,8 +791,10 @@ proc procParamTypeRel(c: var TCandidate; f, a: PType): TTypeRelation =
|
||||
# different C types (size_t vs unsigned long long).
|
||||
let fCheck = concreteType(c, f)
|
||||
let aCheck = concreteType(c, a)
|
||||
# Note that `result` is equal; now check whether they have the same
|
||||
# backend type.
|
||||
if fCheck != nil and aCheck != nil and
|
||||
not sameBackendTypePickyAliases(fCheck, aCheck):
|
||||
not sameBackendTypePickyAliases(fCheck, aCheck, {IgnoreFlags}):
|
||||
result = isNone
|
||||
|
||||
if result <= isSubrange or inconsistentVarTypes(f, a):
|
||||
@@ -2471,6 +2473,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
return arg
|
||||
elif f.kind == tyStatic and arg.typ.n != nil:
|
||||
return arg.typ.n
|
||||
elif f.kind == tyUntyped:
|
||||
# bug #25693: a different overload candidate may have sem-checked the
|
||||
# operand and left symbols behind; templates expect the pristine AST.
|
||||
return argOrig
|
||||
else:
|
||||
return argSemantized # argOrig
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements threadpool's ``spawn``.
|
||||
|
||||
import ast, types, idents, magicsys, msgs, options, modulegraphs,
|
||||
lowerings, liftdestructors, renderer
|
||||
lowerings, liftdestructors, renderer, trees
|
||||
from trees import getMagic, getRoot
|
||||
|
||||
proc callProc(a: PNode): PNode =
|
||||
@@ -53,6 +53,24 @@ proc typeNeedsNoDeepCopy(t: PType): bool =
|
||||
if t.kind in {tyVar, tyLent, tySequence}: t = t.elementType
|
||||
result = not containsGarbageCollectedRef(t)
|
||||
|
||||
proc newSpawnMoveStmt(g: ModuleGraph; idgen: IdGenerator; le, ri: PNode): PNode =
|
||||
let op = getAttachedOp(g, ri.typ.skipTypes({tyGenericInst, tyAlias, tyVar, tySink}), attachedWasMoved)
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
result = newNodeI(nkStmtList, le.info)
|
||||
result.add newFastAsgnStmt(le, ri)
|
||||
|
||||
let wasMovedCall = newNodeI(nkCall, ri.info)
|
||||
wasMovedCall.add newSymNode(op)
|
||||
|
||||
if op.typ != nil and op.typ.signatureLen > 1 and op.typ.firstParamType.kind != tyVar:
|
||||
wasMovedCall.add ri.skipAddr
|
||||
else:
|
||||
wasMovedCall.add makeAddr(ri.skipAddr, idgen)
|
||||
|
||||
result.add wasMovedCall
|
||||
else:
|
||||
result = newFastMoveStmt(g, le, ri)
|
||||
|
||||
proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator; owner: PSym; typ: PType;
|
||||
v: PNode; useShallowCopy=false): PSym =
|
||||
result = newSym(skTemp, getIdent(g.cache, genPrefix), idgen, owner, varSection.info,
|
||||
@@ -68,10 +86,10 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator;
|
||||
if varInit != nil:
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc}:
|
||||
# inject destructors pass will do its own analysis
|
||||
varInit.add newFastMoveStmt(g, newSymNode(result), v)
|
||||
varInit.add newSpawnMoveStmt(g, idgen, newSymNode(result), v)
|
||||
else:
|
||||
if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions:
|
||||
varInit.add newFastMoveStmt(g, newSymNode(result), v)
|
||||
varInit.add newSpawnMoveStmt(g, idgen, newSymNode(result), v)
|
||||
else:
|
||||
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||
deepCopyCall[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
|
||||
|
||||
@@ -156,7 +156,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
result = typeAllowedAux(marker, t.elementType, kind, c, flags+{taIsOpenArray})
|
||||
of tySink:
|
||||
# you cannot nest openArrays/sinks/etc.
|
||||
if kind != skParam or taIsOpenArray in flags or t.elementType.kind in {tySink, tyLent, tyVar}:
|
||||
# `sink openarray` is not allowed
|
||||
if kind != skParam or taIsOpenArray in flags or t.elementType.kind in {tySink, tyLent, tyVar, tyOpenArray, tyVarargs}:
|
||||
result = t
|
||||
else:
|
||||
result = typeAllowedAux(marker, t.elementType, kind, c, flags)
|
||||
|
||||
@@ -1069,9 +1069,10 @@ proc sameBackendTypeIgnoreRange*(x, y: PType): bool =
|
||||
c.cmp = dcEqIgnoreDistinct
|
||||
result = sameTypeAux(x, y, c)
|
||||
|
||||
proc sameBackendTypePickyAliases*(x, y: PType): bool =
|
||||
proc sameBackendTypePickyAliases*(x, y: PType, flags: TTypeCmpFlags = {}): bool =
|
||||
var c = initSameTypeClosure()
|
||||
c.flags.incl {IgnoreTupleFields, IgnoreRangeShallow, PickyCAliases, PickyBackendAliases}
|
||||
c.flags.incl flags
|
||||
c.cmp = dcEqIgnoreDistinct
|
||||
result = sameTypeAux(x, y, c)
|
||||
|
||||
|
||||
@@ -495,13 +495,16 @@ func `$`*[T](c: CritBitTree[T]): string =
|
||||
const avgItemLen = 16
|
||||
result = newStringOfCap(c.count * avgItemLen)
|
||||
result.add("{")
|
||||
var first = true
|
||||
when T is void:
|
||||
for key in keys(c):
|
||||
if result.len > 1: result.add(", ")
|
||||
if first: first = false
|
||||
else: result.add(", ")
|
||||
result.addQuoted(key)
|
||||
else:
|
||||
for key, val in pairs(c):
|
||||
if result.len > 1: result.add(", ")
|
||||
if first: first = false
|
||||
else: result.add(", ")
|
||||
result.addQuoted(key)
|
||||
result.add(": ")
|
||||
result.addQuoted(val)
|
||||
@@ -523,7 +526,7 @@ func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} =
|
||||
else: c.root.byte
|
||||
else: 0
|
||||
|
||||
proc toCritBitTree*[T](pairs: sink openArray[(string, T)]): CritBitTree[T] {.since: (1, 3).} =
|
||||
proc toCritBitTree*[T](pairs: openArray[(string, T)]): CritBitTree[T] {.since: (1, 3).} =
|
||||
## Creates a new `CritBitTree` that contains the given `pairs`.
|
||||
runnableExamples:
|
||||
doAssert {"a": "0", "b": "1", "c": "2"}.toCritBitTree is CritBitTree[string]
|
||||
@@ -531,7 +534,7 @@ proc toCritBitTree*[T](pairs: sink openArray[(string, T)]): CritBitTree[T] {.sin
|
||||
|
||||
for item in pairs: result.incl item[0], item[1]
|
||||
|
||||
proc toCritBitTree*(items: sink openArray[string]): CritBitTree[void] {.since: (1, 3).} =
|
||||
proc toCritBitTree*(items: openArray[string]): CritBitTree[void] {.since: (1, 3).} =
|
||||
## Creates a new `CritBitTree` that contains the given `items`.
|
||||
runnableExamples:
|
||||
doAssert ["a", "b", "c"].toCritBitTree is CritBitTree[void]
|
||||
|
||||
@@ -454,8 +454,10 @@ proc `$`*[T](deq: Deque[T]): string =
|
||||
assert $a == "[10, 20, 30]"
|
||||
|
||||
result = "["
|
||||
var first = true
|
||||
for x in deq:
|
||||
if result.len > 1: result.add(", ")
|
||||
if first: first = false
|
||||
else: result.add(", ")
|
||||
result.addQuoted(x)
|
||||
result.add("]")
|
||||
|
||||
|
||||
@@ -260,7 +260,9 @@ proc `$`*[T](heap: HeapQueue[T]): string =
|
||||
assert $heap == "[1, 2]"
|
||||
|
||||
result = "["
|
||||
var first = true
|
||||
for x in heap.data:
|
||||
if result.len > 1: result.add(", ")
|
||||
if first: first = false
|
||||
else: result.add(", ")
|
||||
result.addQuoted(x)
|
||||
result.add("]")
|
||||
|
||||
@@ -304,8 +304,10 @@ proc `$`*[T](L: SomeLinkedCollection[T]): string =
|
||||
assert $a == "[1, 2, 3, 4]"
|
||||
|
||||
result = "["
|
||||
var first = true
|
||||
for x in nodes(L):
|
||||
if result.len > 1: result.add(", ")
|
||||
if first: first = false
|
||||
else: result.add(", ")
|
||||
result.addQuoted(x.value)
|
||||
result.add("]")
|
||||
|
||||
|
||||
@@ -175,23 +175,48 @@ proc parseEscapedUTF16*(buf: cstring, pos: var int): int =
|
||||
else:
|
||||
return -1
|
||||
|
||||
proc addSpan(dst: var string; src: string; startPos, endPos: int) {.inline.} =
|
||||
let n = endPos - startPos
|
||||
if n <= 0:
|
||||
return
|
||||
|
||||
let old = dst.len
|
||||
dst.setLen old + n
|
||||
|
||||
template impl =
|
||||
for i in 0..<n:
|
||||
dst[old + i] = src[startPos + i]
|
||||
|
||||
when nimvm:
|
||||
impl
|
||||
else:
|
||||
when defined(js) or defined(nimscript):
|
||||
impl
|
||||
else:
|
||||
{.noSideEffect.}:
|
||||
copyMem dst[old].addr, src[startPos].unsafeAddr, n
|
||||
|
||||
proc parseString(my: var JsonParser): TokKind =
|
||||
result = tkString
|
||||
var pos = my.bufpos + 1
|
||||
var spanStart = pos
|
||||
if my.rawStringLiterals:
|
||||
add(my.a, '"')
|
||||
while true:
|
||||
case my.buf[pos]
|
||||
of '\0':
|
||||
my.err = errQuoteExpected
|
||||
my.err = errInvalidToken
|
||||
addSpan(my.a, my.buf, spanStart, pos)
|
||||
result = tkError
|
||||
break
|
||||
of '"':
|
||||
addSpan(my.a, my.buf, spanStart, pos)
|
||||
if my.rawStringLiterals:
|
||||
add(my.a, '"')
|
||||
inc(pos)
|
||||
break
|
||||
of '\\':
|
||||
addSpan(my.a, my.buf, spanStart, pos)
|
||||
if my.rawStringLiterals:
|
||||
add(my.a, '\\')
|
||||
case my.buf[pos+1]
|
||||
@@ -251,14 +276,18 @@ proc parseString(my: var JsonParser): TokKind =
|
||||
# don't bother with the error
|
||||
add(my.a, my.buf[pos])
|
||||
inc(pos)
|
||||
spanStart = pos
|
||||
of '\c':
|
||||
addSpan(my.a, my.buf, spanStart, pos)
|
||||
pos = lexbase.handleCR(my, pos)
|
||||
add(my.a, '\c')
|
||||
spanStart = pos
|
||||
of '\L':
|
||||
addSpan(my.a, my.buf, spanStart, pos)
|
||||
pos = lexbase.handleLF(my, pos)
|
||||
add(my.a, '\L')
|
||||
spanStart = pos
|
||||
else:
|
||||
add(my.a, my.buf[pos])
|
||||
inc(pos)
|
||||
my.bufpos = pos # store back
|
||||
|
||||
|
||||
@@ -1668,7 +1668,10 @@ func getSymbol(c: var PegLexer, tok: var Token) =
|
||||
while pos < c.buf.len:
|
||||
add(tok.literal, c.buf[pos])
|
||||
inc(pos)
|
||||
if pos < c.buf.len and c.buf[pos] notin strutils.IdentChars: break
|
||||
if pos < c.buf.len:
|
||||
let ch = c.buf[pos]
|
||||
# Keep non-ASCII bytes so UTF-8 terminals reach the rune-aware matchers.
|
||||
if ch notin strutils.IdentChars and ord(ch) < 0x80: break
|
||||
c.bufpos = pos
|
||||
tok.kind = tkIdentifier
|
||||
|
||||
|
||||
@@ -380,8 +380,10 @@ proc `$`*(t: StringTableRef): string {.rtlFunc, extern: "nstDollar".} =
|
||||
result = "{:}"
|
||||
else:
|
||||
result = "{"
|
||||
var first = true
|
||||
for key, val in pairs(t):
|
||||
if result.len > 1: result.add(", ")
|
||||
if first: first = false
|
||||
else: result.add(", ")
|
||||
result.add(key)
|
||||
result.add(": ")
|
||||
result.add(val)
|
||||
|
||||
@@ -166,7 +166,7 @@ proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.}
|
||||
## it was "moved" and to signify its destructor should do nothing and
|
||||
## ideally be optimized away.
|
||||
|
||||
proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} =
|
||||
proc move*[T](x: var T): T {.magic: "Move", noSideEffect, nodestroy.} =
|
||||
result = x
|
||||
{.cast(raises: []), cast(tags: []).}:
|
||||
`=wasMoved`(x)
|
||||
|
||||
13
tests/ccgbugs2/m25294/c.nim
Normal file
13
tests/ccgbugs2/m25294/c.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
template a(T: type): int =
|
||||
when T is uint64: 1 else: 2
|
||||
|
||||
type
|
||||
M*[T] = object
|
||||
data*: seq[T]
|
||||
b: seq[int]
|
||||
indices*: array[a(T), int64]
|
||||
U = distinct uint64
|
||||
D* = object
|
||||
c: M[U]
|
||||
v: array[180000, int64]
|
||||
g*: M[uint64]
|
||||
5
tests/ccgbugs2/m25294/t.nim
Normal file
5
tests/ccgbugs2/m25294/t.nim
Normal file
@@ -0,0 +1,5 @@
|
||||
import ./c
|
||||
|
||||
proc p*(): D =
|
||||
let c = M[uint64](data: @[0], indices: [1])
|
||||
result = D(g: c)
|
||||
7
tests/ccgbugs2/m25800.h
Normal file
7
tests/ccgbugs2/m25800.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*TYPESECTION*/
|
||||
struct CppRef {
|
||||
int* data;
|
||||
CppRef() : data(new int(42)) {}
|
||||
~CppRef() { delete data; data = nullptr; }
|
||||
void reset() { delete data; data = nullptr; }
|
||||
};
|
||||
18
tests/ccgbugs2/t25294.nim
Normal file
18
tests/ccgbugs2/t25294.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
matrix: "--mm:refc; --mm:orc"
|
||||
"""
|
||||
|
||||
import ./m25294/[c, t]
|
||||
|
||||
block:
|
||||
let a = new D
|
||||
a[] = p()
|
||||
discard a[]
|
||||
block:
|
||||
let a = new D
|
||||
a[] = p()
|
||||
discard a[]
|
||||
block:
|
||||
let a = new D
|
||||
a[] = p()
|
||||
discard a[]
|
||||
23
tests/ccgbugs2/t25800.nim
Normal file
23
tests/ccgbugs2/t25800.nim
Normal file
@@ -0,0 +1,23 @@
|
||||
discard """
|
||||
cmd: "nim cpp $file"
|
||||
action: "compile"
|
||||
"""
|
||||
|
||||
# Bug Report 1: {.importcpp.} on =wasMoved generates invalid preprocessor directive #.
|
||||
|
||||
|
||||
type CppRef* {.importcpp, bycopy, noInit, header: "m25800.h".} = object
|
||||
|
||||
proc `=destroy`(x: var CppRef) {.importcpp: "#.~CppRef()".}
|
||||
proc `=wasMoved`(x: var CppRef) {.importcpp: "#.reset()".}
|
||||
proc `=copy`(dest: var CppRef; src: CppRef) {.importcpp: "dest = src".}
|
||||
proc `=sink`(dest: var CppRef; src: CppRef) {.importcpp: "dest = std::move(src)".}
|
||||
|
||||
# This triggers =wasMoved when passing to sink parameter
|
||||
proc consume(x: sink CppRef) = discard
|
||||
|
||||
proc test() =
|
||||
var x: CppRef
|
||||
consume(move(x)) # =wasMoved MUST be called here after the move
|
||||
|
||||
test()
|
||||
@@ -186,7 +186,7 @@ type
|
||||
TableNonCopyable = object
|
||||
x: seq[(string, MySeqNonCopyable)]
|
||||
|
||||
proc toTable(pairs: sink openArray[(string, MySeqNonCopyable)]): TableNonCopyable =
|
||||
proc toTable(pairs: openArray[(string, MySeqNonCopyable)]): TableNonCopyable =
|
||||
discard
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
discard """
|
||||
cmd: '''nim cpp -d:nimAllocStats --newruntime --threads:on $file'''
|
||||
disabled: true
|
||||
output: '''(field: "value")
|
||||
Indeed
|
||||
axc
|
||||
|
||||
@@ -12,3 +12,51 @@ proc foo =
|
||||
doAssert m.id == 999
|
||||
|
||||
foo()
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
a,b,c: int
|
||||
|
||||
var dest: Foo
|
||||
|
||||
# proc `=wasMoved`(x: var Foo) =
|
||||
# debugEcho "wasMoved called"
|
||||
|
||||
proc main() =
|
||||
var x = Foo(a:11, b:12, c:13)
|
||||
dest = move(x)
|
||||
|
||||
main()
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
a,b,c: int
|
||||
|
||||
var dest: Foo
|
||||
|
||||
proc `=wasMoved`(x: var Foo) =
|
||||
discard "wasMoved called"
|
||||
|
||||
proc main() =
|
||||
var x = Foo(a:11, b:12, c:13)
|
||||
dest = move(x)
|
||||
|
||||
main()
|
||||
|
||||
|
||||
import std/threadpool
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
data: string
|
||||
|
||||
proc `=wasMoved`(x: var Foo) =
|
||||
discard
|
||||
|
||||
proc work(x: Foo) =
|
||||
discard
|
||||
|
||||
var x = Foo(data: "hello")
|
||||
spawn work(x)
|
||||
sync()
|
||||
|
||||
|
||||
8
tests/effects/tcast_effect_violation.nim
Normal file
8
tests/effects/tcast_effect_violation.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
discard """
|
||||
errormsg: "cast(raises: ValueError) can raise an unlisted exception: ValueError"
|
||||
line: 7
|
||||
"""
|
||||
|
||||
proc fff() {.raises: [].} =
|
||||
{.cast(raises: ValueError).}:
|
||||
discard
|
||||
30
tests/exception/treraise_typeless_except_finally.nim
Normal file
30
tests/exception/treraise_typeless_except_finally.nim
Normal file
@@ -0,0 +1,30 @@
|
||||
discard """
|
||||
targets: "cpp"
|
||||
matrix: "--mm:arc; --mm:orc; --mm:refc"
|
||||
output: '''
|
||||
finally
|
||||
after
|
||||
'''
|
||||
"""
|
||||
|
||||
# Regression test: typeless `except:` followed by `finally:` must not
|
||||
# trigger ReraiseDefect at the end of the proc.
|
||||
#
|
||||
# Previously, `genTryCpp` only emitted `T_ = nullptr;` in the *typed*
|
||||
# except branches, leaving the typeless `except:` path with a still-set
|
||||
# `T_`. After the handler body and `popCurrentException`, the trailing
|
||||
# `if (T_) std::rethrow_exception(T_);` in the finally block would still
|
||||
# fire — but with the Nim exception stack already popped, the rethrow
|
||||
# bubbled up as a `ReraiseDefect: no exception to reraise`.
|
||||
|
||||
proc test() =
|
||||
try:
|
||||
raise newException(CatchableError, "x")
|
||||
except:
|
||||
let e = getCurrentException()
|
||||
discard e
|
||||
finally:
|
||||
echo "finally"
|
||||
|
||||
test()
|
||||
echo "after"
|
||||
@@ -20,3 +20,25 @@ block: # issue #24021
|
||||
discard
|
||||
else:
|
||||
discard foo.z
|
||||
|
||||
|
||||
# bug #22791
|
||||
type Foo = object
|
||||
case a: bool
|
||||
of false:
|
||||
discard
|
||||
of true:
|
||||
case b: bool
|
||||
of false:
|
||||
discard
|
||||
of true:
|
||||
c: bool
|
||||
|
||||
const f = Foo(a: true, b: true, c: true)
|
||||
case f.a
|
||||
of true:
|
||||
case f.b
|
||||
of true:
|
||||
echo f.c
|
||||
else: discard
|
||||
else: discard
|
||||
@@ -29,3 +29,30 @@ block tnestprc:
|
||||
result = x + y
|
||||
result = add(x, 3)
|
||||
doAssert Add3(7) == 10
|
||||
|
||||
block:
|
||||
type A = object
|
||||
c: int
|
||||
type H = proc(): lent A {.nimcall.}
|
||||
const u = A(c: 0)
|
||||
proc e(T: typedesc): lent A = u
|
||||
proc y(T: typedesc): H =
|
||||
proc(): lent A {.nimcall.} = T.e
|
||||
discard y(int)
|
||||
|
||||
block:
|
||||
type A = object
|
||||
c: int
|
||||
type H = proc(): lent A {.nimcall.}
|
||||
let u = A(c: 0)
|
||||
proc y(_: int | int): H =
|
||||
proc(): lent A {.nimcall.} = u
|
||||
discard y(0)
|
||||
|
||||
block:
|
||||
type A = object
|
||||
c: int
|
||||
type H = proc(): lent A {.nimcall.}
|
||||
let u = A()
|
||||
let _: H = proc(): lent A {.nimcall.} = u
|
||||
|
||||
|
||||
@@ -241,3 +241,12 @@ proc main() =
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/18583
|
||||
# $ separator must be emitted even when the item's string repr is empty
|
||||
type EmptyStr18583 = object
|
||||
proc `$`(x: EmptyStr18583): string = ""
|
||||
|
||||
block:
|
||||
var d = [EmptyStr18583(), EmptyStr18583()].toDeque
|
||||
doAssert $d == "[, ]", "got: " & $d
|
||||
|
||||
@@ -104,3 +104,15 @@ template main() =
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/18583
|
||||
type EmptyStr18583HeapQ = object
|
||||
proc `$`(x: EmptyStr18583HeapQ): string = ""
|
||||
proc `<`(a, b: EmptyStr18583HeapQ): bool = false
|
||||
|
||||
block:
|
||||
var h = initHeapQueue[EmptyStr18583HeapQ]()
|
||||
push(h, EmptyStr18583HeapQ())
|
||||
push(h, EmptyStr18583HeapQ())
|
||||
let s = $h
|
||||
doAssert s == "[, ]", "got: " & s
|
||||
|
||||
@@ -287,3 +287,14 @@ template main =
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/18583
|
||||
type EmptyStr18583List = object
|
||||
proc `$`(x: EmptyStr18583List): string = ""
|
||||
|
||||
block:
|
||||
var L: SinglyLinkedList[EmptyStr18583List]
|
||||
L.prepend(EmptyStr18583List())
|
||||
L.prepend(EmptyStr18583List())
|
||||
let s = $L
|
||||
doAssert s == "[, ]", "got: " & s
|
||||
|
||||
@@ -259,6 +259,11 @@ block:
|
||||
doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
|
||||
doAssert(not match("456678", peg"(\letter)+"))
|
||||
|
||||
block:
|
||||
doAssert match("CAFÉ", peg"\i café")
|
||||
doAssert match("Café", peg"\i café")
|
||||
doAssert "two cafés: Café and CAFÉ".findAll(peg"\i café").len == 3
|
||||
|
||||
doAssert("var1 = key; var2 = key2".replacef(
|
||||
peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
|
||||
"var1<-keykey;var2<-key2key2")
|
||||
|
||||
32
tests/template/toverload_over_untyped.nim
Normal file
32
tests/template/toverload_over_untyped.nim
Normal file
@@ -0,0 +1,32 @@
|
||||
discard """
|
||||
output: "ok"
|
||||
"""
|
||||
|
||||
# bug #25693
|
||||
|
||||
template g(b: untyped) {.dirty.} =
|
||||
template t: untyped = b
|
||||
|
||||
proc d() = discard @[0]
|
||||
proc g(_: int) = discard
|
||||
|
||||
proc f(a: var seq[int], _: string) =
|
||||
let p = @[0]
|
||||
d()
|
||||
a = p
|
||||
|
||||
let q = "a"
|
||||
g:
|
||||
var a: seq[int]
|
||||
try:
|
||||
f(a, q & "1")
|
||||
except CatchableError:
|
||||
discard
|
||||
try:
|
||||
f(a, q & "1")
|
||||
except CatchableError:
|
||||
discard
|
||||
block: t()
|
||||
block: t()
|
||||
echo "ok"
|
||||
|
||||
@@ -45,12 +45,3 @@ elif compiles(nonexistent):
|
||||
else:
|
||||
output("whenElse")
|
||||
|
||||
|
||||
template test(): typedesc =
|
||||
when true:
|
||||
int
|
||||
else:
|
||||
bool
|
||||
|
||||
const c = default(test())
|
||||
echo c
|
||||
|
||||
Reference in New Issue
Block a user