newruntime: progress
This commit is contained in:
parent
fda1352ccf
commit
c3067e36bb
12 changed files with 57 additions and 46 deletions
|
|
@ -12,6 +12,14 @@
|
||||||
|
|
||||||
# included from sempass2.nim
|
# included from sempass2.nim
|
||||||
|
|
||||||
|
# Todo:
|
||||||
|
# - specialize destructors for constant arrays of strings
|
||||||
|
# (they don't require any)
|
||||||
|
# - use openArray instead of array to avoid over-specializations
|
||||||
|
# - make 'owned' mean 'sink' in parameters
|
||||||
|
|
||||||
|
import sighashes
|
||||||
|
|
||||||
type
|
type
|
||||||
TLiftCtx = object
|
TLiftCtx = object
|
||||||
graph: ModuleGraph
|
graph: ModuleGraph
|
||||||
|
|
@ -286,25 +294,10 @@ proc seqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
doAssert t.destructor != nil
|
doAssert t.destructor != nil
|
||||||
moveCall.add destructorCall(c.graph, t.destructor, x)
|
moveCall.add destructorCall(c.graph, t.destructor, x)
|
||||||
body.add moveCall
|
body.add moveCall
|
||||||
when false:
|
|
||||||
# we generate:
|
|
||||||
# if a.len != 0 and a.p != b.p:
|
|
||||||
# `=destroy`(x)
|
|
||||||
# a.len = b.len
|
|
||||||
# a.p = b.p
|
|
||||||
# Note: '@' is either '.' or '->'.
|
|
||||||
body.add genIf(c, genVerbatim("dest@len != 0 && dest@p != src.p", c.info),
|
|
||||||
destructorCall(c.graph, t.destructor, x))
|
|
||||||
body.add genVerbatim("dest@len=src.len; dest@p=src.p;", c.info)
|
|
||||||
of attachedDestructor:
|
of attachedDestructor:
|
||||||
# destroy all elements:
|
# destroy all elements:
|
||||||
forallElements(c, t, body, x, y)
|
forallElements(c, t, body, x, y)
|
||||||
body.add genBuiltin(c.graph, mDestroy, "destroy", x)
|
body.add genBuiltin(c.graph, mDestroy, "destroy", x)
|
||||||
when false:
|
|
||||||
var deallocStmt = genVerbatim("dest@region->dealloc(dest@region, dest@p, " &
|
|
||||||
"(dest@p->cap * sizeof($)) + sizeof(NI) + sizeof(void*)); dest@len = 0;", c.info)
|
|
||||||
deallocStmt.typ = t.lastSon
|
|
||||||
body.add genIf(c, genVerbatim("dest@len != 0 && dest@region", c.info), deallocStmt)
|
|
||||||
|
|
||||||
proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
case c.kind
|
case c.kind
|
||||||
|
|
@ -603,19 +596,29 @@ template inst(field, t) =
|
||||||
if field.ast != nil:
|
if field.ast != nil:
|
||||||
patchBody(c, field.ast, info)
|
patchBody(c, field.ast, info)
|
||||||
|
|
||||||
proc createTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
proc createTypeBoundOps*(c: PContext; orig: PType; info: TLineInfo) =
|
||||||
## In the semantic pass this is called in strategic places
|
## In the semantic pass this is called in strategic places
|
||||||
## to ensure we lift assignment, destructors and moves properly.
|
## to ensure we lift assignment, destructors and moves properly.
|
||||||
## The later 'injectdestructors' pass depends on it.
|
## The later 'injectdestructors' pass depends on it.
|
||||||
if typ == nil or {tfCheckedForDestructor, tfHasMeta} * typ.flags != {}: return
|
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
|
||||||
incl typ.flags, tfCheckedForDestructor
|
incl orig.flags, tfCheckedForDestructor
|
||||||
|
|
||||||
|
let h = sighashes.hashType(orig, {CoType, CoConsiderOwned})
|
||||||
|
var canon = c.graph.canonTypes.getOrDefault(h)
|
||||||
|
var overwrite = false
|
||||||
|
if canon == nil:
|
||||||
|
c.graph.canonTypes[h] = orig
|
||||||
|
canon = orig
|
||||||
|
elif canon != orig:
|
||||||
|
overwrite = true
|
||||||
|
|
||||||
# multiple cases are to distinguish here:
|
# multiple cases are to distinguish here:
|
||||||
# 1. we don't know yet if 'typ' has a nontrival destructor.
|
# 1. we don't know yet if 'typ' has a nontrival destructor.
|
||||||
# 2. we have a nop destructor. --> mDestroy
|
# 2. we have a nop destructor. --> mDestroy
|
||||||
# 3. we have a lifted destructor.
|
# 3. we have a lifted destructor.
|
||||||
# 4. We have a custom destructor.
|
# 4. We have a custom destructor.
|
||||||
# 5. We have a (custom) generic destructor.
|
# 5. We have a (custom) generic destructor.
|
||||||
let typ = typ.skipTypes({tyGenericInst, tyAlias})
|
let typ = canon.skipTypes({tyGenericInst, tyAlias})
|
||||||
# we generate the destructor first so that other operators can depend on it:
|
# we generate the destructor first so that other operators can depend on it:
|
||||||
if typ.destructor == nil:
|
if typ.destructor == nil:
|
||||||
liftBody(c, typ, attachedDestructor, info)
|
liftBody(c, typ, attachedDestructor, info)
|
||||||
|
|
@ -629,3 +632,8 @@ proc createTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||||
liftBody(c, typ, attachedSink, info)
|
liftBody(c, typ, attachedSink, info)
|
||||||
else:
|
else:
|
||||||
inst(typ.sink, typ)
|
inst(typ.sink, typ)
|
||||||
|
|
||||||
|
if overwrite:
|
||||||
|
orig.destructor = canon.destructor
|
||||||
|
orig.assignment = canon.assignment
|
||||||
|
orig.sink = canon.sink
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
import ast, intsets, tables, options, lineinfos, hashes, idents,
|
import ast, intsets, tables, options, lineinfos, hashes, idents,
|
||||||
incremental, btrees
|
incremental, btrees, sighashes
|
||||||
|
|
||||||
type
|
type
|
||||||
ModuleGraph* = ref object
|
ModuleGraph* = ref object
|
||||||
|
|
@ -57,6 +57,7 @@ type
|
||||||
opContains*, opNot*: PSym
|
opContains*, opNot*: PSym
|
||||||
emptyNode*: PNode
|
emptyNode*: PNode
|
||||||
incr*: IncrementalCtx
|
incr*: IncrementalCtx
|
||||||
|
canonTypes*: Table[SigHash, PType]
|
||||||
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
|
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
|
||||||
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
|
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
|
||||||
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
|
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
|
||||||
|
|
@ -138,6 +139,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||||
result.cacheSeqs = initTable[string, PNode]()
|
result.cacheSeqs = initTable[string, PNode]()
|
||||||
result.cacheCounters = initTable[string, BiggestInt]()
|
result.cacheCounters = initTable[string, BiggestInt]()
|
||||||
result.cacheTables = initTable[string, BTree[string, PNode]]()
|
result.cacheTables = initTable[string, BTree[string, PNode]]()
|
||||||
|
result.canonTypes = initTable[SigHash, PType]()
|
||||||
|
|
||||||
proc resetAllModules*(g: ModuleGraph) =
|
proc resetAllModules*(g: ModuleGraph) =
|
||||||
initStrTable(g.packageSyms)
|
initStrTable(g.packageSyms)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||||
wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
|
wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
|
||||||
modulegraphs, lowerings, sigmatch
|
modulegraphs, lowerings, sigmatch, tables
|
||||||
|
|
||||||
when not defined(leanCompiler):
|
when not defined(leanCompiler):
|
||||||
import writetracking
|
import writetracking
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ type
|
||||||
CoType
|
CoType
|
||||||
CoOwnerSig
|
CoOwnerSig
|
||||||
CoIgnoreRange
|
CoIgnoreRange
|
||||||
|
CoConsiderOwned
|
||||||
|
|
||||||
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag])
|
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag])
|
||||||
|
|
||||||
|
|
@ -165,7 +166,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||||
c.hashType t.sons[i], flags
|
c.hashType t.sons[i], flags
|
||||||
else:
|
else:
|
||||||
c.hashType t.lastSon, flags
|
c.hashType t.lastSon, flags
|
||||||
of tyAlias, tySink, tyUserTypeClasses, tyInferred, tyOwned:
|
of tyAlias, tySink, tyUserTypeClasses, tyInferred:
|
||||||
|
c.hashType t.lastSon, flags
|
||||||
|
of tyOwned:
|
||||||
|
if CoConsiderOwned in flags:
|
||||||
|
c &= char(t.kind)
|
||||||
c.hashType t.lastSon, flags
|
c.hashType t.lastSon, flags
|
||||||
of tyBool, tyChar, tyInt..tyUInt64:
|
of tyBool, tyChar, tyInt..tyUInt64:
|
||||||
# no canonicalization for integral types, so that e.g. ``pid_t`` is
|
# no canonicalization for integral types, so that e.g. ``pid_t`` is
|
||||||
|
|
|
||||||
|
|
@ -413,7 +413,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||||
typ.size = typ.lastSon.size
|
typ.size = typ.lastSon.size
|
||||||
typ.align = typ.lastSon.align
|
typ.align = typ.lastSon.align
|
||||||
|
|
||||||
of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink:
|
of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned:
|
||||||
computeSizeAlign(conf, typ.lastSon)
|
computeSizeAlign(conf, typ.lastSon)
|
||||||
typ.size = typ.lastSon.size
|
typ.size = typ.lastSon.size
|
||||||
typ.align = typ.lastSon.align
|
typ.align = typ.lastSon.align
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,7 @@ proc unloadLib*(lib: LibHandle) {.gcsafe.}
|
||||||
|
|
||||||
proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} =
|
proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} =
|
||||||
## raises an `EInvalidLibrary` exception.
|
## raises an `EInvalidLibrary` exception.
|
||||||
var e: ref LibraryError
|
raise newException(LibraryError, "could not find symbol: " & $name)
|
||||||
new(e)
|
|
||||||
e.msg = "could not find symbol: " & $name
|
|
||||||
raise e
|
|
||||||
|
|
||||||
proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.}
|
proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.}
|
||||||
## retrieves the address of a procedure/variable from `lib`. Returns nil
|
## retrieves the address of a procedure/variable from `lib`. Returns nil
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
|
||||||
## See also:
|
## See also:
|
||||||
## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_
|
## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_
|
||||||
## * `osLastError proc <#osLastError>`_
|
## * `osLastError proc <#osLastError>`_
|
||||||
var e: ref OSError; new(e)
|
var e: owned(ref OSError); new(e)
|
||||||
e.errorCode = errorCode.int32
|
e.errorCode = errorCode.int32
|
||||||
e.msg = osErrorMsg(errorCode)
|
e.msg = osErrorMsg(errorCode)
|
||||||
if additionalInfo.len > 0:
|
if additionalInfo.len > 0:
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ proc startProcess*(command: string,
|
||||||
args: openArray[string] = [],
|
args: openArray[string] = [],
|
||||||
env: StringTableRef = nil,
|
env: StringTableRef = nil,
|
||||||
options: set[ProcessOption] = {poStdErrToStdOut}):
|
options: set[ProcessOption] = {poStdErrToStdOut}):
|
||||||
Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect,
|
owned Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect,
|
||||||
RootEffect].}
|
RootEffect].}
|
||||||
## Starts a process. `Command` is the executable file, `workingDir` is the
|
## Starts a process. `Command` is the executable file, `workingDir` is the
|
||||||
## process's working directory. If ``workingDir == ""`` the current directory
|
## process's working directory. If ``workingDir == ""`` the current directory
|
||||||
|
|
@ -470,7 +470,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
addr bytesWritten, nil)
|
addr bytesWritten, nil)
|
||||||
if a == 0: raiseOSError(osLastError())
|
if a == 0: raiseOSError(osLastError())
|
||||||
|
|
||||||
proc newFileHandleStream(handle: Handle): FileHandleStream =
|
proc newFileHandleStream(handle: Handle): owned FileHandleStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.handle = handle
|
result.handle = handle
|
||||||
result.closeImpl = hsClose
|
result.closeImpl = hsClose
|
||||||
|
|
@ -573,7 +573,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
workingDir: string = "",
|
workingDir: string = "",
|
||||||
args: openArray[string] = [],
|
args: openArray[string] = [],
|
||||||
env: StringTableRef = nil,
|
env: StringTableRef = nil,
|
||||||
options: set[ProcessOption] = {poStdErrToStdOut}): Process =
|
options: set[ProcessOption] = {poStdErrToStdOut}): owned Process =
|
||||||
var
|
var
|
||||||
si: STARTUPINFO
|
si: STARTUPINFO
|
||||||
procInfo: PROCESS_INFORMATION
|
procInfo: PROCESS_INFORMATION
|
||||||
|
|
@ -840,7 +840,7 @@ elif not defined(useNimRtl):
|
||||||
workingDir: string = "",
|
workingDir: string = "",
|
||||||
args: openArray[string] = [],
|
args: openArray[string] = [],
|
||||||
env: StringTableRef = nil,
|
env: StringTableRef = nil,
|
||||||
options: set[ProcessOption] = {poStdErrToStdOut}): Process =
|
options: set[ProcessOption] = {poStdErrToStdOut}): owned Process =
|
||||||
var
|
var
|
||||||
pStdin, pStdout, pStderr: array[0..1, cint]
|
pStdin, pStdout, pStderr: array[0..1, cint]
|
||||||
new(result)
|
new(result)
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
||||||
proc newEIO(msg: string): ref IOError =
|
proc newEIO(msg: string): owned(ref IOError) =
|
||||||
new(result)
|
new(result)
|
||||||
result.msg = msg
|
result.msg = msg
|
||||||
|
|
||||||
|
|
@ -403,7 +403,7 @@ when not defined(js):
|
||||||
else:
|
else:
|
||||||
s.data = nil
|
s.data = nil
|
||||||
|
|
||||||
proc newStringStream*(s: string = ""): StringStream =
|
proc newStringStream*(s: string = ""): owned StringStream =
|
||||||
## creates a new stream from the string `s`.
|
## creates a new stream from the string `s`.
|
||||||
new(result)
|
new(result)
|
||||||
result.data = s
|
result.data = s
|
||||||
|
|
@ -446,7 +446,7 @@ when not defined(js):
|
||||||
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
|
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
|
||||||
raise newEIO("cannot write to stream")
|
raise newEIO("cannot write to stream")
|
||||||
|
|
||||||
proc newFileStream*(f: File): FileStream =
|
proc newFileStream*(f: File): owned FileStream =
|
||||||
## creates a new stream from the file `f`.
|
## creates a new stream from the file `f`.
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
|
|
@ -460,7 +460,7 @@ when not defined(js):
|
||||||
result.writeDataImpl = fsWriteData
|
result.writeDataImpl = fsWriteData
|
||||||
result.flushImpl = fsFlush
|
result.flushImpl = fsFlush
|
||||||
|
|
||||||
proc newFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): FileStream =
|
proc newFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): owned FileStream =
|
||||||
## creates a new stream from the file named `filename` with the mode `mode`.
|
## creates a new stream from the file named `filename` with the mode `mode`.
|
||||||
## If the file cannot be opened, nil is returned. See the `system
|
## If the file cannot be opened, nil is returned. See the `system
|
||||||
## <system.html>`_ module for a list of available FileMode enums.
|
## <system.html>`_ module for a list of available FileMode enums.
|
||||||
|
|
@ -469,7 +469,7 @@ when not defined(js):
|
||||||
var f: File
|
var f: File
|
||||||
if open(f, filename, mode, bufSize): result = newFileStream(f)
|
if open(f, filename, mode, bufSize): result = newFileStream(f)
|
||||||
|
|
||||||
proc openFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): FileStream =
|
proc openFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): owned FileStream =
|
||||||
## creates a new stream from the file named `filename` with the mode `mode`.
|
## creates a new stream from the file named `filename` with the mode `mode`.
|
||||||
## If the file cannot be opened, an IO exception is raised.
|
## If the file cannot be opened, an IO exception is raised.
|
||||||
var f: File
|
var f: File
|
||||||
|
|
@ -522,7 +522,7 @@ else:
|
||||||
raise newEIO("cannot write to stream")
|
raise newEIO("cannot write to stream")
|
||||||
inc(s.pos, bufLen)
|
inc(s.pos, bufLen)
|
||||||
|
|
||||||
proc newFileHandleStream*(handle: FileHandle): FileHandleStream =
|
proc newFileHandleStream*(handle: FileHandle): owned FileHandleStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.handle = handle
|
result.handle = handle
|
||||||
result.pos = 0
|
result.pos = 0
|
||||||
|
|
@ -535,7 +535,7 @@ else:
|
||||||
result.writeData = hsWriteData
|
result.writeData = hsWriteData
|
||||||
|
|
||||||
proc newFileHandleStream*(filename: string,
|
proc newFileHandleStream*(filename: string,
|
||||||
mode: FileMode): FileHandleStream =
|
mode: FileMode): owned FileHandleStream =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ proc `[]=`*(t: StringTableRef, key, val: string) {.
|
||||||
rawInsert(t, t.data, key, val)
|
rawInsert(t, t.data, key, val)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
proc newStringTable*(mode: StringTableMode): StringTableRef {.
|
proc newStringTable*(mode: StringTableMode): owned StringTableRef {.
|
||||||
rtlFunc, extern: "nst$1".} =
|
rtlFunc, extern: "nst$1".} =
|
||||||
## Creates a new empty string table.
|
## Creates a new empty string table.
|
||||||
##
|
##
|
||||||
|
|
@ -260,7 +260,7 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {.
|
||||||
newSeq(result.data, startSize)
|
newSeq(result.data, startSize)
|
||||||
|
|
||||||
proc newStringTable*(keyValuePairs: varargs[string],
|
proc newStringTable*(keyValuePairs: varargs[string],
|
||||||
mode: StringTableMode): StringTableRef {.
|
mode: StringTableMode): owned StringTableRef {.
|
||||||
rtlFunc, extern: "nst$1WithPairs".} =
|
rtlFunc, extern: "nst$1WithPairs".} =
|
||||||
## Creates a new string table with given `key, value` string pairs.
|
## Creates a new string table with given `key, value` string pairs.
|
||||||
##
|
##
|
||||||
|
|
@ -290,10 +290,7 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]],
|
||||||
for key, val in items(keyValuePairs): result[key] = val
|
for key, val in items(keyValuePairs): result[key] = val
|
||||||
|
|
||||||
proc raiseFormatException(s: string) =
|
proc raiseFormatException(s: string) =
|
||||||
var e: ref ValueError
|
raise newException(ValueError, "format string: key not found: " & s)
|
||||||
new(e)
|
|
||||||
e.msg = "format string: key not found: " & s
|
|
||||||
raise e
|
|
||||||
|
|
||||||
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
||||||
if hasKey(t, key): return t.getOrDefault(key)
|
if hasKey(t, key): return t.getOrDefault(key)
|
||||||
|
|
|
||||||
|
|
@ -959,7 +959,7 @@ proc newTimezone*(
|
||||||
{.tags: [], raises: [], benign.},
|
{.tags: [], raises: [], benign.},
|
||||||
zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime
|
zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime
|
||||||
{.tags: [], raises: [], benign.}
|
{.tags: [], raises: [], benign.}
|
||||||
): Timezone =
|
): owned Timezone =
|
||||||
## Create a new ``Timezone``.
|
## Create a new ``Timezone``.
|
||||||
##
|
##
|
||||||
## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used
|
## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used
|
||||||
|
|
|
||||||
|
|
@ -1638,6 +1638,8 @@ when defined(nimV2) and not defined(nimscript):
|
||||||
new(r)
|
new(r)
|
||||||
return r
|
return r
|
||||||
else:
|
else:
|
||||||
|
template owned*(t: typeDesc): typedesc = t
|
||||||
|
|
||||||
proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
|
proc new*[T](a: var ref T) {.magic: "New", 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)
|
||||||
## reference to it in ``a``.
|
## reference to it in ``a``.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue