mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 15:31:28 +00:00
deepCopy is instantiated when its corresponding type is instantiated
This commit is contained in:
@@ -898,7 +898,7 @@ include ccgtrav
|
||||
|
||||
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
||||
genProc(m, s)
|
||||
appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n",
|
||||
appf(m.s[cfsTypeInit3], "$1.deepcopy =(N_NIMCALL_PTR(void*,)(void*))$2;$n",
|
||||
[result, s.loc.r])
|
||||
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
|
||||
@@ -371,6 +371,8 @@ proc myOpen(module: PSym): PPassContext =
|
||||
c.semInferredLambda = semInferredLambda
|
||||
c.semGenerateInstance = generateInstance
|
||||
c.semTypeNode = semTypeNode
|
||||
c.instDeepCopy = sigmatch.instDeepCopy
|
||||
|
||||
pushProcCon(c, module)
|
||||
pushOwner(c.module)
|
||||
c.importTable = openScope(c)
|
||||
|
||||
@@ -92,6 +92,9 @@ type
|
||||
lastGenericIdx*: int # used for the generics stack
|
||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||
inParallelStmt*: int
|
||||
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
||||
info: TLineInfo): PSym {.nimcall.}
|
||||
|
||||
|
||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||
result.genericSym = s
|
||||
|
||||
@@ -1029,7 +1029,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
sameType(s.typ.sons[1], s.typ.sons[0]):
|
||||
# Note: we store the deepCopy in the base of the pointer to mitigate
|
||||
# the problem that pointers are structural types:
|
||||
let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||
var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||
while true:
|
||||
if t.kind == tyGenericBody: t = t.lastSon
|
||||
elif t.kind == tyGenericInvokation: t = t.sons[0]
|
||||
else: break
|
||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||
if t.deepCopy.isNil: t.deepCopy = s
|
||||
else:
|
||||
@@ -1044,6 +1048,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
of "=": discard
|
||||
else: localError(n.info, errGenerated,
|
||||
"'destroy' or 'deepCopy' expected for 'override'")
|
||||
incl(s.flags, sfUsed)
|
||||
|
||||
type
|
||||
TProcCompilationSteps = enum
|
||||
|
||||
@@ -299,6 +299,18 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.info, newbody)
|
||||
let dc = newbody.deepCopy
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
|
||||
when false:
|
||||
var bindings: TIdTable
|
||||
initIdTable(bindings)
|
||||
debug newbody
|
||||
bindings.idTablePut(dc.ast[genericParamsPos].sons[0].typ, newbody)
|
||||
newbody.deepCopy = cl.c.semGenerateInstance(cl.c, dc, bindings, cl.info)
|
||||
assert sfFromGeneric in newbody.deepCopy.flags
|
||||
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
||||
|
||||
@@ -1482,6 +1482,18 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
# instantiate generic converters for that
|
||||
result = res != nil
|
||||
|
||||
proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.
|
||||
procvar.} =
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, dc.typ)
|
||||
var f = dc.typ.sons[1]
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
if typeRel(m, f, t) == isNone:
|
||||
localError(info, errGenerated, "cannot instantiate 'deepCopy'")
|
||||
else:
|
||||
result = c.semGenerateInstance(c, dc, m.bindings, info)
|
||||
assert sfFromGeneric in result.flags
|
||||
|
||||
include suggest
|
||||
|
||||
when not declared(tests):
|
||||
|
||||
@@ -4386,6 +4386,8 @@ like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for
|
||||
parameter passing no assignment is performed. The ``override`` pragma is
|
||||
optional for overriding ``=``.
|
||||
|
||||
**Note**: Overriding of operator ``=`` is not yet implemented.
|
||||
|
||||
|
||||
destructors
|
||||
-----------
|
||||
@@ -4446,6 +4448,9 @@ Be aware that destructors are not called for objects allocated with ``new``.
|
||||
This may change in future versions of language, but for now the ``finalizer``
|
||||
parameter to ``new`` has to be used.
|
||||
|
||||
**Note**: Destructors are still experimental and the spec might change
|
||||
significantly in order to incorporate an escape analysis.
|
||||
|
||||
|
||||
deepCopy
|
||||
--------
|
||||
|
||||
@@ -82,17 +82,16 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
|
||||
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||
of tyRef:
|
||||
if mt.base.deepcopy != nil:
|
||||
let z = mt.base.deepcopy(cast[PPointer](src)[])
|
||||
let s2 = cast[PPointer](src)[]
|
||||
if s2 == nil:
|
||||
unsureAsgnRef(cast[PPointer](dest), s2)
|
||||
elif mt.base.deepcopy != nil:
|
||||
let z = mt.base.deepcopy(s2)
|
||||
unsureAsgnRef(cast[PPointer](dest), z)
|
||||
else:
|
||||
# we modify the header of the cell temporarily; instead of the type
|
||||
# field we store a forwarding pointer. XXX This is bad when the cloning
|
||||
# fails due to OOM etc.
|
||||
let s2 = cast[PPointer](src)[]
|
||||
if s2 == nil:
|
||||
unsureAsgnRef(cast[PPointer](dest), s2)
|
||||
return
|
||||
when declared(usrToCell):
|
||||
# unfortunately we only have cycle detection for our native GCs.
|
||||
let x = usrToCell(s2)
|
||||
@@ -116,10 +115,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||
genericDeepCopyAux(z, s2, realType.base)
|
||||
of tyPtr:
|
||||
# no cycle check here, but also not really required
|
||||
if mt.base.deepcopy != nil:
|
||||
cast[PPointer](dest)[] = mt.base.deepcopy(cast[PPointer](s)[])
|
||||
let s2 = cast[PPointer](src)[]
|
||||
if s2 != nil and mt.base.deepcopy != nil:
|
||||
cast[PPointer](dest)[] = mt.base.deepcopy(s2)
|
||||
else:
|
||||
cast[PPointer](dest)[] = cast[PPointer](s)[]
|
||||
cast[PPointer](dest)[] = s2
|
||||
else:
|
||||
copyMem(dest, src, mt.size)
|
||||
|
||||
|
||||
35
tests/parallel/tdeepcopy2.nim
Normal file
35
tests/parallel/tdeepcopy2.nim
Normal file
@@ -0,0 +1,35 @@
|
||||
discard """
|
||||
output: '''called deepCopy for int
|
||||
called deepCopy for int
|
||||
done999 999
|
||||
"""
|
||||
|
||||
import threadpool
|
||||
|
||||
|
||||
type
|
||||
Bar[T] = object
|
||||
x: T
|
||||
|
||||
proc deepCopy[T](b: ref Bar[T]): ref Bar[T] {.override.} =
|
||||
result.new
|
||||
result.x = b.x
|
||||
when T is int:
|
||||
echo "called deepCopy for int"
|
||||
else:
|
||||
echo "called deepCopy for something else"
|
||||
|
||||
proc foo(b: ref Bar[int]): int = 999
|
||||
|
||||
# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
|
||||
|
||||
proc main =
|
||||
var dummy: ref Bar[int]
|
||||
new(dummy)
|
||||
dummy.x = 44
|
||||
parallel:
|
||||
let f = spawn foo(dummy)
|
||||
let b = spawn foo(dummy)
|
||||
echo "done", f, " ", b
|
||||
|
||||
main()
|
||||
6
todo.txt
6
todo.txt
@@ -1,6 +1,7 @@
|
||||
version 0.10
|
||||
============
|
||||
|
||||
- use the effect system for static deadlock prevention
|
||||
- Test nimfix on various babel packages
|
||||
- deprecate recursive tuples; tuple needs laxer type checking
|
||||
- string case should require an 'else'
|
||||
@@ -20,9 +21,7 @@ version 0.9.6
|
||||
Concurrency
|
||||
-----------
|
||||
|
||||
- 'deepCopy' needs to be instantiated for
|
||||
generics *when the type is constructed*
|
||||
- test 'deepCopy'
|
||||
- test 'deepCopy' for closures
|
||||
|
||||
- implement 'foo[1..4] = spawn(f[4..7])'
|
||||
- document the new 'spawn' and 'parallel' statements
|
||||
@@ -117,7 +116,6 @@ Concurrency/Effect system
|
||||
provide a ``syncgc`` pragma to trigger compiler injection --> more general:
|
||||
an ``injectLoop`` pragma
|
||||
- 'writes: []' effect; track reads/writes for shared types
|
||||
- use the effect system for static deadlock prevention and race detection
|
||||
- ``~`` operator for effects
|
||||
- introduce 'noaddr' pragma to prevent taking the address of a location; this
|
||||
is very handy to prevent aliasing of global data
|
||||
|
||||
Reference in New Issue
Block a user