diff options
author | cooldome <cdome@bk.ru> | 2019-05-04 22:34:37 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-05-04 22:34:37 +0200 |
commit | d3db189eb42c1c44d8be1a1fc847ed8db428638f (patch) | |
tree | 6156800598db9699a093056f890e83c5271f4ddc | |
parent | 9c3e23e0751881b16fab813fd3c2edc1b98b7f68 (diff) | |
download | Nim-d3db189eb42c1c44d8be1a1fc847ed8db428638f.tar.gz |
Destructor lifting fixes #11149 (#11163)
* fixes #11149 * add test
-rw-r--r-- | compiler/injectdestructors.nim | 2 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 17 | ||||
-rw-r--r-- | compiler/sighashes.nim | 7 | ||||
-rw-r--r-- | tests/destructor/topt.nim | 61 |
4 files changed, 77 insertions, 10 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 0e414c975..0111bd4af 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -325,7 +325,7 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = if op == nil: # give up and find the canonical type instead: - let h = sighashes.hashType(t, {CoType, CoConsiderOwned}) + let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.graph.canonTypes.getOrDefault(h) if canon != nil: op = canon.attachedOps[kind] diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 2dcaa7984..3e3b74f64 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -593,12 +593,13 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) = if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.skipTypes({tyAlias}).flags != {}: return incl orig.flags, tfCheckedForDestructor - let h = sighashes.hashType(orig, {CoType, CoConsiderOwned}) + let h = sighashes.hashType(orig, {CoType, CoConsiderOwned, CoDistinct}) var canon = c.graph.canonTypes.getOrDefault(h) var overwrite = false if canon == nil: - c.graph.canonTypes[h] = orig - canon = orig + let typ = orig.skipTypes({tyGenericInst, tyAlias}) + c.graph.canonTypes[h] = typ + canon = typ elif canon != orig: overwrite = true @@ -608,17 +609,17 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) = # 3. we have a lifted destructor. # 4. We have a custom destructor. # 5. We have a (custom) generic destructor. - let typ = canon.skipTypes({tyGenericInst, tyAlias}) + # we generate the destructor first so that other operators can depend on it: for k in attachedDestructor..attachedSink: - if typ.attachedOps[k] == nil: - discard produceSym(c, typ, k, info) + if canon.attachedOps[k] == nil: + discard produceSym(c, canon, k, info) else: - inst(typ.attachedOps[k], typ) + inst(canon.attachedOps[k], canon) if overwrite: for k in attachedDestructor..attachedSink: - orig.attachedOps[k] = typ.attachedOps[k] + orig.attachedOps[k] = canon.attachedOps[k] if not isTrival(orig.destructor): #or not isTrival(orig.assignment) or diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index c69d58cd3..90c4cd18b 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -36,6 +36,7 @@ type CoOwnerSig CoIgnoreRange CoConsiderOwned + CoDistinct proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) @@ -97,7 +98,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i], flags of tyDistinct: - if {CoType, CoConsiderOwned} * flags == {CoType} or t.sym == nil: + if CoDistinct in flags: + if t.sym != nil: c.hashSym(t.sym) + if t.sym == nil or tfFromGeneric in t.flags: + c.hashType t.lastSon, flags + elif CoType in flags or t.sym == nil: c.hashType t.lastSon, flags else: c.hashSym(t.sym) diff --git a/tests/destructor/topt.nim b/tests/destructor/topt.nim new file mode 100644 index 000000000..829500f8a --- /dev/null +++ b/tests/destructor/topt.nim @@ -0,0 +1,61 @@ + +discard """ + output: '''5 +vseq destroy +''' +""" +type + opt*[T] = object + case exists: bool + of true: val: T + of false: discard + +proc some*[T](val: sink T): opt[T] {.inline.} = + ## Returns an ``opt`` that has the value. + ## nil is considered as none for reference types + result.exists = true + result.val = val + +proc none*(T: typedesc): opt[T] {.inline.} = + ## Returns an ``opt`` for this type that has no value. + # the default is the none type + discard + +proc none*[T]: opt[T] {.inline.} = + ## Alias for ``none(T)``. + none(T) + +proc unsafeGet*[T](self: opt[T]): lent T {.inline.} = + ## Returns the value of a ``some``. Behavior is undefined for ``none``. + self.val + +type + VSeq*[T] = object + len: int + data: ptr UncheckedArray[T] + +proc `=destroy`*[T](m: var VSeq[T]) {.inline.} = + if m.data != nil: + echo "vseq destroy" + dealloc(m.data) + m.data = nil + +proc `=`*[T](m: var VSeq[T], m2: VSeq[T]) {.error.} + +proc `=sink`*[T](m: var VSeq[T], m2: VSeq[T]) {.inline.} = + if m.data != m2.data: + `=destroy`(m) + m.len = m2.len + m.data = m2.data + +proc newVSeq*[T](len: int): VSeq[T] = + ## Only support sequence creation from scalar size because creation from + ## vetorized size can't reproduce the original scalar size + result.len = len + if len > 0: + result.data = cast[ptr UncheckedArray[T]](alloc(sizeof(T) * len)) + +let x = some newVSeq[float](5) +echo x.unsafeGet.len +let y = none(VSeq[float]) + |