Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1837,6 +1837,18 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
for (owner, field, expectedType) in c.forwardFieldUpdates:
semDelayedFieldDefault(c, owner, expectedType, field)
c.forwardFieldUpdates = @[]

# every type in the section started out as a `tyForward`, so types that were
# referenced before their definition could not propagate `tfHasAsgn` and
# friends to their owners yet. Now that all bodies are known, redo it:
block:
var marker = initIntSet()
for i in 0..<n.len:
let a = n[i]
if a.kind == nkCommentStmt: continue
let s = typeSectionTypeName(c, a[0]).sym
if s.typ != nil: repropagateFlags(s.typ, marker)

for i in 0..<n.len:
var a = n[i]
if a.kind == nkCommentStmt: continue
Expand Down
47 changes: 47 additions & 0 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,53 @@ proc containsForwardType(t: PType): bool =
var seen = initIntSet()
containsForwardTypeAux(t, seen)

proc repropagateFlags(t: PType; marker: var IntSet)

proc repropagateFlagsNode(owner: PType; n: PNode; marker: var IntSet) =
## walks the fields of an object/tuple, see `searchTypeNodeForAux`.
case n.kind
of nkRecList:
for i in 0..<n.len: repropagateFlagsNode(owner, n[i], marker)
of nkRecCase:
repropagateFlagsNode(owner, n[0], marker)
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse: repropagateFlagsNode(owner, lastSon(n[i]), marker)
else: discard
of nkSym:
let field = n.sym.typ
if field != nil and field.state == Complete:
repropagateFlags(field, marker)
propagateToOwner(owner, field)
else: discard

proc repropagateFlags(t: PType; marker: var IntSet) =
## `propagateToOwner` computes `tfHasAsgn` & friends when a type is
## constructed. Within a type section a type can be used before it has been
## reified, so back then a `tyForward` had nothing to propagate yet and the
## enclosing types ended up with stale flags. Now that every forward
## declaration has a body, redo the propagation bottom-up. Only value based
## containment is followed (as in `searchTypeForAux`) because that is the
## only relation `propagateToOwner` propagates these flags along; this also
## keeps the traversal acyclic so a single pass suffices.
if t.state != Complete or containsOrIncl(marker, t.id): return

template follow(elem: PType) =
let e = elem
if e != nil and e.state == Complete:
repropagateFlags(e, marker)
propagateToOwner(t, e)

case t.kind
of tyObject:
follow(t.baseClass)
if t.n != nil: repropagateFlagsNode(t, t.n, marker)
of tyGenericInst, tyDistinct, tyAlias, tySink:
follow(t.skipModifier)
of tyArray, tySet, tyTuple:
for a in t.kids: follow(a)
else: discard

proc semFieldDefault(c: PContext; owner, expectedType: PType; field: PNode): PType =
result = expectedType
field[^1] = semExprWithType(c, field[^1], {efDetermineType, efAllowSymChoice}, result)
Expand Down
20 changes: 20 additions & 0 deletions tests/arc/tarcmisc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -937,3 +937,23 @@ proc mainRegen() =
doAssert b.a.c == right

mainRegen()


from std/typetraits import distinctBase, supportsCopyMem

block: # bug #26025
type
M[B] = distinct seq[B]
W = object
g: U # `U` is only declared below, so it used to be a `tyForward`
# here and `W` ended up without `tfHasAsgn`
U = M[uint64]

doAssert not supportsCopyMem(W)

var h: M[W]
seq[W](h).add W(g: U(@[1'u64]))
var copied = h
for it in items(distinctBase(copied)):
doAssert seq[uint64](it.g) == @[1'u64]
doAssert seq[uint64](seq[W](h)[0].g) == @[1'u64]
Loading