diff options
-rw-r--r-- | compiler/liftdestructors.nim | 46 | ||||
-rw-r--r-- | compiler/modulegraphs.nim | 4 | ||||
-rw-r--r-- | compiler/sempass2.nim | 2 | ||||
-rw-r--r-- | compiler/sighashes.nim | 7 | ||||
-rw-r--r-- | compiler/sizealignoffsetimpl.nim | 2 | ||||
-rw-r--r-- | lib/pure/dynlib.nim | 5 | ||||
-rw-r--r-- | lib/pure/includes/oserr.nim | 2 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 8 | ||||
-rw-r--r-- | lib/pure/streams.nim | 14 | ||||
-rw-r--r-- | lib/pure/strtabs.nim | 9 | ||||
-rw-r--r-- | lib/pure/times.nim | 2 | ||||
-rw-r--r-- | lib/system.nim | 2 |
12 files changed, 57 insertions, 46 deletions
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 4ae438e48..b85360ead 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -12,6 +12,14 @@ # 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 TLiftCtx = object graph: ModuleGraph @@ -286,25 +294,10 @@ proc seqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = doAssert t.destructor != nil moveCall.add destructorCall(c.graph, t.destructor, x) 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: # destroy all elements: forallElements(c, t, body, x, y) 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) = case c.kind @@ -603,19 +596,29 @@ template inst(field, t) = if field.ast != nil: 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 ## to ensure we lift assignment, destructors and moves properly. ## The later 'injectdestructors' pass depends on it. - if typ == nil or {tfCheckedForDestructor, tfHasMeta} * typ.flags != {}: return - incl typ.flags, tfCheckedForDestructor + if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return + 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: # 1. we don't know yet if 'typ' has a nontrival destructor. # 2. we have a nop destructor. --> mDestroy # 3. we have a lifted destructor. # 4. We have a custom 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: if typ.destructor == nil: liftBody(c, typ, attachedDestructor, info) @@ -629,3 +632,8 @@ proc createTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = liftBody(c, typ, attachedSink, info) else: inst(typ.sink, typ) + + if overwrite: + orig.destructor = canon.destructor + orig.assignment = canon.assignment + orig.sink = canon.sink diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 8c081da08..82b9750b6 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -26,7 +26,7 @@ ## import ast, intsets, tables, options, lineinfos, hashes, idents, - incremental, btrees + incremental, btrees, sighashes type ModuleGraph* = ref object @@ -57,6 +57,7 @@ type opContains*, opNot*: PSym emptyNode*: PNode incr*: IncrementalCtx + canonTypes*: Table[SigHash, PType] importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.} includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): 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.cacheCounters = initTable[string, BiggestInt]() result.cacheTables = initTable[string, BTree[string, PNode]]() + result.canonTypes = initTable[SigHash, PType]() proc resetAllModules*(g: ModuleGraph) = initStrTable(g.packageSyms) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index fa4941ba4..cab79314a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, lowerings, sigmatch + modulegraphs, lowerings, sigmatch, tables when not defined(leanCompiler): import writetracking diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 4247c6caa..19175f3b3 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -90,6 +90,7 @@ type CoType CoOwnerSig CoIgnoreRange + CoConsiderOwned 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 else: 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 of tyBool, tyChar, tyInt..tyUInt64: # no canonicalization for integral types, so that e.g. ``pid_t`` is diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 665f4b1ab..45febeea8 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -413,7 +413,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.size = typ.lastSon.size typ.align = typ.lastSon.align - of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink: + of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned: computeSizeAlign(conf, typ.lastSon) typ.size = typ.lastSon.size typ.align = typ.lastSon.align diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index d030ad532..97bc51bc5 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -72,10 +72,7 @@ proc unloadLib*(lib: LibHandle) {.gcsafe.} proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = ## raises an `EInvalidLibrary` exception. - var e: ref LibraryError - new(e) - e.msg = "could not find symbol: " & $name - raise e + raise newException(LibraryError, "could not find symbol: " & $name) proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.} ## retrieves the address of a procedure/variable from `lib`. Returns nil diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index 25e221d3b..947bdd9a9 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -73,7 +73,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} = ## See also: ## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ ## * `osLastError proc <#osLastError>`_ - var e: ref OSError; new(e) + var e: owned(ref OSError); new(e) e.errorCode = errorCode.int32 e.msg = osErrorMsg(errorCode) if additionalInfo.len > 0: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index af0e2e782..1888df813 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -126,7 +126,7 @@ proc startProcess*(command: string, args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut}): - Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect, + owned Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect, RootEffect].} ## Starts a process. `Command` is the executable file, `workingDir` is the ## process's working directory. If ``workingDir == ""`` the current directory @@ -470,7 +470,7 @@ when defined(Windows) and not defined(useNimRtl): addr bytesWritten, nil) if a == 0: raiseOSError(osLastError()) - proc newFileHandleStream(handle: Handle): FileHandleStream = + proc newFileHandleStream(handle: Handle): owned FileHandleStream = new(result) result.handle = handle result.closeImpl = hsClose @@ -573,7 +573,7 @@ when defined(Windows) and not defined(useNimRtl): workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut}): Process = + options: set[ProcessOption] = {poStdErrToStdOut}): owned Process = var si: STARTUPINFO procInfo: PROCESS_INFORMATION @@ -840,7 +840,7 @@ elif not defined(useNimRtl): workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut}): Process = + options: set[ProcessOption] = {poStdErrToStdOut}): owned Process = var pStdin, pStdout, pStderr: array[0..1, cint] new(result) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 6c69a9bb6..ff2b72725 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -34,7 +34,7 @@ include "system/inclrtl" -proc newEIO(msg: string): ref IOError = +proc newEIO(msg: string): owned(ref IOError) = new(result) result.msg = msg @@ -403,7 +403,7 @@ when not defined(js): else: s.data = nil - proc newStringStream*(s: string = ""): StringStream = + proc newStringStream*(s: string = ""): owned StringStream = ## creates a new stream from the string `s`. new(result) result.data = s @@ -446,7 +446,7 @@ when not defined(js): if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: 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`. new(result) result.f = f @@ -460,7 +460,7 @@ when not defined(js): result.writeDataImpl = fsWriteData 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`. ## If the file cannot be opened, nil is returned. See the `system ## <system.html>`_ module for a list of available FileMode enums. @@ -469,7 +469,7 @@ when not defined(js): var f: File 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`. ## If the file cannot be opened, an IO exception is raised. var f: File @@ -522,7 +522,7 @@ else: raise newEIO("cannot write to stream") inc(s.pos, bufLen) - proc newFileHandleStream*(handle: FileHandle): FileHandleStream = + proc newFileHandleStream*(handle: FileHandle): owned FileHandleStream = new(result) result.handle = handle result.pos = 0 @@ -535,7 +535,7 @@ else: result.writeData = hsWriteData proc newFileHandleStream*(filename: string, - mode: FileMode): FileHandleStream = + mode: FileMode): owned FileHandleStream = when defined(windows): discard else: diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 2568f83c2..f158bb2fc 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -247,7 +247,7 @@ proc `[]=`*(t: StringTableRef, key, val: string) {. rawInsert(t, t.data, key, val) inc(t.counter) -proc newStringTable*(mode: StringTableMode): StringTableRef {. +proc newStringTable*(mode: StringTableMode): owned StringTableRef {. rtlFunc, extern: "nst$1".} = ## Creates a new empty string table. ## @@ -260,7 +260,7 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {. newSeq(result.data, startSize) proc newStringTable*(keyValuePairs: varargs[string], - mode: StringTableMode): StringTableRef {. + mode: StringTableMode): owned StringTableRef {. rtlFunc, extern: "nst$1WithPairs".} = ## 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 proc raiseFormatException(s: string) = - var e: ref ValueError - new(e) - e.msg = "format string: key not found: " & s - raise e + raise newException(ValueError, "format string: key not found: " & s) proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = if hasKey(t, key): return t.getOrDefault(key) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 1bb23a311..5fd57c843 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -959,7 +959,7 @@ proc newTimezone*( {.tags: [], raises: [], benign.}, zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.} - ): Timezone = + ): owned Timezone = ## Create a new ``Timezone``. ## ## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used diff --git a/lib/system.nim b/lib/system.nim index c0f32961b..7bd3aa625 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1638,6 +1638,8 @@ when defined(nimV2) and not defined(nimscript): new(r) return r else: + template owned*(t: typeDesc): typedesc = t + proc new*[T](a: var ref T) {.magic: "New", noSideEffect.} ## Creates a new object of type ``T`` and returns a safe (traced) ## reference to it in ``a``. |