Skip to content

Commit

Permalink
skip structural generics instead, might be incorrect for C++ imports
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Nov 6, 2024
1 parent 3abf367 commit 2cbfa42
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 15 deletions.
12 changes: 6 additions & 6 deletions compiler/injectdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
c.genOp(op, dest)

proc genDestroy(c: var Con; dest: PNode): PNode =
let t = dest.typ.skipTypes({tyAlias, tySink})
let t = dest.typ.skipStructuralGenerics({tyAlias, tySink})
result = c.genOp(t, attachedDestructor, dest, nil)

proc canBeMoved(c: Con; t: PType): bool {.inline.} =
let t = t.skipTypes({tyAlias, tySink})
let t = t.skipStructuralGenerics({tyAlias, tySink})
if optOwnedRefs in c.graph.config.globalOptions:
result = t.kind != tyRef and getAttachedOp(c.graph, t, attachedSink) != nil
else:
Expand All @@ -281,7 +281,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
let t = dest.typ.skipTypes({tyAlias, tySink})
let t = dest.typ.skipStructuralGenerics({tyAlias, tySink})
if getAttachedOp(c.graph, t, attachedSink) != nil:
result = c.genOp(t, attachedSink, dest, ri)
result.add ri
Expand Down Expand Up @@ -336,7 +336,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) =
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv)

proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
let t = dest.typ.skipTypes({tyAlias, tySink})
let t = dest.typ.skipStructuralGenerics({tyAlias, tySink})
result = c.genOp(t, a, dest, ri)
assert ri.typ != nil

Expand Down Expand Up @@ -392,7 +392,7 @@ It is best to factor out piece of object that needs custom destructor into separ
result.add newTree(nkFastAsgn, le, tmp)

proc genWasMoved(c: var Con, n: PNode): PNode =
let typ = n.typ.skipTypes({tyAlias, tySink})
let typ = n.typ.skipStructuralGenerics({tyAlias, tySink})
let op = getAttachedOp(c.graph, n.typ, attachedWasMoved)
if op != nil:
if sfError in op.flags:
Expand Down Expand Up @@ -450,7 +450,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
let tmp = c.getTemp(s, nTyp, n.info)
if hasDestructor(c, nTyp):
let typ = nTyp.skipTypes({tyAlias, tySink})
let typ = nTyp.skipStructuralGenerics({tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil and tfHasOwned notin typ.flags:
if sfError in op.flags:
Expand Down
4 changes: 1 addition & 3 deletions compiler/liftdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1277,13 +1277,11 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
incl orig.flags, tfCheckedForDestructor

let skipped = orig.skipTypes({tyAlias, tySink})
let skipped = orig.skipStructuralGenerics({tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return

let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
var canon = g.canonTypes.getOrDefault(h)

#echo "NOW FOR ", typeToString(skipped), " ", canon == nil
if canon == nil:
g.canonTypes[h] = skipped
canon = skipped
Expand Down
11 changes: 7 additions & 4 deletions compiler/sighashes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,13 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
# This is an imported C++ generic type.
# We cannot trust the `lastSon` to hold a properly populated and unique
# value for each instantiation, so we hash the generic parameters here:
let normalizedType = t.skipGenericAlias
c.hashType normalizedType.genericHead, flags, conf
for _, a in normalizedType.genericInstParams:
c.hashType a, flags, conf
let normalizedType = t.skipStructuralGenerics
if normalizedType.kind == tyGenericInst:
c.hashType normalizedType.genericHead, flags, conf
for _, a in normalizedType.genericInstParams:
c.hashType a, flags, conf
else:
c.hashType normalizedType, flags, conf
else:
c.hashType t.skipModifier, flags, conf
of tyAlias, tySink, tyUserTypeClasses, tyInferred:
Expand Down
14 changes: 12 additions & 2 deletions compiler/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1936,6 +1936,10 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
else:
result = false

proc isConcreteNominal*(t: PType): bool {.inline.} =
t.kind in {tyDistinct, tyEnum, tyObject} or
(t.kind in {tyRef, tyPtr} and tfRefsAnonObj in t.flags)

proc nominalRoot*(t: PType): PType =
## the "name" type of a given instance of a nominal type,
## i.e. the type directly associated with the symbol where the root
Expand Down Expand Up @@ -1967,8 +1971,7 @@ proc nominalRoot*(t: PType): PType =
while result.skipModifier.kind in {tyGenericInvocation, tyGenericInst}:
result = result.skipModifier[0]
let val = result.skipModifier
if val.kind in {tyDistinct, tyEnum, tyObject} or
(val.kind in {tyRef, tyPtr} and tfRefsAnonObj in val.flags):
if isConcreteNominal(val):
# atomic nominal types, this generic body is attached to them
discard
else:
Expand Down Expand Up @@ -1998,3 +2001,10 @@ proc nominalRoot*(t: PType): PType =
# skips all typeclasses
# is this correct for `concept`?
result = nil

proc skipStructuralGenerics*(t: PType, otherKinds: TTypeKinds = {}): PType =
result = t
while result.kind in otherKinds or
(result.kind == tyGenericInst and
not isConcreteNominal(result.skipModifier)):
result = result.last
19 changes: 19 additions & 0 deletions tests/arc/tphantomgeneric1.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
discard """
output: '''
int
float
'''
"""

# issue #22479

type Obj[T] = object

proc `=destroy`[T](self: var Obj[T]) =
echo T

block:
let intObj = Obj[int]()

block:
let floatObj = Obj[float]()
33 changes: 33 additions & 0 deletions tests/arc/tphantomgeneric2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
discard """
output: '''
created Phantom[system.float] with value 1
created Phantom[system.string] with value 2
created Phantom[system.byte] with value 3
destroyed Phantom[system.byte] with value 3
destroyed Phantom[system.string] with value 2
destroyed Phantom[system.float] with value 1
'''
"""

# issue #24374

type Phantom[T] = object
value: int
# markerField: T

proc initPhantom[T](value: int): Phantom[T] =
doAssert value >= 0
echo "created " & $Phantom[T] & " with value " & $value
result = Phantom[T](value: value)

proc `=wasMoved`[T](x: var Phantom[T]) =
x.value = -1

proc `=destroy`[T](x: Phantom[T]) =
if x.value >= 0:
echo "destroyed " & $Phantom[T] & " with value " & $x.value

let
x = initPhantom[float](1)
y = initPhantom[string](2)
z = initPhantom[byte](3)

0 comments on commit 2cbfa42

Please sign in to comment.