Merge remote-tracking branch 'upstream/devel' into pr_object

This commit is contained in:
ringabout
2023-03-24 23:29:14 +08:00
29 changed files with 188 additions and 64 deletions

View File

@@ -510,7 +510,7 @@ type
nfLastRead # this node is a last read
nfFirstWrite # this node is a first write
nfHasComment # node has a comment
nfUseDefaultField # node has a default value (object constructor)
nfSkipFieldChecking # node skips field visable checking
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
@@ -1081,7 +1081,7 @@ const
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
nfFromTemplate, nfDefaultRefsParam,
nfExecuteOnReload, nfLastRead,
nfFirstWrite, nfUseDefaultField}
nfFirstWrite, nfSkipFieldChecking}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2

View File

@@ -572,7 +572,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s
let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
if asgnExpr != nil:
hasDefault = true
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
return
@@ -582,7 +582,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s
newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, recNode.info, asgnType)
)
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recType
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
@@ -604,7 +604,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
defaultValue = newIntNode(nkIntLit#[c.graph]#, 0)
defaultValue.typ = discriminator.typ
selectedBranch = recNode.pickCaseBranchIndex defaultValue
defaultValue.flags.incl nfUseDefaultField
defaultValue.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1])
of nkSym:
@@ -616,7 +616,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
let asgnExpr = defaultNodeField(c, recNode, recType)
if asgnExpr != nil:
asgnExpr.typ = recType
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
doAssert false

View File

@@ -338,7 +338,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
if n[0].kind in nkIdentKinds:
let ident = considerQuotedIdent(c, n[0], n).s
localError(c.config, n.info, errUndeclaredRoutine % ident)
else:
else:
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
return
@@ -630,7 +630,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
if efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
elif efNoUndeclared notin flags:
notFoundError(c, n, errors)

View File

@@ -302,7 +302,7 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
result = newNodeI(nkConv, n.info)
var targetType = semTypeNode(c, n[0], nil)
case targetType.kind
case targetType.skipTypes({tyDistinct}).kind
of tyTypeDesc:
internalAssert c.config, targetType.len > 0
if targetType.base.kind == tyNone:
@@ -787,7 +787,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
else:
result = newHiddenAddrTaken(c, n, isOutParam)
proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
checkMinSonsLen(n, 1, c.config)
const
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
@@ -795,10 +795,15 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
mWasMoved}
template checkIfConverterCalled(c: PContext, n: PNode) =
## Checks if there is a converter call which wouldn't be checked otherwise
# Call can sometimes be wrapped in a deref
let node = if n.kind == nkHiddenDeref: n[0] else: n
if node.kind == nkHiddenCallConv:
analyseIfAddressTakenInCall(c, node, true)
# get the real type of the callee
# it may be a proc var with a generic alias type, so we skip over them
var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink})
if n[0].kind == nkSym and n[0].sym.magic in FakeVarParams:
# BUGFIX: check for L-Value still needs to be done for the arguments!
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
@@ -813,6 +818,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
discard "allow access within a cast(unsafeAssign) section"
else:
localError(c.config, it.info, errVarForOutParamNeededX % $it)
# Make sure to still check arguments for converters
c.checkIfConverterCalled(n[i])
# bug #5113: disallow newSeq(result) where result is a 'var T':
if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}:
var arg = n[1] #.skipAddr
@@ -824,15 +831,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
return
for i in 1..<n.len:
let n = if n.kind == nkHiddenDeref: n[0] else: n
if n[i].kind == nkHiddenCallConv:
# we need to recurse explicitly here as converters can create nested
# calls and then they wouldn't be analysed otherwise
analyseIfAddressTakenInCall(c, n[i])
c.checkIfConverterCalled(n[i])
if i < t.len and
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
if n[i].kind != nkHiddenAddr:
n[i] = analyseIfAddressTaken(c, n[i], isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
# Converters wrap var parameters in nkHiddenAddr but they haven't been analysed yet.
# So we need to make sure we are checking them still when in a converter call
if n[i].kind != nkHiddenAddr or isConverter:
n[i] = analyseIfAddressTaken(c, n[i].skipAddr(), isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
include semmagic
proc evalAtCompileTime(c: PContext, n: PNode): PNode =

View File

@@ -78,14 +78,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if macroToExpandSym(s):
onUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, {}, ctx)
discard c.friendModules.pop()
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
if macroToExpandSym(s):
onUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, {}, ctx)
discard c.friendModules.pop()
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
@@ -245,7 +249,9 @@ proc semGenericStmt(c: PContext, n: PNode,
if macroToExpand(s) and sc.safeLen <= 1:
onUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, flags, ctx)
discard c.friendModules.pop()
else:
n[0] = sc
result = n
@@ -254,7 +260,9 @@ proc semGenericStmt(c: PContext, n: PNode,
if macroToExpand(s) and sc.safeLen <= 1:
onUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, flags, ctx)
discard c.friendModules.pop()
else:
n[0] = sc
result = n
@@ -493,6 +501,20 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2, c.config)
result[1] = semGenericStmt(c, n[1], flags, ctx)
of nkObjConstr:
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)
if result[0].kind == nkSym:
let fmoduleId = getModule(result[0].sym).id
var isVisable = false
for module in c.friendModules:
if module.id == fmoduleId:
isVisable = true
break
if isVisable:
for i in 1..<result.len:
if result[i].kind == nkExprColonExpr:
result[i][1].flags.incl nfSkipFieldChecking
else:
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)

View File

@@ -76,7 +76,7 @@ proc semConstrField(c: PContext, flags: TExprFlags,
let assignment = locateFieldInInitExpr(c, field, initExpr)
if assignment != nil:
if nfSem in assignment.flags: return assignment[1]
if nfUseDefaultField in assignment[1].flags:
if nfSkipFieldChecking in assignment[1].flags:
discard
elif not fieldVisible(c, field):
localError(c.config, initExpr.info,
@@ -178,7 +178,7 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
newSymNode(getSysMagic(c.graph, constrCtx.initExpr.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, constrCtx.initExpr.info, asgnType)
)
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)

View File

@@ -519,7 +519,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
let fSym = newSymNode(field)
if hasDefaultField:
fSym.sym.ast = a[^1]
fSym.sym.ast.flags.incl nfUseDefaultField
fSym.sym.ast.flags.incl nfSkipFieldChecking
result.n.add fSym
addSonSkipIntLit(result, typ, c.idgen)
styleCheckDef(c, a[j].info, field)
@@ -868,7 +868,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
let fSym = newSymNode(f)
if hasDefaultField:
fSym.sym.ast = n[^1]
fSym.sym.ast.flags.incl nfUseDefaultField
fSym.sym.ast.flags.incl nfSkipFieldChecking
if a.kind == nkEmpty: father.add fSym
else: a.add fSym
styleCheckDef(c, f)

View File

@@ -1979,8 +1979,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if srca == isSubtype:
param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c)
elif src.kind in {tyVar}:
# Analyse the converter return type
arg.sym.flags.incl sfAddrTaken
# Analyse the converter return type.
param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1])
param.add copyTree(arg)
else:

View File

@@ -1829,7 +1829,7 @@ proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currP
let field = newNodeI(nkExprColonExpr, result.info)
field.add(obj)
let value = getNullValue(obj.sym.typ, result.info, conf)
value.flags.incl nfUseDefaultField
value.flags.incl nfSkipFieldChecking
field.add(value)
result.add field
doAssert obj.sym.position == currPosition

View File

@@ -5455,7 +5455,7 @@ more complex type classes:
```nim
# create a type class that will match all tuple and object types
type RecordType = tuple or object
type RecordType = (tuple or object)
proc printFields[T: RecordType](rec: T) =
for key, value in fieldPairs(rec):
@@ -5504,7 +5504,7 @@ A type class can be used directly as the parameter's type.
```nim
# create a type class that will match all tuple and object types
type RecordType = tuple or object
type RecordType = (tuple or object)
proc printFields(rec: RecordType) =
for key, value in fieldPairs(rec):

View File

@@ -958,7 +958,7 @@ proc `==`*(x, y: SocketHandle): bool {.borrow.}
proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen): SocketHandle {.
importc, header: "<sys/socket.h>", sideEffect.}
when defined(linux) or defined(bsd):
when defined(linux) or defined(bsd) or defined(nuttx):
proc accept4*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen,
flags: cint): SocketHandle {.importc, header: "<sys/socket.h>".}

View File

@@ -10,7 +10,7 @@
when defined(nimHasStyleChecks):
{.push styleChecks: off.}
when defined(freertos) or defined(zephyr) or defined(nuttx):
when defined(freertos) or defined(zephyr):
const
hasSpawnH = false # should exist for every Posix system nowadays
hasAioH = false
@@ -646,7 +646,7 @@ elif defined(nuttx):
else:
var SO_REUSEPORT* {.importc, header: "<sys/socket.h>".}: cint
when defined(linux) or defined(bsd):
when defined(linux) or defined(bsd) or defined(nuttx):
var SOCK_CLOEXEC* {.importc, header: "<sys/socket.h>".}: cint
when defined(macosx):
@@ -675,14 +675,14 @@ when defined(haiku):
when hasSpawnH:
when defined(linux):
# better be safe than sorry; Linux has this flag, macosx doesn't, don't
# know about the other OSes
# better be safe than sorry; Linux has this flag, macosx and NuttX don't,
# don't know about the other OSes
# Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we
# Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we
# can't get the magic number from spawn.h
const POSIX_SPAWN_USEVFORK* = cint(0x40)
else:
# macosx lacks this, so we define the constant to be 0 to not affect
# macosx and NuttX lack this, so we define the constant to be 0 to not affect
# OR'ing of flags:
const POSIX_SPAWN_USEVFORK* = cint(0)

View File

@@ -1077,9 +1077,9 @@ template newSeqWith*(len: int, init: untyped): untyped =
import std/random
var seqRand = newSeqWith(20, rand(1.0))
assert seqRand[0] != seqRand[1]
var result = newSeq[typeof(init)](len)
for i in 0 ..< len:
let newLen = len
var result = newSeq[typeof(init)](newLen)
for i in 0 ..< newLen:
result[i] = init
move(result) # refs bug #7295

View File

@@ -10,6 +10,8 @@
## This module implements a simple HTTP client that can be used to retrieve
## webpages and other data.
##
## .. warning:: Validate untrusted inputs: URI parsers and getters are not detecting malicious URIs.
##
## Retrieving a website
## ====================
##

View File

@@ -1053,13 +1053,15 @@ elif not defined(useNimRtl):
var mask: Sigset
chck sigemptyset(mask)
chck posix_spawnattr_setsigmask(attr, mask)
if poDaemon in data.options:
chck posix_spawnattr_setpgroup(attr, 0'i32)
when not defined(nuttx):
if poDaemon in data.options:
chck posix_spawnattr_setpgroup(attr, 0'i32)
var flags = POSIX_SPAWN_USEVFORK or
POSIX_SPAWN_SETSIGMASK
if poDaemon in data.options:
flags = flags or POSIX_SPAWN_SETPGROUP
when not defined(nuttx):
if poDaemon in data.options:
flags = flags or POSIX_SPAWN_SETPGROUP
chck posix_spawnattr_setflags(attr, flags)
if not (poParentStreams in data.options):

View File

@@ -14,6 +14,8 @@
## as a locator, a name, or both. The term "Uniform Resource Locator"
## (URL) refers to the subset of URIs.
##
## .. warning:: URI parsers in this module do not perform security validation.
##
## # Basic usage

View File

@@ -190,7 +190,7 @@ proc text*(n: XmlNode): lent string {.inline.} =
assert $c == "<!-- my comment -->"
assert c.text == "my comment"
n.expect {xnText, xnComment, xnCData, xnEntity}
n.expect {xnText, xnVerbatimText, xnComment, xnCData, xnEntity}
result = n.fText
proc `text=`*(n: XmlNode, text: sink string) {.inline.} =
@@ -208,7 +208,7 @@ proc `text=`*(n: XmlNode, text: sink string) {.inline.} =
e.text = "a new entity text"
assert $e == "&a new entity text;"
n.expect {xnText, xnComment, xnCData, xnEntity}
n.expect {xnText, xnVerbatimText, xnComment, xnCData, xnEntity}
n.fText = text
proc tag*(n: XmlNode): lent string {.inline.} =
@@ -735,7 +735,7 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2,
addNewLines = true, lastNodeIsText = false) =
proc noWhitespace(n: XmlNode): bool =
for i in 0 ..< n.len:
if n[i].kind in {xnText, xnEntity}: return true
if n[i].kind in {xnText, xnVerbatimText, xnEntity}: return true
proc addEscapedAttr(result: var string, s: string) =
# `addEscaped` alternative with less escaped characters.
@@ -784,7 +784,7 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2,
var lastNodeIsText = false
for i in 0 ..< n.len:
result.addImpl(n[i], indentNext, indWidth, addNewLines, lastNodeIsText)
lastNodeIsText = n[i].kind == xnText
lastNodeIsText = (n[i].kind == xnText) or (n[i].kind == xnVerbatimText)
if not n.noWhitespace():
result.addIndent(indent, addNewLines)

View File

@@ -268,6 +268,20 @@ proc getMaxMem(a: var MemRegion): int =
# maximum of these both values here:
result = max(a.currMem, a.maxMem)
const nimMaxHeap {.intdefine.} = 0
proc allocPages(a: var MemRegion, size: int): pointer =
when nimMaxHeap != 0:
if a.occ + size > nimMaxHeap * 1024 * 1024:
raiseOutOfMem()
osAllocPages(size)
proc tryAllocPages(a: var MemRegion, size: int): pointer =
when nimMaxHeap != 0:
if a.occ + size > nimMaxHeap * 1024 * 1024:
raiseOutOfMem()
osTryAllocPages(size)
proc llAlloc(a: var MemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation
# is done at the end of the allocator's life time.
@@ -277,7 +291,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer =
# is one page:
sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
var old = a.llmem # can be nil and is correct with nil
a.llmem = cast[PLLChunk](osAllocPages(PageSize))
a.llmem = cast[PLLChunk](allocPages(a, PageSize))
when defined(nimAvlcorruption):
trackLocation(a.llmem, PageSize)
incCurrMem(a, PageSize)
@@ -453,15 +467,10 @@ when false:
it, it.next, it.prev, it.size)
it = it.next
const nimMaxHeap {.intdefine.} = 0
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
when not defined(emscripten):
if not a.blockChunkSizeIncrease:
let usedMem = a.occ #a.currMem # - a.freeMem
when nimMaxHeap != 0:
if usedMem > nimMaxHeap * 1024 * 1024:
raiseOutOfMem()
if usedMem < 64 * 1024:
a.nextChunkSize = PageSize*4
else:
@@ -470,11 +479,11 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
var size = size
if size > a.nextChunkSize:
result = cast[PBigChunk](osAllocPages(size))
result = cast[PBigChunk](allocPages(a, size))
else:
result = cast[PBigChunk](osTryAllocPages(a.nextChunkSize))
result = cast[PBigChunk](tryAllocPages(a, a.nextChunkSize))
if result == nil:
result = cast[PBigChunk](osAllocPages(size))
result = cast[PBigChunk](allocPages(a, size))
a.blockChunkSizeIncrease = true
else:
size = a.nextChunkSize
@@ -654,7 +663,7 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
releaseSys a.lock
proc getHugeChunk(a: var MemRegion; size: int): PBigChunk =
result = cast[PBigChunk](osAllocPages(size))
result = cast[PBigChunk](allocPages(a, size))
when RegionHasLock:
if not a.lockActive:
a.lockActive = true
@@ -811,9 +820,9 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
var size = roundup(requestedSize, MemAlign)
sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small")
sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
if size <= SmallChunkSize-smallChunkOverhead():
# allocate a small block: for small chunks, we use only its next pointer
let s = size div MemAlign

View File

@@ -391,7 +391,6 @@ else:
let regEnd = sp +% sizeof(registers)
while sp <% regEnd:
gcMark(gch, cast[PPointer](sp)[])
gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[])
sp = sp +% sizeof(pointer)
# Make sure sp is word-aligned
sp = sp and not (sizeof(pointer) - 1)

View File

@@ -10,6 +10,8 @@ skipDirs = @["build" , "changelogs" , "ci" , "csources_v2" , "drnim" , "nimdoc",
before install:
when defined(windows):
exec "build_all.bat"
if not "bin\nim.exe".fileExists:
exec "build_all.bat"
else:
exec "./build_all.sh"
if not "bin/nim".fileExists:
exec "./build_all.sh"

View File

@@ -234,7 +234,7 @@ proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int,
localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos))
proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, graph: ModuleGraph) =
executeNoHooks(cmd, file, dirtyfile, line, col, graph)
executeNoHooks(cmd, file, dirtyfile, line, col, "", graph)
proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; tag: string,
graph: ModuleGraph) =

View File

@@ -5,6 +5,7 @@ discard """
t20588.nim(20, 12) Error: illegal type conversion to 'auto'
t20588.nim(21, 14) Error: illegal type conversion to 'typed'
t20588.nim(22, 16) Error: illegal type conversion to 'untyped'
t20588.nim(24, 7) Error: illegal type conversion to 'any'
'''
"""
@@ -16,7 +17,9 @@ t20588.nim(22, 16) Error: illegal type conversion to 'untyped'
discard 0.0.auto
discard typed("abc")
discard untyped(4)
var a = newSeq[bool](1000)
if any(a):
echo "ok?"

View File

@@ -0,0 +1,10 @@
import std/typetraits
type Foo* = distinct string
converter toBase*(headers: var Foo): var string =
headers.distinctBase
proc bar*(headers: var Foo) =
for x in headers: discard

6
tests/generics/m3770.nim Normal file
View File

@@ -0,0 +1,6 @@
type
Noice* = object
hidden: int
template jjj*: Noice =
Noice(hidden: 15)

9
tests/generics/t3770.nim Normal file
View File

@@ -0,0 +1,9 @@
# bug #3770
import m3770
doAssert $jjj() == "(hidden: 15)" # works
proc someGeneric(_: type) =
doAssert $jjj() == "(hidden: 15)" # fails: "Error: the field 'hidden' is not accessible."
someGeneric(int)

View File

@@ -388,6 +388,11 @@ block: # newSeqWith tests
seq2D[0][1] = true
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
block: # bug #21538
var x: seq[int] = @[2, 4]
var y = newSeqWith(x.pop(), true)
doAssert y == @[true, true, true, true]
block: # mapLiterals tests
let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int)
doAssert x is array[4, int]

View File

@@ -99,3 +99,18 @@ block: # bug #21290
doAssert s == """<foo>
<bar>Hola<qux> <plugh /> </qux></bar>
</foo>"""
block: #21541
let root = <>root()
root.add <>child(newText("hello"))
root.add <>more(newVerbatimText("hola"))
let s = $root
doAssert s == """<root>
<child>hello</child>
<more>hola</more>
</root>"""
let temp = newVerbatimText("Hello!")
doAssert temp.text == "Hello!"
temp.text = "Hola!"
doAssert temp.text == "Hola!"

View File

@@ -79,3 +79,9 @@ in its description (or name or list of tags).
### Install <proj.nimble>
Use the .nimble file to setup the project's dependencies.
### Update [filter]
Update every package in the workspace that has a remote URL that
matches `filter` if a filter is given. The package is only updated
if there are no uncommitted changes.

View File

@@ -9,9 +9,11 @@
## Simple tool to automate frequent workflows: Can "clone"
## a Nimble dependency and its dependencies recursively.
import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonutils]
import std/[parseopt, strutils, os, osproc, tables, sets, json, jsonutils]
import parse_requires, osutils, packagesjson
from unicode import nil
const
Version = "0.2"
Usage = "atlas - Nim Package Cloner Version " & Version & """
@@ -25,6 +27,8 @@ Command:
search keyw keywB... search for package that contains the given keywords
extract file.nimble extract the requirements and custom commands from
the given Nimble file
update [filter] update every package in the workspace that has a remote
URL that matches `filter` if a filter is given
Options:
--keepCommits do not perform any `git checkouts`
@@ -146,7 +150,7 @@ proc toDepRelation(s: string): DepRelation =
of ">": strictlyGreater
else: normal
proc isCleanGit(c: var AtlasContext; dir: string): string =
proc isCleanGit(c: var AtlasContext): string =
result = ""
let (outp, status) = exec(c, GitDiff, [])
if outp.len != 0:
@@ -264,7 +268,7 @@ proc checkoutCommit(c: var AtlasContext; w: Dependency) =
if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0:
gitPull(c, w.name)
else:
let err = isCleanGit(c, dir)
let err = isCleanGit(c)
if err != "":
warn c, w.name, err
else:
@@ -448,6 +452,27 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) =
let paths = cloneLoop(c, work)
patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c))
proc updateWorkspace(c: var AtlasContext; filter: string) =
for kind, file in walkDir(c.workspace):
if kind == pcDir and dirExists(file / ".git"):
c.withDir file:
let pkg = PackageName(file)
let (remote, _) = osproc.execCmdEx("git remote -v")
if filter.len == 0 or filter in remote:
let diff = isCleanGit(c)
if diff != "":
warn(c, pkg, "has uncommitted changes; skipped")
else:
let (branch, _) = osproc.execCmdEx("git rev-parse --abbrev-ref HEAD")
if branch.strip.len > 0:
let (output, exitCode) = osproc.execCmdEx("git pull origin " & branch.strip)
if exitCode != 0:
error c, pkg, output
else:
message(c, "[Hint] ", pkg, "successfully updated")
else:
error c, pkg, "could not fetch current branch name"
proc main =
var action = ""
var args: seq[string] = @[]
@@ -525,6 +550,8 @@ proc main =
of "search", "list":
updatePackages(c)
search getPackages(c.workspace), args
of "update":
updateWorkspace(c, if args.len == 0: "" else: args[0])
of "extract":
singleArg()
if fileExists(args[0]):