deepCopy is instantiated when its corresponding type is instantiated
This commit is contained in:
parent
dfd7390277
commit
1088814e56
10 changed files with 87 additions and 15 deletions
|
|
@ -898,7 +898,7 @@ include ccgtrav
|
||||||
|
|
||||||
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
||||||
genProc(m, s)
|
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])
|
[result, s.loc.r])
|
||||||
|
|
||||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,8 @@ proc myOpen(module: PSym): PPassContext =
|
||||||
c.semInferredLambda = semInferredLambda
|
c.semInferredLambda = semInferredLambda
|
||||||
c.semGenerateInstance = generateInstance
|
c.semGenerateInstance = generateInstance
|
||||||
c.semTypeNode = semTypeNode
|
c.semTypeNode = semTypeNode
|
||||||
|
c.instDeepCopy = sigmatch.instDeepCopy
|
||||||
|
|
||||||
pushProcCon(c, module)
|
pushProcCon(c, module)
|
||||||
pushOwner(c.module)
|
pushOwner(c.module)
|
||||||
c.importTable = openScope(c)
|
c.importTable = openScope(c)
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,9 @@ type
|
||||||
lastGenericIdx*: int # used for the generics stack
|
lastGenericIdx*: int # used for the generics stack
|
||||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||||
inParallelStmt*: int
|
inParallelStmt*: int
|
||||||
|
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
||||||
|
info: TLineInfo): PSym {.nimcall.}
|
||||||
|
|
||||||
|
|
||||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||||
result.genericSym = s
|
result.genericSym = s
|
||||||
|
|
|
||||||
|
|
@ -1029,7 +1029,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
sameType(s.typ.sons[1], s.typ.sons[0]):
|
sameType(s.typ.sons[1], s.typ.sons[0]):
|
||||||
# Note: we store the deepCopy in the base of the pointer to mitigate
|
# Note: we store the deepCopy in the base of the pointer to mitigate
|
||||||
# the problem that pointers are structural types:
|
# 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.kind in {tyObject, tyDistinct, tyEnum}:
|
||||||
if t.deepCopy.isNil: t.deepCopy = s
|
if t.deepCopy.isNil: t.deepCopy = s
|
||||||
else:
|
else:
|
||||||
|
|
@ -1044,6 +1048,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
of "=": discard
|
of "=": discard
|
||||||
else: localError(n.info, errGenerated,
|
else: localError(n.info, errGenerated,
|
||||||
"'destroy' or 'deepCopy' expected for 'override'")
|
"'destroy' or 'deepCopy' expected for 'override'")
|
||||||
|
incl(s.flags, sfUsed)
|
||||||
|
|
||||||
type
|
type
|
||||||
TProcCompilationSteps = enum
|
TProcCompilationSteps = enum
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,18 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||||
rawAddSon(result, newbody)
|
rawAddSon(result, newbody)
|
||||||
checkPartialConstructedType(cl.info, 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) =
|
proc eraseVoidParams*(t: PType) =
|
||||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
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
|
# instantiate generic converters for that
|
||||||
result = res != nil
|
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
|
include suggest
|
||||||
|
|
||||||
when not declared(tests):
|
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
|
parameter passing no assignment is performed. The ``override`` pragma is
|
||||||
optional for overriding ``=``.
|
optional for overriding ``=``.
|
||||||
|
|
||||||
|
**Note**: Overriding of operator ``=`` is not yet implemented.
|
||||||
|
|
||||||
|
|
||||||
destructors
|
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``
|
This may change in future versions of language, but for now the ``finalizer``
|
||||||
parameter to ``new`` has to be used.
|
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
|
deepCopy
|
||||||
--------
|
--------
|
||||||
|
|
|
||||||
|
|
@ -82,17 +82,16 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||||
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
|
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
|
||||||
cast[pointer](s +% i*% mt.base.size), mt.base)
|
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||||
of tyRef:
|
of tyRef:
|
||||||
if mt.base.deepcopy != nil:
|
let s2 = cast[PPointer](src)[]
|
||||||
let z = mt.base.deepcopy(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)
|
unsureAsgnRef(cast[PPointer](dest), z)
|
||||||
else:
|
else:
|
||||||
# we modify the header of the cell temporarily; instead of the type
|
# 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
|
# field we store a forwarding pointer. XXX This is bad when the cloning
|
||||||
# fails due to OOM etc.
|
# fails due to OOM etc.
|
||||||
let s2 = cast[PPointer](src)[]
|
|
||||||
if s2 == nil:
|
|
||||||
unsureAsgnRef(cast[PPointer](dest), s2)
|
|
||||||
return
|
|
||||||
when declared(usrToCell):
|
when declared(usrToCell):
|
||||||
# unfortunately we only have cycle detection for our native GCs.
|
# unfortunately we only have cycle detection for our native GCs.
|
||||||
let x = usrToCell(s2)
|
let x = usrToCell(s2)
|
||||||
|
|
@ -116,10 +115,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||||
genericDeepCopyAux(z, s2, realType.base)
|
genericDeepCopyAux(z, s2, realType.base)
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
# no cycle check here, but also not really required
|
# no cycle check here, but also not really required
|
||||||
if mt.base.deepcopy != nil:
|
let s2 = cast[PPointer](src)[]
|
||||||
cast[PPointer](dest)[] = mt.base.deepcopy(cast[PPointer](s)[])
|
if s2 != nil and mt.base.deepcopy != nil:
|
||||||
|
cast[PPointer](dest)[] = mt.base.deepcopy(s2)
|
||||||
else:
|
else:
|
||||||
cast[PPointer](dest)[] = cast[PPointer](s)[]
|
cast[PPointer](dest)[] = s2
|
||||||
else:
|
else:
|
||||||
copyMem(dest, src, mt.size)
|
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
|
version 0.10
|
||||||
============
|
============
|
||||||
|
|
||||||
|
- use the effect system for static deadlock prevention
|
||||||
- Test nimfix on various babel packages
|
- Test nimfix on various babel packages
|
||||||
- deprecate recursive tuples; tuple needs laxer type checking
|
- deprecate recursive tuples; tuple needs laxer type checking
|
||||||
- string case should require an 'else'
|
- string case should require an 'else'
|
||||||
|
|
@ -20,9 +21,7 @@ version 0.9.6
|
||||||
Concurrency
|
Concurrency
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
- 'deepCopy' needs to be instantiated for
|
- test 'deepCopy' for closures
|
||||||
generics *when the type is constructed*
|
|
||||||
- test 'deepCopy'
|
|
||||||
|
|
||||||
- implement 'foo[1..4] = spawn(f[4..7])'
|
- implement 'foo[1..4] = spawn(f[4..7])'
|
||||||
- document the new 'spawn' and 'parallel' statements
|
- document the new 'spawn' and 'parallel' statements
|
||||||
|
|
@ -117,7 +116,6 @@ Concurrency/Effect system
|
||||||
provide a ``syncgc`` pragma to trigger compiler injection --> more general:
|
provide a ``syncgc`` pragma to trigger compiler injection --> more general:
|
||||||
an ``injectLoop`` pragma
|
an ``injectLoop`` pragma
|
||||||
- 'writes: []' effect; track reads/writes for shared types
|
- 'writes: []' effect; track reads/writes for shared types
|
||||||
- use the effect system for static deadlock prevention and race detection
|
|
||||||
- ``~`` operator for effects
|
- ``~`` operator for effects
|
||||||
- introduce 'noaddr' pragma to prevent taking the address of a location; this
|
- introduce 'noaddr' pragma to prevent taking the address of a location; this
|
||||||
is very handy to prevent aliasing of global data
|
is very handy to prevent aliasing of global data
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue