mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-16 03:48:19 +00:00
Merge branch 'devel' into pr_mui
This commit is contained in:
@@ -592,10 +592,12 @@ proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode =
|
||||
result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x))
|
||||
result.add lenCall
|
||||
|
||||
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
|
||||
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode; noinit = false): PNode =
|
||||
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
|
||||
lenCall.typ = getSysType(c.g, x.info, tyInt)
|
||||
var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
|
||||
let name = if noinit: "setLenUninit" else: "setLen"
|
||||
let magic = if noinit: mSetLengthSeqUninit else: mSetLengthSeq
|
||||
var op = getSysMagic(c.g, x.info, name, magic)
|
||||
op = instantiateGeneric(c, op, t, t)
|
||||
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
|
||||
|
||||
@@ -643,8 +645,9 @@ proc genBulkCopySeq(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedDup:
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
if supportsCopyMem(t.elementType):
|
||||
let bulkCopy = supportsCopyMem(t.elementType)
|
||||
body.add setLenSeqCall(c, t, x, y, noinit = bulkCopy)
|
||||
if bulkCopy:
|
||||
genBulkCopySeq(c, t, body, x, y)
|
||||
else:
|
||||
forallElements(c, t, body, x, y)
|
||||
@@ -658,8 +661,9 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# This is usually more efficient than a destroy/create pair.
|
||||
# For trivially copyable types, use bulk copyMem instead of element loop.
|
||||
checkSelfAssignment(c, t, body, x, y)
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
if supportsCopyMem(t.elementType):
|
||||
let bulkCopy = supportsCopyMem(t.elementType)
|
||||
body.add setLenSeqCall(c, t, x, y, noinit = bulkCopy)
|
||||
if bulkCopy:
|
||||
genBulkCopySeq(c, t, body, x, y)
|
||||
else:
|
||||
forallElements(c, t, body, x, y)
|
||||
|
||||
@@ -1693,6 +1693,22 @@ proc containsGenericInvocationWithForward(n: PNode): bool =
|
||||
return true
|
||||
return false
|
||||
|
||||
proc containsRecWhen(n: PNode): bool =
|
||||
if n == nil:
|
||||
return false
|
||||
case n.kind
|
||||
of nkRecWhen:
|
||||
return true
|
||||
else:
|
||||
for i in 0..<n.safeLen:
|
||||
if containsRecWhen(n[i]):
|
||||
return true
|
||||
return false
|
||||
|
||||
proc requiresForwardTypeDelay(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.ast != nil and n.sym.ast.len > 2 and
|
||||
containsRecWhen(n.sym.ast[2])
|
||||
|
||||
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
if s.typ == nil:
|
||||
localError(c.config, n.info, "cannot instantiate the '$1' $2" %
|
||||
@@ -1772,11 +1788,16 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
# XXX: What kind of error is this? is it still relevant?
|
||||
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
elif containsGenericInvocationWithForward(n[0]) or hasForwardTypeParam:
|
||||
# isConcrete == false means this generic type is not instanciated here because it invoked with generic parameters.
|
||||
# Even if isConcrete == true, don't instanciate it now if there are any `tyForward` type params.
|
||||
# Such `tyForward` type params will be semchecked later and we can instanciate this next time.
|
||||
# Some generic types like std/options.Option[T] needs a type kinds of the given type argument.
|
||||
elif containsGenericInvocationWithForward(n[0]) or
|
||||
(hasForwardTypeParam and requiresForwardTypeDelay(n[0])):
|
||||
# isConcrete == false means this generic type is not instanciated here because
|
||||
# it invoked with generic parameters.
|
||||
# Even if isConcrete == true, don't instanciate it now if the type
|
||||
# shape depends on unresolved `tyForward` type params.
|
||||
# Such `tyForward` type params will be semchecked later and we can
|
||||
# instanciate this next time.
|
||||
# Some generic types like std/options.Option[T] need the kind of the
|
||||
# given type argument before their fields can be resolved.
|
||||
|
||||
# return `tyForward` instead of `tyGenericInvocation` because:
|
||||
# ```nim
|
||||
|
||||
@@ -118,6 +118,24 @@ proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite
|
||||
le.flags.incl nfFirstWrite
|
||||
result[1] = ri
|
||||
|
||||
proc resolveBorrowedRoutineSym(c: PTransf; s: PSym; info: TLineInfo): PSym =
|
||||
# Follow borrow aliases to the underlying implementation symbol.
|
||||
var s = s
|
||||
while true:
|
||||
# Skips over all borrowed procs getting the last proc symbol without an implementation
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
|
||||
s = body.sym
|
||||
else:
|
||||
break
|
||||
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym:
|
||||
result = body.sym
|
||||
else:
|
||||
result = nil
|
||||
internalError(c.graph.config, info, "wrong AST for borrowed symbol")
|
||||
|
||||
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
let s = n.sym
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
@@ -136,17 +154,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
var tc = c.transCon
|
||||
if sfBorrow in s.flags and s.kind in routineKinds:
|
||||
# simply exchange the symbol:
|
||||
var s = s
|
||||
while true:
|
||||
# Skips over all borrowed procs getting the last proc symbol without an implementation
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
|
||||
s = body.sym
|
||||
else:
|
||||
break
|
||||
b = getBody(c.graph, s)
|
||||
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
|
||||
b = newSymNode(b.sym, n.info)
|
||||
b = newSymNode(resolveBorrowedRoutineSym(c, s, n.info), n.info)
|
||||
elif c.inlining > 0:
|
||||
# see bug #13596: we use ref-based equality in the DFA for destruction
|
||||
# injections so we need to ensure unique nodes after iterator inlining
|
||||
@@ -785,7 +793,9 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
|
||||
discard c.breakSyms.pop
|
||||
|
||||
let iter = call[0].sym
|
||||
var iter = call[0].sym
|
||||
if sfBorrow in iter.flags and iter.kind in routineKinds:
|
||||
iter = resolveBorrowedRoutineSym(c, iter, n.info)
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
for i in 0..<n.len - 2:
|
||||
|
||||
@@ -262,8 +262,11 @@ proc setLen[T](s: var seq[T], newlen: Natural) {.nodestroy.} =
|
||||
if xu.p == nil or (xu.p.cap and not strlitFlag) < newlen:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAddUninit(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
||||
xu.len = newlen
|
||||
|
||||
{.push overflowChecks: off.}
|
||||
for i in oldLen..<newlen:
|
||||
xu.p.data[i] = default(T)
|
||||
{.pop.}
|
||||
|
||||
proc newSeq[T](s: var seq[T], len: Natural) =
|
||||
shrink(s, 0)
|
||||
|
||||
@@ -130,3 +130,14 @@ block: # issue #22646
|
||||
var x: Vec[3, float]
|
||||
let y = Color(x)
|
||||
doAssert Vec3[float](y) == x
|
||||
|
||||
block: # bug #25697
|
||||
type MyList = distinct seq[int]
|
||||
|
||||
iterator items(x: MyList): lent int {.borrow.}
|
||||
|
||||
let s = MyList(@[1, 2, 3])
|
||||
var count = 0
|
||||
for item in s:
|
||||
count += 1
|
||||
doAssert count == 3, "Expected 3 items, got " & $count
|
||||
|
||||
22
tests/objects/t25627.nim
Normal file
22
tests/objects/t25627.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
# issue #25627
|
||||
|
||||
import std/tables
|
||||
|
||||
type
|
||||
FsoKind = enum
|
||||
fsoFile
|
||||
fsoDir
|
||||
fsoLink
|
||||
|
||||
FakeFso = ref object
|
||||
kind: FsoKind
|
||||
dirName: string
|
||||
files: OrderedTable[string, FakeFso]
|
||||
|
||||
DirStruct = object
|
||||
root = FakeFso(kind: fsoDir, dirName: "/")
|
||||
|
||||
let dir = DirStruct()
|
||||
doAssert dir.root.kind == fsoDir
|
||||
doAssert dir.root.dirName == "/"
|
||||
doAssert dir.root.files.len == 0
|
||||
Reference in New Issue
Block a user