deepCopy is instantiated when its corresponding type is instantiated

This commit is contained in:
Araq
2014-09-26 09:36:09 +02:00
parent dfd7390277
commit 1088814e56
10 changed files with 87 additions and 15 deletions

View File

@@ -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 =

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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):

View File

@@ -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
--------

View File

@@ -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)

View 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()

View File

@@ -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