60 changes: 34 additions & 26 deletions compiler/renderer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -557,8 +557,16 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkIfExpr:
result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
len("if_:_")
of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
of nkElifExpr, nkElifBranch:
if isEmptyType(n[1].typ):
result = lsons(g, n) + len("elif_:_")
else:
result = lsons(g, n) + len("_elif_:_")
of nkElseExpr, nkElse:
if isEmptyType(n[0].typ):
result = lsub(g, n[0]) + len("else:_")
else:
result = lsub(g, n[0]) + len("_else:_") # type descriptions
of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
Expand Down Expand Up @@ -601,8 +609,6 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkCommentStmt: result = n.comment.len
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
of nkElse: result = lsub(g, n[0]) + len("else:_")
of nkFinally: result = lsub(g, n[0]) + len("finally:_")
of nkGenericParams: result = lcomma(g, n) + 2
of nkFormalParams:
Expand Down Expand Up @@ -1459,15 +1465,30 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
putWithSpace(g, tkColon, ":")
if n.len > 0: gsub(g, n[0], 1)
gsons(g, n, emptyContext, 1)
of nkElifExpr:
putWithSpace(g, tkElif, " elif")
gcond(g, n[0])
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkElseExpr:
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n, 0)
of nkElifExpr, nkElifBranch:
if isEmptyType(n[1].typ):
optNL(g)
putWithSpace(g, tkElif, "elif")
gsub(g, n, 0)
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[1], c)
else:
putWithSpace(g, tkElif, " elif")
gcond(g, n[0])
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkElseExpr, nkElse:
if isEmptyType(n[0].typ):
optNL(g)
put(g, tkElse, "else")
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[0], c)
else:
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n, 0)
of nkTypeOfExpr:
put(g, tkType, "typeof")
put(g, tkParLe, "(")
Expand Down Expand Up @@ -1729,19 +1750,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkMixinStmt:
putWithSpace(g, tkMixin, "mixin")
gcomma(g, n, c)
of nkElifBranch:
optNL(g)
putWithSpace(g, tkElif, "elif")
gsub(g, n, 0)
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[1], c)
of nkElse:
optNL(g)
put(g, tkElse, "else")
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[0], c)
of nkFinally, nkDefer:
optNL(g)
if n.kind == nkFinally:
Expand Down
3 changes: 2 additions & 1 deletion compiler/semfold.nim
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
of nkCast:
var a = getConstExpr(m, n[1], idgen, g)
if a == nil: return
if n.typ != nil and n.typ.kind in NilableTypes:
if n.typ != nil and n.typ.kind in NilableTypes and
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
# we allow compile-time 'cast' for pointer types:
result = a
result.typ = n.typ
Expand Down
16 changes: 12 additions & 4 deletions compiler/sempass2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables,
semstrictfuncs
semstrictfuncs, lowerings

when defined(nimPreviewSlimSystem):
import std/assertions
Expand Down Expand Up @@ -89,10 +89,11 @@ const
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
errLetNeedsInit = "'let' symbol requires an initialization"

proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
if typ == nil or sfGeneratedOp in tracked.owner.flags:
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit = false) =
if typ == nil or (sfGeneratedOp in tracked.owner.flags and not explicit):
# don't create type bound ops for anything in a function with a `nodestroy` pragma
# bug #21987
# unless this is an explicit call, bug #24626
return
when false:
let realType = typ.skipTypes(abstractInst)
Expand Down Expand Up @@ -926,10 +927,17 @@ proc trackCall(tracked: PEffects; n: PNode) =
# rebind type bounds operations after createTypeBoundOps call
let t = n[1].typ.skipTypes({tyAlias, tyVar})
if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)):
createTypeBoundOps(tracked, t, n.info)
createTypeBoundOps(tracked, t, n.info, explicit = true)
let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind))
if op != nil:
n[0].sym = op
if TTypeAttachedOp(opKind) == attachedDestructor and
op.typ.len == 2 and op.typ.firstParamType.kind != tyVar:
if n[1].kind == nkSym and n[1].sym.kind == skParam and
n[1].typ.kind == tyVar:
n[1] = genDeref(n[1])
else:
n[1] = skipAddr(n[1])

if op != nil and op.kind == tyProc:
for i in 1..<min(n.safeLen, op.len):
Expand Down
11 changes: 11 additions & 0 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,17 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# check the style here after the pragmas have been processed:
styleCheckDef(c, s)
# compute the type's size and check for illegal recursions:
if a[0].kind == nkPragmaExpr:
let pragmas = a[0][1]
for i in 0 ..< pragmas.len:
if pragmas[i].kind == nkExprColonExpr and
pragmas[i][0].kind == nkIdent and
whichKeyword(pragmas[i][0].ident) == wSize:
if s.typ.kind != tyEnum and sfImportc notin s.flags:
# EventType* {.size: sizeof(uint32).} = enum
# AtomicFlag* {.importc: "atomic_flag", header: "<stdatomic.h>", size: 1.} = object
localError(c.config, pragmas[i].info, "size pragma only allowed for enum types and imported types")

if a[1].kind == nkEmpty:
var x = a[2]
if x.kind in nkCallKinds and nfSem in x.flags:
Expand Down
7 changes: 6 additions & 1 deletion compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
if isField:
# possibly not final field sym
incl(s.flags, sfUsed)
markOwnerModuleAsUsed(c, s)
else:
markUsed(c, info, s)
onUse(info, s)
else:
result = n
Expand Down
25 changes: 22 additions & 3 deletions compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ proc transformSons(c: PTransf, n: PNode, noConstFold = false): PNode =
for i in 0..<n.len:
result[i] = transform(c, n[i], noConstFold)

proc transformSonsAfterType(c: PTransf, n: PNode, noConstFold = false): PNode =
result = newTransNode(n)
assert n.len != 0
result[0] = copyTree(n[0])
for i in 1..<n.len:
result[i] = transform(c, n[i], noConstFold)

proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite: bool): PNode =
result = newTransNode(kind, ri.info, 2)
result[0] = le
Expand Down Expand Up @@ -835,9 +842,18 @@ proc transformArrayAccess(c: PTransf, n: PNode): PNode =
if n[0].kind == nkSym and n[0].sym.kind == skType:
result = n
else:
result = newTransNode(n)
for i in 0..<n.len:
result[i] = transform(c, skipConv(n[i]))
result = transformSons(c, n)
if n.len >= 2 and result[1].kind in {nkChckRange, nkChckRange64} and
n[1].kind in {nkHiddenStdConv, nkHiddenSubConv}:
# implicit conversion, was transformed into range check
# remove in favor of index check if conversion to array index type
# has to be done here because the array index type needs to be relaxed
# i.e. a uint32 index can implicitly convert to range[0..3] but not int
let arr = skipTypes(n[0].typ, abstractVarRange)
if arr.kind == tyArray and
firstOrd(c.graph.config, arr) == getOrdValue(result[1][1]) and
lastOrd(c.graph.config, arr) == getOrdValue(result[1][2]):
result[1] = result[1].skipConv

proc getMergeOp(n: PNode): PSym =
case n.kind
Expand Down Expand Up @@ -1058,6 +1074,9 @@ proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = transformConv(c, n)
of nkObjConstr, nkCast:
# don't try to transform type node
result = transformSonsAfterType(c, n)
of nkDiscardStmt:
result = n
if n[0].kind != nkEmpty:
Expand Down
5 changes: 4 additions & 1 deletion compiler/vm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import semmacrosanity
import
std/[strutils, tables, parseutils],
std/[strutils, tables, intsets, parseutils],
msgs, vmdef, vmgen, nimsets, types,
parser, vmdeps, idents, trees, renderer, options, transf,
gorgeimpl, lineinfos, btrees, macrocacheimpl,
Expand Down Expand Up @@ -2375,8 +2375,11 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
setupGlobalCtx(module, g, idgen)
var c = PCtx g.vm
let oldMode = c.mode
let oldLocals = c.locals
c.mode = mode
c.locals = initIntSet()
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
c.locals = oldLocals
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)
assert c.code[start].opcode != opcEof
when debugEchoCode: c.echoCode start
Expand Down
3 changes: 2 additions & 1 deletion compiler/vmdef.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.

import std/[tables, strutils]
import std/[tables, strutils, intsets]

import ast, idents, options, modulegraphs, lineinfos

Expand Down Expand Up @@ -270,6 +270,7 @@ type
templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
locals*: IntSet

PStackFrame* = ref TStackFrame
TStackFrame* {.acyclic.} = object
Expand Down
5 changes: 3 additions & 2 deletions compiler/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
# are in the right scope:
if sfGenSym in s.flags and c.prc.sym == nil: discard
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
elif s.kind in {skVar, skLet} and s.id in c.locals: discard
else: cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
Expand Down Expand Up @@ -1948,7 +1949,7 @@ proc genVarSection(c: PCtx; n: PNode) =
c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner))
elif a[0].kind == nkSym:
let s = a[0].sym
checkCanEval(c, a[0])
c.locals.incl(s.id)
if s.isGlobal:
let runtimeAccessToCompileTime = c.mode == emRepl and
sfCompileTime in s.flags and s.position > 0
Expand Down Expand Up @@ -2013,7 +2014,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
c.gABx(n, opcLdNull, dest, c.genType(n.typ))

let intType = getSysType(c.graph, n.info, tyInt)
let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
let seqType = n.typ.skipTypes(abstractVar+{tyStatic}-{tyTypeDesc})
if seqType.kind == tySequence:
var tmp = c.getTemp(intType)
c.gABx(n, opcLdImmInt, tmp, n.len)
Expand Down
10 changes: 5 additions & 5 deletions doc/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -5096,22 +5096,22 @@ caught by reference. Example:
proc fn() =
let a = initRuntimeError("foo")
doAssert $a.what == "foo"
var b: cstring
var b = ""
try: raise initRuntimeError("foo2")
except CStdException as e:
doAssert e is CStdException
b = e.what()
doAssert $b == "foo2"
b = $e.what()
doAssert b == "foo2"
try: raise initStdException()
except CStdException: discard
try: raise initRuntimeError("foo3")
except CRuntimeError as e:
b = e.what()
b = $e.what()
except CStdException:
doAssert false
doAssert $b == "foo3"
doAssert b == "foo3"
fn()
```
Expand Down
8 changes: 5 additions & 3 deletions lib/pure/parseutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -514,16 +514,18 @@ proc parseSaturatedNatural*(s: openArray[char], b: var int): int {.
proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int =
var
res = 0.BiggestUInt
prev = 0.BiggestUInt
i = 0
if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}:
integerOutOfRangeError()
if i < s.len and s[i] == '+': inc(i) # Allow
if i < s.len and s[i] in {'0'..'9'}:
b = 0
while i < s.len and s[i] in {'0'..'9'}:
prev = res
res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
if res > BiggestUInt.high div 10: # Highest value that you can multiply 10 without overflow
integerOutOfRangeError()
res = res * 10
let prev = res
res += (ord(s[i]) - ord('0')).BiggestUInt
if prev > res:
integerOutOfRangeError()
inc(i)
Expand Down
5 changes: 4 additions & 1 deletion lib/system/arc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ else:
template count(x: Cell): untyped =
x.rc shr rcShift

when not defined(nimHasQuirky):
{.pragma: quirky.}

proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
let hdrSize = align(sizeof(RefHeader), alignment)
let s = size + hdrSize
Expand Down Expand Up @@ -173,7 +176,7 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} =
template `=dispose`*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf)
#proc dispose*(x: pointer) = nimRawDispose(x)

proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} =
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, quirky, raises: [].} =
let rti = cast[ptr PNimTypeV2](p)
if rti.destructor != nil:
cast[DestructorProc](rti.destructor)(p)
Expand Down
2 changes: 1 addition & 1 deletion lib/system/compilation.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const
## is the minor number of Nim's version.
## Odd for devel, even for releases.

NimPatch* {.intdefine.}: int = 14
NimPatch* {.intdefine.}: int = 16
## is the patch number of Nim's version.
## Odd for devel, even for releases.

Expand Down
29 changes: 18 additions & 11 deletions lib/system/dollars.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ when not defined(nimPreviewSlimSystem):
## Outplace version of `addFloat`.
result.addFloat(x)

proc `$`*(x: int): string {.raises: [].} =
## Outplace version of `addInt`.
result.addInt(x)

proc `$`*(x: int64): string {.raises: [].} =
## Outplace version of `addInt`.
result.addInt(x)

proc `$`*(x: uint64): string {.raises: [].} =
## Outplace version of `addInt`.
addInt(result, x)
template addIntAlias(T: typedesc) =
proc `$`*(x: T): string {.raises: [].} =
## Outplace version of `addInt`.
result = ""
result.addInt(x)

# need to declare for bit types as well to not clash with converters:
addIntAlias int
addIntAlias int8
addIntAlias int16
addIntAlias int32
addIntAlias int64

addIntAlias uint
addIntAlias uint8
addIntAlias uint16
addIntAlias uint32
addIntAlias uint64

# same as old `ctfeWhitelist` behavior, whether or not this is a good idea.
template gen(T) =
Expand Down
35 changes: 20 additions & 15 deletions lib/system/repr_v2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,26 @@ proc rangeBase(T: typedesc): typedesc {.magic: "TypeTrait".}

proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.}

proc repr*(x: int): string =
## Same as $x
$x

proc repr*(x: int64): string =
## Same as $x
$x

proc repr*(x: uint64): string {.noSideEffect.} =
## Same as $x
$x

proc repr*(x: float): string =
## Same as $x
$x
template dollarAlias(T: typedesc) =
proc repr*(x: T): string {.noSideEffect.} =
## Same as $x
$x

# need to declare for bit types as well to not clash with converters:
dollarAlias int
dollarAlias int8
dollarAlias int16
dollarAlias int32
dollarAlias int64

dollarAlias uint
dollarAlias uint8
dollarAlias uint16
dollarAlias uint32
dollarAlias uint64

dollarAlias float
dollarAlias float32

proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
## repr for a boolean argument. Returns `x`
Expand Down
13 changes: 7 additions & 6 deletions testament/categories.nim
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) =
if pkg.allowFailure:
inc r.passed
inc r.failedButAllowed
addResult(r, test, targetC, "", "", cmd & "\n" & outp, reFailed, allowFailure = pkg.allowFailure)
discard r.finishTest(test, targetC, "", "", cmd & "\n" & outp, reFailed, allowFailure = pkg.allowFailure)
continue
outp

Expand All @@ -462,21 +462,21 @@ proc testNimblePackages(r: var TResults; cat: Category; packageFilter: string) =
discard tryCommand(cmds[i], maxRetries = 3)
discard tryCommand(cmds[^1], reFailed = reBuildFailed)
inc r.passed
r.addResult(test, targetC, "", "", "", reSuccess, allowFailure = pkg.allowFailure)
discard r.finishTest(test, targetC, "", "", "", reSuccess, allowFailure = pkg.allowFailure)

errors = r.total - r.passed
if errors == 0:
r.addResult(packageFileTest, targetC, "", "", "", reSuccess)
discard r.finishTest(packageFileTest, targetC, "", "", "", reSuccess)
else:
r.addResult(packageFileTest, targetC, "", "", "", reBuildFailed)
discard r.finishTest(packageFileTest, targetC, "", "", "", reBuildFailed)

except JsonParsingError:
errors = 1
r.addResult(packageFileTest, targetC, "", "", "Invalid package file", reBuildFailed)
discard r.finishTest(packageFileTest, targetC, "", "", "Invalid package file", reBuildFailed)
raise
except ValueError:
errors = 1
r.addResult(packageFileTest, targetC, "", "", "Unknown package", reBuildFailed)
discard r.finishTest(packageFileTest, targetC, "", "", "Unknown package", reBuildFailed)
raise # bug #18805
finally:
if errors == 0: removeDir(packagesDir)
Expand Down Expand Up @@ -565,6 +565,7 @@ proc isJoinableSpec(spec: TSpec): bool =
spec.err != reDisabled and
not spec.unjoinable and
spec.exitCode == 0 and
spec.retries == 0 and
spec.input.len == 0 and
spec.nimout.len == 0 and
spec.nimoutFull == false and
Expand Down
2 changes: 1 addition & 1 deletion testament/important_packages.nim
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ pkg "sim"
pkg "smtp", "nimble compileExample"
pkg "snip", "nimble test", "https://github.com/genotrance/snip"
pkg "stew"
pkg "stint", "nim c stint.nim"
pkg "stint", "nimble test_internal"
pkg "strslice"
pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim"
pkg "supersnappy"
Expand Down
5 changes: 5 additions & 0 deletions testament/lib/stdtest/testutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ template enableRemoteNetworking*: bool =
## a `nim` invocation (possibly via additional intermediate processes).
getEnv("NIM_TESTAMENT_REMOTE_NETWORKING") == "1"

template disableSSLTesting*: bool =
## TODO: workaround for GitHub Action gcc 14 matrix; remove this
## matrix and the flag after Azure agent supports ubuntu 24.04
getEnv("NIM_TESTAMENT_DISABLE_SSL") == "1"

template whenRuntimeJs*(bodyIf, bodyElse) =
##[
Behaves as `when defined(js) and not nimvm` (which isn't legal yet).
Expand Down
4 changes: 4 additions & 0 deletions testament/specs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type
reJoined, # test is disabled because it was joined into the megatest
reSuccess # test was successful
reInvalidSpec # test had problems to parse the spec
reRetry # test is being retried

TTarget* = enum
targetC = "c"
Expand Down Expand Up @@ -102,6 +103,7 @@ type
# but don't rely on much precision
inlineErrors*: seq[InlineError] # line information to error message
debugInfo*: string # debug info to give more context
retries*: int # number of retry attempts after the test fails

proc getCmd*(s: TSpec): string =
if s.cmd.len == 0:
Expand Down Expand Up @@ -478,6 +480,8 @@ proc parseSpec*(filename: string): TSpec =
result.timeout = parseFloat(e.value)
except ValueError:
result.parseErrors.addLine "cannot interpret as a float: ", e.value
of "retries":
discard parseInt(e.value, result.retries)
of "targets", "target":
try:
result.targets.incl parseTargets(e.value)
Expand Down
68 changes: 42 additions & 26 deletions testament/testament.nim
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,13 @@ proc testName(test: TTest, target: TTarget, extraOptions: string, allowFailure:
name.strip()

proc addResult(r: var TResults, test: TTest, target: TTarget,
extraOptions, expected, given: string, successOrig: TResultEnum,
extraOptions, expected, given: string, success: TResultEnum, duration: float,
allowFailure = false, givenSpec: ptr TSpec = nil) =
# instead of `ptr TSpec` we could also use `Option[TSpec]`; passing `givenSpec` makes it easier to get what we need
# instead of having to pass individual fields, or abusing existing ones like expected vs given.
# test.name is easier to find than test.name.extractFilename
# A bit hacky but simple and works with tests/testament/tshould_not_work.nim
let name = testName(test, target, extraOptions, allowFailure)
let duration = epochTime() - test.startTime
let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout
else: successOrig

let durationStr = duration.formatFloat(ffDecimal, precision = 2).align(5)
if backendLogging:
Expand Down Expand Up @@ -342,6 +339,18 @@ proc addResult(r: var TResults, test: TTest, target: TTarget,
discard waitForExit(p)
close(p)

proc finishTest(r: var TResults, test: TTest, target: TTarget,
extraOptions, expected, given: string, successOrig: TResultEnum,
allowFailure = false, givenSpec: ptr TSpec = nil): bool =
result = false
let duration = epochTime() - test.startTime
let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout
else: successOrig
if test.spec.retries > 0 and success notin {reSuccess, reDisabled, reJoined, reInvalidSpec}:
return true
else:
addResult(r, test, target, extraOptions, expected, given, success, duration, allowFailure, givenSpec)

proc toString(inlineError: InlineError, filename: string): string =
result.add "$file($line, $col) $kind: $msg" % [
"file", filename,
Expand Down Expand Up @@ -370,23 +379,23 @@ proc nimoutCheck(expected, given: TSpec): bool =
result = false

proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest,
target: TTarget, extraOptions: string) =
target: TTarget, extraOptions: string): bool =
if not checkForInlineErrors(expected, given) or
(not expected.nimoutFull and not nimoutCheck(expected, given)):
r.addResult(test, target, extraOptions, expected.nimout & inlineErrorsMsgs(expected), given.nimout, reMsgsDiffer)
result = r.finishTest(test, target, extraOptions, expected.nimout & inlineErrorsMsgs(expected), given.nimout, reMsgsDiffer)
elif strip(expected.msg) notin strip(given.msg):
r.addResult(test, target, extraOptions, expected.msg, given.msg, reMsgsDiffer)
result = r.finishTest(test, target, extraOptions, expected.msg, given.msg, reMsgsDiffer)
elif not nimoutCheck(expected, given):
r.addResult(test, target, extraOptions, expected.nimout, given.nimout, reMsgsDiffer)
result = r.finishTest(test, target, extraOptions, expected.nimout, given.nimout, reMsgsDiffer)
elif extractFilename(expected.file) != extractFilename(given.file) and
"internal error:" notin expected.msg:
r.addResult(test, target, extraOptions, expected.file, given.file, reFilesDiffer)
result = r.finishTest(test, target, extraOptions, expected.file, given.file, reFilesDiffer)
elif expected.line != given.line and expected.line != 0 or
expected.column != given.column and expected.column != 0:
r.addResult(test, target, extraOptions, $expected.line & ':' & $expected.column,
result = r.finishTest(test, target, extraOptions, $expected.line & ':' & $expected.column,
$given.line & ':' & $given.column, reLinesDiffer)
else:
r.addResult(test, target, extraOptions, expected.msg, given.msg, reSuccess)
result = r.finishTest(test, target, extraOptions, expected.msg, given.msg, reSuccess)
inc(r.passed)

proc generatedFile(test: TTest, target: TTarget): string =
Expand Down Expand Up @@ -425,7 +434,7 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st
echo getCurrentExceptionMsg()

proc compilerOutputTests(test: TTest, target: TTarget, extraOptions: string,
given: var TSpec, expected: TSpec; r: var TResults) =
given: var TSpec, expected: TSpec; r: var TResults): bool =
var expectedmsg: string = ""
var givenmsg: string = ""
if given.err == reSuccess:
Expand All @@ -440,7 +449,7 @@ proc compilerOutputTests(test: TTest, target: TTarget, extraOptions: string,
else:
givenmsg = "$ " & given.cmd & '\n' & given.nimout
if given.err == reSuccess: inc(r.passed)
r.addResult(test, target, extraOptions, expectedmsg, givenmsg, given.err)
result = r.finishTest(test, target, extraOptions, expectedmsg, givenmsg, given.err)

proc getTestSpecTarget(): TTarget =
if getEnv("NIM_COMPILE_TO_CPP", "false") == "true":
Expand All @@ -456,31 +465,38 @@ proc equalModuloLastNewline(a, b: string): bool =

proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec,
target: TTarget, extraOptions: string, nimcache: string) =
test.startTime = epochTime()
template maybeRetry(x: bool) =
if x:
test.spec.err = reRetry
dec test.spec.retries
testSpecHelper(r, test, expected, target, extraOptions, nimcache)
return
if test.spec.err != reRetry:
test.startTime = epochTime()
if testName(test, target, extraOptions, false) in skips:
test.spec.err = reDisabled

if test.spec.err in {reDisabled, reJoined}:
r.addResult(test, target, extraOptions, "", "", test.spec.err)
discard r.finishTest(test, target, extraOptions, "", "", test.spec.err)
inc(r.skipped)
return
var given = callNimCompiler(expected.getCmd, test.name, test.options, nimcache, target, extraOptions)
case expected.action
of actionCompile:
compilerOutputTests(test, target, extraOptions, given, expected, r)
maybeRetry compilerOutputTests(test, target, extraOptions, given, expected, r)
of actionRun:
if given.err != reSuccess:
r.addResult(test, target, extraOptions, "", "$ " & given.cmd & '\n' & given.nimout, given.err, givenSpec = given.addr)
maybeRetry r.finishTest(test, target, extraOptions, "", "$ " & given.cmd & '\n' & given.nimout, given.err, givenSpec = given.addr)
else:
let isJsTarget = target == targetJS
var exeFile = changeFileExt(test.name, if isJsTarget: "js" else: ExeExt)
if not fileExists(exeFile):
r.addResult(test, target, extraOptions, expected.output,
maybeRetry r.finishTest(test, target, extraOptions, expected.output,
"executable not found: " & exeFile, reExeNotFound)
else:
let nodejs = if isJsTarget: findNodeJs() else: ""
if isJsTarget and nodejs == "":
r.addResult(test, target, extraOptions, expected.output, "nodejs binary not in PATH",
maybeRetry r.finishTest(test, target, extraOptions, expected.output, "nodejs binary not in PATH",
reExeNotFound)
else:
var exeCmd: string
Expand Down Expand Up @@ -512,27 +528,27 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec,
buf
if exitCode != expected.exitCode:
given.err = reExitcodesDiffer
r.addResult(test, target, extraOptions, "exitcode: " & $expected.exitCode,
maybeRetry r.finishTest(test, target, extraOptions, "exitcode: " & $expected.exitCode,
"exitcode: " & $exitCode & "\n\nOutput:\n" &
bufB, reExitcodesDiffer)
elif (expected.outputCheck == ocEqual and not expected.output.equalModuloLastNewline(bufB)) or
(expected.outputCheck == ocSubstr and expected.output notin bufB):
given.err = reOutputsDiffer
r.addResult(test, target, extraOptions, expected.output, bufB, reOutputsDiffer)
compilerOutputTests(test, target, extraOptions, given, expected, r)
maybeRetry r.finishTest(test, target, extraOptions, expected.output, bufB, reOutputsDiffer)
maybeRetry compilerOutputTests(test, target, extraOptions, given, expected, r)
of actionReject:
# Make sure its the compiler rejecting and not the system (e.g. segfault)
cmpMsgs(r, expected, given, test, target, extraOptions)
maybeRetry cmpMsgs(r, expected, given, test, target, extraOptions)
if given.exitCode != QuitFailure:
r.addResult(test, target, extraOptions, "exitcode: " & $QuitFailure,
maybeRetry r.finishTest(test, target, extraOptions, "exitcode: " & $QuitFailure,
"exitcode: " & $given.exitCode & "\n\nOutput:\n" &
given.nimout, reExitcodesDiffer)

proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: string) =
for target in expected.targets:
inc(r.total)
if target notin gTargets:
r.addResult(test, target, extraOptions, "", "", reDisabled)
discard r.finishTest(test, target, extraOptions, "", "", reDisabled)
inc(r.skipped)
elif simulate:
inc count
Expand All @@ -546,7 +562,7 @@ proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) =
var expected = test.spec
if expected.parseErrors.len > 0:
# targetC is a lie, but a parameter is required
r.addResult(test, targetC, "", "", expected.parseErrors, reInvalidSpec)
discard r.finishTest(test, targetC, "", "", expected.parseErrors, reInvalidSpec)
inc(r.total)
return

Expand Down
20 changes: 20 additions & 0 deletions testament/tests/shouldfail/tnotenoughretries.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
discard """
retries: 1
"""

import os

const tempFile = "tnotenoughretries_temp"

if not fileExists(tempFile):
writeFile(tempFile, "abc")
quit(1)
else:
let content = readFile(tempFile)
if content == "abc":
writeFile(tempFile, "def")
quit(1)
else:
# success
removeFile(tempFile)
discard
13 changes: 13 additions & 0 deletions tests/arc/tarc_orc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,16 @@ block:
testCase()

main()

block: # bug #24147
type
O = object of RootObj
val: string
OO = object of O

proc `=copy`(dest: var O, src: O) =
dest.val = src.val

let oo = OO(val: "hello world")
var ooCopy : OO
`=copy`(ooCopy, oo)
20 changes: 20 additions & 0 deletions tests/arc/tnodestroyexplicithook.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# issue #24626

proc arrayWith2[T](y: T, size: static int): array[size, T] {.noinit, nodestroy, raises: [].} =
## Creates a new array filled with `y`.
for i in 0..size-1:
when defined(nimHasDup):
result[i] = `=dup`(y)
else:
wasMoved(result[i])
`=copy`(result[i], y)

proc useArray(x: seq[int]) =
var a = arrayWith2(x, 2)

proc main =
let x = newSeq[int](100)
for i in 0..5:
useArray(x)

main()
3 changes: 2 additions & 1 deletion tests/arc/topt_cursor.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ var
try:
x_cursor = ("hi", 5)
if cond:
x_cursor = ("different", 54) else:
x_cursor = ("different", 54)
else:
x_cursor = ("string here", 80)
echo [
:tmpD = `$$`(x_cursor)
Expand Down
3 changes: 2 additions & 1 deletion tests/arc/topt_no_cursor.nim
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ if dirExists(this.value):
var :tmpD
par = (dir:
:tmpD = `=dup`(this.value)
:tmpD, front: "") else:
:tmpD, front: "")
else:
var
:tmpD_1
:tmpD_2
Expand Down
16 changes: 16 additions & 0 deletions tests/arc/tvalgrind.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
discard """
cmd: "nim c --mm:orc -d:useMalloc $file"
valgrind: "true"
"""

import std/streams


proc foo() =
var name = newStringStream("2r2")
raise newException(ValueError, "sh")

try:
foo()
except:
discard
4 changes: 4 additions & 0 deletions tests/array/tindexconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
block: # issue #17958
var mem: array[uint8, uint8]
let val = 0xffff'u16
discard mem[uint8 val] # Error: unhandled exception: index 65535 not in 0 .. 255 [IndexDefect]
2 changes: 1 addition & 1 deletion tests/array/tinvalidarrayaccess.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
discard """
errormsg: "index 2 not in 0 .. 1"
errormsg: "conversion from int literal(2) to range 0..1(int) is invalid"
line: 18
"""
block:
Expand Down
2 changes: 1 addition & 1 deletion tests/array/tinvalidarrayaccess2.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
discard """
errormsg: "index 3 not in 0 .. 1"
errormsg: "conversion from int literal(3) to range 0..1(int) is invalid"
line: 9
"""

Expand Down
12 changes: 5 additions & 7 deletions tests/cpp/tmanual_exception.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
discard """
# doesn't work on macos 13 seemingly due to libc++ linking issue https://stackoverflow.com/a/77375947
disabled: osx
targets: cpp
"""

Expand All @@ -18,21 +16,21 @@ proc initStdException(): CStdException {.importcpp: "std::exception()", construc
proc fn() =
let a = initRuntimeError("foo")
doAssert $a.what == "foo"
var b: cstring
var b = ""
try: raise initRuntimeError("foo2")
except CStdException as e:
doAssert e is CStdException
b = e.what()
doAssert $b == "foo2"
b = $e.what()
doAssert b == "foo2"

try: raise initStdException()
except CStdException: discard

try: raise initRuntimeError("foo3")
except CRuntimeError as e:
b = e.what()
b = $e.what()
except CStdException:
doAssert false
doAssert $b == "foo3"
doAssert b == "foo3"

fn()
23 changes: 23 additions & 0 deletions tests/destructor/tdistinctseq.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,26 @@ type DistinctSeq* = distinct seq[int]
# `=destroy`(cast[ptr DistinctSeq](0)[])
var x = @[].DistinctSeq
`=destroy`(x)


import std/options

# bug #24801
type
B[T] = object
case r: bool
of false:
v: ref int
of true:
x: T
E = distinct seq[int]
U = ref object of RootObj
G = ref object of U

proc a(): E = default(E)
method c(_: U): seq[E] {.base.} = discard
proc p(): seq[E] = c(default(U))
method c(_: G): seq[E] = discard E(newSeq[seq[int]](1)[0])
method y(_: U) {.base.} =
let s = default(B[tuple[f: B[int], w: B[int]]])
discard some(s.x)
4 changes: 4 additions & 0 deletions tests/gc/bintrees.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
discard """
retries: 2
"""

# -*- nim -*-

import os, strutils
Expand Down
1 change: 1 addition & 0 deletions tests/gc/closureleak.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
discard """
outputsub: "true"
disabled: "32bit"
retries: 2
"""

type
Expand Down
3 changes: 3 additions & 0 deletions tests/gc/cyclecollector.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
discard """
retries: 2
"""

# Program to detect bug #1796 reliably

Expand Down
1 change: 1 addition & 0 deletions tests/gc/cycleleak.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

type
Expand Down
1 change: 1 addition & 0 deletions tests/gc/foreign_thr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Hello from thread
Hello from thread
'''
cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file"
retries: 2
"""
# Copied from stdlib
import strutils
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcbench.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "Success!"
retries: 2
"""

# This is adapted from a benchmark written by John Ellis and Pete Kovac
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcemscripten.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "77\n77"
retries: 2
"""

## Check how GC/Alloc works in Emscripten
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcleak.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

when defined(GC_setMaxPause):
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcleak2.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

when defined(GC_setMaxPause):
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcleak3.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

when defined(GC_setMaxPause):
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcleak4.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

type
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gcleak5.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
output: "success"
retries: 2
"""

import os, times
Expand Down
1 change: 1 addition & 0 deletions tests/gc/gctest.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "finished"
retries: 2
"""

# Test the garbage collector.
Expand Down
4 changes: 4 additions & 0 deletions tests/gc/growobjcrash.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
discard """
retries: 2
"""

import std/[cgi, strtabs]

proc handleRequest(query: string): StringTableRef =
Expand Down
1 change: 1 addition & 0 deletions tests/gc/refarrayleak.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

type
Expand Down
1 change: 1 addition & 0 deletions tests/gc/stackrefleak.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
outputsub: "no leak: "
retries: 2
"""

type
Expand Down
1 change: 1 addition & 0 deletions tests/gc/tdisable_orc.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
joinable: false
retries: 2
"""

import std/asyncdispatch
Expand Down
1 change: 1 addition & 0 deletions tests/gc/thavlak.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Performing Loop Recognition
Another 3 iterations...
...
Found 1 loops (including artificial root node) (3)'''
retries: 2
"""

# bug #3184
Expand Down
1 change: 1 addition & 0 deletions tests/gc/tlists.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
output: '''Success'''
retries: 2
"""

# bug #3793
Expand Down
1 change: 1 addition & 0 deletions tests/gc/trace_globals.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ discard """
10000000
10000000
10000000'''
retries: 2
"""

# bug #17085
Expand Down
1 change: 1 addition & 0 deletions tests/gc/tregionleak.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ discard """
finalized
finalized
'''
retries: 2
"""

proc finish(o: RootRef) =
Expand Down
1 change: 1 addition & 0 deletions tests/gc/weakrefs.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
output: "true"
retries: 2
"""

import intsets
Expand Down
7 changes: 7 additions & 0 deletions tests/iter/ttypeofclosureiter.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# issue #24859

template u(): int =
yield 0
0
iterator s(): int {.closure.} = discard default(typeof(u()))
let _ = s
5 changes: 3 additions & 2 deletions tests/js/tindexdefect.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ discard """
"""

var s = ['a']
let z = s[10000] == 'a'
echo z
let i = 10000
let z = s[i] == 'a'
echo z
7 changes: 6 additions & 1 deletion tests/misc/tcast.nim
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
discard """
output: '''
Hello World
Hello World
Hello World'''
joinable: false
"""
type MyProc = proc() {.cdecl.}
type MyProc2 = proc() {.nimcall.}
type MyProc3 = proc() #{.closure.} is implicit

proc testProc() = echo "Hello World"
proc testProc() {.exportc:"foo".} = echo "Hello World"

template reject(x) = doAssert(not compiles(x))

Expand All @@ -23,6 +24,10 @@ proc callPointer(p: pointer) =
ffunc0()
ffunc1()

# bug #5901
proc foo() {.importc.}
(cast[proc(a: int) {.cdecl.}](foo))(5)

callPointer(cast[pointer](testProc))

reject: discard cast[enum](0)
Expand Down
7 changes: 6 additions & 1 deletion tests/misc/trunner_special.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ xxx test all tests/untestable/* here, possibly with adjustments to make running
import std/[strformat,os,unittest,compilesettings]
import stdtest/specialpaths


from stdtest/testutils import disableSSLTesting


const
nim = getCurrentCompilerExe()
mode = querySetting(backend)
Expand All @@ -29,4 +33,5 @@ proc main =
block: # SSL certificate check integration tests
runCmd fmt"{nim} r {options} -d:ssl --threads:on --mm:refc {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim"

main()
when not disableSSLTesting():
main()
1 change: 1 addition & 0 deletions tests/niminaction/Chapter8/sfml/sfml_test.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
discard """
action: compile
disabled: "windows"
disabled: osx
"""

import sfml, os
Expand Down
30 changes: 30 additions & 0 deletions tests/objects/t24847.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# issue #24847

block: # original issue test
type
R[C] = ref object of RootObj
b: C
K[S] = ref object of R[S]
W[J] = object
case y: bool
of false, true: discard

proc e[T]() = discard K[T]()
iterator h(): int {.closure.} = e[W[int]]()
let _ = h
type U = distinct int
e[W[U]]()

block: # simplified
type
R[C] = ref object of RootObj
b: C
K[S] = ref object of R[S]
W[J] = object
case y: bool
of false, true: discard

type U = distinct int

discard K[W[int]]()
discard K[W[U]]()
6 changes: 5 additions & 1 deletion tests/stdlib/thttpclient_ssl.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
discard """
cmd: "nim $target --mm:refc -d:ssl $options $file"
disabled: "openbsd"
retries: 2
"""

# Nim - Basic SSL integration tests
Expand All @@ -13,7 +14,10 @@ discard """
## Test with:
## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim

when not defined(windows):

from stdtest/testutils import disableSSLTesting

when not defined(windows) and not disableSSLTesting():
# Disabled on Windows due to old OpenSSL version
import std/[formatfloat, syncio]
import
Expand Down
48 changes: 48 additions & 0 deletions tests/stdlib/tparseuints.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,54 @@ import unittest, strutils

block: # parseutils
check: parseBiggestUInt("0") == 0'u64
check: parseBiggestUInt("1") == 1'u64
check: parseBiggestUInt("2") == 2'u64
check: parseBiggestUInt("10") == 10'u64
check: parseBiggestUInt("11") == 11'u64
check: parseBiggestUInt("99") == 99'u64
check: parseBiggestUInt("123") == 123'u64
check: parseBiggestUInt("9876") == 9876'u64
check: parseBiggestUInt("1_234") == 1234'u64
check: parseBiggestUInt("123__4") == 1234'u64
for i in 1.BiggestUInt .. 9.BiggestUInt:
var x = i
for j in 1 .. 19:
check parseBiggestUInt((i + '0'.uint).char.repeat j) == x
x *= 10
x += i
check: parseBiggestUInt("18446744073709551609") == 0xFFFF_FFFF_FFFF_FFF9'u64
check: parseBiggestUInt("18446744073709551610") == 0xFFFF_FFFF_FFFF_FFFA'u64
check: parseBiggestUInt("18446744073709551611") == 0xFFFF_FFFF_FFFF_FFFB'u64
check: parseBiggestUInt("18446744073709551612") == 0xFFFF_FFFF_FFFF_FFFC'u64
check: parseBiggestUInt("18446744073709551613") == 0xFFFF_FFFF_FFFF_FFFD'u64
check: parseBiggestUInt("18446744073709551614") == 0xFFFF_FFFF_FFFF_FFFE'u64
check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64
expect(ValueError):
discard parseBiggestUInt("18446744073709551616")
expect(ValueError):
discard parseBiggestUInt("18446744073709551617")
expect(ValueError):
discard parseBiggestUInt("18446744073709551618")
expect(ValueError):
discard parseBiggestUInt("18446744073709551619")
expect(ValueError):
discard parseBiggestUInt("18446744073709551620")
expect(ValueError):
discard parseBiggestUInt("18446744073709551621")
expect(ValueError):
discard parseBiggestUInt("18446744073709551622")
expect(ValueError):
discard parseBiggestUInt("18446744073709551623")
expect(ValueError):
for i in 0 .. 999:
discard parseBiggestUInt("18446744073709552" & intToStr(i, 3))
expect(ValueError):
discard parseBiggestUInt("22751622367522324480000000")
expect(ValueError):
discard parseBiggestUInt("41404969074137497600000000")
expect(ValueError):
discard parseBiggestUInt("20701551093035827200000000000000000")
expect(ValueError):
discard parseBiggestUInt("225462255024603136000000000000000000")
expect(ValueError):
discard parseBiggestUInt("204963831854661632000000000000000000")
24 changes: 24 additions & 0 deletions tests/stdlib/trepr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,27 @@ do:

static: main()
main()

import std/macros

# bug #24850
macro a() =
let
y = quote do: discard
b = nnkIfStmt.newTree(
nnkElifExpr.newTree(ident "true", y), nnkElseExpr.newTree(y))
d = nnkWhenStmt.newTree(
nnkElifExpr.newTree(ident "true", y), nnkElseExpr.newTree(y))
doAssert repr(b) == """
if true:
discard
else:
discard"""

doAssert repr(d) == """
when true:
discard
else:
discard"""

a()
5 changes: 5 additions & 0 deletions tests/system/treprconverter.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# issue #24864

type S = distinct uint16
converter d(field: uint8 | uint16): S = discard
discard (repr(0'u16), repr(0'u8))
9 changes: 9 additions & 0 deletions tests/template/tfielduse.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# issue #24657

proc g() {.error.} = discard

type T = object
g: int

template B(): untyped = typeof(T.g)
type _ = B()
15 changes: 15 additions & 0 deletions tests/template/tgenericobjconstr.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
discard """
matrix: "--skipParentCfg"
"""

# issue #24631

type
V[d: static bool] = object
l: int

template y(): V[false] = V[false](l: 0)
discard y()

template z(): V[false] = cast[V[false]](V[false](l: 0))
discard z()
20 changes: 20 additions & 0 deletions tests/testament/tretries.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
discard """
retries: 2
"""

import os

const tempFile = "tretries_temp"

if not fileExists(tempFile):
writeFile(tempFile, "abc")
quit(1)
else:
let content = readFile(tempFile)
if content == "abc":
writeFile(tempFile, "def")
quit(1)
else:
# success
removeFile(tempFile)
discard
4 changes: 3 additions & 1 deletion tests/testament/tshould_not_work.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ FAIL: tests/shouldfail/tnimout.nim
Failure: reMsgsDiffer
FAIL: tests/shouldfail/tnimoutfull.nim
Failure: reMsgsDiffer
FAIL: tests/shouldfail/tnotenoughretries.nim
Failure: reExitcodesDiffer
FAIL: tests/shouldfail/toutput.nim
Failure: reOutputsDiffer
FAIL: tests/shouldfail/toutputsub.nim
Expand All @@ -43,7 +45,7 @@ import stdtest/testutils

proc main =
const nim = getCurrentCompilerExe()
let testamentExe = "bin/testament"
let testamentExe = "testament/testament"
let cmd = fmt"{testamentExe} --directory:testament --colors:off --backendLogging:off --nim:{nim} category shouldfail"
let (outp, status) = execCmdEx(cmd)
doAssert status == 1, $status
Expand Down
3 changes: 2 additions & 1 deletion tests/untestable/thttpclient_ssl_disabled.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimDisableCertificateValidation -d:ssl -p:. tests/untestable/thttpclient_ssl_disabled.nim

from stdtest/testutils import enableRemoteNetworking
when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
# badssl tests disabled indefinitely
when false and enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
import httpclient, net, unittest

const expired = "https://expired.badssl.com/"
Expand Down
14 changes: 7 additions & 7 deletions tests/untestable/thttpclient_ssl_env_var.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ from net import newSocket, newContext, wrapSocket, connect, close, Port,
from strutils import contains

const
expired = "https://expired.badssl.com/"
good = "https://google.com/"


Expand Down Expand Up @@ -56,12 +55,13 @@ suite "SSL certificate check":
var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars)
ctx.wrapSocket(sock)
checkpoint("Socket created")
try:
sock.connect("expired.badssl.com", 443.Port)
fail()
except:
sock.close
check getCurrentExceptionMsg().contains("certificate verify failed")
when false: # badssl tests disabled indefinitely
try:
sock.connect("expired.badssl.com", 443.Port)
fail()
except:
sock.close
check getCurrentExceptionMsg().contains("certificate verify failed")

elif existsEnv("SSL_CERT_DIR"):
var sock = newSocket()
Expand Down
5 changes: 3 additions & 2 deletions tests/untestable/thttpclient_ssl_remotenetwork.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win
CertTest = tuple[url:string, category:Category, desc: string]

# badssl certs sometimes expire, set to false when that happens
when true:
# badssl now disabled indefinitely
when false:
const certificate_tests: array[0..54, CertTest] = [
("https://wrong.host.badssl.com/", bad, "wrong.host"),
("https://captive-portal.badssl.com/", bad, "captive-portal"),
Expand Down Expand Up @@ -197,7 +198,7 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win

type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string]
# badssl certs sometimes expire, set to false when that happens
when true:
when false:
const net_tests:array[0..3, NetSocketTest] = [
("imap.gmail.com", 993.Port, good, "IMAP"),
("wrong.host.badssl.com", 443.Port, bad, "wrong.host"),
Expand Down
79 changes: 79 additions & 0 deletions tests/vm/tconststaticvar.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
block: # issue #8758
template baz() =
var i = 0

proc foo() =
static:
var i = 0
baz()

block: # issue #10828
proc test(i: byte): bool =
const SET = block: # No issues when defined outside proc
var s: set[byte]
for i in 0u8 .. 255u8: incl(s, i)
s
return i in SET
doAssert test(0)
doAssert test(127)
doAssert test(255)

block: # issue #12172
const TEST = block:
var test: array[5, string]
for i in low(test)..high(test):
test[i] = $i
test
proc test =
const TEST2 = block:
var test: array[5, string] # Error here
for i in low(test)..high(test):
test[i] = $i
test
doAssert TEST == TEST2
doAssert TEST == @["0", "1", "2", "3", "4"]
doAssert TEST2 == @["0", "1", "2", "3", "4"]
test()

block: # issue #21610
func stuff(): int =
const r = block:
var r = 1 # Error: cannot evaluate at compile time: r
for i in 2..10:
r *= i
r
r
doAssert stuff() == 3628800

block: # issue #23803
func foo1(c: int): int {.inline.} =
const arr = block:
var res: array[0..99, int]
res[42] = 43
res
arr[c]
doAssert foo1(41) == 0
doAssert foo1(42) == 43
doAssert foo1(43) == 0

# works
func foo2(c: int): int {.inline.} =
func initArr(): auto =
var res: array[0..99, int]
res[42] = 43
res
const arr = initArr()
arr[c]
doAssert foo2(41) == 0
doAssert foo2(42) == 43
doAssert foo2(43) == 0

# also works
const globalArr = block:
var res: array[0..99, int]
res[42] = 43
res
func foo3(c: int): int {.inline.} = globalArr[c]
doAssert foo3(41) == 0
doAssert foo3(42) == 43
doAssert foo3(43) == 0
13 changes: 13 additions & 0 deletions tests/vm/tconststaticvar2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# issue #24634

type J = object

template m(u: J): int =
let v = u
0

proc g() =
const x = J()
const _ = m(x)

g()
9 changes: 9 additions & 0 deletions tests/vm/tconststaticvar3.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# issue #24633

import std/sequtils

proc f(a: static openArray[int]) =
const s1 = a.mapIt(it)
const s2 = a.toSeq()

f([1,2,3])
6 changes: 6 additions & 0 deletions tests/vm/tconststaticvar_wrong.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
proc test =
const TEST = block:
let i = 1
const j = i + 1 #[tt.Error
^ cannot evaluate at compile time: i]#
j
9 changes: 9 additions & 0 deletions tests/vm/topenarrays.nim
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,12 @@ template fn=
doAssert test([0,1,2,3,4,5]).id == 0
fn() # ok
static: fn()

block: # bug #24630
func f(a: static openArray[int]): int =
12

func g(a: static openArray[int]) =
const b = f(a)

g(@[1,2,3])
2 changes: 1 addition & 1 deletion tests/vm/tvmmisc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ block: # bug #8007
block: # bug #14340
block:
proc opl3EnvelopeCalcSin0() = discard
type EnvelopeSinfunc = proc()
type EnvelopeSinfunc = proc() {.nimcall.} # todo: fixme
# const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok
const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug
const envelopeSin = [EnvelopeCalcSin0]
Expand Down