more arc features (#13098)
* config update * ARC now supports 'repr' and 'new' with finalizers is supported
This commit is contained in:
parent
c0973d1b47
commit
767592a3c3
7 changed files with 252 additions and 13 deletions
|
|
@ -2172,7 +2172,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
genRepr(p, e, d)
|
genRepr(p, e, d)
|
||||||
of mOf: genOf(p, e, d)
|
of mOf: genOf(p, e, d)
|
||||||
of mNew: genNew(p, e)
|
of mNew: genNew(p, e)
|
||||||
of mNewFinalize: genNewFinalize(p, e)
|
of mNewFinalize:
|
||||||
|
if optTinyRtti in p.config.globalOptions:
|
||||||
|
genNew(p, e)
|
||||||
|
else:
|
||||||
|
genNewFinalize(p, e)
|
||||||
of mNewSeq: genNewSeq(p, e)
|
of mNewSeq: genNewSeq(p, e)
|
||||||
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
|
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
|
||||||
of mSizeOf:
|
of mSizeOf:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# Special configuration file for the Nim project
|
# Special configuration file for the Nim project
|
||||||
|
|
||||||
hint[XDeclaredButNotUsed]:off
|
hint[XDeclaredButNotUsed]:off
|
||||||
|
hint[Link]:off
|
||||||
|
|
||||||
define:booting
|
define:booting
|
||||||
define:nimcore
|
define:nimcore
|
||||||
|
|
|
||||||
|
|
@ -383,6 +383,35 @@ proc semUnown(c: PContext; n: PNode): PNode =
|
||||||
# little hack for injectdestructors.nim (see bug #11350):
|
# little hack for injectdestructors.nim (see bug #11350):
|
||||||
#result[0].typ = nil
|
#result[0].typ = nil
|
||||||
|
|
||||||
|
proc turnFinalizerIntoDestructor(c: PContext; orig: PSym): PSym =
|
||||||
|
# We need to do 2 things: Replace n.typ which is a 'ref T' by a 'var T' type.
|
||||||
|
# Replace nkDerefExpr by nkHiddenDeref
|
||||||
|
# nkDeref is for 'ref T': x[].field
|
||||||
|
# nkHiddenDeref is for 'var T': x<hidden deref [] here>.field
|
||||||
|
proc transform(n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
|
||||||
|
result = shallowCopy(n)
|
||||||
|
if sameTypeOrNil(n.typ, old):
|
||||||
|
result.typ = fresh
|
||||||
|
if n.kind == nkSym and n.sym == oldParam:
|
||||||
|
result.sym = newParam
|
||||||
|
for i in 0 ..< safeLen(n):
|
||||||
|
result[i] = transform(n[i], old, fresh, oldParam, newParam)
|
||||||
|
#if n.kind == nkDerefExpr and sameType(n[0].typ, old):
|
||||||
|
# result =
|
||||||
|
|
||||||
|
result = copySym(orig)
|
||||||
|
result.flags.incl sfFromGeneric
|
||||||
|
let origParamType = orig.typ[1]
|
||||||
|
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs))
|
||||||
|
let oldParam = orig.typ.n[1].sym
|
||||||
|
let newParam = newSym(skParam, oldParam.name, result, result.info)
|
||||||
|
newParam.typ = newParamType
|
||||||
|
# proc body:
|
||||||
|
result.ast = transform(orig.ast, origParamType, newParamType, oldParam, newParam)
|
||||||
|
# proc signature:
|
||||||
|
result.typ = newProcType(result.info, result)
|
||||||
|
result.typ.addParam newParam
|
||||||
|
|
||||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
## This is the preferred code point to implement magics.
|
## This is the preferred code point to implement magics.
|
||||||
|
|
@ -447,6 +476,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
# Make sure the finalizer procedure refers to a procedure
|
# Make sure the finalizer procedure refers to a procedure
|
||||||
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:
|
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:
|
||||||
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
|
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
|
||||||
|
elif optTinyRtti in c.config.globalOptions:
|
||||||
|
bindTypeHook(c, turnFinalizerIntoDestructor(c, n[^1].sym), n, attachedDestructor)
|
||||||
result = n
|
result = n
|
||||||
of mDestroy:
|
of mDestroy:
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -758,6 +758,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if n[1].typ.len > 0:
|
if n[1].typ.len > 0:
|
||||||
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
|
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
|
||||||
createTypeBoundOps(tracked, n[1].typ, n.info)
|
createTypeBoundOps(tracked, n[1].typ, n.info)
|
||||||
|
# new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
|
||||||
|
|
||||||
if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
|
if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
|
||||||
tracked.owner.kind != skMacro:
|
tracked.owner.kind != skMacro:
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ const ThisIsSystem = true
|
||||||
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
|
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
|
||||||
## Leaked implementation detail. Do not use.
|
## Leaked implementation detail. Do not use.
|
||||||
|
|
||||||
when not defined(gcDestructors):
|
when true:
|
||||||
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
||||||
magic: "NewFinalize", noSideEffect.}
|
magic: "NewFinalize", noSideEffect.}
|
||||||
## Creates a new object of type ``T`` and returns a safe (traced)
|
## Creates a new object of type ``T`` and returns a safe (traced)
|
||||||
|
|
@ -2197,6 +2197,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
|
||||||
defaultImpl()
|
defaultImpl()
|
||||||
x[i] = item
|
x[i] = item
|
||||||
|
|
||||||
|
when not defined(nimV2):
|
||||||
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
||||||
## Takes any Nim variable and returns its string representation.
|
## Takes any Nim variable and returns its string representation.
|
||||||
##
|
##
|
||||||
|
|
@ -3555,6 +3556,9 @@ template unlikely*(val: bool): bool =
|
||||||
import system/dollars
|
import system/dollars
|
||||||
export dollars
|
export dollars
|
||||||
|
|
||||||
|
when defined(nimV2):
|
||||||
|
import system/repr_v2
|
||||||
|
export repr_v2
|
||||||
|
|
||||||
const
|
const
|
||||||
NimMajor* {.intdefine.}: int = 1
|
NimMajor* {.intdefine.}: int = 1
|
||||||
|
|
@ -4218,6 +4222,9 @@ type
|
||||||
NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
|
NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
|
||||||
## Represents a Nim AST node. Macros operate on this type.
|
## Represents a Nim AST node. Macros operate on this type.
|
||||||
|
|
||||||
|
when defined(nimV2):
|
||||||
|
proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.}
|
||||||
|
|
||||||
macro lenVarargs*(x: varargs[untyped]): int {.since: (1, 1).} =
|
macro lenVarargs*(x: varargs[untyped]): int {.since: (1, 1).} =
|
||||||
## returns number of variadic arguments in `x`
|
## returns number of variadic arguments in `x`
|
||||||
proc lenVarargsImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.}
|
proc lenVarargsImpl(x: NimNode): NimNode {.magic: "LengthOpenArray", noSideEffect.}
|
||||||
|
|
|
||||||
170
lib/system/repr_v2.nim
Normal file
170
lib/system/repr_v2.nim
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
proc repr*(x: int): string {.magic: "IntToStr", noSideEffect.}
|
||||||
|
## repr for an integer argument. Returns `x`
|
||||||
|
## converted to a decimal string.
|
||||||
|
|
||||||
|
proc repr*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
|
||||||
|
## repr for an integer argument. Returns `x`
|
||||||
|
## converted to a decimal string.
|
||||||
|
|
||||||
|
proc repr*(x: float): string {.magic: "FloatToStr", noSideEffect.}
|
||||||
|
## repr for a float argument. Returns `x`
|
||||||
|
## converted to a decimal string.
|
||||||
|
|
||||||
|
proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||||
|
## repr for a boolean argument. Returns `x`
|
||||||
|
## converted to the string "false" or "true".
|
||||||
|
|
||||||
|
proc repr*(x: char): string {.magic: "CharToStr", noSideEffect.}
|
||||||
|
## repr for a character argument. Returns `x`
|
||||||
|
## converted to a string.
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## assert $'c' == "c"
|
||||||
|
|
||||||
|
proc repr*(x: cstring): string {.magic: "CStrToStr", noSideEffect.}
|
||||||
|
## repr for a CString argument. Returns `x`
|
||||||
|
## converted to a string.
|
||||||
|
|
||||||
|
proc repr*(x: string): string {.magic: "StrToStr", noSideEffect.}
|
||||||
|
## repr for a string argument. Returns `x`
|
||||||
|
## as it is. This operator is useful for generic code, so
|
||||||
|
## that ``$expr`` also works if ``expr`` is already a string.
|
||||||
|
|
||||||
|
proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
|
||||||
|
## repr for an enumeration argument. This works for
|
||||||
|
## any enumeration type thanks to compiler magic.
|
||||||
|
##
|
||||||
|
## If a `repr` operator for a concrete enumeration is provided, this is
|
||||||
|
## used instead. (In other words: *Overwriting* is possible.)
|
||||||
|
|
||||||
|
template repr(t: typedesc): string = $t
|
||||||
|
|
||||||
|
proc isNamedTuple(T: typedesc): bool =
|
||||||
|
# Taken from typetraits.
|
||||||
|
when T isnot tuple: result = false
|
||||||
|
else:
|
||||||
|
var t: T
|
||||||
|
for name, _ in t.fieldPairs:
|
||||||
|
when name == "Field0":
|
||||||
|
return compiles(t.Field0)
|
||||||
|
else:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc repr*[T: tuple|object](x: T): string =
|
||||||
|
## Generic `repr` operator for tuples that is lifted from the components
|
||||||
|
## of `x`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## $(23, 45) == "(23, 45)"
|
||||||
|
## $(a: 23, b: 45) == "(a: 23, b: 45)"
|
||||||
|
## $() == "()"
|
||||||
|
when T is object:
|
||||||
|
result = $typeof(x)
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
result.add '('
|
||||||
|
var firstElement = true
|
||||||
|
const isNamed = T is object or isNamedTuple(T)
|
||||||
|
when not isNamed:
|
||||||
|
var count = 0
|
||||||
|
for name, value in fieldPairs(x):
|
||||||
|
if not firstElement: result.add(", ")
|
||||||
|
when isNamed:
|
||||||
|
result.add(name)
|
||||||
|
result.add(": ")
|
||||||
|
else:
|
||||||
|
count.inc
|
||||||
|
when compiles($value):
|
||||||
|
when value isnot string and value isnot seq and compiles(value.isNil):
|
||||||
|
if value.isNil: result.add "nil"
|
||||||
|
else: result.addQuoted(value)
|
||||||
|
else:
|
||||||
|
result.addQuoted(value)
|
||||||
|
firstElement = false
|
||||||
|
else:
|
||||||
|
result.add("...")
|
||||||
|
firstElement = false
|
||||||
|
when not isNamed:
|
||||||
|
if count == 1:
|
||||||
|
result.add(',') # $(1,) should print as the semantically legal (1,)
|
||||||
|
result.add(')')
|
||||||
|
|
||||||
|
proc repr*[T: (ref object)](x: T): string =
|
||||||
|
## Generic `repr` operator for tuples that is lifted from the components
|
||||||
|
## of `x`.
|
||||||
|
if x == nil: return "nil"
|
||||||
|
result = $typeof(x) & "("
|
||||||
|
var firstElement = true
|
||||||
|
for name, value in fieldPairs(x[]):
|
||||||
|
if not firstElement: result.add(", ")
|
||||||
|
result.add(name)
|
||||||
|
result.add(": ")
|
||||||
|
when compiles($value):
|
||||||
|
when value isnot string and value isnot seq and compiles(value.isNil):
|
||||||
|
if value.isNil: result.add "nil"
|
||||||
|
else: result.addQuoted(value)
|
||||||
|
else:
|
||||||
|
result.addQuoted(value)
|
||||||
|
firstElement = false
|
||||||
|
else:
|
||||||
|
result.add("...")
|
||||||
|
firstElement = false
|
||||||
|
result.add(')')
|
||||||
|
|
||||||
|
proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string =
|
||||||
|
result = prefix
|
||||||
|
var firstElement = true
|
||||||
|
for value in items(x):
|
||||||
|
if firstElement:
|
||||||
|
firstElement = false
|
||||||
|
else:
|
||||||
|
result.add(separator)
|
||||||
|
|
||||||
|
when value isnot string and value isnot seq and compiles(value.isNil):
|
||||||
|
# this branch should not be necessary
|
||||||
|
if value.isNil:
|
||||||
|
result.add "nil"
|
||||||
|
else:
|
||||||
|
result.addQuoted(value)
|
||||||
|
else:
|
||||||
|
result.addQuoted(value)
|
||||||
|
result.add(suffix)
|
||||||
|
|
||||||
|
proc repr*[T](x: set[T]): string =
|
||||||
|
## Generic `repr` operator for sets that is lifted from the components
|
||||||
|
## of `x`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## ${23, 45} == "{23, 45}"
|
||||||
|
collectionToRepr(x, "{", ", ", "}")
|
||||||
|
|
||||||
|
proc repr*[T](x: seq[T]): string =
|
||||||
|
## Generic `repr` operator for seqs that is lifted from the components
|
||||||
|
## of `x`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## $(@[23, 45]) == "@[23, 45]"
|
||||||
|
collectionToRepr(x, "@[", ", ", "]")
|
||||||
|
|
||||||
|
proc repr*[T, U](x: HSlice[T, U]): string =
|
||||||
|
## Generic `repr` operator for slices that is lifted from the components
|
||||||
|
## of `x`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## $(1 .. 5) == "1 .. 5"
|
||||||
|
result = $x.a
|
||||||
|
result.add(" .. ")
|
||||||
|
result.add($x.b)
|
||||||
|
|
||||||
|
proc repr*[T, IDX](x: array[IDX, T]): string =
|
||||||
|
## Generic `repr` operator for arrays that is lifted from the components.
|
||||||
|
collectionToRepr(x, "[", ", ", "]")
|
||||||
|
|
||||||
|
proc repr*[T](x: openArray[T]): string =
|
||||||
|
## Generic `repr` operator for openarrays that is lifted from the components
|
||||||
|
## of `x`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]"
|
||||||
|
collectionToRepr(x, "[", ", ", "]")
|
||||||
25
tests/destructor/tfinalizer.nim
Normal file
25
tests/destructor/tfinalizer.nim
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim c --gc:arc $file"
|
||||||
|
output: '''Foo(field: "Dick Laurent", k: ka, x: 0.0)
|
||||||
|
Dick Laurent is dead'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
Kind = enum
|
||||||
|
ka, kb
|
||||||
|
Foo = ref object
|
||||||
|
field: string
|
||||||
|
case k: Kind
|
||||||
|
of ka: x: float
|
||||||
|
of kb: discard
|
||||||
|
|
||||||
|
#var x = Foo(field: "lovely")
|
||||||
|
proc finalizer(x: Foo) =
|
||||||
|
echo x.field, " is dead"
|
||||||
|
|
||||||
|
var x: Foo
|
||||||
|
new(x, finalizer)
|
||||||
|
x.field = "Dick Laurent"
|
||||||
|
# reference to a great movie. If you haven't seen it, highly recommended.
|
||||||
|
|
||||||
|
echo repr x
|
||||||
Loading…
Add table
Add a link
Reference in a new issue