Skip to content

Commit 51f6baa

Browse files
authored
Merge pull request #27 from nim-lang/devel
more arc features (nim-lang#13098)
2 parents a72b2e5 + 767592a commit 51f6baa

File tree

7 files changed

+252
-13
lines changed

7 files changed

+252
-13
lines changed

compiler/ccgexprs.nim

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2172,7 +2172,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
21722172
genRepr(p, e, d)
21732173
of mOf: genOf(p, e, d)
21742174
of mNew: genNew(p, e)
2175-
of mNewFinalize: genNewFinalize(p, e)
2175+
of mNewFinalize:
2176+
if optTinyRtti in p.config.globalOptions:
2177+
genNew(p, e)
2178+
else:
2179+
genNewFinalize(p, e)
21762180
of mNewSeq: genNewSeq(p, e)
21772181
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
21782182
of mSizeOf:

compiler/nim.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Special configuration file for the Nim project
22

33
hint[XDeclaredButNotUsed]:off
4+
hint[Link]:off
45

56
define:booting
67
define:nimcore

compiler/semmagic.nim

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,35 @@ proc semUnown(c: PContext; n: PNode): PNode =
383383
# little hack for injectdestructors.nim (see bug #11350):
384384
#result[0].typ = nil
385385

386+
proc turnFinalizerIntoDestructor(c: PContext; orig: PSym): PSym =
387+
# We need to do 2 things: Replace n.typ which is a 'ref T' by a 'var T' type.
388+
# Replace nkDerefExpr by nkHiddenDeref
389+
# nkDeref is for 'ref T': x[].field
390+
# nkHiddenDeref is for 'var T': x<hidden deref [] here>.field
391+
proc transform(n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
392+
result = shallowCopy(n)
393+
if sameTypeOrNil(n.typ, old):
394+
result.typ = fresh
395+
if n.kind == nkSym and n.sym == oldParam:
396+
result.sym = newParam
397+
for i in 0 ..< safeLen(n):
398+
result[i] = transform(n[i], old, fresh, oldParam, newParam)
399+
#if n.kind == nkDerefExpr and sameType(n[0].typ, old):
400+
# result =
401+
402+
result = copySym(orig)
403+
result.flags.incl sfFromGeneric
404+
let origParamType = orig.typ[1]
405+
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs))
406+
let oldParam = orig.typ.n[1].sym
407+
let newParam = newSym(skParam, oldParam.name, result, result.info)
408+
newParam.typ = newParamType
409+
# proc body:
410+
result.ast = transform(orig.ast, origParamType, newParamType, oldParam, newParam)
411+
# proc signature:
412+
result.typ = newProcType(result.info, result)
413+
result.typ.addParam newParam
414+
386415
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
387416
flags: TExprFlags): PNode =
388417
## This is the preferred code point to implement magics.
@@ -447,6 +476,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
447476
# Make sure the finalizer procedure refers to a procedure
448477
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:
449478
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
479+
elif optTinyRtti in c.config.globalOptions:
480+
bindTypeHook(c, turnFinalizerIntoDestructor(c, n[^1].sym), n, attachedDestructor)
450481
result = n
451482
of mDestroy:
452483
result = n

compiler/sempass2.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@ proc track(tracked: PEffects, n: PNode) =
758758
if n[1].typ.len > 0:
759759
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
760760
createTypeBoundOps(tracked, n[1].typ, n.info)
761+
# new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
761762

762763
if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
763764
tracked.owner.kind != skMacro:

lib/system.nim

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ const ThisIsSystem = true
250250
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
251251
## Leaked implementation detail. Do not use.
252252
253-
when not defined(gcDestructors):
253+
when true:
254254
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
255255
magic: "NewFinalize", noSideEffect.}
256256
## Creates a new object of type ``T`` and returns a safe (traced)
@@ -2197,17 +2197,18 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
21972197
defaultImpl()
21982198
x[i] = item
21992199

2200-
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
2201-
## Takes any Nim variable and returns its string representation.
2202-
##
2203-
## It works even for complex data graphs with cycles. This is a great
2204-
## debugging tool.
2205-
##
2206-
## .. code-block:: Nim
2207-
## var s: seq[string] = @["test2", "test2"]
2208-
## var i = @[1, 2, 3, 4, 5]
2209-
## echo repr(s) # => 0x1055eb050[0x1055ec050"test2", 0x1055ec078"test2"]
2210-
## echo repr(i) # => 0x1055ed050[1, 2, 3, 4, 5]
2200+
when not defined(nimV2):
2201+
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
2202+
## Takes any Nim variable and returns its string representation.
2203+
##
2204+
## It works even for complex data graphs with cycles. This is a great
2205+
## debugging tool.
2206+
##
2207+
## .. code-block:: Nim
2208+
## var s: seq[string] = @["test2", "test2"]
2209+
## var i = @[1, 2, 3, 4, 5]
2210+
## echo repr(s) # => 0x1055eb050[0x1055ec050"test2", 0x1055ec078"test2"]
2211+
## echo repr(i) # => 0x1055ed050[1, 2, 3, 4, 5]
22112212

22122213
type
22132214
ByteAddress* = int
@@ -3555,6 +3556,9 @@ template unlikely*(val: bool): bool =
35553556
import system/dollars
35563557
export dollars
35573558
3559+
when defined(nimV2):
3560+
import system/repr_v2
3561+
export repr_v2
35583562
35593563
const
35603564
NimMajor* {.intdefine.}: int = 1
@@ -4218,6 +4222,9 @@ type
42184222
NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
42194223
## Represents a Nim AST node. Macros operate on this type.
42204224
4225+
when defined(nimV2):
4226+
proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.}
4227+
42214228
macro lenVarargs*(x: varargs[untyped]): int {.since: (1, 1).} =
42224229
## returns number of variadic arguments in `x`
42234230
proc lenVarargsImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.}

lib/system/repr_v2.nim

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
proc repr*(x: int): string {.magic: "IntToStr", noSideEffect.}
2+
## repr for an integer argument. Returns `x`
3+
## converted to a decimal string.
4+
5+
proc repr*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
6+
## repr for an integer argument. Returns `x`
7+
## converted to a decimal string.
8+
9+
proc repr*(x: float): string {.magic: "FloatToStr", noSideEffect.}
10+
## repr for a float argument. Returns `x`
11+
## converted to a decimal string.
12+
13+
proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
14+
## repr for a boolean argument. Returns `x`
15+
## converted to the string "false" or "true".
16+
17+
proc repr*(x: char): string {.magic: "CharToStr", noSideEffect.}
18+
## repr for a character argument. Returns `x`
19+
## converted to a string.
20+
##
21+
## .. code-block:: Nim
22+
## assert $'c' == "c"
23+
24+
proc repr*(x: cstring): string {.magic: "CStrToStr", noSideEffect.}
25+
## repr for a CString argument. Returns `x`
26+
## converted to a string.
27+
28+
proc repr*(x: string): string {.magic: "StrToStr", noSideEffect.}
29+
## repr for a string argument. Returns `x`
30+
## as it is. This operator is useful for generic code, so
31+
## that ``$expr`` also works if ``expr`` is already a string.
32+
33+
proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
34+
## repr for an enumeration argument. This works for
35+
## any enumeration type thanks to compiler magic.
36+
##
37+
## If a `repr` operator for a concrete enumeration is provided, this is
38+
## used instead. (In other words: *Overwriting* is possible.)
39+
40+
template repr(t: typedesc): string = $t
41+
42+
proc isNamedTuple(T: typedesc): bool =
43+
# Taken from typetraits.
44+
when T isnot tuple: result = false
45+
else:
46+
var t: T
47+
for name, _ in t.fieldPairs:
48+
when name == "Field0":
49+
return compiles(t.Field0)
50+
else:
51+
return true
52+
return false
53+
54+
proc repr*[T: tuple|object](x: T): string =
55+
## Generic `repr` operator for tuples that is lifted from the components
56+
## of `x`. Example:
57+
##
58+
## .. code-block:: Nim
59+
## $(23, 45) == "(23, 45)"
60+
## $(a: 23, b: 45) == "(a: 23, b: 45)"
61+
## $() == "()"
62+
when T is object:
63+
result = $typeof(x)
64+
else:
65+
result = ""
66+
result.add '('
67+
var firstElement = true
68+
const isNamed = T is object or isNamedTuple(T)
69+
when not isNamed:
70+
var count = 0
71+
for name, value in fieldPairs(x):
72+
if not firstElement: result.add(", ")
73+
when isNamed:
74+
result.add(name)
75+
result.add(": ")
76+
else:
77+
count.inc
78+
when compiles($value):
79+
when value isnot string and value isnot seq and compiles(value.isNil):
80+
if value.isNil: result.add "nil"
81+
else: result.addQuoted(value)
82+
else:
83+
result.addQuoted(value)
84+
firstElement = false
85+
else:
86+
result.add("...")
87+
firstElement = false
88+
when not isNamed:
89+
if count == 1:
90+
result.add(',') # $(1,) should print as the semantically legal (1,)
91+
result.add(')')
92+
93+
proc repr*[T: (ref object)](x: T): string =
94+
## Generic `repr` operator for tuples that is lifted from the components
95+
## of `x`.
96+
if x == nil: return "nil"
97+
result = $typeof(x) & "("
98+
var firstElement = true
99+
for name, value in fieldPairs(x[]):
100+
if not firstElement: result.add(", ")
101+
result.add(name)
102+
result.add(": ")
103+
when compiles($value):
104+
when value isnot string and value isnot seq and compiles(value.isNil):
105+
if value.isNil: result.add "nil"
106+
else: result.addQuoted(value)
107+
else:
108+
result.addQuoted(value)
109+
firstElement = false
110+
else:
111+
result.add("...")
112+
firstElement = false
113+
result.add(')')
114+
115+
proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string =
116+
result = prefix
117+
var firstElement = true
118+
for value in items(x):
119+
if firstElement:
120+
firstElement = false
121+
else:
122+
result.add(separator)
123+
124+
when value isnot string and value isnot seq and compiles(value.isNil):
125+
# this branch should not be necessary
126+
if value.isNil:
127+
result.add "nil"
128+
else:
129+
result.addQuoted(value)
130+
else:
131+
result.addQuoted(value)
132+
result.add(suffix)
133+
134+
proc repr*[T](x: set[T]): string =
135+
## Generic `repr` operator for sets that is lifted from the components
136+
## of `x`. Example:
137+
##
138+
## .. code-block:: Nim
139+
## ${23, 45} == "{23, 45}"
140+
collectionToRepr(x, "{", ", ", "}")
141+
142+
proc repr*[T](x: seq[T]): string =
143+
## Generic `repr` operator for seqs that is lifted from the components
144+
## of `x`. Example:
145+
##
146+
## .. code-block:: Nim
147+
## $(@[23, 45]) == "@[23, 45]"
148+
collectionToRepr(x, "@[", ", ", "]")
149+
150+
proc repr*[T, U](x: HSlice[T, U]): string =
151+
## Generic `repr` operator for slices that is lifted from the components
152+
## of `x`. Example:
153+
##
154+
## .. code-block:: Nim
155+
## $(1 .. 5) == "1 .. 5"
156+
result = $x.a
157+
result.add(" .. ")
158+
result.add($x.b)
159+
160+
proc repr*[T, IDX](x: array[IDX, T]): string =
161+
## Generic `repr` operator for arrays that is lifted from the components.
162+
collectionToRepr(x, "[", ", ", "]")
163+
164+
proc repr*[T](x: openArray[T]): string =
165+
## Generic `repr` operator for openarrays that is lifted from the components
166+
## of `x`. Example:
167+
##
168+
## .. code-block:: Nim
169+
## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]"
170+
collectionToRepr(x, "[", ", ", "]")

tests/destructor/tfinalizer.nim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
discard """
2+
cmd: "nim c --gc:arc $file"
3+
output: '''Foo(field: "Dick Laurent", k: ka, x: 0.0)
4+
Dick Laurent is dead'''
5+
"""
6+
7+
type
8+
Kind = enum
9+
ka, kb
10+
Foo = ref object
11+
field: string
12+
case k: Kind
13+
of ka: x: float
14+
of kb: discard
15+
16+
#var x = Foo(field: "lovely")
17+
proc finalizer(x: Foo) =
18+
echo x.field, " is dead"
19+
20+
var x: Foo
21+
new(x, finalizer)
22+
x.field = "Dick Laurent"
23+
# reference to a great movie. If you haven't seen it, highly recommended.
24+
25+
echo repr x

0 commit comments

Comments
 (0)