From eba87c7e972db4f992fdad5f825ac6940ba4a7e1 Mon Sep 17 00:00:00 2001 From: Pylgos <43234674+Pylgos@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:50:38 +0900 Subject: [PATCH 001/123] fixes #22971; `inferGenericTypes` does not work with method call syntax (#22972) fixes #22971 --- compiler/semexprs.nim | 4 ++-- tests/generics/treturn_inference.nim | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b7fac6046c99f..96904f0dd3055 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1052,7 +1052,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType result.transitionSonsKind(nkCall) result.flags.incl nfExplicitCall for i in 1.. Date: Wed, 22 Nov 2023 09:58:17 +0100 Subject: [PATCH 002/123] progress: 'm' command line switch (#22976) --- compiler/ic/ic.nim | 3 +++ compiler/pipelines.nim | 7 +++++-- compiler/sem.nim | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index b244d7afb7a76..867bc95aed298 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -944,6 +944,9 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: result = nil else: let si = moduleIndex(c, g, thisModule, s) + if si >= g.len: + g.pm.setLen(si+1) + if g[si].status == undefined and c.config.cmd == cmdM: var cachedModules: seq[FileIndex] = @[] discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules) diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index c3b7a8b7ecb16..b7220760722fb 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -259,8 +259,11 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF partialInitModule(result, graph, fileIdx, filename) for m in cachedModules: registerModuleById(graph, m) - replayStateChanges(graph.packed.pm[m.int].module, graph) - replayGenericCacheInformation(graph, m.int) + if sfMainModule in flags and graph.config.cmd == cmdM: + discard + else: + replayStateChanges(graph.packed.pm[m.int].module, graph) + replayGenericCacheInformation(graph, m.int) elif graph.isDirty(result): result.flags.excl sfDirty # reset module fields: diff --git a/compiler/sem.nim b/compiler/sem.nim index 568db0d0f9f66..960fc9165bf2f 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -871,6 +871,7 @@ proc semWithPContext*(c: PContext, n: PNode): PNode = proc reportUnusedModules(c: PContext) = + if c.config.cmd == cmdM: return for i in 0..high(c.unusedImports): if sfUsed notin c.unusedImports[i][0].flags: message(c.config, c.unusedImports[i][1], warnUnusedImportX, c.unusedImports[i][0].name.s) From 816ddd8be7cbae2513469cfccc516169a0cad7b2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 24 Nov 2023 22:41:57 +0800 Subject: [PATCH 003/123] build nimble with ORC and bump nimble version (#22978) ref https://github.com/nim-lang/nimble/pull/1074 --- koch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index 5fa2e8cfa7786..708b65ab6ff4c 100644 --- a/koch.nim +++ b/koch.nim @@ -11,7 +11,7 @@ const # examples of possible values for repos: Head, ea82b54 - NimbleStableCommit = "603e329442059947d63e4c1b2ef5294f1f544485" # master + NimbleStableCommit = "a1fdbe8912a0e3dfd30cef030bbabef218d84687" # master AtlasStableCommit = "7b780811a168f3f32bff4822369dda46a7f87f9a" ChecksumsStableCommit = "025bcca3915a1b9f19878cea12ad68f9884648fc" @@ -161,7 +161,7 @@ proc bundleNimbleExe(latest: bool, args: string) = commit = ChecksumsStableCommit, allowBundled = true) # or copy it from dist? # installer.ini expects it under $nim/bin nimCompile("dist/nimble/src/nimble.nim", - options = "-d:release --mm:refc --noNimblePath " & args) + options = "-d:release --noNimblePath " & args) proc bundleAtlasExe(latest: bool, args: string) = let commit = if latest: "HEAD" else: AtlasStableCommit From 502a4486aeb8d0a5dcdf86540522d3dc16960536 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Fri, 24 Nov 2023 20:55:53 +0200 Subject: [PATCH 004/123] nimsuggest: Added optional command line option '--clientProcessId:XXX' (#22969) When it is specified, the nimsuggest instance monitors whether this process is still alive. In case it's found to be dead, nimsuggest shuts itself down. Currently only implemented on POSIX and Windows platforms. The switch is silently ignored on other platforms. Note that the Nim language server should still try to shut down its child nimsuggest processes. This switch just adds extra protection against crashing Nim language server and gets rid of the remaining nimsuggest processes, which consume memory and system resources. --- compiler/options.nim | 1 + nimsuggest/nimsuggest.nim | 7 +++++++ nimsuggest/procmonitor.nim | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 nimsuggest/procmonitor.nim diff --git a/compiler/options.nim b/compiler/options.nim index e50acbf493bcc..3731304c7b286 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -442,6 +442,7 @@ type expandPosition*: TLineInfo currentConfigDir*: string # used for passPP only; absolute dir + clientProcessId*: int proc parseNimVersion*(a: string): NimVer = diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index ca0f5112e1a01..03a6e32e19007 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -12,6 +12,7 @@ import strformat import algorithm import tables import times +import procmonitor template tryImport(module) = import module @@ -56,6 +57,7 @@ Options: --address:HOST binds to that address, by default "" --stdin read commands from stdin and write results to stdout instead of using sockets + --clientProcessId:PID shutdown nimsuggest in case this process dies --epc use emacs epc mode --debug enable debug output --log enable verbose logging to nimsuggest.log file @@ -625,6 +627,9 @@ proc mainCommand(graph: ModuleGraph) = open(requests) open(results) + if graph.config.clientProcessId != 0: + hookProcMonitor(graph.config.clientProcessId) + case gMode of mstdin: createThread(inputThread, replStdin, (gPort, gAddress)) of mtcp: createThread(inputThread, replTcp, (gPort, gAddress)) @@ -700,6 +705,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = conf.suggestMaxResults = parseInt(p.val) of "find": findProject = true + of "clientprocessid": + conf.clientProcessId = parseInt(p.val) else: processSwitch(pass, p, conf) of cmdArgument: let a = unixToNativePath(p.key) diff --git a/nimsuggest/procmonitor.nim b/nimsuggest/procmonitor.nim new file mode 100644 index 0000000000000..0f1ba1e0d39d0 --- /dev/null +++ b/nimsuggest/procmonitor.nim @@ -0,0 +1,34 @@ +# Monitor a client process and shutdown the current process, if the client +# process is found to be dead + +import os + +when defined(posix): + import posix_utils + import posix + +when defined(windows): + import winlean + +when defined(posix): + proc monitorClientProcessIdThreadProc(pid: int) {.thread.} = + while true: + sleep(1000) + try: + sendSignal(Pid(pid), 0) + except: + discard kill(Pid(getCurrentProcessId()), cint(SIGTERM)) + +when defined(windows): + proc monitorClientProcessIdThreadProc(pid: int) {.thread.} = + var process = openProcess(SYNCHRONIZE, 0, DWORD(pid)) + if process != 0: + discard waitForSingleObject(process, INFINITE) + discard closeHandle(process) + quit(0) + +var tid: Thread[int] + +proc hookProcMonitor*(pid: int) = + when defined(posix) or defined(windows): + createThread(tid, monitorClientProcessIdThreadProc, pid) From 379299a5ac06f67863525fe253f3de4a4e01ff01 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 26 Nov 2023 01:27:27 +0800 Subject: [PATCH 005/123] fixes #22286; enforce Non-var T destructors by `nimPreviewNonVarDestructor` (#22975) fixes #22286 ref https://forum.nim-lang.org/t/10642 For backwards compatibilities, we might need to keep the changes under a preview compiler flag. Let's see how many packags it break. **TODO** in the following PRs - [ ] Turn the `var T` destructors warning into an error with `nimPreviewNonVarDestructor` --------- Co-authored-by: Andreas Rumpf --- changelog.md | 1 + compiler/liftdestructors.nim | 8 +++--- compiler/nim.cfg | 1 + lib/system.nim | 23 ++++++++++------- tests/arc/thard_alignment.nim | 4 ++- tests/arc/topt_no_cursor.nim | 2 +- tests/ccgbugs/tforward_decl_only.nim | 3 +-- tests/config.nims | 1 + tests/converter/tconverter_unique_ptr.nim | 15 +++++------ tests/destructor/const_smart_ptr.nim | 10 +++----- tests/destructor/tnonvardestructor.nim | 31 +++++++++++++++++++++-- tests/destructor/tv2_cast.nim | 12 ++++----- tests/gc/closureleak.nim | 14 ++++++++-- 13 files changed, 84 insertions(+), 41 deletions(-) diff --git a/changelog.md b/changelog.md index 3351a6f7a0526..ab121f5a13594 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,7 @@ - `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility. - The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/` instead of `Nim httpclient/` which was incorrect according to the HTTP spec. +- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default. ## Standard library additions and changes diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 8995e1073bf18..36d9d5b1a1648 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -1082,7 +1082,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache incl result.flags, sfGeneratedOp proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp; - info: TLineInfo; idgen: IdGenerator): PSym = + info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym = if kind == attachedDup: return symDupPrototype(g, typ, owner, kind, info, idgen) @@ -1092,7 +1092,8 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), idgen, result, info) - if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: + if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and + ((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or typ.kind in {tyRef, tyString, tySequence}): dest.typ = typ else: dest.typ = makeVarType(typ.owner, typ, idgen) @@ -1185,7 +1186,8 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, info: TLineInfo; idgen: IdGenerator): PSym = assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject) - result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen) + # discrimantor assignments needs pointers to destroy fields; alas, we cannot use non-var destructor here + result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen, isDiscriminant = true) var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ, idgen: idgen, fn: result) a.asgnForType = typ diff --git a/compiler/nim.cfg b/compiler/nim.cfg index e4425065e704c..8488cb9efcb6c 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -9,6 +9,7 @@ define:nimPreviewSlimSystem define:nimPreviewCstringConversion define:nimPreviewProcConversion define:nimPreviewRangeDefault +define:nimPreviewNonVarDestructor threads:off #import:"$projectpath/testability" diff --git a/lib/system.nim b/lib/system.nim index 4f2a051632d35..5d0bbb9c7f672 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -366,19 +366,24 @@ proc arrPut[I: Ordinal;T,S](a: T; i: I; const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc) -when defined(nimAllowNonVarDestructor) and arcLikeMem: - proc `=destroy`*(x: string) {.inline, magic: "Destroy".} = +when defined(nimAllowNonVarDestructor) and arcLikeMem and defined(nimPreviewNonVarDestructor): + proc `=destroy`*[T](x: T) {.inline, magic: "Destroy".} = + ## Generic `destructor`:idx: implementation that can be overridden. discard - - proc `=destroy`*[T](x: seq[T]) {.inline, magic: "Destroy".} = +else: + proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = + ## Generic `destructor`:idx: implementation that can be overridden. discard - proc `=destroy`*[T](x: ref T) {.inline, magic: "Destroy".} = - discard + when defined(nimAllowNonVarDestructor) and arcLikeMem: + proc `=destroy`*(x: string) {.inline, magic: "Destroy".} = + discard -proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = - ## Generic `destructor`:idx: implementation that can be overridden. - discard + proc `=destroy`*[T](x: seq[T]) {.inline, magic: "Destroy".} = + discard + + proc `=destroy`*[T](x: ref T) {.inline, magic: "Destroy".} = + discard when defined(nimHasDup): proc `=dup`*[T](x: T): T {.inline, magic: "Dup".} = diff --git a/tests/arc/thard_alignment.nim b/tests/arc/thard_alignment.nim index baa964c77dbe9..30cfddb055319 100644 --- a/tests/arc/thard_alignment.nim +++ b/tests/arc/thard_alignment.nim @@ -1,9 +1,11 @@ discard """ disabled: "arm64" -cmd: "nim c --gc:arc $file" +cmd: "nim c --mm:arc -u:nimPreviewNonVarDestructor $file" output: "y" """ +# TODO: fixme: investigate why it failed with non-var destructors + {.passC: "-march=native".} proc isAlignedCheck(p: pointer, alignment: int) = diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index b24e8e5a9d7b9..0a4984a690999 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -97,7 +97,7 @@ try: finally: `=destroy`(splitted) finally: - `=destroy`(lan_ip) + `=destroy_1`(lan_ip) -- end of expandArc ------------------------ --expandArc: mergeShadowScope diff --git a/tests/ccgbugs/tforward_decl_only.nim b/tests/ccgbugs/tforward_decl_only.nim index d62c36b180ab3..b115dcbe70f2e 100644 --- a/tests/ccgbugs/tforward_decl_only.nim +++ b/tests/ccgbugs/tforward_decl_only.nim @@ -1,6 +1,5 @@ discard """ -ccodecheck: "\\i !@('struct tyObject_MyRefObject'[0-z]+' {')" -ccodecheck: "\\i !@('mymoduleInit')" +ccodecheck: "\\i !@('struct tyObject_MyRefObject'[0-z]+' _')" output: "hello" """ diff --git a/tests/config.nims b/tests/config.nims index b288bec2ae11d..e0de65fc42fc7 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -40,6 +40,7 @@ switch("define", "nimPreviewFloatRoundtrip") switch("define", "nimPreviewJsonutilsHoleyEnum") switch("define", "nimPreviewHashRef") switch("define", "nimPreviewRangeDefault") +switch("define", "nimPreviewNonVarDestructor") switch("warningAserror", "UnnamedBreak") switch("legacy", "verboseTypeMismatch") diff --git a/tests/converter/tconverter_unique_ptr.nim b/tests/converter/tconverter_unique_ptr.nim index 23c1a3d96db3a..6902f9e9e0ce1 100644 --- a/tests/converter/tconverter_unique_ptr.nim +++ b/tests/converter/tconverter_unique_ptr.nim @@ -22,12 +22,11 @@ proc `$`(x: MyLen): string {.borrow.} proc `==`(x1, x2: MyLen): bool {.borrow.} -proc `=destroy`*(m: var MySeq) {.inline.} = +proc `=destroy`*(m: MySeq) {.inline.} = if m.data != nil: deallocShared(m.data) - m.data = nil -proc `=`*(m: var MySeq, m2: MySeq) = +proc `=copy`*(m: var MySeq, m2: MySeq) = if m.data == m2.data: return if m.data != nil: `=destroy`(m) @@ -77,13 +76,12 @@ converter literalToLen*(x: int{lit}): MyLen = # Unique pointer implementation #------------------------------------------------------------- -proc `=destroy`*[T](p: var UniquePtr[T]) = +proc `=destroy`*[T](p: UniquePtr[T]) = if p.val != nil: `=destroy`(p.val[]) dealloc(p.val) - p.val = nil -proc `=`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.} +proc `=copy`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.} proc `=sink`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.inline.} = if dest.val != nil and dest.val != src.val: @@ -118,13 +116,12 @@ type ## as it returns only `lent T` val: ptr T -proc `=destroy`*[T](p: var ConstPtr[T]) = +proc `=destroy`*[T](p: ConstPtr[T]) = if p.val != nil: `=destroy`(p.val[]) dealloc(p.val) - p.val = nil -proc `=`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.} +proc `=copy`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.} proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} = if dest.val != nil and dest.val != src.val: diff --git a/tests/destructor/const_smart_ptr.nim b/tests/destructor/const_smart_ptr.nim index 4d8c7c9a375ec..25dd46500d9f5 100644 --- a/tests/destructor/const_smart_ptr.nim +++ b/tests/destructor/const_smart_ptr.nim @@ -2,13 +2,12 @@ type ConstPtr*[T] = object val: ptr T -proc `=destroy`*[T](p: var ConstPtr[T]) = +proc `=destroy`*[T](p: ConstPtr[T]) = if p.val != nil: `=destroy`(p.val[]) dealloc(p.val) - p.val = nil -proc `=`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.} +proc `=copy`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.} proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} = if dest.val != nil and dest.val != src.val: @@ -31,12 +30,11 @@ type len: int data: ptr UncheckedArray[float] -proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} = +proc `=destroy`*(m: MySeqNonCopyable) {.inline.} = if m.data != nil: deallocShared(m.data) - m.data = nil -proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.} +proc `=copy`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.} proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} = if m.data != m2.data: diff --git a/tests/destructor/tnonvardestructor.nim b/tests/destructor/tnonvardestructor.nim index 1f59a397839f6..1b44137906ea1 100644 --- a/tests/destructor/tnonvardestructor.nim +++ b/tests/destructor/tnonvardestructor.nim @@ -152,7 +152,7 @@ type Graph = object nodes: seq[Node] -proc `=destroy`(x: var NodeObj) = +proc `=destroy`(x: NodeObj) = `=destroy`(x.neighbors) `=destroy`(x.label) @@ -210,7 +210,7 @@ block: # bug #22197 ## If this does not exist, it also works! proc newFileID(): FileID = FileID(H5Id()) - proc `=destroy`(grp: var H5GroupObj) = + proc `=destroy`(grp: H5GroupObj) = ## Closes the group and resets all references to nil. if cast[pointer](grp.fileId) != nil: `=destroy`(grp.file_id) @@ -218,3 +218,30 @@ block: # bug #22197 var grp = H5Group() reset(grp.file_id) reset(grp) + +import std/tables + +block: # bug #22286 + type + A = object + B = object + a: A + C = object + b: B + + proc `=destroy`(self: A) = + echo "destroyed" + + proc `=destroy`(self: C) = + `=destroy`(self.b) + + var c = C() + +block: # https://forum.nim-lang.org/t/10642 + type AObj = object + name: string + tableField: Table[string, string] + + proc `=destroy`(x: AObj) = + `=destroy`(x.name) + `=destroy`(x.tableField) diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 6fcb5994c3a4e..4ff2dc9a07f19 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -20,8 +20,8 @@ data = :tmpD_2)) :tmpD `=destroy`(:tmpD_2) -`=destroy`(:tmpD_1) -`=destroy`(data) +`=destroy_1`(:tmpD_1) +`=destroy_1`(data) -- end of expandArc ------------------------ --expandArc: main1 @@ -37,8 +37,8 @@ data = :tmpD_1)) :tmpD `=destroy`(:tmpD_1) -`=destroy`(data) -`=destroy`(s) +`=destroy_1`(data) +`=destroy_1`(s) -- end of expandArc ------------------------ --expandArc: main2 @@ -54,7 +54,7 @@ data = :tmpD_1)) :tmpD `=destroy`(:tmpD_1) -`=destroy`(data) +`=destroy_1`(data) `=destroy`(s) -- end of expandArc ------------------------ --expandArc: main3 @@ -73,7 +73,7 @@ data = :tmpD `=destroy`(:tmpD_2) `=destroy`(:tmpD_1) -`=destroy`(data) +`=destroy_1`(data) -- end of expandArc ------------------------ ''' """ diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim index 0265431d04631..e67beb513d154 100644 --- a/tests/gc/closureleak.nim +++ b/tests/gc/closureleak.nim @@ -11,9 +11,19 @@ var foo_counter = 0 var alive_foos = newseq[int](0) when defined(gcDestructors): - proc `=destroy`(some: var TFoo) = + proc `=destroy`(some: TFoo) = alive_foos.del alive_foos.find(some.id) - `=destroy`(some.fn) + # TODO: fixme: investigate why `=destroy` requires `some.fn` to be `gcsafe` + # the debugging info below came from `symPrototype` in the liftdestructors + # proc (){.closure, gcsafe.}, {tfThread, tfHasAsgn, tfCheckedForDestructor, tfExplicitCallConv} + # var proc (){.closure, gcsafe.}, {tfHasGCedMem} + # it worked by accident with var T destructors because in the sempass2 + # + # let argtype = skipTypes(a.typ, abstractInst) # !!! it does't skip `tyVar` + # if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe: + # localError(tracked.config, n.info, $n & " is not GC safe") + {.cast(gcsafe).}: + `=destroy`(some.fn) else: proc free*(some: ref TFoo) = From 26f2ea149c50ebfe882560c83d1d7cf7bb9d10c4 Mon Sep 17 00:00:00 2001 From: tersec Date: Sat, 25 Nov 2023 19:52:42 +0000 Subject: [PATCH 006/123] remove unnecessary side-effects from base64.encode(mime) (#22986) Fixes https://github.com/nim-lang/Nim/issues/22985 --- lib/pure/base64.nim | 16 ++++------------ tests/stdlib/tbase64.nim | 4 ++++ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 7958204331036..6af5345f294dd 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -66,14 +66,10 @@ template cbBase(a, b): untyped = [ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', a, b] -let +const cb64 = cbBase('+', '/') cb64safe = cbBase('-', '_') -const - cb64VM = cbBase('+', '/') - cb64safeVM = cbBase('-', '_') - const invalidChar = 255 @@ -134,14 +130,10 @@ template encodeInternal(s, alphabet: typed): untyped = result.setLen(outputIndex) template encodeImpl() {.dirty.} = - when nimvm: - block: - let lookupTableVM = if safe: cb64safeVM else: cb64VM - encodeInternal(s, lookupTableVM) + if safe: + encodeInternal(s, cb64safe) else: - block: - let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64) - encodeInternal(s, lookupTable) + encodeInternal(s, cb64) proc encode*[T: byte|char](s: openArray[T], safe = false): string = ## Encodes `s` into base64 representation. diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index 5739b1621c721..98388bb6c57d2 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -53,5 +53,9 @@ template main() = doAssert encode("", safe = true) == "" doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==" +func mainNoSideEffects() = main() + static: main() main() +static: mainNoSideEffects() +mainNoSideEffects() From 5b2fcabff5dc28b3df49960c052feeda98dbb7d0 Mon Sep 17 00:00:00 2001 From: John Viega Date: Sun, 26 Nov 2023 00:32:32 -0500 Subject: [PATCH 007/123] fix: std/marshal unmarshaling of ref objects (#22983) Fixes #16496 ![Marshal doesn't properly unmarshal *most* ref objects; the exceptions being nil ones](https://github-production-user-asset-6210df.s3.amazonaws.com/4764481/285471431-a39ee2c5-5670-4b12-aa10-7a10ba6b5b96.gif) Test case added. Note that this test (t9754) does pass locally, but there are tons of failures by default on OS X arm64, mostly around the bohem GC, so it's pretty spammy, and could easily have missed something. If there are better instructions please do let me know. --------- Co-authored-by: John Viega Co-authored-by: John Viega Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/pure/marshal.nim | 3 ++- tests/stdlib/tmarshal.nim | 42 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 5785605c6de80..f9b3d3e4ca8e7 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -210,7 +210,8 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) = setPointer(a, nil) next(p) of jsonInt: - setPointer(a, t.getOrDefault(p.getInt)) + var raw = t.getOrDefault(p.getInt) + setPointer(a, addr raw) next(p) of jsonArrayStart: next(p) diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index f972332a240d1..32991ccc911ca 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -3,7 +3,7 @@ discard """ """ import std/marshal -import std/[assertions, objectdollar] +import std/[assertions, objectdollar, streams] # TODO: add static tests @@ -166,6 +166,46 @@ block: let a: ref A = new(B) doAssert $$a[] == "{}" # not "{f: 0}" +# bug #16496 +block: + type + A = ref object + data: seq[int] + + B = ref object + x: A + let o = A(data: @[1, 2, 3, 4]) + let s1 = @[B(x: o), B(x: o)] + let m = $$ s1 + let s2 = to[seq[B]](m) + doAssert s2[0].x.data == s2[1].x.data + doAssert s1[0].x.data == s2[1].x.data + + +block: + type + Obj = ref object + i: int + b: bool + + let + strm = newStringStream() + + var + o = Obj(i: 1, b: false) + t1 = @[o, o] + t2: seq[Obj] + + doAssert t1[0] == t1[1] + + strm.store(t1) + strm.setPosition(0) + strm.load(t2) + strm.close() + + doAssert t2[0] == t2[1] + + template checkMarshal(data: typed) = let orig = data let m = $$orig From c31bbb07fb2d1ea8f69b47de50631442154bd3de Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 28 Nov 2023 08:08:05 +1100 Subject: [PATCH 008/123] Register declaration of enum field has a use (#22990) Currently when using `use` with nimsuggest on an enum field, it doesn't return the definition of the field. Breaks renaming in IDEs since it will replace all the usages, but not the declaration --- compiler/semtypes.nim | 1 + nimsuggest/tests/tuse_enum.nim | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 nimsuggest/tests/tuse_enum.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index ebbf75e351048..afc06234d33e2 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -148,6 +148,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = result.n.add symNode styleCheckDef(c, e) onDef(e.info, e) + suggestSym(c.graph, e.info, e, c.graph.usageSym) if sfGenSym notin e.flags: if not isPure: addInterfaceOverloadableSymAt(c, c.currentScope, e) diff --git a/nimsuggest/tests/tuse_enum.nim b/nimsuggest/tests/tuse_enum.nim new file mode 100644 index 0000000000000..8a40a83489105 --- /dev/null +++ b/nimsuggest/tests/tuse_enum.nim @@ -0,0 +1,15 @@ +discard """ +$nimsuggest --tester $file +>use $1 +def;;skEnumField;;tuse_enum.Colour.Red;;Colour;;$file;;10;;4;;"";;100 +use;;skEnumField;;tuse_enum.Colour.Red;;Colour;;$file;;14;;8;;"";;100 +""" + +type + Colour = enum + Red + Green + Blue + +discard #[!]#Red + From 8cad6ac0487800f7d41e38303e52129777e6c22e Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Tue, 28 Nov 2023 19:38:10 +1100 Subject: [PATCH 009/123] Don't try and get enum value if its invalid (#22997) Currently running `nimsuggest`/`check` on this code causes the compiler to raise an exception ```nim type Test = enum A = 9.0 ``` ``` assertions.nim(34) raiseAssert Error: unhandled exception: int128.nim(69, 11) `arg.sdata(3) == 0` out of range [AssertionDefect] ``` Issue was the compiler still trying to get the ordinal value even if it wasn't an ordinal --- compiler/semtypes.nim | 7 ++++--- tests/enum/tenum_invalid.nim | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 tests/enum/tenum_invalid.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index afc06234d33e2..db7ce9d732617 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -113,10 +113,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = strVal = v x = counter else: - if not isOrdinalType(v.typ, allowEnumWithHoles=true): + if isOrdinalType(v.typ, allowEnumWithHoles=true): + x = toInt64(getOrdValue(v)) + n[i][1] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt)) + else: localError(c.config, v.info, errOrdinalTypeExpected % typeToString(v.typ, preferDesc)) - x = toInt64(getOrdValue(v)) - n[i][1] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt)) if i != 1: if x != counter: incl(result.flags, tfEnumHasHoles) if x < counter: diff --git a/tests/enum/tenum_invalid.nim b/tests/enum/tenum_invalid.nim new file mode 100644 index 0000000000000..8ae0a10574a77 --- /dev/null +++ b/tests/enum/tenum_invalid.nim @@ -0,0 +1,8 @@ +discard """ +cmd: "nim check $file" +""" + +type + Test = enum + A = 9.0 #[tt.Error + ^ ordinal type expected; given: float]# From 30cf33f04dfb768182accb3ad35ec6364c998664 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:11:43 +0800 Subject: [PATCH 010/123] rework the vtable implementation embedding the vtable array directly with new strictions on methods (#22991) **TODO** - [x] fixes changelog With the new option `nimPreviewVtables`, `methods` are confined in the same module where the type of the first parameter is defined - [x] make it opt in after CI checks its feasibility ## In the following-up PRs - [ ] in the following PRs, refactor code into a more efficient one - [ ] cpp needs special treatments since it cannot embed array in light of the preceding limits: ref https://github.com/nim-lang/Nim/pull/20977#discussion_r1035528927; we can support cpp backends with vtable implementations later on the comprise that uses indirect vtable access --------- Co-authored-by: Andreas Rumpf --- changelog.md | 1 + compiler/ccgtypes.nim | 20 +++- compiler/cgen.nim | 14 ++- compiler/cgmeth.nim | 23 ++-- compiler/ic/cbackend.nim | 7 +- compiler/ic/ic.nim | 12 +- compiler/ic/integrity.nim | 4 +- compiler/ic/replayer.nim | 15 ++- compiler/ic/rodfiles.nim | 4 +- compiler/jsgen.nim | 5 +- compiler/modulegraphs.nim | 40 ++++++- compiler/nim.cfg | 1 + compiler/pipelines.nim | 15 +-- compiler/sem.nim | 10 ++ compiler/sempass2.nim | 64 ++++++++-- compiler/vtables.nim | 167 ++++++++++++++++++++++++++ config/config.nims | 1 - lib/system.nim | 2 + lib/system/arc.nim | 5 + tests/config.nims | 1 + tests/generics/tobjecttyperel.nim | 1 + tests/method/nim.cfg | 1 - tests/method/tcompilegenerics.nim | 24 ++++ tests/method/tgeneric_methods.nim | 84 ++++++------- tests/method/tmethod_various.nim | 7 +- tests/method/tmethods_old.nim | 12 ++ tests/method/tmultim.nim | 193 +++++++++++++++--------------- tests/method/tvtable.nim | 19 +++ 28 files changed, 555 insertions(+), 197 deletions(-) create mode 100644 compiler/vtables.nim delete mode 100644 tests/method/nim.cfg create mode 100644 tests/method/tcompilegenerics.nim create mode 100644 tests/method/tmethods_old.nim create mode 100644 tests/method/tvtable.nim diff --git a/changelog.md b/changelog.md index ab121f5a13594..fb70a9a6b088d 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,7 @@ - `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility. - The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/` instead of `Nim httpclient/` which was incorrect according to the HTTP spec. +- Methods now support implementations based on vtable by using `-d:nimPreviewVtables`. methods are confined in the same module where the type has been defined. - With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default. ## Standard library additions and changes diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 855ec4cd9be3f..2f304852b1273 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -13,6 +13,7 @@ import sighashes, modulegraphs, std/strscans import ../dist/checksums/src/checksums/md5 +import std/sequtils type TypeDescKind = enum @@ -1718,6 +1719,13 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) +proc genVTable(seqs: seq[PSym]): string = + result = "{" + for i in 0.. 0: result.add ", " + result.add "(void *) " & seqs[i].loc.r + result.add "}" + proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = cgsym(m, "TNimTypeV2") m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) @@ -1754,8 +1762,16 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn add(typeEntry, ", .traceImpl = (void*)") genHook(m, t, info, attachedTrace, typeEntry) - addf(typeEntry, ", .flags = $1};$n", [rope(flags)]) - m.s[cfsVars].add typeEntry + let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t)) + if dispatchMethods.len > 0: + addf(typeEntry, ", .flags = $1", [rope(flags)]) + for i in dispatchMethods: + genProcPrototype(m, i) + addf(typeEntry, ", .vTable = $1};$n", [genVTable(dispatchMethods)]) + m.s[cfsVars].add typeEntry + else: + addf(typeEntry, ", .flags = $1};$n", [rope(flags)]) + m.s[cfsVars].add typeEntry if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0011cb90e3a91..5a331ae7c8fd0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -366,6 +366,8 @@ proc dataField(p: BProc): Rope = else: result = rope"->data" +proc genProcPrototype(m: BModule, sym: PSym) + include ccgliterals include ccgtypes @@ -734,7 +736,7 @@ proc genVarPrototype(m: BModule, n: PNode) proc requestConstImpl(p: BProc, sym: PSym) proc genStmts(p: BProc, t: PNode) proc expr(p: BProc, n: PNode, d: var TLoc) -proc genProcPrototype(m: BModule, sym: PSym) + proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) proc intLiteral(i: BiggestInt; result: var Rope) proc genLiteral(p: BProc, n: PNode; result: var Rope) @@ -2181,9 +2183,8 @@ proc updateCachedModule(m: BModule) = cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) -proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode = +proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = ## Also called from IC. - result = nil if sfMainModule in m.module.flags: # phase ordering problem here: We need to announce this # dependency to 'nimTestErrorFlag' before system.c has been written to disk. @@ -2231,7 +2232,12 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode = if m.g.forwardedProcs.len == 0: incl m.flags, objHasKidsValid - result = generateMethodDispatchers(graph, m.idgen) + if optMultiMethods in m.g.config.globalOptions or + m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or + not m.g.config.isDefined("nimPreviewVtables") or + m.g.config.backend == backendCpp or sfCompileToCpp in m.module.flags: + generateIfMethodDispatchers(graph, m.idgen) + let mm = m m.g.modulesClosed.add mm diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 2cd5f36722d89..3bbe7b3f4a0d4 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -11,14 +11,14 @@ import options, ast, msgs, idents, renderer, types, magicsys, - sempass2, modulegraphs, lineinfos - + sempass2, modulegraphs, lineinfos, astalgo import std/intsets when defined(nimPreviewSlimSystem): import std/assertions +import std/[tables] proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = var dest = skipTypes(d, abstractPtrs) @@ -157,6 +157,9 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = var witness: PSym = nil + if s.typ[1].owner.getModule != s.getModule and g.config.isDefined("nimPreviewVtables"): + localError(g.config, s.info, errGenerated, "method `" & s.name.s & + "` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")") for i in 0.. 0: let ctx = preparePContext(graph, module, idgen) - for disp in disps: - let retTyp = disp.sym.typ[0] + for disp in getDispatchers(graph): + let retTyp = disp.typ[0] if retTyp != nil: - # todo properly semcheck the code of dispatcher? - createTypeBoundOps(graph, ctx, retTyp, disp.info, idgen) - genProcAux(BModule(bModule), disp.sym) + # TODO: properly semcheck the code of dispatcher? + createTypeBoundOps(graph, ctx, retTyp, disp.ast.info, idgen) + genProcAux(m, disp) discard closePContext(graph, ctx, nil) of JSgenPass: when not defined(leanCompiler): diff --git a/compiler/sem.nim b/compiler/sem.nim index 960fc9165bf2f..0dcc66432aa58 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -20,6 +20,7 @@ import isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs, extccomp +import vtables import std/[strtabs, math, tables, intsets, strutils] when not defined(leanCompiler): @@ -839,6 +840,15 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if c.config.cmd == cmdIdeTools: appendToModule(c.module, result) trackStmt(c, c.module, result, isTopLevel = true) + if optMultiMethods notin c.config.globalOptions and + c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and + c.config.isDefined("nimPreviewVtables") and + c.config.backend != backendCpp and + sfCompileToCpp notin c.module.flags: + sortVTableDispatchers(c.graph) + + if sfMainModule in c.module.flags: + collectVTableDispatchers(c.graph) proc recoverContext(c: PContext) = # clean up in case of a semantic error: We clean up the stacks, etc. This is diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 54f46fa73c2c9..e010bf1799c13 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -24,6 +24,9 @@ when defined(useDfa): import liftdestructors include sinkparameter_inference + +import std/options as opt + #[ Second semantic checking pass over the AST. Necessary because the old way had some inherent problems. Performs: @@ -91,6 +94,37 @@ const errXCannotBeAssignedTo = "'$1' cannot be assigned to" errLetNeedsInit = "'let' symbol requires an initialization" +proc getObjDepth(t: PType): Option[tuple[depth: int, root: ItemId]] = + var x = t + var res: tuple[depth: int, root: ItemId] + res.depth = -1 + var stack = newSeq[ItemId]() + while x != nil: + x = skipTypes(x, skipPtrs) + if x.kind != tyObject: + return none(tuple[depth: int, root: ItemId]) + stack.add x.itemId + x = x[0] + inc(res.depth) + res.root = stack[^2] + result = some(res) + +proc collectObjectTree(graph: ModuleGraph, n: PNode) = + for section in n: + if section.kind == nkTypeDef and section[^1].kind in {nkObjectTy, nkRefTy, nkPtrTy}: + let typ = section[^1].typ.skipTypes(skipPtrs) + if typ.len > 0 and typ[0] != nil: + let depthItem = getObjDepth(typ) + if isSome(depthItem): + let (depthLevel, root) = depthItem.unsafeGet + if depthLevel == 1: + graph.objectTree[root] = @[] + else: + if root notin graph.objectTree: + graph.objectTree[root] = @[(depthLevel, typ)] + else: + graph.objectTree[root].add (depthLevel, typ) + proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = if typ == nil or sfGeneratedOp in tracked.owner.flags: # don't create type bound ops for anything in a function with a `nodestroy` pragma @@ -1323,8 +1357,11 @@ proc track(tracked: PEffects, n: PNode) = of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo: if n[0].kind == nkSym and n[0].sym.ast != nil: trackInnerProc(tracked, getBody(tracked.graph, n[0].sym)) - of nkTypeSection, nkMacroDef, nkTemplateDef: + of nkMacroDef, nkTemplateDef: discard + of nkTypeSection: + if tracked.isTopLevel: + collectObjectTree(tracked.graph, n) of nkCast: if n.len == 2: track(tracked, n[1]) @@ -1637,13 +1674,18 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = checkNil(s, body, g.config, c.idgen) proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = - if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef, - nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}: - return - let g = c.graph - var effects = newNodeI(nkEffectList, n.info) - var t: TEffects = initEffects(g, effects, module, c) - t.isTopLevel = isTopLevel - track(t, n) - when defined(drnim): - if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, module, n) + case n.kind + of {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef, + nkConverterDef, nkMethodDef, nkIteratorDef}: + discard + of nkTypeSection: + if isTopLevel: + collectObjectTree(c.graph, n) + else: + let g = c.graph + var effects = newNodeI(nkEffectList, n.info) + var t: TEffects = initEffects(g, effects, module, c) + t.isTopLevel = isTopLevel + track(t, n) + when defined(drnim): + if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, module, n) diff --git a/compiler/vtables.nim b/compiler/vtables.nim new file mode 100644 index 0000000000000..f57b59eaef9d1 --- /dev/null +++ b/compiler/vtables.nim @@ -0,0 +1,167 @@ +import ast, modulegraphs, magicsys, lineinfos, options, cgmeth, types +import std/[algorithm, tables, intsets, assertions] + + + +proc genVTableDispatcher(g: ModuleGraph; methods: seq[PSym]; index: int): PSym = +#[ +proc dispatch(x: Base, params: ...) = + cast[proc bar(x: Base, params: ...)](x.vTable[index])(x, params) +]# + var base = methods[0].ast[dispatcherPos].sym + result = base + var paramLen = base.typ.len + var body = newNodeI(nkStmtList, base.info) + + var disp = newNodeI(nkIfStmt, base.info) + + var vTableAccess = newNodeIT(nkBracketExpr, base.info, base.typ) + let nimGetVTableSym = getCompilerProc(g, "nimGetVTable") + let ptrPNimType = nimGetVTableSym.typ.n[1].sym.typ + + var nTyp = base.typ.n[1].sym.typ + var dispatchObject = newSymNode(base.typ.n[1].sym) + if nTyp.kind == tyObject: + dispatchObject = newTree(nkAddr, dispatchObject) + else: + if g.config.backend != backendCpp: # TODO: maybe handle ptr? + if nTyp.kind == tyVar and nTyp.skipTypes({tyVar}).kind != tyObject: + dispatchObject = newTree(nkDerefExpr, dispatchObject) + + var getVTableCall = newTree(nkCall, + newSymNode(nimGetVTableSym), + dispatchObject, + newIntNode(nkIntLit, index) + ) + getVTableCall.typ = base.typ + var vTableCall = newNodeIT(nkCall, base.info, base.typ[0]) + var castNode = newTree(nkCast, + newNodeIT(nkType, base.info, base.typ), + getVTableCall) + + castNode.typ = base.typ + vTableCall.add castNode + for col in 1..= y.depth: 1 + else: -1 + ) + + for item in g.objectTree[baseType.itemId]: + if item.value.itemId notin itemTable: + itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen) + + var mIndex = 0 # here is the correpsonding index + if baseType.itemId notin rootItemIdCount: + rootItemIdCount[baseType.itemId] = 1 + else: + mIndex = rootItemIdCount[baseType.itemId] + rootItemIdCount.inc(baseType.itemId) + for idx in 0..= y.depth: 1 + else: -1 + ) + + for item in g.objectTree[baseType.itemId]: + if item.value.itemId notin itemTable: + itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen) + + var mIndex = 0 # here is the correpsonding index + if baseType.itemId notin rootItemIdCount: + rootItemIdCount[baseType.itemId] = 1 + else: + mIndex = rootItemIdCount[baseType.itemId] + rootItemIdCount.inc(baseType.itemId) + for idx in 0.. prefer unit, thing! -test(b, c) -collide(a, b) -staticCollide(a, b) - - - -# tmultim6 -type - Thing {.inheritable.} = object - Unit[T] = object of Thing - x: T - Particle = object of Thing - a, b: int - -method collide(a, b: Thing) {.base, inline.} = - quit "to override!" - -method collide[T](a: Thing, b: Unit[T]) {.inline.} = - echo "collide: thing, unit |" - -method collide[T](a: Unit[T], b: Thing) {.inline.} = - echo "collide: unit, thing |" - -proc test(a, b: Thing) {.inline.} = - collide(a, b) - -var - aaa: Thing - bbb, ccc: Unit[string] -collide(bbb, Thing(ccc)) -test(bbb, ccc) -collide(aaa, bbb) - - - -# tmethods1 -method somethin(obj: RootObj) {.base.} = - echo "do nothing" - -type - TNode* {.inheritable.} = object - PNode* = ref TNode - - PNodeFoo* = ref object of TNode - - TSomethingElse = object - PSomethingElse = ref TSomethingElse - -method foo(a: PNode, b: PSomethingElse) {.base.} = discard -method foo(a: PNodeFoo, b: PSomethingElse) = discard - -var o: RootObj -o.somethin() +discard """ + matrix: "--multimethods:on" + output: ''' +collide: unit, thing +collide: unit, thing +collide: thing, unit +collide: thing, thing +collide: unit, thing | +collide: unit, thing | +collide: thing, unit | +do nothing +''' + joinable: false + disabled: true +""" + + +# tmultim2 +type + TThing {.inheritable.} = object + TUnit = object of TThing + x: int + TParticle = object of TThing + a, b: int + +method collide(a, b: TThing) {.base, inline.} = + echo "collide: thing, thing" + +method collide(a: TThing, b: TUnit) {.inline.} = + echo "collide: thing, unit" + +method collide(a: TUnit, b: TThing) {.inline.} = + echo "collide: unit, thing" + +proc test(a, b: TThing) {.inline.} = + collide(a, b) + +proc staticCollide(a, b: TThing) {.inline.} = + procCall collide(a, b) + +var + a: TThing + b, c: TUnit +collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing! +test(b, c) +collide(a, b) +staticCollide(a, b) + + + +# tmultim6 +type + Thing {.inheritable.} = object + Unit[T] = object of Thing + x: T + Particle = object of Thing + a, b: int + +method collide(a, b: Thing) {.base, inline.} = + quit "to override!" + +method collide[T](a: Thing, b: Unit[T]) {.inline.} = + echo "collide: thing, unit |" + +method collide[T](a: Unit[T], b: Thing) {.inline.} = + echo "collide: unit, thing |" + +proc test(a, b: Thing) {.inline.} = + collide(a, b) + +var + aaa: Thing + bbb, ccc: Unit[string] +collide(bbb, Thing(ccc)) +test(bbb, ccc) +collide(aaa, bbb) + + + +# tmethods1 +method somethin(obj: RootObj) {.base.} = + echo "do nothing" + +type + TNode* {.inheritable.} = object + PNode* = ref TNode + + PNodeFoo* = ref object of TNode + + TSomethingElse = object + PSomethingElse = ref TSomethingElse + +method foo(a: PNode, b: PSomethingElse) {.base.} = discard +method foo(a: PNodeFoo, b: PSomethingElse) = discard + +var o: RootObj +o.somethin() diff --git a/tests/method/tvtable.nim b/tests/method/tvtable.nim new file mode 100644 index 0000000000000..8d98dd42c3c63 --- /dev/null +++ b/tests/method/tvtable.nim @@ -0,0 +1,19 @@ +type FooBase = ref object of RootObj + dummy: int +type Foo = ref object of FooBase + value : float32 +type Foo2 = ref object of Foo + change : float32 +method bar(x: FooBase, a: float32) {.base.} = + discard +method bar(x: Foo, a: float32) = + x.value += a +method bar(x: Foo2, a: float32) = + x.value += a + + +proc test() = + var x = new Foo2 + x.bar(2.3) + +test() \ No newline at end of file From 795aad4f2a0032ed9b54a7b89dc08b420981e208 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:35:50 +0800 Subject: [PATCH 011/123] fixes #22996; `typeAllowedCheck` for default fields (#22998) fixes #22996 --- compiler/semtypes.nim | 5 +++++ compiler/typeallowed.nim | 5 +++-- tests/errmsgs/t22996.nim | 7 +++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/errmsgs/t22996.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index db7ce9d732617..a2e7bb639a623 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -237,6 +237,7 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool = return false proc fitDefaultNode(c: PContext, n: PNode): PType = + inc c.inStaticContext let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil n[^1] = semConstExpr(c, n[^1], expectedType = expectedType) let oldType = n[^1].typ @@ -247,6 +248,10 @@ proc fitDefaultNode(c: PContext, n: PNode): PType = result = n[^1].typ else: result = n[^1].typ + # xxx any troubles related to defaults fields, consult `semConst` for a potential answer + if n[^1].kind != nkNilLit: + typeAllowedCheck(c, n.info, result, skConst, {taProcContextIsNotMacro, taIsDefaultField}) + dec c.inStaticContext proc isRecursiveType*(t: PType): bool = # handle simple recusive types before typeFinalPass diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index d0df66f1851f5..483e55bc9dbd8 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -26,6 +26,7 @@ type taIsTemplateOrMacro taProcContextIsNotMacro taIsCastable + taIsDefaultField TTypeAllowedFlags* = set[TTypeAllowedFlag] @@ -172,7 +173,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, elif kind in {skVar, skLet}: result = t[1] of tyRef: - if kind == skConst: result = t + if kind == skConst and taIsDefaultField notin flags: result = t else: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) of tyPtr: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) @@ -182,7 +183,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if result != nil: break of tyObject, tyTuple: if kind in {skProc, skFunc, skConst} and - t.kind == tyObject and t[0] != nil: + t.kind == tyObject and t[0] != nil and taIsDefaultField notin flags: result = t else: let flags = flags+{taField} diff --git a/tests/errmsgs/t22996.nim b/tests/errmsgs/t22996.nim new file mode 100644 index 0000000000000..3a51fd8b0f6b0 --- /dev/null +++ b/tests/errmsgs/t22996.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "invalid type: 'typedesc[string]' for const" +""" + +# bug #22996 +type MyObject = ref object + _ = string From 96513b2506d9057744da9926986181294a3da653 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:36:20 +0800 Subject: [PATCH 012/123] fixes #22926; Different type inferred when setting a default value for an array field (#22999) fixes #22926 --- compiler/semtypes.nim | 6 ++++++ tests/objects/tdefaultfieldscheck.nim | 9 +++------ tests/objects/tobject_default_value.nim | 27 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index a2e7bb639a623..e234c6b1fd91e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -245,6 +245,12 @@ proc fitDefaultNode(c: PContext, n: PNode): PType = if n[^2].kind != nkEmpty: if expectedType != nil and oldType != expectedType: n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info) + changeType(c, n[^1], expectedType, true) # infer types for default fields value + # bug #22926; be cautious that it uses `semConstExpr` to + # evaulate the default fields; it's only natural to use + # `changeType` to infer types for constant values + # that's also the reason why we don't use `semExpr` to check + # the type since two overlapping error messages might be produced result = n[^1].typ else: result = n[^1].typ diff --git a/tests/objects/tdefaultfieldscheck.nim b/tests/objects/tdefaultfieldscheck.nim index d6feb29883c2e..8a05439d920a2 100644 --- a/tests/objects/tdefaultfieldscheck.nim +++ b/tests/objects/tdefaultfieldscheck.nim @@ -4,16 +4,13 @@ discard """ nimout: ''' tdefaultfieldscheck.nim(14, 17) Error: type mismatch: got but expected 'int' -tdefaultfieldscheck.nim(15, 20) Error: type mismatch: got but expected 'string' -tdefaultfieldscheck.nim(17, 16) Error: type mismatch: got but expected 'int' ''' """ + type Date* = object - name: int = "string" - time: string = 12 goal: float = 7 - fun: int = 1.4 + name: int = "string" -echo default(Date) \ No newline at end of file +echo default(Date) diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index 3af790da6a4e6..152b355f4b4e1 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -717,6 +717,33 @@ template main {.dirty.} = doAssert T().kind == B + block: # bug #22926 + type + Direction = enum + North + South + East + West + + ArrayObj1 = object + list: array[Direction, int] + + ArrayObj2 = object + list: array[Direction, int] = [1, 2, 3, 4] + + block: + var a: ArrayObj1 + doAssert a.list[West] == 0 + var b = default ArrayObj1 + doAssert b.list[North] == 0 + + + block: + var a: ArrayObj2 + doAssert a.list[West] == 0 + var b = default ArrayObj2 + doAssert b.list[North] == 1 + static: main() main() From beeacc86ff8b0fb6e1507a4a9462c93d8a0eb989 Mon Sep 17 00:00:00 2001 From: c-blake Date: Wed, 29 Nov 2023 21:36:47 +0000 Subject: [PATCH 013/123] Silence several Hint[Performance] warnings (#23003) With `--mm:arc` one gets the "implicit copy; if possible, rearrange your program's control flow" `Performance` warnings without these `move`s. --- lib/pure/httpclient.nim | 2 +- lib/pure/httpcore.nim | 3 +-- lib/pure/parsecfg.nim | 4 ++-- lib/std/cmdline.nim | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index fc66b96f522f5..08ea99627c1cf 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -1232,7 +1232,7 @@ proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync ## A `HttpRequestError` will be raised if the server responds with a ## client error (status code 4xx) or a server error (status code 5xx). if resp.code.is4xx or resp.code.is5xx: - raise newException(HttpRequestError, resp.status) + raise newException(HttpRequestError, resp.status.move) else: return await resp.bodyStream.readAll() diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index ab0c030a5c73e..45365c185153b 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -234,10 +234,9 @@ func parseList(line: string, list: var seq[string], start: int): int = while start+i < line.len and line[start + i] notin {'\c', '\l'}: i += line.skipWhitespace(start + i) i += line.parseUntil(current, {'\c', '\l', ','}, start + i) - list.add(current) + list.add(move current) # implicit current.setLen(0) if start+i < line.len and line[start + i] == ',': i.inc # Skip , - current.setLen(0) func parseHeader*(line: string): tuple[key: string, value: seq[string]] = ## Parses a single raw header HTTP line into key value pairs. diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index ea9c183336654..8a43daf54fed5 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -452,7 +452,7 @@ proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent = if c.tok.kind == tkSymbol: case kind of cfgOption, cfgKeyValuePair: - result = CfgEvent(kind: kind, key: c.tok.literal, value: "") + result = CfgEvent(kind: kind, key: c.tok.literal.move, value: "") else: discard rawGetTok(c, c.tok) if c.tok.kind in {tkEquals, tkColon}: @@ -481,7 +481,7 @@ proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} = of tkBracketLe: rawGetTok(c, c.tok) if c.tok.kind == tkSymbol: - result = CfgEvent(kind: cfgSectionStart, section: c.tok.literal) + result = CfgEvent(kind: cfgSectionStart, section: c.tok.literal.move) else: result = CfgEvent(kind: cfgError, msg: errorStr(c, "symbol expected, but found: " & c.tok.literal)) diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim index 29c357d9d0d78..a57fb76a4e0db 100644 --- a/lib/std/cmdline.nim +++ b/lib/std/cmdline.nim @@ -138,7 +138,7 @@ proc parseCmdLine*(c: string): seq[string] {. while i < c.len and c[i] > ' ': add(a, c[i]) inc(i) - add(result, a) + add(result, move a) when defined(nimdoc): # Common forward declaration docstring block for parameter retrieval procs. From 0f7ebb490ca1e2b7776aef1ec2b0cd8d942d42ce Mon Sep 17 00:00:00 2001 From: inv2004 Date: Thu, 30 Nov 2023 11:00:33 +0100 Subject: [PATCH 014/123] table.`mgetOrPut` without default val (#22994) RFC: https://github.com/nim-lang/RFCs/issues/539 - ~~mgetOrPutDefaultImpl template into `tableimpl.nim` to avoid macros~~ - mgetOrPut for `Table`, `TableRef`, `OrderedTable`, `OrderedTableRef` - `tests/stdlib/tmget.nim` tests update --------- Co-authored-by: inv2004 <> --- lib/pure/collections/tableimpl.nim | 21 ++++++++++--- lib/pure/collections/tables.nim | 48 ++++++++++++++++++++++++++++++ tests/stdlib/tmget.nim | 16 ++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 630af397026c9..3542741fac5dd 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -45,7 +45,7 @@ template addImpl(enlarge) {.dirty.} = rawInsert(t, t.data, key, val, hc, j) inc(t.counter) -template maybeRehashPutImpl(enlarge) {.dirty.} = +template maybeRehashPutImpl(enlarge, val) {.dirty.} = checkIfInitialized() if mustRehash(t): enlarge(t) @@ -59,7 +59,7 @@ template putImpl(enlarge) {.dirty.} = var hc: Hash = default(Hash) var index = rawGet(t, key, hc) if index >= 0: t.data[index].val = val - else: maybeRehashPutImpl(enlarge) + else: maybeRehashPutImpl(enlarge, val) template mgetOrPutImpl(enlarge) {.dirty.} = checkIfInitialized() @@ -67,17 +67,30 @@ template mgetOrPutImpl(enlarge) {.dirty.} = var index = rawGet(t, key, hc) if index < 0: # not present: insert (flipping index) - maybeRehashPutImpl(enlarge) + when declared(val): + maybeRehashPutImpl(enlarge, val) + else: + maybeRehashPutImpl(enlarge, default(B)) # either way return modifiable val result = t.data[index].val +# template mgetOrPutDefaultImpl(enlarge) {.dirty.} = +# checkIfInitialized() +# var hc: Hash = default(Hash) +# var index = rawGet(t, key, hc) +# if index < 0: +# # not present: insert (flipping index) +# maybeRehashPutImpl(enlarge, default(B)) +# # either way return modifiable val +# result = t.data[index].val + template hasKeyOrPutImpl(enlarge) {.dirty.} = checkIfInitialized() var hc: Hash = default(Hash) var index = rawGet(t, key, hc) if index < 0: result = false - maybeRehashPutImpl(enlarge) + maybeRehashPutImpl(enlarge, val) else: result = true # delImplIdx is KnuthV3 Algo6.4R adapted to i=i+1 (from i=i-1) which has come to diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 0a902ba8412de..8e4a3c35f346e 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -474,6 +474,18 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = mgetOrPutImpl(enlarge) +proc mgetOrPut*[A, B](t: var Table[A, B], key: A): var B = + ## Retrieves the value at `t[key]` or puts the + ## default initialization value for type `B` (e.g. 0 for any + ## integer type). + runnableExamples: + var a = {'a': 5}.newTable + doAssert a.mgetOrPut('a') == 5 + a.mgetOrPut('z').inc + doAssert a == {'a': 5, 'z': 1}.newTable + + mgetOrPutImpl(enlarge) + proc len*[A, B](t: Table[A, B]): int = ## Returns the number of keys in `t`. runnableExamples: @@ -1013,6 +1025,18 @@ proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = doAssert t[25] == @[25, 35] t[].mgetOrPut(key, val) +proc mgetOrPut*[A, B](t: TableRef[A, B], key: A): var B = + ## Retrieves the value at `t[key]` or puts the + ## default initialization value for type `B` (e.g. 0 for any + ## integer type). + runnableExamples: + var a = {'a': 5}.newTable + doAssert a.mgetOrPut('a') == 5 + a.mgetOrPut('z').inc + doAssert a == {'a': 5, 'z': 1}.newTable + + t[].mgetOrPut(key) + proc len*[A, B](t: TableRef[A, B]): int = ## Returns the number of keys in `t`. runnableExamples: @@ -1503,6 +1527,18 @@ proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B = mgetOrPutImpl(enlarge) +proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A): var B = + ## Retrieves the value at `t[key]` or puts the + ## default initialization value for type `B` (e.g. 0 for any + ## integer type). + runnableExamples: + var a = {'a': 5}.toOrderedTable + doAssert a.mgetOrPut('a') == 5 + a.mgetOrPut('z').inc + doAssert a == {'a': 5, 'z': 1}.toOrderedTable + + mgetOrPutImpl(enlarge) + proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} = ## Returns the number of keys in `t`. runnableExamples: @@ -1992,6 +2028,18 @@ proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = result = t[].mgetOrPut(key, val) +proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A): var B = + ## Retrieves the value at `t[key]` or puts the + ## default initialization value for type `B` (e.g. 0 for any + ## integer type). + runnableExamples: + var a = {'a': 5}.toOrderedTable + doAssert a.mgetOrPut('a') == 5 + a.mgetOrPut('z').inc + doAssert a == {'a': 5, 'z': 1}.toOrderedTable + + t[].mgetOrPut(key) + proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} = ## Returns the number of keys in `t`. runnableExamples: diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim index bf5e53560815c..f41963f025cec 100644 --- a/tests/stdlib/tmget.nim +++ b/tests/stdlib/tmget.nim @@ -3,15 +3,19 @@ discard """ output: '''Can't access 6 10 11 +2 Can't access 6 10 11 +2 Can't access 6 10 11 +2 Can't access 6 10 11 +2 0 10 11 @@ -41,6 +45,9 @@ block: x[5] += 1 var c = x[5] echo c + x.mgetOrPut(7).inc + x.mgetOrPut(7).inc + echo x[7] block: var x = newTable[int, int]() @@ -53,6 +60,9 @@ block: x[5] += 1 var c = x[5] echo c + x.mgetOrPut(7).inc + x.mgetOrPut(7).inc + echo x[7] block: var x = initOrderedTable[int, int]() @@ -65,6 +75,9 @@ block: x[5] += 1 var c = x[5] echo c + x.mgetOrPut(7).inc + x.mgetOrPut(7).inc + echo x[7] block: var x = newOrderedTable[int, int]() @@ -77,6 +90,9 @@ block: x[5] += 1 var c = x[5] echo c + x.mgetOrPut(7).inc + x.mgetOrPut(7).inc + echo x[7] block: var x = initCountTable[int]() From 9140f8e2212c91347704cec0f98c0345ddf0ea1e Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:01:42 +0100 Subject: [PATCH 015/123] Fix endsInNoReturn for case statements (#23009) While looking at the CI I noticed that there's a couple false positives for `case` statements that cannot be checked for exhaustiveness since my changes, this should resolve them. --------- Co-authored-by: SirOlaf <> --- compiler/sem.nim | 23 +++++++++++++-- compiler/semstmts.nim | 10 ++----- tests/controlflow/tunreachable.nim | 45 +++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 0dcc66432aa58..2bdb1284f40d1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -210,6 +210,18 @@ proc commonType*(c: PContext; x, y: PType): PType = result = newType(k, c.idgen, r.owner) result.addSonSkipIntLit(r, c.idgen) +const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool} +proc shouldCheckCaseCovered(caseTyp: PType): bool = + result = false + case caseTyp.kind + of shouldChckCovered: + result = true + of tyRange: + if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered: + result = true + else: + discard + proc endsInNoReturn(n: PNode): bool = ## check if expr ends the block like raising or call of noreturn procs do result = false # assume it does return @@ -239,6 +251,12 @@ proc endsInNoReturn(n: PNode): bool = # none of the branches returned result = hasElse # Only truly a no-return when it's exhaustive of nkCaseStmt: + let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc}) + # semCase should already have checked for exhaustiveness in this case + # effectively the same as having an else + var hasElse = caseTyp.shouldCheckCaseCovered() + + # actual noreturn checks for i in 1 ..< it.len: let branch = it[i] checkBranch: @@ -248,11 +266,12 @@ proc endsInNoReturn(n: PNode): bool = of nkElifBranch: branch[1] of nkElse: + hasElse = true branch[0] else: raiseAssert "Malformed `case` statement in endsInNoReturn" - # none of the branches returned - result = true + # Can only guarantee a noreturn if there is an else or it's exhaustive + result = hasElse of nkTryStmt: checkBranch(it[0]) for i in 1 ..< it.len: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 48447c0eb894b..dcf270a22587d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1146,20 +1146,14 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil openScope(c) pushCaseContext(c, n) n[0] = semExprWithType(c, n[0]) - var chckCovered = false var covered: Int128 = toInt128(0) var typ = commonTypeBegin var expectedType = expectedType var hasElse = false let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc}) - const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool} + var chckCovered = caseTyp.shouldCheckCaseCovered() case caseTyp.kind - of shouldChckCovered: - chckCovered = true - of tyRange: - if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered: - chckCovered = true - of tyFloat..tyFloat128, tyString, tyCstring, tyError: + of tyFloat..tyFloat128, tyString, tyCstring, tyError, shouldChckCovered, tyRange: discard else: popCaseContext(c) diff --git a/tests/controlflow/tunreachable.nim b/tests/controlflow/tunreachable.nim index 64e199e17f010..06321ce8a9855 100644 --- a/tests/controlflow/tunreachable.nim +++ b/tests/controlflow/tunreachable.nim @@ -2,9 +2,11 @@ discard """ cmd: "nim check --warningAsError:UnreachableCode $file" action: "reject" nimout: ''' -tunreachable.nim(24, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] -tunreachable.nim(31, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] -tunreachable.nim(40, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] +tunreachable.nim(26, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] +tunreachable.nim(33, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] +tunreachable.nim(42, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] +tunreachable.nim(65, 5) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] +tunreachable.nim(77, 5) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode] ''' """ @@ -39,4 +41,39 @@ proc main3() = return echo "after" -main3() \ No newline at end of file +main3() + + +block: + # Cases like strings are not checked for exhaustiveness unless they have an else + proc main4(x: string) = + case x + of "a": + return + # reachable + echo "after" + + main4("a") + + proc main5(x: string) = + case x + of "a": + return + else: + return + # unreachable + echo "after" + + main5("a") + +block: + # In this case no else is needed because it's exhaustive + proc exhaustive(x: bool) = + case x + of true: + return + of false: + return + echo "after" + + exhaustive(true) From b5f5b74fc8308593f04e3bc11f7c5ead24b73eb5 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 30 Nov 2023 21:05:45 +0800 Subject: [PATCH 016/123] enable vtable implementation for C++ and make it an experimental feature (#23004) follow up https://github.com/nim-lang/Nim/pull/22991 - [x] turning it into an experimental feature --------- Co-authored-by: Andreas Rumpf --- changelog.md | 2 +- compiler/ccgtypes.nim | 22 +++++++++++++++------- compiler/cgen.nim | 3 +-- compiler/cgmeth.nim | 2 +- compiler/condsyms.nim | 2 ++ compiler/nim.cfg | 5 ++++- compiler/options.nim | 3 ++- compiler/sem.nim | 4 +--- lib/system.nim | 7 +++++-- lib/system/arc.nim | 2 +- tests/config.nims | 3 +-- tests/generics/tobjecttyperel.nim | 2 +- tests/method/tgeneric_methods.nim | 2 +- tests/method/tmethods_old.nim | 2 +- tests/method/tvtable.nim | 5 +++++ 15 files changed, 42 insertions(+), 24 deletions(-) diff --git a/changelog.md b/changelog.md index fb70a9a6b088d..f21ab39da5c55 100644 --- a/changelog.md +++ b/changelog.md @@ -5,7 +5,7 @@ - `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility. - The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/` instead of `Nim httpclient/` which was incorrect according to the HTTP spec. -- Methods now support implementations based on vtable by using `-d:nimPreviewVtables`. methods are confined in the same module where the type has been defined. +- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined. - With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default. ## Standard library additions and changes diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 2f304852b1273..462b08a438154 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1678,6 +1678,13 @@ proc genDisplay(m: BModule; t: PType, depth: int): Rope = result.add seqs[0] result.add "}" +proc genVTable(seqs: seq[PSym]): string = + result = "{" + for i in 0.. 0: result.add ", " + result.add "(void *) " & seqs[i].loc.r + result.add "}" + proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = cgsym(m, "TNimTypeV2") m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) @@ -1714,18 +1721,19 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)]) + let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t)) + if dispatchMethods.len > 0: + let vTablePointerName = getTempName(m) + m.s[cfsVars].addf("static void* $1[$2] = $3;$n", [vTablePointerName, rope(dispatchMethods.len), genVTable(dispatchMethods)]) + for i in dispatchMethods: + genProcPrototype(m, i) + addf(typeEntry, "$1.vTable = $2;$n", [name, vTablePointerName]) + m.s[cfsTypeInit3].add typeEntry if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) -proc genVTable(seqs: seq[PSym]): string = - result = "{" - for i in 0.. 0: result.add ", " - result.add "(void *) " & seqs[i].loc.r - result.add "}" - proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = cgsym(m, "TNimTypeV2") m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5a331ae7c8fd0..d22a6bdc2414f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2234,8 +2234,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = incl m.flags, objHasKidsValid if optMultiMethods in m.g.config.globalOptions or m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or - not m.g.config.isDefined("nimPreviewVtables") or - m.g.config.backend == backendCpp or sfCompileToCpp in m.module.flags: + vtables notin m.g.config.features: generateIfMethodDispatchers(graph, m.idgen) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 3bbe7b3f4a0d4..833bb6fe500c2 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -157,7 +157,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = var witness: PSym = nil - if s.typ[1].owner.getModule != s.getModule and g.config.isDefined("nimPreviewVtables"): + if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"): localError(g.config, s.info, errGenerated, "method `" & s.name.s & "` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")") for i in 0.. Date: Thu, 30 Nov 2023 21:08:49 +0800 Subject: [PATCH 017/123] fixes #23006; newSeqUninit -> CT Error; imitate `newStringUninit` (#23007) fixes #23006 --- lib/system.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 4a52a0014a66b..8c17afaa026bf 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1661,7 +1661,10 @@ when not defined(js): assert len(x) == 3 x[0] = 10 when supportsCopyMem(T): - newSeqImpl(T, len) + when nimvm: + result = newSeq[T](len) + else: + newSeqImpl(T, len) else: {.error: "The type T cannot contain managed memory or have destructors".} From 7ea5aaaebb10369f202490581da6912b491503dd Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 30 Nov 2023 21:12:12 +0800 Subject: [PATCH 018/123] fixes #23001; give a better warning for PtrToCstringConv (#23005) fixes #23001 --- compiler/lineinfos.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index ef3222288a22a..d21825be767ac 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -187,7 +187,7 @@ const warnAnyEnumConv: "$1", warnHoleEnumConv: "$1", warnCstringConv: "$1", - warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future", + warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future", warnEffect: "$1", warnCastSizes: "$1", # deadcode warnAboveMaxSizeSet: "$1", From ab7faa73ef879548be2eaa462eb95c4c8ffd6ef2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 30 Nov 2023 17:59:16 +0100 Subject: [PATCH 019/123] fixes #22852; real bugfix is tied to bug #22672 (#23013) --- lib/system/indices.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/system/indices.nim b/lib/system/indices.nim index f4a1403464d03..fb6151a7444f5 100644 --- a/lib/system/indices.nim +++ b/lib/system/indices.nim @@ -112,8 +112,11 @@ proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] {.s ## ``` let xa = a ^^ x.a let L = (a ^^ x.b) - xa + 1 - result = newSeq[T](L) + # Workaround bug #22852: + result = newSeq[T](if L < 0: 0 else: L) for i in 0.. Date: Fri, 1 Dec 2023 00:21:42 -0600 Subject: [PATCH 020/123] related #22534; fixes documentation rendering of custom number literal routine declaration (#23015) I'm not sure if this is a complete fix, as it does not match the expected output given in the issue. The expected output given in the issue highlights the identifier after the `'` the same color as numeric literals (blue), and this change does not address that. I think that would involve simplifying `nimNumberPostfix`. However, this fixes the issue where the routine declaration was rendered as a string. New rendering: ![Screenshot from 2023-11-30 22-17-17](https://github.com/nim-lang/Nim/assets/80008541/b604ce27-a4ad-496b-82c3-0b568d99a8bf) --- lib/packages/docutils/highlite.nim | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index f0da1545c7439..f8376f46c371a 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -324,17 +324,18 @@ proc nimNextToken(g: var GeneralTokenizer, keywords: openArray[string] = @[]) = pos = nimNumber(g, pos) of '\'': inc(pos) - g.kind = gtCharLit - while true: - case g.buf[pos] - of '\0', '\r', '\n': - break - of '\'': - inc(pos) - break - of '\\': - inc(pos, 2) - else: inc(pos) + if g.kind != gtPunctuation: + g.kind = gtCharLit + while true: + case g.buf[pos] + of '\0', '\r', '\n': + break + of '\'': + inc(pos) + break + of '\\': + inc(pos, 2) + else: inc(pos) of '\"': inc(pos) if (g.buf[pos] == '\"') and (g.buf[pos + 1] == '\"'): From 0d24f765461785e5648ee580e0a4158eb344ee97 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 2 Dec 2023 05:28:24 +0100 Subject: [PATCH 021/123] fixes #22552 (#23014) --- compiler/ic/ic.nim | 3 +- compiler/injectdestructors.nim | 2 + compiler/magicsys.nim | 7 ++++ compiler/semdata.nim | 7 ---- compiler/transf.nim | 19 +++++++++- tests/arc/titeration_doesnt_copy.nim | 56 ++++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 tests/arc/titeration_doesnt_copy.nim diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 2f03ffb435050..b12db194cda1f 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -1089,7 +1089,8 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache else: result = optForceFullMake in conf.globalOptions # check its dependencies: - for dep in g[m].fromDisk.imports: + let imp = g[m].fromDisk.imports + for dep in imp: let fid = toFileIndex(dep, g[m].fromDisk, conf) # Warning: we need to traverse the full graph, so # do **not use break here**! diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 4870ca1a39894..7a64790c267b6 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -211,6 +211,8 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFr m.add " a 'sink' parameter" m.add "; routine: " m.add c.owner.name.s + #m.add "\n\n" + #m.add renderTree(c.body, {renderIds}) localError(c.graph.config, ri.info, errGenerated, m) proc makePtrType(c: var Con, baseType: PType): PType = diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index dcde49bfffa05..b365a3a194772 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -103,6 +103,13 @@ proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) = father.add(s) propagateToOwner(father, s) +proc makeVarType*(owner: PSym; baseType: PType; idgen: IdGenerator; kind = tyVar): PType = + if baseType.kind == kind: + result = baseType + else: + result = newType(kind, idgen, owner) + addSonSkipIntLit(result, baseType, idgen) + proc getCompilerProc*(g: ModuleGraph; name: string): PSym = let ident = getIdent(g.cache, name) result = strTableGet(g.compilerprocs, ident) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index a24fa4fb5afcc..b1ffbec4965ec 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -424,13 +424,6 @@ proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType = result = newTypeS(kind, c) addSonSkipIntLit(result, baseType, c.idgen) -proc makeVarType*(owner: PSym, baseType: PType; idgen: IdGenerator; kind = tyVar): PType = - if baseType.kind == kind: - result = baseType - else: - result = newType(kind, idgen, owner) - addSonSkipIntLit(result, baseType, idgen) - proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = newTypeS(tyTypeDesc, c) incl typedesc.flags, tfCheckedForDestructor diff --git a/compiler/transf.nim b/compiler/transf.nim index 65b4c6c3bd00f..edae6b847df8a 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -614,7 +614,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = type TPutArgInto = enum paDirectMapping, paFastAsgn, paFastAsgnTakeTypeFromArg - paVarAsgn, paComplexOpenarray + paVarAsgn, paComplexOpenarray, paViaIndirection proc putArgInto(arg: PNode, formal: PType): TPutArgInto = # This analyses how to treat the mapping "formal <-> arg" in an @@ -634,6 +634,7 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = result = paDirectMapping of nkDotExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr: result = putArgInto(arg[0], formal) + #if result == paViaIndirection: result = paFastAsgn of nkCurly, nkBracket: for i in 0.. Date: Sat, 2 Dec 2023 15:29:10 +1100 Subject: [PATCH 022/123] Show proper error message if trying to run a Nim file in a directory that doesn't exist (#23017) For example with the command `nim r foo/bar.nim`, if `foo/` doesn't exist then it shows this message ``` oserrors.nim(92) raiseOSError Error: unhandled exception: No such file or directory Additional info: foo [OSError] ``` After PR it shows ``` Error: cannot open 'foo/bar.nim' ``` Which makes it line up with the error message if `foo/` did exist but `bar.nim` didn't. Does this by using the same logic for [handling if the file doesn't exist](https://github.com/ire4ever1190/Nim/blob/0dc12ec24b7902ef0023a9e694faa11bcf99e257/compiler/options.nim#L785-L788) --- compiler/options.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/options.nim b/compiler/options.nim index 9282247c3efff..45ed8c23e725e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -789,7 +789,10 @@ proc setFromProjectName*(conf: ConfigRef; projectName: string) = conf.projectFull = AbsoluteFile projectName let p = splitFile(conf.projectFull) let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir - conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir) + try: + conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir) + except OSError: + conf.projectPath = dir conf.projectName = p.name proc removeTrailingDirSep*(path: string): string = From d5780a3e4ee9f2275a5253c55525ce5ead89efb2 Mon Sep 17 00:00:00 2001 From: Joachim Hereth <7327644+jhereth@users.noreply.github.com> Date: Sat, 2 Dec 2023 22:41:53 +0100 Subject: [PATCH 023/123] strutils.multiReplace: Making order of replacement explicit (#23022) In the docs for strutils.multiReplace: Making it more explicit that left to right comes before the order in the replacements arg (but that the latter matters too). E.g. ``` echo "ab".multiReplace(@[("a", "1"), ("ax", "2")]) echo "ab".multiReplace(@[("ab", "2"), ("a", "1")]) ``` gives ``` 1b 2 ``` resolves #23016 --- lib/pure/strutils.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 6d79259412bca..479acc0753de2 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2290,8 +2290,9 @@ func multiReplace*(s: string, replacements: varargs[(string, string)]): string = ## If the resulting string is not longer than the original input string, ## only a single memory allocation is required. ## - ## The order of the replacements does matter. Earlier replacements are - ## preferred over later replacements in the argument list. + ## Replacements are done left to right in the string. If at a given position + ## multiple replacements match, earlier replacements are preferred over + ## later replacements in the argument list. result = newStringOfCap(s.len) var i = 0 var fastChk: set[char] = {} From b8fa78939398397f557dbae1c905800850829e29 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Mon, 4 Dec 2023 17:15:16 +1100 Subject: [PATCH 024/123] Fix nimsuggest `def` being different on proc definition/use (#23025) Currently the documentation isn't shown when running `def` on the definition of a proc (Which works for things like variables). `gcsafe`/`noSideEffects` status also isn't showing up when running `def` on the definition Images of current behavior. After PR both look like "Usage" **Definition** ![image](https://github.com/nim-lang/Nim/assets/19339842/bf75ff0b-9a96-49e5-bf8a-d2c503efa784) **Usage** ![image](https://github.com/nim-lang/Nim/assets/19339842/15ea3ebf-64e1-48f5-9233-22605183825f) Issue was the symbol getting passed too early to nimsuggest so it didn't have all that info, now gets passed once proc is fully semmed --- compiler/semstmts.nim | 14 ++++++++++++-- nimsuggest/tests/tdef1.nim | 10 ++++++---- nimsuggest/tests/tsug_recursive.nim | 8 ++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 nimsuggest/tests/tsug_recursive.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index dcf270a22587d..4b08767c0fd99 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2153,7 +2153,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, result = n checkMinSonsLen(n, bodyPos + 1, c.config) - let isAnon = n[namePos].kind == nkEmpty + let + isAnon = n[namePos].kind == nkEmpty + isHighlight = c.config.ideCmd == ideHighlight var s: PSym @@ -2166,7 +2168,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, s = n[namePos].sym s.owner = c.getCurrOwner else: - s = semIdentDef(c, n[namePos], kind) + # Highlighting needs to be done early so the position for + # name isn't changed (see taccent_highlight). We don't want to check if this is the + # defintion yet since we are missing some info (comments, side effects) + s = semIdentDef(c, n[namePos], kind, reportToNimsuggest=isHighlight) n[namePos] = newSymNode(s) when false: # disable for now @@ -2413,6 +2418,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, elif isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure: localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid") + # Prevent double highlights. We already highlighted before. + # When not highlighting we still need to allow for suggestions though + if not isHighlight: + suggestSym(c.graph, s.info, s, c.graph.usageSym) + proc determineType(c: PContext, s: PSym) = if s.typ != nil: return #if s.magic != mNone: return diff --git a/nimsuggest/tests/tdef1.nim b/nimsuggest/tests/tdef1.nim index 5c86923b6b057..46d7c0b5d716e 100644 --- a/nimsuggest/tests/tdef1.nim +++ b/nimsuggest/tests/tdef1.nim @@ -1,12 +1,14 @@ discard """ $nimsuggest --tester $file >def $1 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;9;;5;;"Return hello";;100 ->def $1 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;9;;5;;"Return hello";;100 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;11;;5;;"Return hello";;100 +>def $2 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;11;;5;;"Return hello";;100 +>def $2 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;11;;5;;"Return hello";;100 """ -proc hello(): string = +proc hel#[!]#lo(): string = ## Return hello "Hello" diff --git a/nimsuggest/tests/tsug_recursive.nim b/nimsuggest/tests/tsug_recursive.nim new file mode 100644 index 0000000000000..97ee5ca0151e1 --- /dev/null +++ b/nimsuggest/tests/tsug_recursive.nim @@ -0,0 +1,8 @@ +discard """ +$nimsuggest --tester $file +>sug $1 +sug;;skProc;;tsug_recursive.fooBar;;proc ();;$file;;7;;5;;"";;100;;Prefix +""" + +proc fooBar() = + fooBa#[!]# From 618ccb6b6a60f9a315997f95cbbd81be9e9d7f53 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Mon, 4 Dec 2023 08:17:42 +0200 Subject: [PATCH 025/123] Also show the `raises` pragma when converting proc types to string (#23026) This affects also nimsuggest hints (e.g. on mouse hover), as well as compiler messages. --- compiler/types.nim | 10 +++++++++- tests/effects/teffects1.nim | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 7bb29405fb001..f10d5aa862409 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -11,7 +11,7 @@ import ast, astalgo, trees, msgs, platform, renderer, options, - lineinfos, int128, modulegraphs, astmsgs + lineinfos, int128, modulegraphs, astmsgs, wordrecg import std/[intsets, strutils] @@ -762,6 +762,14 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(')') if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0])) var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv + if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos: + let pragmasNode = t.owner.ast[pragmasPos] + let raisesSpec = effectSpec(pragmasNode, wRaises) + if not isNil(raisesSpec): + addSep(prag) + prag.add("raises: ") + prag.add($raisesSpec) + if tfNoSideEffect in t.flags: addSep(prag) prag.add("noSideEffect") diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 49c9040296b15..1d267b5faf1bd 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -39,7 +39,7 @@ proc foo(x: int): string {.nimcall, raises: [ValueError].} = var p: MyProcType = foo #[tt.Error ^ -type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' +type mismatch: got but expected 'MyProcType = proc (x: int): string{.closure.}' Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'. .raise effects differ ]# From 202e21daba1424762cf330effb52220c6f1d5772 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 4 Dec 2023 23:20:19 +0800 Subject: [PATCH 026/123] forbides adding sons for `PType` (#23030) I image `add` for `PType` to be used everythere --- compiler/ast.nim | 7 ------- compiler/ic/ic.nim | 4 +++- compiler/semexprs.nim | 3 +-- compiler/semtypes.nim | 9 +++------ 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 8a71522e6075b..e25ce42dd14ca 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1567,10 +1567,6 @@ when false: result = prev result.sons = sons -proc addSon*(father, son: PType) = - # todo fixme: in IC, `son` might be nil - father.sons.add(son) - proc mergeLoc(a: var TLoc, b: TLoc) = if a.k == low(typeof(a.k)): a.k = b.k if a.storage == low(typeof(a.storage)): a.storage = b.storage @@ -1713,9 +1709,6 @@ proc rawAddSon*(father, son: PType; propagateHasAsgn = true) = father.sons.add(son) if not son.isNil: propagateToOwner(father, son, propagateHasAsgn) -proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) = - father.sons.add(son) - proc addSonNilAllowed*(father, son: PNode) = father.sons.add(son) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index b12db194cda1f..0085ea7485537 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -994,8 +994,10 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; for op, item in pairs t.attachedOps: result.attachedOps[op] = loadSym(c, g, si, item) result.typeInst = loadType(c, g, si, t.typeInst) + var sons = newSeq[PType]() for son in items t.types: - result.addSon loadType(c, g, si, son) + sons.add loadType(c, g, si, son) + result.setSons(sons) loadAstBody(t, n) when false: for gen, id in items t.methods: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 96904f0dd3055..82ff000a74a10 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -345,10 +345,9 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType if targetType.kind in {tySink, tyLent} or isOwnedSym(c, n[0]): let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc}) - let t = newTypeS(targetType.kind, c) + let t = newTypeS(targetType.kind, c, @[baseType]) if targetType.kind == tyOwned: t.flags.incl tfHasOwned - t.rawAddSonNoPropagationOfTypeFlags baseType result = newNodeI(nkType, n.info) result.typ = makeTypeDesc(c, t) return diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e234c6b1fd91e..be33114f5865f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -424,10 +424,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = typeToString(indxB.skipTypes({tyRange}))) base = semTypeNode(c, n[2], nil) # ensure we only construct a tyArray when there was no error (bug #3048): - result = newOrPrevType(tyArray, prev, c) # bug #6682: Do not propagate initialization requirements etc for the # index type: - rawAddSonNoPropagationOfTypeFlags(result, indx) + result = newOrPrevType(tyArray, prev, c, @[indx]) addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errArrayExpectsTwoTypeParams) @@ -1019,13 +1018,11 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = case wrapperKind of tyOwned: if optOwnedRefs in c.config.globalOptions: - let t = newTypeS(tyOwned, c) + let t = newTypeS(tyOwned, c, @[result]) t.flags.incl tfHasOwned - t.rawAddSonNoPropagationOfTypeFlags result result = t of tySink: - let t = newTypeS(tySink, c) - t.rawAddSonNoPropagationOfTypeFlags result + let t = newTypeS(tySink, c, @[result]) result = t else: discard if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: From d20b4d5168780b9c6a3bd2fde28b171cb7414c98 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 6 Dec 2023 04:04:41 +0800 Subject: [PATCH 027/123] =?UTF-8?q?fixes=20#23019;=20Regression=20from=202?= =?UTF-8?q?.0=20to=20devel=20with=20raise=20an=20unlisted=20exc=E2=80=A6?= =?UTF-8?q?=20(#23034)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …eption: Exception fixes #23019 I suppose `implicitPragmas` is called somewhere which converts `otherPragmas`. --- compiler/pragmas.nim | 2 +- tests/pragmas/tpush.nim | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index d4817ce7a57bf..a800edaf82689 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1313,7 +1313,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo, if sym != nil and sym.kind != skModule: for it in c.optionStack: let o = it.otherPragmas - if not o.isNil: + if not o.isNil and sfFromGeneric notin sym.flags: # bug #23019 pushInfoContext(c.config, info) var i = 0 while i < o.len: diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim index 6a95f1ca00186..8ebbfe3d3d6f5 100644 --- a/tests/pragmas/tpush.nim +++ b/tests/pragmas/tpush.nim @@ -77,3 +77,25 @@ block: # bug #22913 {.pop.} discard foo2() + +block: # bug #23019 + proc f(x: bool) + + proc a(x: int) = + if false: f(true) + + proc f(x: bool) = + if false: a(0) + + proc k(r: int|int) {.inline.} = # seems to require being generic and inline + if false: a(0) + + + # {.push tags: [].} + {.push raises: [].} + + {.push warning[ObservableStores]:off.} # can be any warning, off or on + let w = 0 + k(w) + {.pop.} + {.pop.} From 44b64e726ec4aa9076d2d69e88c5d593131f8ee3 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Wed, 6 Dec 2023 14:59:38 +1100 Subject: [PATCH 028/123] Don't recurse into inner functions during asyncjs transform (#23036) Closes #13341 --- lib/js/asyncjs.nim | 2 ++ tests/js/tasyncjs.nim | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 8e2f85156bb48..045d1e6b56673 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -90,6 +90,8 @@ proc replaceReturn(node: var NimNode) = node[z] = nnkReturnStmt.newTree(value) elif son.kind == nnkAsgn and son[0].kind == nnkIdent and $son[0] == "result": node[z] = nnkAsgn.newTree(son[0], nnkCall.newTree(jsResolve, son[1])) + elif son.kind in RoutineNodes: + discard else: replaceReturn(son) inc z diff --git a/tests/js/tasyncjs.nim b/tests/js/tasyncjs.nim index 3de1436431cd3..f3b273c447ca3 100644 --- a/tests/js/tasyncjs.nim +++ b/tests/js/tasyncjs.nim @@ -99,4 +99,9 @@ block asyncPragmaInType: proc foo() {.async.} = discard var x: Handler = foo +block: # 13341 + proc f {.async.} = + proc g: int = + result = 123 + discard main() From e1a0ff1b8a5b84f4e9e338691b280678bc03f650 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 6 Dec 2023 18:17:57 +0100 Subject: [PATCH 029/123] lexer cleanups (#23037) * remove some dead code and leftovers from past features * fix yaml printing of uint64 literals --- compiler/astalgo.nim | 2 +- compiler/lexer.nim | 73 ++++++++--------------------------------- compiler/main.nim | 1 - compiler/nimconf.nim | 1 - compiler/parser.nim | 12 +++---- compiler/renderer.nim | 6 ++-- tools/grammar_nanny.nim | 1 - 7 files changed, 20 insertions(+), 76 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 720f6087f9663..cd772f0f142ed 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -370,7 +370,7 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int, if conf != nil: result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)]) case n.kind - of nkCharLit..nkInt64Lit: + of nkCharLit..nkUInt64Lit: result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.addf(",$N$1\"floatVal\": $2", diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 5aed196362473..1ef0ce879e21d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -122,7 +122,6 @@ type # this is needed because scanning comments # needs so much look-ahead currLineIndent*: int - strongSpaces*, allowTabs*: bool errorHandler*: ErrorHandler cache*: IdentCache when defined(nimsuggest): @@ -176,32 +175,6 @@ proc printTok*(conf: ConfigRef; tok: Token) = # xxx factor with toLocation msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok) -proc initToken*(L: var Token) = - L.tokType = tkInvalid - L.iNumber = 0 - L.indent = 0 - L.spacing = {} - L.literal = "" - L.fNumber = 0.0 - L.base = base10 - L.ident = nil - when defined(nimpretty): - L.commentOffsetA = 0 - L.commentOffsetB = 0 - -proc fillToken(L: var Token) = - L.tokType = tkInvalid - L.iNumber = 0 - L.indent = 0 - L.spacing = {} - setLen(L.literal, 0) - L.fNumber = 0.0 - L.base = base10 - L.ident = nil - when defined(nimpretty): - L.commentOffsetA = 0 - L.commentOffsetB = 0 - proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = openBaseLexer(lex, inputstream) @@ -798,7 +771,7 @@ proc getString(L: var Lexer, tok: var Token, mode: StringMode) = if mode != normal: tok.tokType = tkRStrLit else: tok.tokType = tkStrLit while true: - var c = L.buf[pos] + let c = L.buf[pos] if c == '\"': if mode != normal and L.buf[pos+1] == '\"': inc(pos, 2) @@ -824,7 +797,7 @@ proc getCharacter(L: var Lexer; tok: var Token) = tokenBegin(tok, L.bufpos) let startPos = L.bufpos inc(L.bufpos) # skip ' - var c = L.buf[L.bufpos] + let c = L.buf[L.bufpos] case c of '\0'..pred(' '), '\'': lexMessage(L, errGenerated, "invalid character literal") @@ -942,7 +915,7 @@ proc getOperator(L: var Lexer, tok: var Token) = tokenBegin(tok, pos) var h: Hash = 0 while true: - var c = L.buf[pos] + let c = L.buf[pos] if c in OpChars: h = h !& ord(c) inc(pos) @@ -1010,23 +983,6 @@ proc getPrecedence*(tok: Token): int = of tkOr, tkXor, tkPtr, tkRef: result = 3 else: return -10 -proc newlineFollows*(L: Lexer): bool = - result = false - var pos = L.bufpos - while true: - case L.buf[pos] - of ' ', '\t': - inc(pos) - of CR, LF: - result = true - break - of '#': - inc(pos) - if L.buf[pos] == '#': inc(pos) - if L.buf[pos] != '[': return true - else: - break - proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; isDoc: bool) = var pos = start @@ -1118,9 +1074,7 @@ proc scanComment(L: var Lexer, tok: var Token) = toStrip = 0 else: # found first non-whitespace character stripInit = true - var lastBackslash = -1 while L.buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: - if L.buf[pos] == '\\': lastBackslash = pos+1 tok.literal.add(L.buf[pos]) inc(pos) tokenEndIgnore(tok, pos) @@ -1163,7 +1117,7 @@ proc skip(L: var Lexer, tok: var Token) = inc(pos) tok.spacing.incl(tsLeading) of '\t': - if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead") + lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead") inc(pos) of CR, LF: tokenEndPrevious(tok, pos) @@ -1231,7 +1185,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = L.previousToken.line = tok.line.uint16 L.previousToken.col = tok.col.int16 - fillToken(tok) + reset(tok) if L.indentAhead >= 0: tok.indent = L.indentAhead L.currLineIndent = L.indentAhead @@ -1243,7 +1197,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = if tok.tokType == tkComment: L.indentAhead = L.currLineIndent return - var c = L.buf[L.bufpos] + let c = L.buf[L.bufpos] tok.line = L.lineNumber tok.col = getColNumber(L, L.bufpos) if c in SymStartChars - {'r', 'R'} - UnicodeOperatorStartChars: @@ -1402,7 +1356,6 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; result = 0 var lex: Lexer = default(Lexer) var tok: Token = default(Token) - initToken(tok) openLexer(lex, fileIdx, inputstream, cache, config) var prevToken = tkEof while tok.tokType != tkEof: @@ -1415,11 +1368,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; proc getPrecedence*(ident: PIdent): int = ## assumes ident is binary operator already - var tok: Token - initToken(tok) - tok.ident = ident - tok.tokType = - if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol): - TokType(tok.ident.id + ord(tkSymbol)) - else: tkOpr + let + tokType = + if ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol): + TokType(ident.id + ord(tkSymbol)) + else: tkOpr + tok = Token(ident: ident, tokType: tokType) + getPrecedence(tok) diff --git a/compiler/main.nim b/compiler/main.nim index d9c3baa0905ea..742530c071bc5 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -224,7 +224,6 @@ proc commandScan(cache: IdentCache, config: ConfigRef) = var L: Lexer tok: Token = default(Token) - initToken(tok) openLexer(L, f, stream, cache, config) while true: rawGetTok(L, tok) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 3a811a106168f..1e7d62b4da425 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -222,7 +222,6 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache; stream: PLLStream stream = llStreamOpen(filename, fmRead) if stream != nil: - initToken(tok) openLexer(L, filename, stream, cache, config) tok.tokType = tkEof # to avoid a pointless warning var condStack: seq[bool] = @[] diff --git a/compiler/parser.nim b/compiler/parser.nim index 20f6868cd2c8b..072540dba62ea 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -83,10 +83,6 @@ type PrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmTrySimple -proc parseAll*(p: var Parser): PNode -proc closeParser*(p: var Parser) -proc parseTopLevelStmt*(p: var Parser): PNode - # helpers for the other parsers proc isOperator*(tok: Token): bool proc getTok*(p: var Parser) @@ -144,7 +140,7 @@ proc openParser*(p: var Parser, fileIdx: FileIndex, inputStream: PLLStream, cache: IdentCache; config: ConfigRef) = ## Open a parser, using the given arguments to set up its internal state. ## - initToken(p.tok) + reset(p.tok) openLexer(p.lex, fileIdx, inputStream, cache, config) when defined(nimpretty): openEmitter(p.em, cache, config, fileIdx) @@ -156,7 +152,7 @@ proc openParser*(p: var Parser, filename: AbsoluteFile, inputStream: PLLStream, cache: IdentCache; config: ConfigRef) = openParser(p, fileInfoIdx(config, filename), inputStream, cache, config) -proc closeParser(p: var Parser) = +proc closeParser*(p: var Parser) = ## Close a parser, freeing up its resources. closeLexer(p.lex) when defined(nimpretty): @@ -2520,7 +2516,7 @@ proc parseStmt(p: var Parser): PNode = if err and p.tok.tokType == tkEof: break setEndInfo() -proc parseAll(p: var Parser): PNode = +proc parseAll*(p: var Parser): PNode = ## Parses the rest of the input stream held by the parser into a PNode. result = newNodeP(nkStmtList, p) while p.tok.tokType != tkEof: @@ -2540,7 +2536,7 @@ proc checkFirstLineIndentation*(p: var Parser) = if p.tok.indent != 0 and tsLeading in p.tok.spacing: parMessage(p, errInvalidIndentation) -proc parseTopLevelStmt(p: var Parser): PNode = +proc parseTopLevelStmt*(p: var Parser): PNode = ## Implements an iterator which, when called repeatedly, returns the next ## top-level statement or emptyNode if end of stream. result = p.emptyNode diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 43ac91e92e68c..2a586386bd477 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -125,6 +125,8 @@ template outside(g: var TSrcGen, section: Section, body: untyped) = const IndentWidth = 2 longIndentWid = IndentWidth * 2 + MaxLineLen = 80 + LineCommentColumn = 30 when defined(nimpretty): proc minmaxLine(n: PNode): (int, int) = @@ -143,10 +145,6 @@ when defined(nimpretty): proc lineDiff(a, b: PNode): int = result = minmaxLine(b)[0] - minmaxLine(a)[1] -const - MaxLineLen = 80 - LineCommentColumn = 30 - proc initSrcGen(renderFlags: TRenderFlags; config: ConfigRef): TSrcGen = result = TSrcGen(comStack: @[], tokens: @[], indent: 0, lineLen: 0, pos: 0, idx: 0, buf: "", diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim index bcb3a044f7fba..cbdc51efc144b 100644 --- a/tools/grammar_nanny.nim +++ b/tools/grammar_nanny.nim @@ -22,7 +22,6 @@ proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) = var L: Lexer tok: Token - initToken(tok) openLexer(L, f, stream, cache, config) # load the first token: rawGetTok(L, tok) From 4fdc6c49bd2a9085d40590bd9ba9696b1e6066d9 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Thu, 7 Dec 2023 18:14:23 +1100 Subject: [PATCH 030/123] Don't process a user pragma if its invalid (#23041) When running `check`/`suggest` in a file with an invalid user pragma like ```nim {.pragma foo: test.} ``` It will continue to try and process it which leads to the compiler running into a `FieldDefect` ``` fatal.nim(53) sysFatal Error: unhandled exception: field 'sons' is not accessible for type 'TNode' using 'kind = nkIdent' [FieldDefect] ``` This makes it instead bail out trying to process the user pragma if its invalid --- compiler/pragmas.nim | 5 ++++- tests/pragmas/tinvalid_user_pragma.nim | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/tinvalid_user_pragma.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index a800edaf82689..fe4ef2b87dd4f 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -685,9 +685,12 @@ proc pragmaLine(c: PContext, n: PNode) = proc processPragma(c: PContext, n: PNode, i: int) = ## Create and add a new custom pragma `{.pragma: name.}` node to the module's context. let it = n[i] - if it.kind notin nkPragmaCallKinds and it.safeLen == 2: invalidPragma(c, n) + if it.kind notin nkPragmaCallKinds and it.safeLen == 2: + invalidPragma(c, n) + return elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent: invalidPragma(c, n) + return var userPragma = newSym(skTemplate, it[1].ident, c.idgen, c.module, it.info, c.config.options) styleCheckDef(c, userPragma) diff --git a/tests/pragmas/tinvalid_user_pragma.nim b/tests/pragmas/tinvalid_user_pragma.nim new file mode 100644 index 0000000000000..3081db842e7a2 --- /dev/null +++ b/tests/pragmas/tinvalid_user_pragma.nim @@ -0,0 +1,9 @@ +discard """ +cmd: "nim check $file" +""" + +{.pragma test: foo.} #[tt.Error +^ invalid pragma: {.pragma, test: foo.} ]# + +{.pragma: 1.} #[tt.Error +^ invalid pragma: {.pragma: 1.} ]# From 0a7094450ec059e10da67d47a76d004d4972b368 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 8 Dec 2023 09:05:41 +1100 Subject: [PATCH 031/123] Only suggest symbols that could be pragmas when typing a pragma (#23040) Currently pragmas just fall through to `suggestSentinel` and show everything which isn't very useful. Now it filters for symbols that could be pragmas (templates with `{.pragma.}`, macros, user pragmas) and only shows them --- compiler/pragmas.nim | 5 ++++ compiler/semstmts.nim | 4 ++++ compiler/semtypes.nim | 2 +- compiler/suggest.nim | 37 ++++++++++++++++++++++++++-- nimsuggest/tests/tsug_pragmas.nim | 40 +++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 nimsuggest/tests/tsug_pragmas.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index fe4ef2b87dd4f..0e434e6f7ebdb 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -14,6 +14,8 @@ import wordrecg, ropes, options, extccomp, magicsys, trees, types, lookups, lineinfos, pathutils, linter, modulepaths +from sigmatch import trySuggestPragmas + import std/[os, math, strutils] when defined(nimPreviewSlimSystem): @@ -119,6 +121,7 @@ const proc invalidPragma*(c: PContext; n: PNode) = localError(c.config, n.info, "invalid pragma: " & renderTree(n, {renderNoComments})) + proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) = var msg = "cannot attach a custom pragma to '" & s.name.s & "'" if s != nil: @@ -790,6 +793,8 @@ proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode = invalidPragma(c, n) return n + trySuggestPragmas(c, callNode[0]) + let r = c.semOverloadedCall(c, callNode, n, {skTemplate}, {efNoUndeclared}) if r.isNil or sfCustomPragma notin r[0].sym.flags: invalidPragma(c, n) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4b08767c0fd99..70818bb671682 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -525,6 +525,8 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode = let it = pragmas[i] let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it + trySuggestPragmas(c, key) + if isPossibleMacroPragma(c, it, key): # we transform ``var p {.m, rest.}`` into ``m(do: var p {.rest.})`` and # let the semantic checker deal with it: @@ -1741,6 +1743,8 @@ proc semProcAnnotation(c: PContext, prc: PNode; let it = n[i] let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it + trySuggestPragmas(c, key) + if isPossibleMacroPragma(c, it, key): # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and # let the semantic checker deal with it: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index be33114f5865f..7968122ed52f3 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1741,10 +1741,10 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode = result = nil for p in pragmas: let key = if p.kind in nkPragmaCallKinds and p.len >= 1: p[0] else: p - if p.kind == nkEmpty or whichPragma(p) != wInvalid: discard "builtin pragma" else: + trySuggestPragmas(c, key) let ident = considerQuotedIdent(c, key) if strTableGet(c.userPragmas, ident) != nil: discard "User-defined pragma" diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 5053fe66919a1..802da1c3e3665 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -126,7 +126,7 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info inTypeContext: bool; scope: int; useSuppliedInfo = false, endLine: uint16 = 0, - endCol = 0): Suggest = + endCol = 0, extractDocs = true): Suggest = new(result) result.section = section result.quality = quality @@ -165,7 +165,8 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info else: result.forth = "" when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): - result.doc = extractDocComment(g, s) + if extractDocs: + result.doc = extractDocComment(g, s) if s.kind == skModule and s.ast.len != 0 and section != ideHighlight: result.filePath = toFullPath(g.config, s.ast[0].info) result.line = 1 @@ -746,6 +747,38 @@ proc suggestEnum*(c: PContext; n: PNode; t: PType) = produceOutput(outputs, c.config) if outputs.len > 0: suggestQuit() +proc suggestPragmas*(c: PContext, n: PNode) = + ## Suggests anything that might be a pragma + ## - template that has {.pragma.} + ## - macros + ## - user pragmas + let info = n.info + var outputs: Suggestions = @[] + # First filter for template/macros + wholeSymTab(filterSym(it, n, pm) and + (sfCustomPragma in it.flags or it.kind == skMacro), + ideSug) + + # Now show suggestions for user pragmas + for pragma in c.userPragmas: + var pm = default(PrefixMatch) + if filterSym(pragma, n, pm): + outputs &= symToSuggest(c.graph, pragma, isLocal=true, ideSug, info, + pragma.getQuality, pm, c.inTypeContext > 0, 0, + extractDocs=false) + + produceOutput(outputs, c.config) + if outputs.len > 0: + suggestQuit() + +template trySuggestPragmas*(c: PContext, n: PNode) = + ## Runs [suggestPragmas] when compiling nimsuggest and + ## we are querying the node + when defined(nimsuggest): + let tmp = n + if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, tmp.info): + suggestPragmas(c, tmp) + proc suggestSentinel*(c: PContext) = if c.config.ideCmd != ideSug or c.module.position != c.config.m.trackPos.fileIndex.int32: return if c.compilesContextId > 0: return diff --git a/nimsuggest/tests/tsug_pragmas.nim b/nimsuggest/tests/tsug_pragmas.nim new file mode 100644 index 0000000000000..03a9cba4c67f3 --- /dev/null +++ b/nimsuggest/tests/tsug_pragmas.nim @@ -0,0 +1,40 @@ +template fooBar1() {.pragma.} +proc fooBar2() = discard +macro fooBar3(x: untyped) = discard +{.pragma: fooBar4 fooBar3.} + +proc test1() {.fooBar#[!]#.} = discard + +var test2 {.fooBar#[!]#.} = 9 + +type + Person {.fooBar#[!]#.} = object + hello {.fooBar#[!]#.}: string + Callback = proc () {.fooBar#[!]#.} + +# Check only macros/templates/pragmas are suggested +discard """ +$nimsuggest --tester $file +>sug $1 +sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix +sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +>sug $2 +sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix +sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +>sug $3 +sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix +sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +>sug $4 +sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix +sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +>sug $5 +sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix +sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +""" + + From cf4cef498489f1dbbb3dea287e88a9a0d820e8b7 Mon Sep 17 00:00:00 2001 From: ASVIEST <71895914+ASVIEST@users.noreply.github.com> Date: Tue, 12 Dec 2023 11:05:00 +0300 Subject: [PATCH 032/123] Ast stmt now saves its ast structure in the compiler (#23053) see https://github.com/nim-lang/Nim/issues/23052 --------- Co-authored-by: Andreas Rumpf --- compiler/ccgstmts.nim | 7 ++++++- compiler/pragmas.nim | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 45a2343320503..c3d44c1d369b6 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1489,7 +1489,12 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = var res = "" - for it in t.sons: + let offset = + if isAsmStmt: 1 # first son is pragmas + else: 0 + + for i in offset.. Date: Tue, 12 Dec 2023 01:06:13 -0700 Subject: [PATCH 033/123] =?UTF-8?q?Look=20up=20generic=20parameters=20when?= =?UTF-8?q?=20found=20inside=20semOverloadedCall,=20fixin=E2=80=A6=20(#230?= =?UTF-8?q?54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …g static procs --------- Co-authored-by: Andreas Rumpf --- compiler/semcall.nim | 13 +++++++++++++ tests/statictypes/tstaticprocparams.nim | 9 +++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/statictypes/tstaticprocparams.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 2c1939c3cf50b..26a40b4dcea71 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -49,6 +49,19 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode, while symx != nil: if symx.kind in filter: result.add((symx, o.lastOverloadScope)) + elif symx.kind == skGenericParam: + #[ + This code handles looking up a generic parameter when it's a static callable. + For instance: + proc name[T: static proc()]() = T() + name[proc() = echo"hello"]() + ]# + for paramSym in searchInScopesAllCandidatesFilterBy(c, symx.name, {skConst}): + let paramTyp = paramSym.typ + if paramTyp.n.sym.kind in filter: + result.add((paramTyp.n.sym, o.lastOverloadScope)) + + symx = nextOverloadIter(o, c, headSymbol) if result.len > 0: best = initCandidate(c, result[0].s, initialBinding, diff --git a/tests/statictypes/tstaticprocparams.nim b/tests/statictypes/tstaticprocparams.nim new file mode 100644 index 0000000000000..f0bb6fb5fd959 --- /dev/null +++ b/tests/statictypes/tstaticprocparams.nim @@ -0,0 +1,9 @@ +proc consumer[T: static proc(i: int): int{.nimcall.}](i: int): int = T(i) +proc addIt(i: int): int = i + i +proc squareIt(i: int): int = i * i + +assert consumer[addIt](10) == 20 +assert consumer[squareIt](30) == 900 +assert consumer[proc(i: int): int{.nimcall.} = i * i + i](10) == 110 + + From db603237c648a796ef7bff77641febd30b3999cd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Dec 2023 16:54:50 +0100 Subject: [PATCH 034/123] Types: Refactorings; step 1 (#23055) --- compiler/aliases.nim | 10 +- compiler/ast.nim | 76 ++++++++---- compiler/astalgo.nim | 2 +- compiler/ccgcalls.nim | 42 +++---- compiler/ccgexprs.nim | 49 ++++---- compiler/ccgreset.nim | 6 +- compiler/ccgtrav.nim | 8 +- compiler/ccgtypes.nim | 112 +++++++++--------- compiler/cgen.nim | 4 +- compiler/cgmeth.nim | 25 ++-- compiler/closureiters.nim | 6 +- compiler/concepts.nim | 6 +- compiler/enumtostr.nim | 2 +- compiler/evalffi.nim | 32 ++--- compiler/expanddefaults.nim | 16 +-- compiler/injectdestructors.nim | 4 +- compiler/isolation_check.nim | 8 +- compiler/jsgen.nim | 22 ++-- compiler/jstypes.nim | 16 +-- compiler/lambdalifting.nim | 9 +- compiler/liftdestructors.nim | 32 ++--- compiler/lowerings.nim | 6 +- compiler/magicsys.nim | 2 +- compiler/nilcheck.nim | 6 +- compiler/nimsets.nim | 2 +- compiler/nir/ast2ir.nim | 16 +-- compiler/nir/types2ir.nim | 22 ++-- compiler/plugins/itersgen.nim | 2 +- compiler/pragmas.nim | 6 +- compiler/renderer.nim | 2 +- compiler/sem.nim | 10 +- compiler/semcall.nim | 6 +- compiler/semdata.nim | 4 - compiler/semexprs.nim | 32 ++--- compiler/semfields.nim | 4 +- compiler/semfold.nim | 4 +- compiler/semmacrosanity.nim | 4 +- compiler/semmagic.nim | 15 ++- compiler/semobjconstr.nim | 8 +- compiler/sempass2.nim | 16 +-- compiler/semstmts.nim | 128 ++++++++++---------- compiler/semtempl.nim | 4 +- compiler/semtypes.nim | 28 ++--- compiler/semtypinst.nim | 20 ++-- compiler/sighashes.nim | 28 +++-- compiler/sigmatch.nim | 133 +++++++++++---------- compiler/sizealignoffsetimpl.nim | 64 +++++----- compiler/spawn.nim | 2 +- compiler/trees.nim | 2 +- compiler/typeallowed.nim | 44 +++---- compiler/types.nim | 193 ++++++++++++++++--------------- compiler/vm.nim | 16 +-- compiler/vmconv.nim | 3 +- compiler/vmdeps.nim | 24 ++-- compiler/vmgen.nim | 4 +- compiler/vmmarshal.nim | 16 +-- compiler/vtables.nim | 8 +- 57 files changed, 713 insertions(+), 658 deletions(-) diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 40d6e272c68fb..3910ecb9dc68d 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -51,12 +51,14 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = if compareTypes(a, b, dcEqIgnoreDistinct): return arYes case a.kind of tyObject: - if a[0] != nil: - result = isPartOfAux(a[0].skipTypes(skipPtrs), b, marker) + if a.baseClass != nil: + result = isPartOfAux(a.baseClass.skipTypes(skipPtrs), b, marker) if result == arNo: result = isPartOfAux(a.n, b, marker) of tyGenericInst, tyDistinct, tyAlias, tySink: - result = isPartOfAux(lastSon(a), b, marker) - of tyArray, tySet, tyTuple: + result = isPartOfAux(skipModifier(a), b, marker) + of tySet, tyArray: + result = isPartOfAux(a.elementType, b, marker) + of tyTuple: for i in 0.. 1: t.lastSon else: nil + if t.sons.len > 1: t.last else: nil when false: import tables, strutils @@ -1474,7 +1488,25 @@ proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode = result = newNode(kind) result.intVal = castToInt64(intVal) -proc lastSon*(n: Indexable): Indexable = n.sons[^1] +proc lastSon*(n: PNode): PNode {.inline.} = n.sons[^1] +proc last*(n: PType): PType {.inline.} = n.sons[^1] + +proc elementType*(n: PType): PType {.inline.} = n.sons[^1] +proc skipModifier*(n: PType): PType {.inline.} = n.sons[^1] + +proc indexType*(n: PType): PType {.inline.} = n.sons[0] +proc baseClass*(n: PType): PType {.inline.} = n.sons[0] + +proc base*(t: PType): PType {.inline.} = + result = t.sons[0] + +proc returnType*(n: PType): PType {.inline.} = n.sons[0] +proc setReturnType*(n, r: PType) {.inline.} = n.sons[0] = r +proc setIndexType*(n, idx: PType) {.inline.} = n.sons[0] = idx + +proc firstParamType*(n: PType): PType {.inline.} = n.sons[1] + +proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons[^1] proc skipTypes*(t: PType, kinds: TTypeKinds): PType = ## Used throughout the compiler code to test whether a type tree contains or @@ -1482,7 +1514,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType = ## last child nodes of a type tree need to be searched. This is a really hot ## path within the compiler! result = t - while result.kind in kinds: result = lastSon(result) + while result.kind in kinds: result = last(result) proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = let kind = skipTypes(typ, abstractVarRange).kind @@ -1557,8 +1589,9 @@ proc newType*(kind: TTypeKind, idgen: IdGenerator; owner: PSym, sons: seq[PType] echo "KNID ", kind writeStackTrace() -template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType = - newType(kind, id, owner, parent.sons) +when false: + template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType = + newType(kind, id, owner, parent.sons) proc setSons*(dest: PType; sons: seq[PType]) {.inline.} = dest.sons = sons @@ -1574,7 +1607,10 @@ proc mergeLoc(a: var TLoc, b: TLoc) = if a.lode == nil: a.lode = b.lode if a.r == "": a.r = b.r -proc newSons*(father: Indexable, length: int) = +proc newSons*(father: PNode, length: int) = + setLen(father.sons, length) + +proc newSons*(father: PType, length: int) = setLen(father.sons, length) proc assignType*(dest, src: PType) = @@ -1665,7 +1701,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType = result = t var i = maxIters while result.kind in kinds: - result = lastSon(result) + result = last(result) dec i if i == 0: return nil @@ -1674,7 +1710,7 @@ proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType = result = t while result != nil and result.kind in kinds: if result.len == 0: return nil - result = lastSon(result) + result = last(result) proc isGCedMem*(t: PType): bool {.inline.} = result = t.kind in {tyString, tyRef, tySequence} or @@ -2009,7 +2045,7 @@ proc toObject*(typ: PType): PType = ## cases should be a ``tyObject``). ## Otherwise ``typ`` is simply returned as-is. let t = typ.skipTypes({tyAlias, tyGenericInst}) - if t.kind == tyRef: t.lastSon + if t.kind == tyRef: t.last else: typ proc toObjectFromRefPtrGeneric*(typ: PType): PType = @@ -2026,7 +2062,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType = result = typ while true: case result.kind - of tyGenericBody: result = result.lastSon + of tyGenericBody: result = result.last of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0] # automatic dereferencing is deep, refs #18298. else: break diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index cd772f0f142ed..9b3a42ebe0f67 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -43,7 +43,7 @@ proc typekinds*(t: PType) {.deprecated.} = while t != nil and t.len > 0: s.add $t.kind s.add " " - t = t.lastSon + t = t.last echo s template debug*(x: PSym|PType|PNode) {.deprecated.} = diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index ad84be3f9ed8e..c2887f00ae623 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -83,13 +83,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, var pl = callee & "(" & params # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) - if typ[0] != nil: + if typ.returnType != nil: if isInvalidReturnType(p.config, typ): if params.len != 0: pl.add(", ") # beware of 'result = p(result)'. We may need to allocate a temporary: if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): # Great, we can use 'd': - if d.k == locNone: d = getTemp(p, typ[0], needsInit=true) + if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true) elif d.k notin {locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: discard "resetLoc(p, d)" @@ -97,7 +97,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl.add(");\n") line(p, cpsStmts, pl) else: - var tmp: TLoc = getTemp(p, typ[0], needsInit=true) + var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true) pl.add(addrLoc(p.config, tmp)) pl.add(");\n") line(p, cpsStmts, pl) @@ -115,23 +115,23 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, excl d.flags, lfSingleUse else: if d.k == locNone and p.splitDecls == 0: - d = getTempCpp(p, typ[0], pl) + d = getTempCpp(p, typ.returnType, pl) else: - if d.k == locNone: d = getTemp(p, typ[0]) + if d.k == locNone: d = getTemp(p, typ.returnType) var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) elif isHarmlessStore(p, canRaise, d): - if d.k == locNone: d = getTemp(p, typ[0]) + if d.k == locNone: d = getTemp(p, typ.returnType) assert(d.t != nil) # generate an assignment to d: var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: - var tmp: TLoc = getTemp(p, typ[0], needsInit=true) + var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true) var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, tmp, list, {}) # no need for deep copying @@ -248,7 +248,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = of tyArray: result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] of tyPtr, tyRef: - case lastSon(a.t).kind + case elementType(a.t).kind of tyString, tySequence: var t: TLoc t.r = "(*$1)" % [a.rdLoc] @@ -256,7 +256,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = [a.rdLoc, lenExpr(p, t), dataField(p), dataFieldAccessor(p, "*" & a.rdLoc)] of tyArray: - result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] + result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, elementType(a.t)))] else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) @@ -287,7 +287,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n[0] openArrayLoc(p, param.typ, n, result) - elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and + elif ccgIntroducedPtr(p.config, param, call[0].typ.returnType) and (optByRef notin param.options or not p.module.compileToCpp): a = initLocExpr(p, n) if n.kind in {nkCharLit..nkNilLit}: @@ -457,14 +457,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = let rawProc = getClosureType(p.module, typ, clHalf) let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0]) - if typ[0] != nil: + if typ.returnType != nil: if isInvalidReturnType(p.config, typ): if ri.len > 1: pl.add(", ") # beware of 'result = p(result)'. We may need to allocate a temporary: if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): # Great, we can use 'd': if d.k == locNone: - d = getTemp(p, typ[0], needsInit=true) + d = getTemp(p, typ.returnType, needsInit=true) elif d.k notin {locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: discard "resetLoc(p, d)" @@ -472,13 +472,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genCallPattern() if canRaise: raiseExit(p) else: - var tmp: TLoc = getTemp(p, typ[0], needsInit=true) + var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true) pl.add(addrLoc(p.config, tmp)) genCallPattern() if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) # no need for deep copying elif isHarmlessStore(p, canRaise, d): - if d.k == locNone: d = getTemp(p, typ[0]) + if d.k == locNone: d = getTemp(p, typ.returnType) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, d.lode, OnUnknown) if tfIterator in typ.flags: @@ -488,7 +488,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: - var tmp: TLoc = getTemp(p, typ[0]) + var tmp: TLoc = getTemp(p, typ.returnType) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, d.lode, OnUnknown) if tfIterator in typ.flags: @@ -685,7 +685,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = genPatternCall(p, ri, pat, typ, pl) # simpler version of 'fixupCall' that works with the pl+params combination: var typ = skipTypes(ri[0].typ, abstractInst) - if typ[0] != nil: + if typ.returnType != nil: if p.module.compileToCpp and lfSingleUse in d.flags: # do not generate spurious temporaries for C++! For C we're better off # with them to prevent undefined behaviour and because the codegen @@ -694,7 +694,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = d.r = pl excl d.flags, lfSingleUse else: - if d.k == locNone: d = getTemp(p, typ[0]) + if d.k == locNone: d = getTemp(p, typ.returnType) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, d.lode, OnUnknown) list.r = pl @@ -752,26 +752,26 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add(param.name.s) pl.add(": ") genArg(p, ri[i], param, ri, pl) - if typ[0] != nil: + if typ.returnType != nil: if isInvalidReturnType(p.config, typ): if ri.len > 1: pl.add(" ") # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: # We already got a temp. Great, special case it: - if d.k == locNone: d = getTemp(p, typ[0], needsInit=true) + if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true) pl.add("Result: ") pl.add(addrLoc(p.config, d)) pl.add("];\n") line(p, cpsStmts, pl) else: - var tmp: TLoc = getTemp(p, typ[0], needsInit=true) + var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true) pl.add(addrLoc(p.config, tmp)) pl.add("];\n") line(p, cpsStmts, pl) genAssignment(p, d, tmp, {}) # no need for deep copying else: pl.add("]") - if d.k == locNone: d = getTemp(p, typ[0]) + if d.k == locNone: d = getTemp(p, typ.returnType) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, ri, OnUnknown) list.r = pl diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2612c5c12172b..75039809229b9 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -748,7 +748,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = var a: TLoc var typ = e[0].typ if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: - typ = typ.lastSon + typ = typ.last typ = typ.skipTypes(abstractInstOwned) if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: d = initLocExprSingleUse(p, e[0][0]) @@ -853,7 +853,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var a: TLoc = default(TLoc) if p.module.compileToCpp and e.kind == nkDotExpr and e[1].kind == nkSym and e[1].typ.kind == tyPtr: # special case for C++: we need to pull the type of the field as member and friends require the complete type. - let typ = e[1].typ[0] + let typ = e[1].typ.elementType if typ.itemId in p.module.g.graph.memberProcsPerType: discard getTypeDesc(p.module, typ) @@ -1082,7 +1082,8 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var b = initLocExpr(p, y) var ty = skipTypes(a.t, abstractVarRange) if ty.kind in {tyRef, tyPtr}: - ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: + ty = skipTypes(ty.elementType, abstractVarRange) + # emit range check: if optBoundsCheck in p.options: linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2){ #raiseIndexError2($1,$2-1); ", @@ -1102,7 +1103,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = var ty = skipTypes(n[0].typ, abstractVarRange + tyUserTypeClasses) - if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) + if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.elementType, abstractVarRange) case ty.kind of tyUncheckedArray: genUncheckedArrayElem(p, n, n[0], n[1], d) of tyArray: genArrayElem(p, n, n[0], n[1], d) @@ -1362,7 +1363,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = var b: TLoc = initLoc(locExpr, a.lode, OnHeap) let refType = typ.skipTypes(abstractInstOwned) assert refType.kind == tyRef - let bt = refType.lastSon + let bt = refType.elementType if sizeExpr == "": sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)] @@ -1452,7 +1453,7 @@ proc genNewSeq(p: BProc, e: PNode) = let seqtype = skipTypes(e[1].typ, abstractVarRange) linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", [a.rdLoc, b.rdLoc, - getTypeDesc(p.module, seqtype.lastSon), + getTypeDesc(p.module, seqtype.elementType), getSeqPayloadType(p.module, seqtype)]) else: let lenIsZero = e[2].kind == nkIntLit and e[2].intVal == 0 @@ -1465,7 +1466,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = if optSeqDestructors in p.config.globalOptions: if d.k == locNone: d = getTemp(p, e.typ, needsInit=false) linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3));$n", - [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon), + [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.elementType), getSeqPayloadType(p.module, seqtype), ]) else: @@ -1544,7 +1545,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = r = rdLoc(tmp) if isRef: rawGenNew(p, tmp, "", needsInit = nfAllFieldsSet notin e.flags) - t = t.lastSon.skipTypes(abstractInstOwned) + t = t.elementType.skipTypes(abstractInstOwned) r = "(*$1)" % [r] gcUsage(p.config, e) elif needsZeroMem: @@ -1590,7 +1591,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [rdLoc dest[], lit, getTypeDesc(p.module, seqtype.lastSon), + [rdLoc dest[], lit, getTypeDesc(p.module, seqtype.elementType), getSeqPayloadType(p.module, seqtype)]) else: # generate call to newSeq before adding the elements per hand: @@ -1623,7 +1624,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon), + [rdLoc d, L, getTypeDesc(p.module, seqtype.elementType), getSeqPayloadType(p.module, seqtype)]) else: var lit = newRopeAppender() @@ -1665,9 +1666,9 @@ proc genNewFinalize(p: BProc, e: PNode) = p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), - ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))]) + ti, getTypeDesc(p.module, skipTypes(refType.elementType, abstractRange))]) genAssignment(p, a, b, {}) # set the object type: - bt = skipTypes(refType.lastSon, abstractRange) + bt = skipTypes(refType.elementType, abstractRange) genObjectInit(p, cpsStmts, bt, a, constructRefObj) gcUsage(p.config, e) @@ -1699,12 +1700,12 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = if t.kind notin {tyVar, tyLent}: nilCheck = r if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: r = ropecg(p.module, "(*$1)", [r]) - t = skipTypes(t.lastSon, typedescInst+{tyOwned}) + t = skipTypes(t.elementType, typedescInst+{tyOwned}) discard getTypeDesc(p.module, t) if not p.module.compileToCpp: - while t.kind == tyObject and t[0] != nil: + while t.kind == tyObject and t.baseClass != nil: r.add(".Sup") - t = skipTypes(t[0], skipPtrs) + t = skipTypes(t.baseClass, skipPtrs) if isObjLackingTypeField(t): globalError(p.config, x.info, "no 'of' operator available for pure objects") @@ -1788,13 +1789,13 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; result: var Rope; enforceV1 if t.kind notin {tyVar, tyLent}: nilCheck = derefs if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: derefs = "(*$1)" % [derefs] - t = skipTypes(t.lastSon, abstractInst) + t = skipTypes(t.elementType, abstractInst) result.add derefs discard getTypeDesc(p.module, t) if not p.module.compileToCpp: - while t.kind == tyObject and t[0] != nil: + while t.kind == tyObject and t.baseClass != nil: result.add(".Sup") - t = skipTypes(t[0], skipPtrs) + t = skipTypes(t.baseClass, skipPtrs) result.add ".m_type" if optTinyRtti in p.config.globalOptions and enforceV1: result.add "->typeInfoV1" @@ -2355,7 +2356,7 @@ proc genDestroy(p: BProc; n: PNode) = linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & "}$n", - [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) + [rdLoc(a), getTypeDesc(p.module, t.elementType)]) else: discard "nothing to do" else: let t = n[1].typ.skipTypes(abstractVar) @@ -2366,7 +2367,7 @@ proc genDestroy(p: BProc; n: PNode) = proc genDispose(p: BProc; n: PNode) = when false: - let elemType = n[1].typ.skipTypes(abstractVar).lastSon + let elemType = n[1].typ.skipTypes(abstractVar).elementType var a: TLoc = initLocExpr(p, n[1].skipAddr) @@ -2381,7 +2382,7 @@ proc genDispose(p: BProc; n: PNode) = lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)]) proc genSlice(p: BProc; e: PNode; d: var TLoc) = - let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon, + let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.elementType, prepareForMutation = e[1].kind == nkHiddenDeref and e[1].typ.skipTypes(abstractInst).kind == tyString and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}) @@ -3199,9 +3200,9 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = result.add "}" of tyArray: result.add "{" - for i in 0.. 0: result.add ", " - getDefaultValue(p, t[1], info, result) + getDefaultValue(p, t.elementType, info, result) result.add "}" #result = rope"{}" of tyOpenArray, tyVarargs: @@ -3308,7 +3309,7 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool; result: var Rope) = proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) = result.add "{" if p.vccAndC and n.len == 0 and n.typ.kind == tyArray: - getDefaultValue(p, n.typ[1], n.info, result) + getDefaultValue(p, n.typ.elementType, n.info, result) for i in 0.. 0: result.add ",\n" diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index 47b6a1e15e7eb..da7f373988a70 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -54,13 +54,13 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = case typ.kind of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred, tySink, tyOwned: - specializeResetT(p, accessor, lastSon(typ)) + specializeResetT(p, accessor, skipModifier(typ)) of tyArray: - let arraySize = lengthOrd(p.config, typ[0]) + let arraySize = lengthOrd(p.config, typ.indexType) var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, arraySize]) - specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1]) + specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ.elementType) lineF(p, cpsStmts, "}$n", []) of tyObject: for i in 0.. 0 and typ.lastSon != nil: - var x = typ.lastSon + if typ.len > 0 and typ.last != nil: + var x = typ.last if typ.kind == tyObject: x = x.skipTypes(skipPtrs) if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x): base = rope("0") @@ -1439,22 +1439,20 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope; else: internalError(m.config, n.info, "genObjectFields") proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = - if typ.kind == tyObject: - if incompleteType(typ): - localError(m.config, info, "request for RTTI generation for incomplete object: " & - typeToString(typ)) - genTypeInfoAux(m, typ, origType, name, info) - else: - genTypeInfoAuxBase(m, typ, origType, name, rope("0"), info) + assert typ.kind == tyObject + if incompleteType(typ): + localError(m.config, info, "request for RTTI generation for incomplete object: " & + typeToString(typ)) + genTypeInfoAux(m, typ, origType, name, info) var tmp = getNimNode(m) if not isImportedType(typ): genObjectFields(m, typ, origType, typ.n, tmp, info) m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), tmp]) - var t = typ[0] + var t = typ.baseClass while t != nil: t = t.skipTypes(skipPtrs) t.flags.incl tfObjHasKids - t = t[0] + t = t.baseClass proc genTupleInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info) @@ -1520,14 +1518,14 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = m.s[cfsTypeInit3].addf("$1.flags = 1<<2;$n", [tiNameForHcr(m, name)]) proc genSetInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = - assert(typ[0] != nil) + assert(typ.elementType != nil) genTypeInfoAux(m, typ, typ, name, info) var tmp = getNimNode(m) m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n$3.node = &$1;$n", [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = - genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info) + genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ.elementType, info), info) proc fakeClosureType(m: BModule; owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] @@ -1596,14 +1594,14 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType n[paramsPos] = result.typ.n let body = newNodeI(nkStmtList, info) let castType = makePtrType(typ, idgen) - if theProc.typ[1].kind != tyVar: + if theProc.typ.firstParamType.kind != tyVar: body.add newTreeI(nkCall, info, newSymNode(theProc), newDeref(newTreeIT( nkCast, info, castType, newNodeIT(nkType, info, castType), newSymNode(dest) )) ) else: - let addrOf = newNodeIT(nkAddr, info, theProc.typ[1]) + let addrOf = newNodeIT(nkAddr, info, theProc.typ.firstParamType) addrOf.add newDeref(newTreeIT( nkCast, info, castType, newNodeIT(nkType, info, castType), newSymNode(dest) @@ -1731,7 +1729,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin m.s[cfsTypeInit3].add typeEntry - if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: + if t.kind == tyObject and t.len > 0 and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = @@ -1781,7 +1779,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn addf(typeEntry, ", .flags = $1};$n", [rope(flags)]) m.s[cfsVars].add typeEntry - if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: + if t.kind == tyObject and t.len > 0 and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope = @@ -1827,7 +1825,7 @@ proc openArrayToTuple(m: BModule; t: PType): PType = result = newType(tyTuple, m.idgen, t.owner) let p = newType(tyPtr, m.idgen, t.owner) let a = newType(tyUncheckedArray, m.idgen, t.owner) - a.add t.lastSon + a.add t.elementType p.add a result.add p result.add getSysType(m.g.graph, t.owner.info, tyInt) @@ -1909,11 +1907,11 @@ proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope = of tyPointer, tyBool, tyChar, tyCstring, tyString, tyInt..tyUInt64, tyVar, tyLent: genTypeInfoAuxBase(m, t, t, result, rope"0", info) of tyStatic: - if t.n != nil: result = genTypeInfoV1(m, lastSon t, info) + if t.n != nil: result = genTypeInfoV1(m, skipModifier t, info) else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')') of tyUserTypeClasses: internalAssert m.config, t.isResolvedUserTypeClass - return genTypeInfoV1(m, t.lastSon, info) + return genTypeInfoV1(m, t.skipModifier, info) of tyProc: if t.callConv != ccClosure: genTypeInfoAuxBase(m, t, t, result, rope"0", info) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d22a6bdc2414f..b6456a7b8e65f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1171,7 +1171,7 @@ proc genProcAux*(m: BModule, prc: PSym) = let tmpInfo = prc.info discard freshLineInfo(p, prc.info) - if sfPure notin prc.flags and prc.typ[0] != nil: + if sfPure notin prc.flags and prc.typ.returnType != nil: if resultPos >= prc.ast.len: internalError(m.config, prc.info, "proc has no result symbol") let resNode = prc.ast[resultPos] @@ -1217,7 +1217,7 @@ proc genProcAux*(m: BModule, prc: PSym) = for i in 1.. resultPos: disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen) else: @@ -157,9 +157,10 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = var witness: PSym = nil - if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"): + if s.typ.firstParamType.owner.getModule != s.getModule and vtables in g.config.features and not + g.config.isDefined("nimInternalNonVtablesTesting"): localError(g.config, s.info, errGenerated, "method `" & s.name.s & - "` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")") + "` can be defined only in the same module with its type (" & s.typ.firstParamType.typeToString() & ")") for i in 0.. 0: - result = searchObjCase(t[0].skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field) + result = searchObjCase(t.baseClass.skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field) doAssert result != nil proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index ab26ca1bbeabd..9cbf931cdff86 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -99,7 +99,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil: result = addr libffi.type_pointer of tyDistinct, tyAlias, tySink: - result = mapType(conf, t[0]) + result = mapType(conf, t.skipModifier) else: result = nil # too risky: @@ -126,16 +126,16 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int = if v.kind in {nkNilLit, nkPtrLit}: result = sizeof(pointer) else: - result = sizeof(pointer) + packSize(conf, v[0], typ.lastSon) + result = sizeof(pointer) + packSize(conf, v[0], typ.elementType) of tyDistinct, tyGenericInst, tyAlias, tySink: - result = packSize(conf, v, typ[0]) + result = packSize(conf, v, typ.skipModifier) of tyArray: # consider: ptr array[0..1000_000, int] which is common for interfacing; # we use the real length here instead if v.kind in {nkNilLit, nkPtrLit}: result = sizeof(pointer) elif v.len != 0: - result = v.len * packSize(conf, v[0], typ[1]) + result = v.len * packSize(conf, v[0], typ.elementType) else: result = 0 else: @@ -234,19 +234,19 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) = packRecCheck = 0 globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ)) inc packRecCheck - pack(conf, v[0], typ.lastSon, res +! sizeof(pointer)) + pack(conf, v[0], typ.elementType, res +! sizeof(pointer)) dec packRecCheck awr(pointer, res +! sizeof(pointer)) of tyArray: - let baseSize = getSize(conf, typ[1]) + let baseSize = getSize(conf, typ.elementType) for i in 0.. 0: - result = expandDefault(t.lastSon, info) + result = expandDefault(t.skipModifier, info) else: result = newZero(t, info, nkEmpty) of tyFromExpr: @@ -100,16 +100,16 @@ proc expandDefault(t: PType; info: TLineInfo): PNode = result = newZero(t, info, nkBracket) let n = toInt64(lengthOrd(nil, t)) for i in 0.. 1 and op.typ[1].kind != tyVar: + if op.typ != nil and op.typ.len > 1 and op.typ.firstParamType.kind != tyVar: addrExp = dest else: addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) @@ -489,7 +489,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = proc isDangerousSeq(t: PType): bool {.inline.} = let t = t.skipTypes(abstractInst) - result = t.kind == tySequence and tfHasOwned notin t[0].flags + result = t.kind == tySequence and tfHasOwned notin t.elementType.flags proc containsConstSeq(n: PNode): bool = if n.kind == nkBracket and n.len > 0 and n.typ != nil and isDangerousSeq(n.typ): diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index b11d64a6b9dd3..08a2cc6045fbc 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -65,7 +65,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool = if result: break of tyArray, tySequence, tyDistinct, tyGenericInst, tyAlias, tyInferred, tySink, tyLent, tyOwned, tyRef: - result = canAlias(arg, ret.lastSon, marker) + result = canAlias(arg, ret.skipModifier, marker) of tyProc: result = ret.callConv == ccClosure else: @@ -119,11 +119,11 @@ proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult = if result != NotFound: return result case t.kind of tyObject: - if t[0] != nil: - result = containsDangerousRefAux(t[0].skipTypes(skipPtrs), marker) + if t.baseClass != nil: + result = containsDangerousRefAux(t.baseClass.skipTypes(skipPtrs), marker) if result == NotFound: result = containsDangerousRefAux(t.n, marker) of tyGenericInst, tyDistinct, tyAlias, tySink: - result = containsDangerousRefAux(lastSon(t), marker) + result = containsDangerousRefAux(skipModifier(t), marker) of tyArray, tySet, tyTuple, tySequence: for i in 0.. 0 and t[0] != nil: - fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y) + if t.len > 0 and t.baseClass != nil: + fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, x, y) fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false) proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = @@ -302,7 +302,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result.add newSymNode(op) if sfNeverRaises notin op.flags: c.canRaise = true - if op.typ[1].kind == tyVar: + if op.typ.firstParamType.kind == tyVar: result.add genAddr(c, x) else: result.add x @@ -317,7 +317,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result.add boolLit(c.g, y.info, true) proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = - result = newNodeIT(nkCall, x.info, op.typ[0]) + result = newNodeIT(nkCall, x.info, op.typ.returnType) result.add(newSymNode(op)) result.add x if sfNeverRaises notin op.flags: @@ -545,7 +545,7 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = let counterIdx = body.len let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t))) let whileLoop = genWhileLoop(c, i, x) - let elemType = t.lastSon + let elemType = t.elementType let b = if c.kind == attachedTrace: y else: y.at(i, elemType) fillBody(c, elemType, whileLoop[1], x.at(i, elemType), b) if whileLoop[1].len > 0: @@ -656,7 +656,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc cyclicType*(g: ModuleGraph, t: PType): bool = case t.kind - of tyRef: result = types.canFormAcycle(g, t.lastSon) + of tyRef: result = types.canFormAcycle(g, t.elementType) of tyProc: result = t.callConv == ccClosure else: result = false @@ -681,7 +681,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ]# var actions = newNodeI(nkStmtList, c.info) - let elemType = t.lastSon + let elemType = t.elementType createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen) let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType) @@ -851,7 +851,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) - let elemType = t.lastSon + let elemType = t.skipModifier #fillBody(c, elemType, actions, genDeref(x), genDeref(y)) #var disposeCall = genBuiltin(c, mDispose, "dispose", x) @@ -1017,7 +1017,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = fillBodyObjT(c, t, body, x, y) of tyDistinct: if not considerUserDefinedOp(c, t, body, x, y): - fillBody(c, t[0], body, x, y) + fillBody(c, t.elementType, body, x, y) of tyTuple: fillBodyTup(c, t, body, x, y) of tyVarargs, tyOpenArray: @@ -1034,14 +1034,14 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = discard of tyOrdinal, tyRange, tyInferred, tyGenericInst, tyAlias, tySink: - fillBody(c, lastSon(t), body, x, y) + fillBody(c, skipModifier(t), body, x, y) of tyConcept, tyIterable: raiseAssert "unreachable" proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo; idgen: IdGenerator): PSym = assert typ.kind == tyDistinct - let baseType = typ[0] + let baseType = typ.elementType if getAttachedOp(g, baseType, kind) == nil: discard produceSym(g, c, baseType, kind, info, idgen) result = getAttachedOp(g, baseType, kind) @@ -1147,7 +1147,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; fn: result) let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym - let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest) + let d = if result.typ.firstParamType.kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest) let src = case kind of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) of attachedDup: newSymNode(result.typ.n[1].sym) @@ -1160,7 +1160,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; ## compiler can use a combination of `=destroy` and memCopy for sink op dest.flags.incl sfCursor let op = getAttachedOp(g, typ, attachedDestructor) - result.ast[bodyPos].add newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d) + result.ast[bodyPos].add newOpCall(a, op, if op.typ.firstParamType.kind == tyVar: d[0] else: d) result.ast[bodyPos].add newAsgnStmt(d, src) else: var tk: TTypeKind diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index f8ae67f411d9b..0ed4c436f38df 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -19,7 +19,7 @@ when defined(nimPreviewSlimSystem): import std/assertions proc newDeref*(n: PNode): PNode {.inline.} = - result = newNodeIT(nkHiddenDeref, n.info, n.typ[0]) + result = newNodeIT(nkHiddenDeref, n.info, n.typ.elementType) result.add n proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode = @@ -262,7 +262,7 @@ proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode = assert t.kind == tyObject field = lookupInRecord(t.n, b) if field != nil: break - t = t[0] + t = t.baseClass if t == nil: break t = t.skipTypes(skipPtrs) #if field == nil: @@ -286,7 +286,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): P assert t.kind == tyObject field = getSymFromList(t.n, bb) if field != nil: break - t = t[0] + t = t.baseClass if t == nil: break t = t.skipTypes(skipPtrs) #if field == nil: diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index b365a3a194772..1ec6b9a693b5b 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -35,7 +35,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy for r in systemModuleSyms(g, id): if r.magic == m: # prefer the tyInt variant: - if r.typ[0] != nil and r.typ[0].kind == tyInt: return r + if r.typ.returnType != nil and r.typ.returnType.kind == tyInt: return r result = r if result != nil: return result localError(g.config, info, "system module needs: " & name) diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 2a6de8733659c..6261c8fda9091 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -507,7 +507,7 @@ proc checkCall(n, ctx, map): Check = # as it might have been mutated # TODO similar for normal refs and fields: find dependent exprs: brackets - if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ[0].kind == tyRef: + if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ.elementType.kind == tyRef: if not isNew: result.map = newNilMap(map) isNew = true @@ -1367,7 +1367,7 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = continue map.store(context, context.index(child), typeNilability(child.typ), TArg, child.info, child) - map.store(context, resultExprIndex, if not s.typ[0].isNil and s.typ[0].kind == tyRef: Nil else: Safe, TResult, s.ast.info) + map.store(context, resultExprIndex, if not s.typ.returnType.isNil and s.typ.returnType.kind == tyRef: Nil else: Safe, TResult, s.ast.info) # echo "checking ", s.name.s, " ", filename @@ -1383,5 +1383,5 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = # (ANotNil, BNotNil) : # do we check on asgn nilability at all? - if not s.typ[0].isNil and s.typ[0].kind == tyRef and tfNotNil in s.typ[0].flags: + if not s.typ.returnType.isNil and s.typ.returnType.kind == tyRef and tfNotNil in s.typ.returnType.flags: checkResult(s.ast, context, res.map) diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 59a542a8582a9..7edf55278c27a 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -65,7 +65,7 @@ proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet = result = @[] var first: Int128 = Zero var j: Int128 = Zero - first = firstOrd(conf, s.typ[0]) + first = firstOrd(conf, s.typ.elementType) bitSetInit(result, int(getSize(conf, s.typ))) for i in 0.. 0: - result = typeToIr(c, g, t.lastSon) + result = typeToIr(c, g, t.skipModifier) else: result = TypeId(-1) of tyFromExpr: @@ -422,7 +422,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = cached(c, t): var n = toInt64(lengthOrd(c.conf, t)) if n <= 0: n = 1 # make an array of at least one element - let elemType = typeToIr(c, g, t[1]) + let elemType = typeToIr(c, g, t.elementType) let a = openType(g, ArrayTy) g.addType(elemType) g.addArrayLen n @@ -430,20 +430,20 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = result = finishType(g, a) of tyPtr, tyRef: cached(c, t): - let e = t.lastSon + let e = t.elementType if e.kind == tyUncheckedArray: - let elemType = typeToIr(c, g, e.lastSon) + let elemType = typeToIr(c, g, e.elementType) let a = openType(g, AArrayPtrTy) g.addType(elemType) result = finishType(g, a) else: - let elemType = typeToIr(c, g, t.lastSon) + let elemType = typeToIr(c, g, t.elementType) let a = openType(g, APtrTy) g.addType(elemType) result = finishType(g, a) of tyVar, tyLent: cached(c, t): - let e = t.lastSon + let e = t.elementType if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}: # skip the modifier, `var openArray` is a (ptr, len) pair too: result = typeToIr(c, g, e) @@ -510,7 +510,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = of tyUncheckedArray: # We already handled the `ptr UncheckedArray` in a special way. cached(c, t): - let elemType = typeToIr(c, g, t.lastSon) + let elemType = typeToIr(c, g, t.elementType) let a = openType(g, LastArrayTy) g.addType(elemType) result = finishType(g, a) diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index c5e9dc853471c..e2c97bdc57a08 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -25,7 +25,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode = return let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst}) - if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject: + if t.kind notin {tyRef, tyPtr} or t.elementType.kind != tyObject: localError(c.config, n[2].info, "type must be a non-generic ref|ptr to object with state field") return diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 35b4d63c28806..001af6ae7fec8 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -145,9 +145,9 @@ proc pragmaEnsures(c: PContext, n: PNode) = else: openScope(c) let o = getCurrOwner(c) - if o.kind in routineKinds and o.typ != nil and o.typ[0] != nil: + if o.kind in routineKinds and o.typ != nil and o.typ.returnType != nil: var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info) - s.typ = o.typ[0] + s.typ = o.typ.returnType incl(s.flags, sfUsed) addDecl(c, s) n[1] = c.semExpr(c, n[1]) @@ -1011,7 +1011,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, # Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode! if c.config.exc != excQuirky: incl(sym.flags, sfNoReturn) - if sym.typ[0] != nil: + if sym.typ.returnType != nil: localError(c.config, sym.ast[paramsPos][0].info, ".noreturn with return type not allowed") of wNoDestroy: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 2a586386bd477..bc1cbd65e908d 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -366,7 +366,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = result = t while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}: - result = lastSon(result) + result = skipModifier(result) result = "" let typ = n.typ.skip diff --git a/compiler/sem.nim b/compiler/sem.nim index 03e59975375c6..d63fa56c914d1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -196,8 +196,8 @@ proc commonType*(c: PContext; x, y: PType): PType = k = a.kind if b.kind != a.kind: return x # bug #7601, array construction of ptr generic - a = a.lastSon.skipTypes({tyGenericInst}) - b = b.lastSon.skipTypes({tyGenericInst}) + a = a.elementType.skipTypes({tyGenericInst}) + b = b.elementType.skipTypes({tyGenericInst}) if a.kind == tyObject and b.kind == tyObject: result = commonSuperclass(a, b) # this will trigger an error later: @@ -498,15 +498,15 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, c.friendModules.add(s.owner.getModule) result = macroResult resetSemFlag result - if s.typ[0] == nil: + if s.typ.returnType == nil: result = semStmt(c, result, flags) else: - var retType = s.typ[0] + var retType = s.typ.returnType if retType.kind == tyTypeDesc and tfUnresolved in retType.flags and retType.len == 1: # bug #11941: template fails(T: type X, v: auto): T # does not mean we expect a tyTypeDesc. - retType = retType[0] + retType = retType.skipModifier case retType.kind of tyUntyped, tyAnything: # Not expecting a type here allows templates like in ``tmodulealias.in``. diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 26a40b4dcea71..6904e6bbce18f 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -680,7 +680,7 @@ proc semResolvedCall(c: PContext, x: var TCandidate, result = x.call instGenericConvertersSons(c, result, x) result[0] = newSymNode(finalCallee, getCallLineInfo(result[0])) - result.typ = finalCallee.typ[0] + result.typ = finalCallee.typ.returnType updateDefaultParams(result) proc canDeref(n: PNode): bool {.inline.} = @@ -821,7 +821,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS ]# t = skipTypes(param.typ, desiredTypes) isDistinct = t.kind == tyDistinct or param.typ.kind == tyDistinct - if t.kind == tyGenericInvocation and t[0].lastSon.kind == tyDistinct: + if t.kind == tyGenericInvocation and t[0].last.kind == tyDistinct: result.state = bsGeneric return if isDistinct: hasDistinct = true @@ -840,7 +840,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS if resolved != nil: result.s = resolved[0].sym result.state = bsMatch - if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct, {IgnoreFlags}): + if not compareTypes(result.s.typ.returnType, fn.typ.returnType, dcEqIgnoreDistinct, {IgnoreFlags}): result.state = bsReturnNotMatch elif result.s.magic in {mArrPut, mArrGet}: # cannot borrow these magics for now diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b1ffbec4965ec..e56cfc944399b 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -446,10 +446,6 @@ proc newTypeWithSons*(c: PContext, kind: TTypeKind, sons: seq[PType]): PType = result = newType(kind, c.idgen, getCurrOwner(c), sons = sons) -proc newTypeWithSons*(c: PContext, kind: TTypeKind, - parent: PType): PType = - result = newType(kind, c.idgen, getCurrOwner(c), parent = parent) - proc makeStaticExpr*(c: PContext, n: PNode): PNode = result = newNodeI(nkStaticExpr, n.info) result.sons = @[n] diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 82ff000a74a10..d20ac92caee7a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -196,19 +196,19 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = var d = skipTypes(targetTyp, abstractVar) var s = srcTyp if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass: - s = s.lastSon + s = s.last s = skipTypes(s, abstractVar-{tyTypeDesc, tyOwned}) if s.kind == tyOwned and d.kind != tyOwned: - s = s.lastSon + s = s.skipModifier var pointers = 0 while (d != nil) and (d.kind in {tyPtr, tyRef, tyOwned}): if s.kind == tyOwned and d.kind != tyOwned: - s = s.lastSon + s = s.skipModifier elif d.kind != s.kind: break else: - d = d.lastSon - s = s.lastSon + d = d.elementType + s = s.elementType inc pointers let targetBaseTyp = skipTypes(targetTyp, abstractVarRange) @@ -442,7 +442,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = of tySequence, tyString, tyCstring, tyOpenArray, tyVarargs: n.typ = getSysType(c.graph, n.info, tyInt) of tyArray: - n.typ = typ[0] # indextype + n.typ = typ.indexType if n.typ.kind == tyRange and emptyRange(n.typ.n[0], n.typ.n[1]): #Invalid range n.typ = getSysType(c.graph, n.info, tyInt) of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64: @@ -640,7 +640,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType = else: var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) addSonSkipIntLit(typ, t, c.idgen) - typ[0] = makeRangeType(c, 0, n.len - 1, n.info) + typ.setIndexType makeRangeType(c, 0, n.len - 1, n.info) result = typ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = @@ -713,7 +713,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp addSonSkipIntLit(result.typ, typ, c.idgen) for i in 0.. 0: - createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) + createTypeBoundOps(tracked, n[1].typ.elementType, n.info) createTypeBoundOps(tracked, n[1].typ, n.info) # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? @@ -1322,7 +1322,7 @@ proc track(tracked: PEffects, n: PNode) = if tracked.owner.kind != skMacro: # XXX n.typ can be nil in runnableExamples, we need to do something about it. if n.typ != nil and n.typ.skipTypes(abstractInst).kind == tyRef: - createTypeBoundOps(tracked, n.typ.lastSon, n.info) + createTypeBoundOps(tracked, n.typ.elementType, n.info) createTypeBoundOps(tracked, n.typ, n.info) of nkTupleConstr: for i in 0.. 0 and not isException(typ.lastSon): + if typ.len > 0 and not isException(typ.elementType): localError(c.config, n.info, "raised object of type $1 does not inherit from Exception" % typeToString(typ)) proc addGenericParamListToScope(c: PContext, n: PNode) = @@ -1401,7 +1401,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) = if t.base.kind == tyGenericParam: return true return traverseSubTypes(c, t.base) of tyDistinct, tyAlias, tySink, tyOwned: - return traverseSubTypes(c, t.lastSon) + return traverseSubTypes(c, t.skipModifier) of tyGenericInst: internalAssert c.config, false else: @@ -1466,7 +1466,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # possibilities such as instantiating C++ generic types with # garbage collected Nim types. if sfImportc in s.flags: - var body = s.typ.lastSon + var body = s.typ.last if body.kind == tyObject: # erases all declared fields body.n.sons = @[] @@ -1509,11 +1509,11 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = aa[0].kind == nkObjectTy: # give anonymous object a dummy symbol: var st = s.typ - if st.kind == tyGenericBody: st = st.lastSon + if st.kind == tyGenericBody: st = st.typeBodyImpl internalAssert c.config, st.kind in {tyPtr, tyRef} - internalAssert c.config, st.lastSon.sym == nil + internalAssert c.config, st.last.sym == nil incl st.flags, tfRefsAnonObj - let objTy = st.lastSon + let objTy = st.last # add flags for `ref object` etc to underlying `object` incl(objTy.flags, oldFlags) # {.inheritable, final.} is already disallowed, but @@ -1526,12 +1526,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = let symNode = newSymNode(obj) obj.ast = a.shallowCopy case a[0].kind - of nkSym: obj.ast[0] = symNode - of nkPragmaExpr: - obj.ast[0] = a[0].shallowCopy - obj.ast[0][0] = symNode - obj.ast[0][1] = a[0][1] - else: assert(false) + of nkSym: obj.ast[0] = symNode + of nkPragmaExpr: + obj.ast[0] = a[0].shallowCopy + obj.ast[0][0] = symNode + obj.ast[0][1] = a[0][1] + else: assert(false) obj.ast[1] = a[1] obj.ast[2] = a[2][0] if sfPure in s.flags: @@ -1682,25 +1682,25 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = # search for the correct alias: var (b, state) = searchForBorrowProc(c, c.currentScope.parent, s) case state - of bsMatch: - # store the alias: - n[bodyPos] = newSymNode(b) - # Carry over the original symbol magic, this is necessary in order to ensure - # the semantic pass is correct - s.magic = b.magic - if b.typ != nil and b.typ.len > 0: - s.typ.n[0] = b.typ.n[0] - s.typ.flags = b.typ.flags - of bsNoDistinct: - localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless") - of bsReturnNotMatch: - localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ[0])) - of bsGeneric: - localError(c.config, n.info, "borrow with generic parameter is not supported") - of bsNotSupported: - localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s) - else: - localError(c.config, n.info, errNoSymbolToBorrowFromFound) + of bsMatch: + # store the alias: + n[bodyPos] = newSymNode(b) + # Carry over the original symbol magic, this is necessary in order to ensure + # the semantic pass is correct + s.magic = b.magic + if b.typ != nil and b.typ.len > 0: + s.typ.n[0] = b.typ.n[0] + s.typ.flags = b.typ.flags + of bsNoDistinct: + localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless") + of bsReturnNotMatch: + localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ.returnType)) + of bsGeneric: + localError(c.config, n.info, "borrow with generic parameter is not supported") + of bsNotSupported: + localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s) + else: + localError(c.config, n.info, errNoSymbolToBorrowFromFound) proc swapResult(n: PNode, sRes: PSym, dNode: PNode) = ## Swap nodes that are (skResult) symbols to d(estination)Node. @@ -1813,8 +1813,8 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = pushOwner(c, s) addParams(c, params, skProc) pushProcCon(c, s) - addResult(c, n, n.typ[0], skProc) - s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], n.typ[0])) + addResult(c, n, n.typ.returnType, skProc) + s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], n.typ.returnType)) trackProc(c, s, s.ast[bodyPos]) popProcCon(c) popOwner(c) @@ -1844,8 +1844,8 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) = if s.kind == skMacro: let resultType = sysTypeFromName(c.graph, n.info, "NimNode") addResult(c, n, resultType, s.kind) - elif s.typ[0] != nil and not isInlineIterator(s.typ): - addResult(c, n, s.typ[0], s.kind) + elif s.typ.returnType != nil and not isInlineIterator(s.typ): + addResult(c, n, s.typ.returnType, s.kind) proc canonType(c: PContext, t: PType): PType = if t.kind == tySequence: @@ -1864,7 +1864,7 @@ proc prevDestructor(c: PContext; prevOp: PSym; obj: PType; info: TLineInfo) = proc whereToBindTypeHook(c: PContext; t: PType): PType = result = t while true: - if result.kind in {tyGenericBody, tyGenericInst}: result = result.lastSon + if result.kind in {tyGenericBody, tyGenericInst}: result = result.skipModifier elif result.kind == tyGenericInvocation: result = result[0] else: break if result.kind in {tyObject, tyDistinct, tySequence, tyString}: @@ -1879,13 +1879,13 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = var obj = t[1] while true: incl(obj.flags, tfHasAsgn) - if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon + if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier elif obj.kind == tyGenericInvocation: obj = obj[0] else: break var res = t[0] while true: - if res.kind in {tyGenericBody, tyGenericInst}: res = res.lastSon + if res.kind in {tyGenericBody, tyGenericInst}: res = res.skipModifier elif res.kind == tyGenericInvocation: res = res[0] else: break @@ -1925,7 +1925,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressV var obj = t[1].skipTypes({tyVar}) while true: incl(obj.flags, tfHasAsgn) - if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon + if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier elif obj.kind == tyGenericInvocation: obj = obj[0] else: break if obj.kind in {tyObject, tyDistinct, tySequence, tyString}: @@ -1969,13 +1969,13 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = newIdentNode(c.cache.getIdent("raises"), s.info), newNodeI(nkBracket, s.info)) of "deepcopy", "=deepcopy": if s.typ.len == 2 and - s.typ[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and - sameType(s.typ[1], s.typ[0]): + s.typ.firstParamType.skipTypes(abstractInst).kind in {tyRef, tyPtr} and + sameType(s.typ.firstParamType, s.typ.returnType): # Note: we store the deepCopy in the base of the pointer to mitigate # the problem that pointers are structural types: - var t = s.typ[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst) + var t = s.typ.firstParamType.skipTypes(abstractInst).elementType.skipTypes(abstractInst) while true: - if t.kind == tyGenericBody: t = t.lastSon + if t.kind == tyGenericBody: t = t.typeBodyImpl elif t.kind == tyGenericInvocation: t = t[0] else: break if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}: @@ -2008,12 +2008,12 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = var obj = t[1][0] while true: incl(obj.flags, tfHasAsgn) - if obj.kind == tyGenericBody: obj = obj.lastSon + if obj.kind == tyGenericBody: obj = obj.skipModifier elif obj.kind == tyGenericInvocation: obj = obj[0] else: break var objB = t[2] while true: - if objB.kind == tyGenericBody: objB = objB.lastSon + if objB.kind == tyGenericBody: objB = objB.skipModifier elif objB.kind in {tyGenericInvocation, tyGenericInst}: objB = objB[0] else: break @@ -2087,15 +2087,15 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) = localError(c.config, n.info, pragmaName & " unsupported for generic routine") var typ: PType if isCtor: - typ = s.typ[0] + typ = s.typ.returnType if typ == nil or typ.kind != tyObject: localError(c.config, n.info, "constructor must return an object") if sfImportc in typ.sym.flags: localError(c.config, n.info, "constructor in an imported type needs importcpp pragma") else: - typ = s.typ[1] + typ = s.typ.firstParamType if typ.kind == tyPtr and not isCtor: - typ = typ[0] + typ = typ.elementType if typ.kind != tyObject: localError(c.config, n.info, pragmaName & " must be either ptr to object or object type.") if typ.owner.id == s.owner.id and c.module.id == s.owner.id: @@ -2106,7 +2106,7 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) = else: localError(c.config, n.info, pragmaName & " procs are only supported in C++") else: - var typ = s.typ[0] + var typ = s.typ.returnType if typ != nil and typ.kind == tyObject and typ.itemId notin c.graph.initializersPerType: var initializerCall = newTree(nkCall, newSymNode(s)) var isInitializer = n[paramsPos].len > 1 @@ -2360,8 +2360,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # absolutely no generics (empty) or a single generic return type are # allowed, everything else, including a nullary generic is an error. pushProcCon(c, s) - addResult(c, n, s.typ[0], skProc) - s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], s.typ[0])) + addResult(c, n, s.typ.returnType, skProc) + s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], s.typ.returnType)) trackProc(c, s, s.ast[bodyPos]) popProcCon(c) elif efOperand notin flags: @@ -2377,7 +2377,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if s.kind == skMacro: sysTypeFromName(c.graph, n.info, "NimNode") elif not isInlineIterator(s.typ): - s.typ[0] + s.typ.returnType else: nil # semantic checking also needed with importc in case used in VM @@ -2386,7 +2386,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # context as it may even be evaluated in 'system.compiles': trackProc(c, s, s.ast[bodyPos]) else: - if (s.typ[0] != nil and s.kind != skIterator): + if (s.typ.returnType != nil and s.kind != skIterator): addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, s, n.info)) openScope(c) @@ -2401,7 +2401,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if hasProto: localError(c.config, n.info, errImplOfXexpected % proto.name.s) if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone: # this is a forward declaration and we're building the prototype - if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyAnything: + if s.kind in {skProc, skFunc} and s.typ.returnType != nil and s.typ.returnType.kind == tyAnything: localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations") incl(s.flags, sfForward) @@ -2483,9 +2483,9 @@ proc semMethod(c: PContext, n: PNode): PNode = # test case): let disp = getDispatcher(s) # auto return type? - if disp != nil and disp.typ[0] != nil and disp.typ[0].kind == tyUntyped: - let ret = s.typ[0] - disp.typ[0] = ret + if disp != nil and disp.typ.returnType != nil and disp.typ.returnType.kind == tyUntyped: + let ret = s.typ.returnType + disp.typ.setReturnType ret if disp.ast[resultPos].kind == nkSym: if isEmptyType(ret): disp.ast[resultPos] = c.graph.emptyNode else: disp.ast[resultPos].sym.typ = ret diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 3256b8d85783a..20c8f57bd4d30 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -657,7 +657,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # a template's parameters are not gensym'ed even if that was originally the # case as we determine whether it's a template parameter in the template # body by the absence of the sfGenSym flag: - let retType = s.typ[0] + let retType = s.typ.returnType if retType != nil and retType.kind != tyUntyped: allUntyped = false for i in 1.. 1: n[1].info else: n.info localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) result = makeRangeWithStaticExpr(c, e) @@ -412,7 +412,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = # 3 = length(array indx base) let indx = semArrayIndex(c, n[1]) var indxB = indx - if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = lastSon(indxB) + if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = skipModifier(indxB) if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and tfUnresolved notin indxB.flags: if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}: @@ -897,7 +897,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} = if result.kind == tyGenericInvocation: result = result[0] while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}: - result = lastSon(result) + result = skipModifier(result) proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int, obj: PType, n: PNode, isPartial = false, innerObj: PType = nil): bool = @@ -1013,7 +1013,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = addSonSkipIntLit(result, region, c.idgen) addSonSkipIntLit(result, t, c.idgen) if tfPartial in result.flags: - if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial) + if result.elementType.kind == tyObject: incl(result.elementType.flags, tfPartial) # if not isNilable: result.flags.incl tfNotNil case wrapperKind of tyOwned: @@ -1159,7 +1159,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, # like: type myseq = distinct seq. # Maybe there is another better place to associate # the seq type class with the seq identifier. - if paramType.kind == tySequence and paramType.lastSon.kind == tyNone: + if paramType.kind == tySequence and paramType.elementType.kind == tyNone: let typ = c.newTypeWithSons(tyBuiltInTypeClass, @[newTypeS(paramType.kind, c)]) result = addImplicitGeneric(c, typ, paramTypId, info, genericParams, paramName) @@ -1185,9 +1185,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, else: result.rawAddSon newTypeS(tyAnything, c) - if paramType.lastSon.kind == tyUserTypeClass: + if paramType.typeBodyImpl.kind == tyUserTypeClass: result.kind = tyUserTypeClassInst - result.rawAddSon paramType.lastSon + result.rawAddSon paramType.typeBodyImpl return addImplicitGeneric(c, result, paramTypId, info, genericParams, paramName) let x = instGenericContainer(c, paramType.sym.info, result, @@ -1199,7 +1199,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericInst: result = nil - if paramType.lastSon.kind == tyUserTypeClass: + if paramType.skipModifier.kind == tyUserTypeClass: var cp = copyType(paramType, c.idgen, getCurrOwner(c)) copyTypeProps(c.graph, c.idgen.module, cp, paramType) @@ -1211,9 +1211,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if lifted != nil: paramType[i] = lifted result = paramType - result.lastSon.shouldHaveMeta + result.last.shouldHaveMeta - let liftBody = recurse(paramType.lastSon, true) + let liftBody = recurse(paramType.skipModifier, true) if liftBody != nil: result = liftBody result.flags.incl tfHasMeta @@ -1232,7 +1232,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, # before one of its param types return - if body.lastSon.kind == tyUserTypeClass: + if body.last.kind == tyUserTypeClass: let expanded = instGenericContainer(c, info, paramType, allowMetaTypes = true) result = recurse(expanded, true) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index bb664c71fba60..b514cc8fa8fc8 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -18,20 +18,16 @@ when defined(nimPreviewSlimSystem): const tfInstClearedFlags = {tfHasMeta, tfUnresolved} proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = - if t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}: + if t.kind in {tyVar, tyLent} and t.elementType.kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) if t.kind in tyTypeClasses: discard - elif t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}: + elif t.kind in {tyVar, tyLent} and t.elementType.kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") elif computeSize(conf, t) == szIllegalRecursion or isTupleRecursive(t): localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") - when false: - if t.kind == tyObject and t[0] != nil: - if t[0].kind != tyObject or tfFinal in t[0].flags: - localError(info, errInheritanceOnlyWithNonFinalObjects) proc searchInstTypes*(g: ModuleGraph; key: PType): PType = result = nil @@ -61,7 +57,7 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType = proc cacheTypeInst(c: PContext; inst: PType) = let gt = inst[0] - let t = if gt.kind == tyGenericBody: gt.lastSon else: gt + let t = if gt.kind == tyGenericBody: gt.typeBodyImpl else: gt if t.kind in {tyStatic, tyError, tyGenericParam} + tyTypeClasses: return addToGenericCache(c, gt.sym, inst) @@ -418,7 +414,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = if body.kind == tyError: return - let bbody = lastSon body + let bbody = last body var newbody = replaceTypeVarsT(cl, bbody) cl.skipTypedesc = oldSkipTypedesc newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) @@ -449,11 +445,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # can come here for tyGenericInst too, see tests/metatype/ttypeor.nim # need to look into this issue later assert newbody.kind in {tyRef, tyPtr} - if newbody.lastSon.typeInst != nil: + if newbody.last.typeInst != nil: #internalError(cl.c.config, cl.info, "ref already has a 'typeInst' field") discard else: - newbody.lastSon.typeInst = result + newbody.last.typeInst = result # DESTROY: adding object|opt for opt[topttree.Tree] # sigmatch: Formal opt[=destroy.T] real opt[topttree.Tree] # adding myseq for myseq[system.int] @@ -554,7 +550,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = case t.kind of tyGenericInvocation: result = handleGenericInvocation(cl, t) - if result.lastSon.kind == tyUserTypeClass: + if result.last.kind == tyUserTypeClass: result.kind = tyUserTypeClassInst of tyGenericBody: @@ -617,7 +613,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = idTablePut(cl.localCache, t, result) for i in 1.. 0 and t[0] != nil: - hashType c, t[0], flags, conf - of tyRef, tyPtr, tyGenericBody, tyVar: + if t.len > 0 and t.baseClass != nil: + hashType c, t.baseClass, flags, conf + of tyRef, tyPtr, tyVar: c &= char(t.kind) if t.len > 0: - c.hashType t.lastSon, flags, conf + c.hashType t.elementType, flags, conf if tfVarIsPtr in t.flags: c &= ".varisptr" + of tyGenericBody: + c &= char(t.kind) + if t.len > 0: + c.hashType t.typeBodyImpl, flags, conf of tyFromExpr: c &= char(t.kind) c.hashTree(t.n, {}, conf) @@ -210,11 +214,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi if CoIgnoreRange notin flags: c &= char(t.kind) c.hashTree(t.n, {}, conf) - c.hashType(t[0], flags, conf) + c.hashType(t.elementType, flags, conf) of tyStatic: c &= char(t.kind) c.hashTree(t.n, {}, conf) - c.hashType(t[0], flags, conf) + c.hashType(t.skipModifier, flags, conf) of tyProc: c &= char(t.kind) c &= (if tfIterator in t.flags: "iterator " else: "proc ") @@ -226,7 +230,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi c &= ':' c.hashType(param.typ, flags, conf) c &= ',' - c.hashType(t[0], flags, conf) + c.hashType(t.returnType, flags, conf) else: for i in 0.. 0 and f[0].skipTypes({tyBuiltInTypeClass, tyOr}).kind == tyProc: - result = t.lastSon + result = t.skipModifier else: result = t else: @@ -468,13 +474,16 @@ proc getObjectTypeOrNil(f: PType): PType = result = nil else: result = getObjectTypeOrNil(f[0]) - of tyGenericBody, tyGenericInst: - result = getObjectTypeOrNil(f.lastSon) + of tyGenericInst: + result = getObjectTypeOrNil(f.skipModifier) + of tyGenericBody: + result = getObjectTypeOrNil(f.typeBodyImpl) + of tyUserTypeClass: if f.isResolvedUserTypeClass: result = f.base # ?? idk if this is right else: - result = f.lastSon + result = f.skipModifier of tyStatic, tyOwned, tyVar, tyLent, tySink: result = getObjectTypeOrNil(f.base) of tyInferred: @@ -483,7 +492,7 @@ proc getObjectTypeOrNil(f: PType): PType = of tyTyped, tyUntyped, tyFromExpr: result = nil of tyRange: - result = f.lastSon + result = f.elementType else: result = f @@ -528,13 +537,15 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = of tyRef: inc ptrs skipped = skippedRef - r = r.lastSon + r = r.elementType of tyPtr: inc ptrs skipped = skippedPtr - r = r.lastSon - of tyGenericBody, tyGenericInst, tyAlias, tySink, tyOwned: - r = r.lastSon + r = r.elementType + of tyGenericInst, tyAlias, tySink, tyOwned: + r = r.elementType + of tyGenericBody: + r = r.typeBodyImpl else: break if r.kind == tyObject and ptrs <= 1: result = r @@ -930,7 +941,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = else: discard elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil: - var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ) + var inferred = newTypeWithSons(c.c, tyStatic, @[lhs.typ.elementType]) inferred.n = newIntNode(nkIntLit, rhs) put(c, lhs.typ, inferred) if c.c.matchedConcept != nil: @@ -973,7 +984,7 @@ proc inferStaticsInRange(c: var TCandidate, doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete)) template subtypeCheck() = - if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in { + if result <= isSubrange and f.last.skipTypes(abstractInst).kind in { tyRef, tyPtr, tyVar, tyLent, tyOwned}: result = isNone @@ -1105,16 +1116,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # situation when nkDotExpr are rotated to nkDotCalls if aOrig.kind in {tyAlias, tySink}: - return typeRel(c, f, lastSon(aOrig), flags) + return typeRel(c, f, skipModifier(aOrig), flags) if a.kind == tyGenericInst and skipTypes(f, {tyStatic, tyVar, tyLent, tySink}).kind notin { tyGenericBody, tyGenericInvocation, tyGenericInst, tyGenericParam} + tyTypeClasses: - return typeRel(c, f, lastSon(a), flags) + return typeRel(c, f, skipModifier(a), flags) if a.isResolvedUserTypeClass: - return typeRel(c, f, a.lastSon, flags) + return typeRel(c, f, a.skipModifier, flags) template bindingRet(res) = if doBind: @@ -1161,7 +1172,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # seq[float] matches the first, but not the second # we must turn the problem around: # is number a subset of int? - return typeRel(c, a.lastSon, f.lastSon, flags) + return typeRel(c, a.elementType, f.elementType, flags) else: # negative type classes are essentially infinite, @@ -1248,12 +1259,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyArray: case a.kind of tyArray: - var fRange = f[0] - var aRange = a[0] + var fRange = f.indexType + var aRange = a.indexType if fRange.kind in {tyGenericParam, tyAnything}: var prev = PType(idTableGet(c.bindings, fRange)) if prev == nil: - put(c, fRange, a[0]) + put(c, fRange, a.indexType) fRange = a else: fRange = prev @@ -1261,7 +1272,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # This typeDesc rule is wrong, see bug #7331 let aa = a[1] #.skipTypes({tyTypeDesc}) - if f[0].kind != tyGenericParam and aa.kind == tyEmpty: + if f.indexType.kind != tyGenericParam and aa.kind == tyEmpty: result = isGeneric else: result = typeRel(c, ff, aa, flags) @@ -1287,7 +1298,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: discard of tyUncheckedArray: if a.kind == tyUncheckedArray: - result = typeRel(c, base(f), base(a), flags) + result = typeRel(c, elementType(f), elementType(a), flags) if result < isGeneric: result = isNone else: discard of tyOpenArray, tyVarargs: @@ -1295,7 +1306,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # handle varargs[typed]: if f.kind == tyVarargs: if tfVarargs in a.flags: - return typeRel(c, f.base, a.lastSon, flags) + return typeRel(c, f.base, a.elementType, flags) if f[0].kind == tyTyped: return template matchArrayOrSeq(aBase: PType) = @@ -1315,13 +1326,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = typeRel(c, base(f), base(a), flags) if result < isGeneric: result = isNone of tyArray: - if (f[0].kind != tyGenericParam) and (a[1].kind == tyEmpty): + if (f[0].kind != tyGenericParam) and (a.elementType.kind == tyEmpty): return isSubtype - matchArrayOrSeq(a[1]) + matchArrayOrSeq(a.elementType) of tySequence: - if (f[0].kind != tyGenericParam) and (a[0].kind == tyEmpty): + if (f[0].kind != tyGenericParam) and (a.elementType.kind == tyEmpty): return isConvertible - matchArrayOrSeq(a[0]) + matchArrayOrSeq(a.elementType) of tyString: if f.kind == tyOpenArray: if f[0].kind == tyChar: @@ -1333,11 +1344,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tySequence: case a.kind of tySequence: - if (f[0].kind != tyGenericParam) and (a[0].kind == tyEmpty): + if (f[0].kind != tyGenericParam) and (a.elementType.kind == tyEmpty): result = isSubtype else: let ff = f[0] - let aa = a[0] + let aa = a.elementType result = typeRel(c, ff, aa, flags) if result < isGeneric: if nimEnableCovariance and @@ -1351,7 +1362,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: discard of tyOrdinal: if isOrdinalType(a): - var x = if a.kind == tyOrdinal: a[0] else: a + var x = if a.kind == tyOrdinal: a.elementType else: a if f[0].kind == tyNone: result = isGeneric else: @@ -1409,7 +1420,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if a.len < f.len: return isNone for i in 0.. 0: - x = x.lastSon + x = x.last let concpt = f[0].skipTypes({tyGenericBody}) var preventHack = concpt.kind == tyConcept if x.kind == tyOwned and f[0].kind != tyOwned: preventHack = true - x = x.lastSon + x = x.last # XXX: This is very hacky. It should be moved back into liftTypeParam if x.kind in {tyGenericInst, tyArray} and c.calleeSym != nil and @@ -1613,7 +1624,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, var askip = skippedNone var fskip = skippedNone let aobj = x.skipToObject(askip) - let fobj = genericBody.lastSon.skipToObject(fskip) + let fobj = genericBody.last.skipToObject(fskip) result = typeRel(c, genericBody, x, flags) if result != isNone: # see tests/generics/tgeneric3.nim for an example that triggers this @@ -1723,7 +1734,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyUserTypeClassInst, tyUserTypeClass: if f.isResolvedUserTypeClass: - result = typeRel(c, f.lastSon, a, flags) + result = typeRel(c, f.last, a, flags) else: considerPreviousT: if aOrig == f: return isEqual @@ -1732,7 +1743,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, bindConcreteTypeToUserTypeClass(matched, a) if doBind: put(c, f, matched) result = isGeneric - elif a.len > 0 and a.lastSon == f: + elif a.len > 0 and a.last == f: # Needed for checking `Y` == `Addable` in the following #[ type @@ -1751,7 +1762,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyCompositeTypeClass: considerPreviousT: let roota = a.skipGenericAlias - let rootf = f.lastSon.skipGenericAlias + let rootf = f.last.skipGenericAlias if a.kind == tyGenericInst and roota.base == rootf.base: for i in 1.. 0: - aa = lastSon(aa) + aa = last(aa) if aa.kind in {tyGenericParam} + tyTypeClasses: # If the constraint is a genericParam or typeClass this isGeneric return isGeneric @@ -1859,7 +1870,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, elif f.base.kind == tyGenericParam: # Handling things like `type A[T; Y: static T] = object` if f.base.len > 0: # There is a constraint, handle it - result = typeRel(c, f.base.lastSon, a, flags) + result = typeRel(c, f.base.last, a, flags) else: # No constraint if tfGenericTypeParam in f.flags: @@ -1872,7 +1883,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if result != isNone: put(c, f, aOrig) elif aOrig.n != nil and aOrig.n.typ != nil: result = if f.base.kind != tyNone: - typeRel(c, f.lastSon, aOrig.n.typ, flags) + typeRel(c, f.last, aOrig.n.typ, flags) else: isGeneric if result != isNone: var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ]) @@ -1882,7 +1893,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNone elif prev.kind == tyStatic: if aOrig.kind == tyStatic: - result = typeRel(c, prev.lastSon, a, flags) + result = typeRel(c, prev.last, a, flags) if result != isNone and prev.n != nil: if not exprStructuralEquivalent(prev.n, aOrig.n): result = isNone @@ -2039,8 +2050,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, arg: PNode): PNode = result = nil for i in 0.. 1: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + if typ.len > 0: + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd of tyTypeClasses: if typ.isResolvedUserTypeClass: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd else: typ.size = szUnknownSize typ.align = szUnknownSize @@ -439,10 +439,10 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = of tyStatic: if typ.n != nil: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd else: typ.size = szUnknownSize typ.align = szUnknownSize diff --git a/compiler/spawn.nim b/compiler/spawn.nim index bfcdd78ea9413..b140729a889b2 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -50,7 +50,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool = # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var' # for the stricter check and likewise we can skip 'seq' for a less # strict check: - if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon + if t.kind in {tyVar, tyLent, tySequence}: t = t.elementType result = not containsGarbageCollectedRef(t) proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator; owner: PSym; typ: PType; diff --git a/compiler/trees.nim b/compiler/trees.nim index e39cbafe61907..99b6a9d014f04 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -116,7 +116,7 @@ proc isDeepConstExpr*(n: PNode; preventInheritance = false): bool = let t = n.typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned}) if t.kind in {tyRef, tyPtr} or tfUnion in t.flags: return false if t.kind == tyObject: - if preventInheritance and t[0] != nil: + if preventInheritance and t.baseClass != nil: result = false elif isCaseObj(t.n): result = false diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 483e55bc9dbd8..e82de29f3092b 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -120,7 +120,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags: discard elif t.isResolvedUserTypeClass: - result = typeAllowedAux(marker, t.lastSon, kind, c, flags) + result = typeAllowedAux(marker, t.last, kind, c, flags) elif kind notin {skParam, skResult}: result = t of tyGenericBody, tyGenericParam, tyGenericInvocation, @@ -133,9 +133,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, of tyOrdinal: if kind != skParam: result = t of tyGenericInst, tyDistinct, tyAlias, tyInferred: - result = typeAllowedAux(marker, lastSon(t), kind, c, flags) + result = typeAllowedAux(marker, skipModifier(t), kind, c, flags) of tyRange: - if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin + if skipTypes(t.elementType, abstractInst-{tyTypeDesc}).kind notin {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64, tyRange}: result = t of tyOpenArray: # you cannot nest openArrays/sinks/etc. @@ -151,39 +151,39 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray}) of tySink: # you cannot nest openArrays/sinks/etc. - if kind != skParam or taIsOpenArray in flags or t[0].kind in {tySink, tyLent, tyVar}: + if kind != skParam or taIsOpenArray in flags or t.elementType.kind in {tySink, tyLent, tyVar}: result = t else: - result = typeAllowedAux(marker, t[0], kind, c, flags) + result = typeAllowedAux(marker, t.elementType, kind, c, flags) of tyUncheckedArray: if kind != skParam and taHeap notin flags: result = t else: - result = typeAllowedAux(marker, lastSon(t), kind, c, flags-{taHeap}) + result = typeAllowedAux(marker, elementType(t), kind, c, flags-{taHeap}) of tySequence: - if t[0].kind != tyEmpty: - result = typeAllowedAux(marker, t[0], kind, c, flags+{taHeap}) + if t.elementType.kind != tyEmpty: + result = typeAllowedAux(marker, t.elementType, kind, c, flags+{taHeap}) elif kind in {skVar, skLet}: result = t[0] of tyArray: - if t[1].kind == tyTypeDesc: - result = t[1] - elif t[1].kind != tyEmpty: - result = typeAllowedAux(marker, t[1], kind, c, flags) + if t.elementType.kind == tyTypeDesc: + result = t.elementType + elif t.elementType.kind != tyEmpty: + result = typeAllowedAux(marker, t.elementType, kind, c, flags) elif kind in {skVar, skLet}: - result = t[1] + result = t.elementType of tyRef: if kind == skConst and taIsDefaultField notin flags: result = t - else: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) + else: result = typeAllowedAux(marker, t.elementType, kind, c, flags+{taHeap}) of tyPtr: - result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) + result = typeAllowedAux(marker, t.elementType, kind, c, flags+{taHeap}) of tySet: for i in 0.. 0: - result = classifyViewTypeAux(marker, lastSon(t)) + result = classifyViewTypeAux(marker, skipModifier(t)) else: result = noView of tyTuple: @@ -262,8 +262,8 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind = result = noView if t.n != nil: result = classifyViewTypeNode(marker, t.n) - if t[0] != nil: - result.combine classifyViewTypeAux(marker, t[0]) + if t.baseClass != nil: + result.combine classifyViewTypeAux(marker, t.baseClass) else: # it doesn't matter what these types contain, 'ptr openArray' is not a # view type! @@ -281,7 +281,7 @@ proc directViewType*(t: PType): ViewTypeKind = of tyLent, tyOpenArray: result = immutableView of abstractInst-{tyTypeDesc}: - result = directViewType(t.lastSon) + result = directViewType(t.skipModifier) else: result = noView diff --git a/compiler/types.nim b/compiler/types.nim index f10d5aa862409..8166db6ae2c7a 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -65,9 +65,6 @@ proc addTypeDeclVerboseMaybe*(result: var string, conf: ConfigRef; typ: PType) = template `$`*(typ: PType): string = typeToString(typ) -proc base*(t: PType): PType = - result = t[0] - # ------------------- type iterator: ---------------------------------------- type TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop @@ -109,7 +106,7 @@ const typedescInst* = abstractInst + {tyTypeDesc, tyOwned, tyUserTypeClass} proc invalidGenericInst*(f: PType): bool = - result = f.kind == tyGenericInst and lastSon(f) == nil + result = f.kind == tyGenericInst and skipModifier(f) == nil proc isPureObject*(typ: PType): bool = var t = typ @@ -184,10 +181,10 @@ proc getProcHeader*(conf: ConfigRef; sym: PSym; prefer: TPreferedDesc = preferNa proc elemType*(t: PType): PType = assert(t != nil) case t.kind - of tyGenericInst, tyDistinct, tyAlias, tySink: result = elemType(lastSon(t)) - of tyArray: result = t[1] + of tyGenericInst, tyDistinct, tyAlias, tySink: result = elemType(skipModifier(t)) + of tyArray: result = t.elementType of tyError: result = t - else: result = t.lastSon + else: result = t.elementType assert(result != nil) proc enumHasHoles*(t: PType): bool = @@ -200,7 +197,7 @@ proc isOrdinalType*(t: PType, allowEnumWithHoles: bool = false): bool = baseKinds = {tyChar, tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyEnum} parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tySink, tyDistinct} result = (t.kind in baseKinds and (not t.enumHasHoles or allowEnumWithHoles)) or - (t.kind in parentKinds and isOrdinalType(t.lastSon, allowEnumWithHoles)) + (t.kind in parentKinds and isOrdinalType(t.skipModifier, allowEnumWithHoles)) proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, closure: RootRef): bool @@ -229,7 +226,7 @@ proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, if not containsOrIncl(marker, t.id): case t.kind of tyGenericInst, tyGenericBody, tyAlias, tySink, tyInferred: - result = iterOverTypeAux(marker, lastSon(t), iter, closure) + result = iterOverTypeAux(marker, skipModifier(t), iter, closure) else: for i in 0.. 0: result.add(", ") result.add(typeToString(t[i], preferTypeName)) result.add(']') of tyTypeDesc: - if t[0].kind == tyNone: result = "typedesc" - else: result = "typedesc[" & typeToString(t[0]) & "]" + if t.elementType.kind == tyNone: result = "typedesc" + else: result = "typedesc[" & typeToString(t.elementType) & "]" of tyStatic: if prefer == preferGenericArg and t.n != nil: result = t.n.renderTree else: - result = "static[" & (if t.len > 0: typeToString(t[0]) else: "") & "]" + result = "static[" & (if t.len > 0: typeToString(t.skipModifier) else: "") & "]" if t.n != nil: result.add "(" & renderTree(t.n) & ")" of tyUserTypeClass: if t.sym != nil and t.sym.owner != nil: - if t.isResolvedUserTypeClass: return typeToString(t.lastSon) + if t.isResolvedUserTypeClass: return typeToString(t.last) return t.sym.owner.name.s else: result = "" of tyBuiltInTypeClass: - result = case t.base.kind + result = + case t.base.kind of tyVar: "var" of tyRef: "ref" of tyPtr: "ptr" @@ -656,7 +654,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < t.len - 1: result.add(" or ") of tyNot: - result = "not " & typeToString(t[0]) + result = "not " & typeToString(t.elementType) of tyUntyped: #internalAssert t.len == 0 result = "untyped" @@ -668,43 +666,43 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyArray: result = "array" if t.len > 0: - if t[0].kind == tyRange: - result &= "[" & rangeToStr(t[0].n) & ", " & - typeToString(t[1]) & ']' + if t.indexType.kind == tyRange: + result &= "[" & rangeToStr(t.indexType.n) & ", " & + typeToString(t.elementType) & ']' else: - result &= "[" & typeToString(t[0]) & ", " & - typeToString(t[1]) & ']' + result &= "[" & typeToString(t.indexType) & ", " & + typeToString(t.elementType) & ']' of tyUncheckedArray: result = "UncheckedArray" if t.len > 0: - result &= "[" & typeToString(t[0]) & ']' + result &= "[" & typeToString(t.elementType) & ']' of tySequence: if t.sym != nil and prefer != preferResolved: result = t.sym.name.s else: result = "seq" if t.len > 0: - result &= "[" & typeToString(t[0]) & ']' + result &= "[" & typeToString(t.elementType) & ']' of tyOrdinal: result = "ordinal" if t.len > 0: - result &= "[" & typeToString(t[0]) & ']' + result &= "[" & typeToString(t.skipModifier) & ']' of tySet: result = "set" if t.len > 0: - result &= "[" & typeToString(t[0]) & ']' + result &= "[" & typeToString(t.elementType) & ']' of tyOpenArray: result = "openArray" if t.len > 0: - result &= "[" & typeToString(t[0]) & ']' + result &= "[" & typeToString(t.elementType) & ']' of tyDistinct: - result = "distinct " & typeToString(t[0], + result = "distinct " & typeToString(t.elementType, if prefer == preferModuleInfo: preferModuleInfo else: preferTypeName) of tyIterable: # xxx factor this pattern result = "iterable" if t.len > 0: - result &= "[" & typeToString(t[0]) & ']' + result &= "[" & typeToString(t.skipModifier) & ']' of tyTuple: # we iterate over t.sons here, because t.n may be nil if t.n != nil: @@ -734,13 +732,13 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < t.len - 1: result.add(", ") result.add ']' else: - result.add typeToString(t[0]) + result.add typeToString(t.elementType) of tyRange: result = "range " if t.n != nil and t.n.kind == nkRange: result.add rangeToStr(t.n) if prefer != preferExported: - result.add("(" & typeToString(t[0]) & ")") + result.add("(" & typeToString(t.elementType) & ")") of tyProc: result = if tfIterator in t.flags: "iterator " elif t.owner != nil: @@ -760,7 +758,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(typeToString(t[i])) if i < t.len - 1: result.add(", ") result.add(')') - if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0])) + if t.len > 0 and t.returnType != nil: result.add(": " & typeToString(t.returnType)) var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos: let pragmasNode = t.owner.ast[pragmasPos] @@ -778,11 +776,11 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = prag.add("gcsafe") if prag.len != 0: result.add("{." & prag & ".}") of tyVarargs: - result = typeToStr[t.kind] % typeToString(t[0]) + result = typeToStr[t.kind] % typeToString(t.elementType) of tySink: - result = "sink " & typeToString(t[0]) + result = "sink " & typeToString(t.skipModifier) of tyOwned: - result = "owned " & typeToString(t[0]) + result = "owned " & typeToString(t.elementType) else: result = typeToStr[t.kind] result.addTypeFlags(t) @@ -792,8 +790,8 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = case t.kind of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: result = Zero - of tySet, tyVar: result = firstOrd(conf, t[0]) - of tyArray: result = firstOrd(conf, t[0]) + of tySet, tyVar: result = firstOrd(conf, t.elementType) + of tyArray: result = firstOrd(conf, t.indexType) of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) @@ -815,8 +813,8 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = of tyUInt..tyUInt64: result = Zero of tyEnum: # if basetype <> nil then return firstOrd of basetype - if t.len > 0 and t[0] != nil: - result = firstOrd(conf, t[0]) + if t.len > 0 and t.baseClass != nil: + result = firstOrd(conf, t.baseClass) else: if t.n.len > 0: assert(t.n[0].kind == nkSym) @@ -824,10 +822,12 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = else: result = Zero of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses, tyLent: - result = firstOrd(conf, lastSon(t)) + tyStatic, tyInferred, tyLent: + result = firstOrd(conf, skipModifier(t)) + of tyUserTypeClasses: + result = firstOrd(conf, last(t)) of tyOrdinal: - if t.len > 0: result = firstOrd(conf, lastSon(t)) + if t.len > 0: result = firstOrd(conf, skipModifier(t)) else: result = Zero internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') @@ -844,10 +844,12 @@ proc firstFloat*(t: PType): BiggestFloat = assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) getFloatValue(t.n[0]) - of tyVar: firstFloat(t[0]) + of tyVar: firstFloat(t.elementType) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses: - firstFloat(lastSon(t)) + tyStatic, tyInferred: + firstFloat(skipModifier(t)) + of tyUserTypeClasses: + firstFloat(last(t)) else: internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')') NaN @@ -915,11 +917,13 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = else: result = Zero of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses, tyLent: - result = lastOrd(conf, lastSon(t)) + tyStatic, tyInferred, tyLent: + result = lastOrd(conf, skipModifier(t)) + of tyUserTypeClasses: + result = lastOrd(conf, last(t)) of tyProxy: result = Zero of tyOrdinal: - if t.len > 0: result = lastOrd(conf, lastSon(t)) + if t.len > 0: result = lastOrd(conf, skipModifier(t)) else: result = Zero internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') @@ -932,14 +936,16 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = proc lastFloat*(t: PType): BiggestFloat = case t.kind of tyFloat..tyFloat128: Inf - of tyVar: lastFloat(t[0]) + of tyVar: lastFloat(t.elementType) of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) getFloatValue(t.n[1]) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses: - lastFloat(lastSon(t)) + tyStatic, tyInferred: + lastFloat(skipModifier(t)) + of tyUserTypeClasses: + lastFloat(last(t)) else: internalError(newPartialConfigRef(), "invalid kind for lastFloat(" & $t.kind & ')') NaN @@ -953,17 +959,19 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool = of tyRange: x in firstFloat(t)..lastFloat(t) of tyVar: - floatRangeCheck(x, t[0]) + floatRangeCheck(x, t.elementType) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, - tyStatic, tyInferred, tyUserTypeClasses: - floatRangeCheck(x, lastSon(t)) + tyStatic, tyInferred: + floatRangeCheck(x, skipModifier(t)) + of tyUserTypeClasses: + floatRangeCheck(x, last(t)) else: internalError(newPartialConfigRef(), "invalid kind for floatRangeCheck:" & $t.kind) false proc lengthOrd*(conf: ConfigRef; t: PType): Int128 = if t.skipTypes(tyUserTypeClasses).kind == tyDistinct: - result = lengthOrd(conf, t[0]) + result = lengthOrd(conf, t.skipModifier) else: let last = lastOrd(conf, t) let first = firstOrd(conf, t) @@ -1191,17 +1199,17 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool = if not result: return proc isGenericAlias*(t: PType): bool = - return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst + return t.kind == tyGenericInst and t.skipModifier.kind == tyGenericInst proc genericAliasDepth*(t: PType): int = result = 0 var it = t while it.isGenericAlias: - it = it.lastSon + it = it.skipModifier inc result proc skipGenericAlias*(t: PType): PType = - return if t.isGenericAlias: t.lastSon else: t + return if t.isGenericAlias: t.skipModifier else: t proc sameFlags*(a, b: PType): bool {.inline.} = result = eqTypeFlags*a.flags == eqTypeFlags*b.flags @@ -1222,10 +1230,10 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if x == y: return true var a = skipTypes(x, {tyAlias}) while a.kind == tyUserTypeClass and tfResolved in a.flags: - a = skipTypes(a[^1], {tyAlias}) + a = skipTypes(a.last, {tyAlias}) var b = skipTypes(y, {tyAlias}) while b.kind == tyUserTypeClass and tfResolved in b.flags: - b = skipTypes(b[^1], {tyAlias}) + b = skipTypes(b.last, {tyAlias}) assert(a != nil) assert(b != nil) if a.kind != b.kind: @@ -1273,7 +1281,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b) if result and a.len == b.len and a.len == 1: cycleCheck() - result = sameTypeAux(a[0], b[0], c) + result = sameTypeAux(a.skipModifier, b.skipModifier, c) of tyObject: ifFastObjectTypeCheckFailed(a, b): cycleCheck() @@ -1283,9 +1291,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if c.cmp == dcEq: if sameFlags(a, b): ifFastObjectTypeCheckFailed(a, b): - result = sameTypeAux(a[0], b[0], c) + result = sameTypeAux(a.elementType, b.elementType, c) else: - result = sameTypeAux(a[0], b[0], c) and sameFlags(a, b) + result = sameTypeAux(a.elementType, b.elementType, c) and sameFlags(a, b) of tyEnum, tyForward: # XXX generic enums do not make much sense, but require structural checking result = a.id == b.id and sameFlags(a, b) @@ -1334,12 +1342,12 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n)) of tyRange: cycleCheck() - result = sameTypeOrNilAux(a[0], b[0], c) and + result = sameTypeOrNilAux(a.elementType, b.elementType, c) and sameValue(a.n[0], b.n[0]) and sameValue(a.n[1], b.n[1]) of tyGenericInst, tyAlias, tyInferred, tyIterable: cycleCheck() - result = sameTypeAux(a.lastSon, b.lastSon, c) + result = sameTypeAux(a.skipModifier, b.skipModifier, c) of tyNone: result = false of tyConcept: result = exprStructuralEquivalent(a.n, b.n) @@ -1374,14 +1382,14 @@ proc inheritanceDiff*(a, b: PType): int = while x != nil: x = skipTypes(x, skipPtrs) if sameObjectTypes(x, b): return - x = x[0] + x = x.baseClass dec(result) var y = b result = 0 while y != nil: y = skipTypes(y, skipPtrs) if sameObjectTypes(y, a): return - y = y[0] + y = y.baseClass inc(result) result = high(int) @@ -1399,7 +1407,7 @@ proc commonSuperclass*(a, b: PType): PType = while x != nil: x = skipTypes(x, skipPtrs) ancestors.incl(x.id) - x = x[0] + x = x.baseClass var y = b while y != nil: var t = y # bug #7818, save type before skip @@ -1408,7 +1416,7 @@ proc commonSuperclass*(a, b: PType): PType = # bug #7818, defer the previous skipTypes if t.kind != tyGenericInst: t = y return t - y = y[0] + y = y.baseClass proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], last: TTypeKind): bool = @@ -1429,7 +1437,7 @@ proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt = proc getReturnType*(s: PSym): PType = # Obtains the return type of a iterator/proc/macro/template assert s.kind in skProcKinds - result = s.typ[0] + result = s.typ.returnType proc getAlign*(conf: ConfigRef; typ: PType): BiggestInt = computeSizeAlign(conf, typ) @@ -1457,7 +1465,7 @@ proc containsGenericType*(t: PType): bool = proc baseOfDistinct*(t: PType; g: ModuleGraph; idgen: IdGenerator): PType = if t.kind == tyDistinct: - result = t[0] + result = t.elementType else: result = copyType(t, idgen, t.owner) copyTypeProps(g, idgen.module, result, t) @@ -1465,7 +1473,7 @@ proc baseOfDistinct*(t: PType; g: ModuleGraph; idgen: IdGenerator): PType = var it = result while it.kind in {tyPtr, tyRef, tyOwned}: parent = it - it = it.lastSon + it = it.elementType if it.kind == tyDistinct and parent != nil: parent[0] = it[0] @@ -1580,7 +1588,7 @@ proc safeSkipTypes*(t: PType, kinds: TTypeKinds): PType = result = t var seen = initIntSet() while result.kind in kinds and not containsOrIncl(seen, result.id): - result = lastSon(result) + result = skipModifier(result) type OrdinalType* = enum @@ -1629,10 +1637,9 @@ proc skipConvTakeType*(n: PNode): PNode = proc isEmptyContainer*(t: PType): bool = case t.kind of tyUntyped, tyNil: result = true - of tyArray: result = t[1].kind == tyEmpty - of tySet, tySequence, tyOpenArray, tyVarargs: - result = t[0].kind == tyEmpty - of tyGenericInst, tyAlias, tySink: result = isEmptyContainer(t.lastSon) + of tyArray, tySet, tySequence, tyOpenArray, tyVarargs: + result = t.elementType.kind == tyEmpty + of tyGenericInst, tyAlias, tySink: result = isEmptyContainer(t.skipModifier) else: result = false proc takeType*(formal, arg: PType; g: ModuleGraph; idgen: IdGenerator): PType = @@ -1784,9 +1791,11 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = cycleDetectorCopy = cycleDetector if isTupleRecursive(t[i], cycleDetectorCopy): return true - of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyLent, tySink, + of tyRef, tyPtr, tyVar, tyLent, tySink, tyArray, tyUncheckedArray, tySequence, tyDistinct: - return isTupleRecursive(t.lastSon, cycleDetector) + return isTupleRecursive(t.elementType, cycleDetector) + of tyAlias, tyGenericInst: + return isTupleRecursive(t.skipModifier, cycleDetector) else: return false @@ -1812,8 +1821,8 @@ proc isDefectException*(t: PType): bool = sfSystemModule in t.sym.owner.flags and t.sym.name.s == "Defect": return true - if t[0] == nil: break - t = skipTypes(t[0], abstractPtrs) + if t.baseClass == nil: break + t = skipTypes(t.baseClass, abstractPtrs) return false proc isDefectOrCatchableError*(t: PType): bool = @@ -1824,8 +1833,8 @@ proc isDefectOrCatchableError*(t: PType): bool = (t.sym.name.s == "Defect" or t.sym.name.s == "CatchableError"): return true - if t[0] == nil: break - t = skipTypes(t[0], abstractPtrs) + if t.baseClass == nil: break + t = skipTypes(t.baseClass, abstractPtrs) return false proc isSinkTypeForParam*(t: PType): bool = @@ -1847,19 +1856,19 @@ proc lookupFieldAgain*(ty: PType; field: PSym): PSym = assert(ty.kind in {tyTuple, tyObject}) result = lookupInRecord(ty.n, field.name) if result != nil: break - ty = ty[0] + ty = ty.baseClass if result == nil: result = field proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool = let t = t.skipTypes(abstractInst) if t.kind == tyPtr: - let pointsTo = t[0].skipTypes(abstractInst) + let pointsTo = t.elementType.skipTypes(abstractInst) case pointsTo.kind of tyUncheckedArray: - result = pointsTo[0].kind == tyChar + result = pointsTo.elementType.kind == tyChar of tyArray: - result = pointsTo[1].kind == tyChar and firstOrd(nil, pointsTo[0]) == 0 and - skipTypes(pointsTo[0], {tyRange}).kind in {tyInt..tyInt64} + result = pointsTo.elementType.kind == tyChar and firstOrd(nil, pointsTo.indexType) == 0 and + skipTypes(pointsTo.indexType, {tyRange}).kind in {tyInt..tyInt64} of tyChar: result = allowPointerToChar else: diff --git a/compiler/vm.nim b/compiler/vm.nim index 8824eca37dbf3..1584b289337bb 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -527,7 +527,7 @@ template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool = if nfIsPtr in node.flags or (typ != nil and typ.kind == tyPtr): assert node.kind == nkIntLit, $(node.kind) assert typ != nil - let typ2 = if typ.kind == tyPtr: typ[0] else: typ + let typ2 = if typ.kind == tyPtr: typ.elementType else: typ if not derefPtrToReg(node.intVal, typ2, reg, isAssign = isAssign2): # tyObject not supported in this context stackTrace(c, tos, pc, "deref unsupported ptr type: " & $(typeToString(typ), typ.kind)) @@ -1410,8 +1410,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = #echo "new pc ", newPc, " calling: ", prc.name.s var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) newSeq(newFrame.slots, prc.offset+ord(isClosure)) - if not isEmptyType(prc.typ[0]): - putIntoReg(newFrame.slots[0], getNullValue(prc.typ[0], prc.info, c.config)) + if not isEmptyType(prc.typ.returnType): + putIntoReg(newFrame.slots[0], getNullValue(prc.typ.returnType, prc.info, c.config)) for i in 1..rc-1: newFrame.slots[i] = regs[rb+i] if isClosure: @@ -1556,7 +1556,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].node.typ = typ newSeq(regs[ra].node.sons, count) for i in 0.. 0: typ = typ[0] + while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.skipModifier createStr regs[ra] regs[ra].node.strVal = typ.typeToString(preferExported) @@ -2293,8 +2293,8 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = newSeq(tos.slots, maxSlots) # setup parameters: - if not isEmptyType(sym.typ[0]) or sym.kind == skMacro: - putIntoReg(tos.slots[0], getNullValue(sym.typ[0], sym.info, c.config)) + if not isEmptyType(sym.typ.returnType) or sym.kind == skMacro: + putIntoReg(tos.slots[0], getNullValue(sym.typ.returnType, sym.info, c.config)) # XXX We could perform some type checking here. for i in 1.. 0 and t[0] != nil: - let b = skipTypes(t[0], skipPtrs) + if t != nil and t.len > 0 and t.baseClass != nil: + let b = skipTypes(t.baseClass, skipPtrs) getNullValueAux(b, b.n, result, conf, currPosition) case obj.kind of nkRecList: diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index 8ce1133691ef0..d80010877256a 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -98,17 +98,17 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; if i > 0: s.add(", ") if a[i].kind == nkRange: var x = copyNode(a[i][0]) - storeAny(s, t.lastSon, x, stored, conf) + storeAny(s, t.elementType, x, stored, conf) inc x.intVal while x.intVal <= a[i][1].intVal: s.add(", ") - storeAny(s, t.lastSon, x, stored, conf) + storeAny(s, t.elementType, x, stored, conf) inc x.intVal else: - storeAny(s, t.lastSon, a[i], stored, conf) + storeAny(s, t.elementType, a[i], stored, conf) s.add("]") of tyRange, tyGenericInst, tyAlias, tySink: - storeAny(s, t.lastSon, a, stored, conf) + storeAny(s, t.skipModifier, a, stored, conf) of tyEnum: # we need a slow linear search because of enums with holes: for e in items(t.n): @@ -127,7 +127,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; s.add("[") s.add($x.ptrToInt) s.add(", ") - storeAny(s, t.lastSon, a, stored, conf) + storeAny(s, t.elementType, a, stored, conf) s.add("]") of tyString, tyCstring: if a.kind == nkNilLit: s.add("null") @@ -245,7 +245,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkCurly) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.lastSon, tab, cache, conf, idgen) + result.add loadAny(p, t.elementType, tab, cache, conf, idgen) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") of tyPtr, tyRef: @@ -264,7 +264,7 @@ proc loadAny(p: var JsonParser, t: PType, if p.kind == jsonInt: let idx = p.getInt next(p) - result = loadAny(p, t.lastSon, tab, cache, conf, idgen) + result = loadAny(p, t.elementType, tab, cache, conf, idgen) tab[idx] = result else: raiseParseErr(p, "index for ref type expected") if p.kind == jsonArrayEnd: next(p) @@ -300,7 +300,7 @@ proc loadAny(p: var JsonParser, t: PType, result = nil raiseParseErr(p, "float expected") of tyRange, tyGenericInst, tyAlias, tySink: - result = loadAny(p, t.lastSon, tab, cache, conf, idgen) + result = loadAny(p, t.skipModifier, tab, cache, conf, idgen) else: result = nil internalError conf, "cannot marshal at compile-time " & t.typeToString diff --git a/compiler/vtables.nim b/compiler/vtables.nim index f57b59eaef9d1..eeacc7b47be3a 100644 --- a/compiler/vtables.nim +++ b/compiler/vtables.nim @@ -91,7 +91,7 @@ proc collectVTableDispatchers*(g: ModuleGraph) = if relevantCol(g.methods[bucket].methods, 1): incl(relevantCols, 1) sortBucket(g.methods[bucket].methods, relevantCols) let base = g.methods[bucket].methods[^1] - let baseType = base.typ[1].skipTypes(skipPtrs-{tyTypeDesc}) + let baseType = base.typ.firstParamType.skipTypes(skipPtrs-{tyTypeDesc}) if baseType.itemId in g.objectTree and not containGenerics(baseType, g.objectTree[baseType.itemId]): let methodIndexLen = g.bucketTable[baseType.itemId] if baseType.itemId notin itemTable: # once is enough @@ -114,7 +114,7 @@ proc collectVTableDispatchers*(g: ModuleGraph) = mIndex = rootItemIdCount[baseType.itemId] rootItemIdCount.inc(baseType.itemId) for idx in 0.. Date: Wed, 13 Dec 2023 01:16:34 +0000 Subject: [PATCH 035/123] Typrel whitespace (#23061) Just makes the case statements easier to look at when folded ```nim case foo of a: of b: of c: else: case bar: of a: of b: of c: of d: else: ``` to ```nim case foo of a: of b: of c: else: case bar: of a: of b: of c: of d: else: ``` --- compiler/sigmatch.nim | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index c52c90c7d8e27..1cfb630e3fc52 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1151,7 +1151,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if x == isNone: return isNone if x < result: result = x return result - of tyAnd: # XXX: deal with the current dual meaning of tyGenericParam c.typedescMatched = true @@ -1162,7 +1161,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if x != isNone: return if x >= isGeneric: isGeneric else: x return isNone - of tyIterable: if f.kind != tyIterable: return isNone of tyNot: @@ -1179,11 +1177,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # so only the `any` type class is their superset return if f.kind == tyAnything: isGeneric else: isNone - of tyAnything: if f.kind == tyAnything: return isGeneric else: return isNone - of tyUserTypeClass, tyUserTypeClassInst: if c.c.matchedConcept != nil and c.c.matchedConcept.depth <= 4: # consider this: 'var g: Node' *within* a concept where 'Node' @@ -1192,7 +1188,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let x = typeRel(c, a, f, flags + {trDontBind}) if x >= isGeneric: return isGeneric - of tyFromExpr: if c.c.inGenericContext > 0: # generic type bodies can sometimes compile call expressions @@ -1200,6 +1195,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # being passed as parameters return isNone else: discard + case f.kind of tyEnum: if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual @@ -1412,7 +1408,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, elif tfIsConstructor notin a.flags: # set constructors are a bit special... result = isNone - of tyPtr, tyRef: skipOwned(a) if a.kind == f.kind: @@ -1487,13 +1482,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, pointsTo[1].kind == tyChar: result = isConvertible else: discard - of tyEmpty, tyVoid: if a.kind == f.kind: result = isEqual - of tyAlias, tySink: result = typeRel(c, skipModifier(f), a, flags) - of tyIterable: if a.kind == tyIterable: if f.len == 1: @@ -1574,7 +1566,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = typeRel(c, last(origF), a, flags) if result != isNone and a.kind != tyNil: put(c, f, a) - of tyGenericBody: considerPreviousT: if a == f or a.kind == tyGenericInst and a.skipGenericAlias[0] == f: @@ -1582,7 +1573,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let ff = last(f) if ff != nil: result = typeRel(c, ff, a, flags) - of tyGenericInvocation: var x = a.skipGenericAlias if x.kind == tyGenericParam and x.len > 0: @@ -1677,7 +1667,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if x < result: result = x if result > isGeneric: result = isGeneric bindingRet result - of tyOr: considerPreviousT: result = isNone @@ -1695,7 +1684,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: result = isNone c.inheritancePenalty = oldInheritancePenalty + maxInheritance - of tyNot: considerPreviousT: for branch in f: @@ -1703,14 +1691,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return isNone bindingRet isGeneric - of tyAnything: considerPreviousT: var concrete = concreteType(c, a) if concrete != nil and doBind: put(c, f, concrete) return isGeneric - of tyBuiltInTypeClass: considerPreviousT: let target = f[0] @@ -1731,7 +1717,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return isGeneric else: return isNone - of tyUserTypeClassInst, tyUserTypeClass: if f.isResolvedUserTypeClass: result = typeRel(c, f.last, a, flags) @@ -1754,11 +1739,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isGeneric else: result = isNone - of tyConcept: result = if concepts.conceptMatch(c.c, f, a, c.bindings, nil): isGeneric else: isNone - of tyCompositeTypeClass: considerPreviousT: let roota = a.skipGenericAlias @@ -1775,7 +1758,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if result != isNone: put(c, f, a) result = isGeneric - of tyGenericParam: let doBindGP = doBind or trBindGenericParam in flags var x = PType(idTableGet(c.bindings, f)) @@ -1902,7 +1884,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # XXX endless recursion? #result = typeRel(c, prev, aOrig, flags) result = isNone - of tyInferred: let prev = f.previouslyInferred if prev != nil: @@ -1912,7 +1893,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if result != isNone: c.inferredTypes.add f f.add a - of tyTypeDesc: var prev = PType(idTableGet(c.bindings, f)) if prev == nil: @@ -1945,15 +1925,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = typeRel(c, prev.base, a.base, flags) else: result = isNone - of tyTyped: if aOrig != nil: put(c, f, aOrig) result = isGeneric - of tyProxy: result = isEqual - of tyFromExpr: # fix the expression, so it contains the already instantiated types if f.n == nil or f.n.kind == nkEmpty: return isGeneric From e51e98997ba0aae748ff51eea8133e83370a7df5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 Dec 2023 10:29:58 +0100 Subject: [PATCH 036/123] type refactoring: part 2 (#23059) --- compiler/ast.nim | 34 ++-- compiler/astmsgs.nim | 2 +- compiler/ccgcalls.nim | 2 +- compiler/ccgexprs.nim | 4 +- compiler/ccgtrav.nim | 8 +- compiler/ccgtypes.nim | 6 +- compiler/cgen.nim | 2 +- compiler/jstypes.nim | 2 +- compiler/lowerings.nim | 10 +- compiler/nir/ast2ir.nim | 4 +- compiler/nir/types2ir.nim | 8 +- compiler/pipelines.nim | 2 +- compiler/sem.nim | 2 +- compiler/semcall.nim | 6 +- compiler/semdata.nim | 44 ++--- compiler/semexprs.nim | 16 +- compiler/seminst.nim | 10 +- compiler/semmacrosanity.nim | 4 +- compiler/semmagic.nim | 24 ++- compiler/semobjconstr.nim | 2 +- compiler/semparallel.nim | 6 +- compiler/sempass2.nim | 24 +-- compiler/semstmts.nim | 54 +++--- compiler/semtypes.nim | 82 ++++----- compiler/semtypinst.nim | 26 +-- compiler/sigmatch.nim | 22 +-- compiler/spawn.nim | 8 +- compiler/suggest.nim | 24 +-- compiler/typeallowed.nim | 18 +- compiler/types.nim | 26 +-- compiler/varpartitions.nim | 4 +- compiler/vm.nim | 2 +- compiler/vmdeps.nim | 28 +-- compiler/vmgen.nim | 2 +- compiler/vtables.nim | 334 ++++++++++++++++++------------------ 35 files changed, 422 insertions(+), 430 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index ae38e55a5919c..ab46a02d6e707 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1505,9 +1505,12 @@ proc setReturnType*(n, r: PType) {.inline.} = n.sons[0] = r proc setIndexType*(n, idx: PType) {.inline.} = n.sons[0] = idx proc firstParamType*(n: PType): PType {.inline.} = n.sons[1] +proc firstGenericParam*(n: PType): PType {.inline.} = n.sons[1] proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons[^1] +proc genericHead*(n: PType): PType {.inline.} = n.sons[0] + proc skipTypes*(t: PType, kinds: TTypeKinds): PType = ## Used throughout the compiler code to test whether a type tree contains or ## doesn't contain a specific type/types - it is often the case that only the @@ -1579,26 +1582,19 @@ iterator items*(t: PType): PType = iterator pairs*(n: PType): tuple[i: int, n: PType] = for i in 0..` and ## returned. Otherwise ``typ`` is simply returned as-is. result = typ if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject: - result = newType(tyRef, idgen, typ.owner) - rawAddSon(result, typ) + result = newType(tyRef, idgen, typ.owner, typ) proc toObject*(typ: PType): PType = ## If ``typ`` is a tyRef then its immediate son is returned (which in many ## cases should be a ``tyObject``). ## Otherwise ``typ`` is simply returned as-is. let t = typ.skipTypes({tyAlias, tyGenericInst}) - if t.kind == tyRef: t.last + if t.kind == tyRef: t.elementType else: typ proc toObjectFromRefPtrGeneric*(typ: PType): PType = @@ -2075,11 +2069,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool = return false let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst}) - - if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}: - result = true - else: - result = false + result = base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {} proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs) diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim index a9027126a6c0f..c990b36e88def 100644 --- a/compiler/astmsgs.nim +++ b/compiler/astmsgs.nim @@ -5,7 +5,7 @@ import options, ast, msgs proc typSym*(t: PType): PSym = result = t.sym if result == nil and t.kind == tyGenericInst: # this might need to be refined - result = t[0].sym + result = t.genericHead.sym proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) = result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)] diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index c2887f00ae623..175100ff4571a 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -218,7 +218,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = for i in 0.. 0 and not isEmptyType(prc.typ[0]) and not isCompileTimeOnly(prc.typ[0]): + elif prc.typ.len > 0 and not isEmptyType(prc.typ.returnType) and not isCompileTimeOnly(prc.typ.returnType): # happens for procs without bodies: - let t = typeToIr(c.m, prc.typ[0]) + let t = typeToIr(c.m, prc.typ.returnType) let tmp = allocTemp(c, t) c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim index aa8bcc12f94b2..cdadc4f0d0eca 100644 --- a/compiler/nir/types2ir.nim +++ b/compiler/nir/types2ir.nim @@ -84,9 +84,9 @@ proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[I assert false, "unknown node kind: " & $n.kind proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = - if t[0] != nil: + if t.baseClass != nil: # ensure we emitted the base type: - discard typeToIr(c, g, t[0]) + discard typeToIr(c, g, t.baseClass) var unionId = 0 var fieldTypes = initTable[ItemId, TypeId]() @@ -96,8 +96,8 @@ proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = g.addSize c.conf.getSize(t) g.addAlign c.conf.getAlign(t) - if t[0] != nil: - g.addNominalType(ObjectTy, mangle(c, t[0])) + if t.baseClass != nil: + g.addNominalType(ObjectTy, mangle(c, t.baseClass)) else: g.addBuiltinType VoidId # object does not inherit if not lacksMTypeField(t): diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index 91f3428be759f..7f318d6f120fb 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -196,7 +196,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator if graph.dispatchers.len > 0: let ctx = preparePContext(graph, module, idgen) for disp in getDispatchers(graph): - let retTyp = disp.typ[0] + let retTyp = disp.typ.returnType if retTyp != nil: # TODO: properly semcheck the code of dispatcher? createTypeBoundOps(graph, ctx, retTyp, disp.ast.info, idgen) diff --git a/compiler/sem.nim b/compiler/sem.nim index d63fa56c914d1..47b9600f51ddb 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -548,7 +548,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, else: result = semExpr(c, result, flags, expectedType) result = fitNode(c, retType, result, result.info) - #globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0])) + #globalError(s.info, errInvalidParamKindX, typeToString(s.typ.returnType)) dec(c.config.evalTemplateCounter) discard c.friendModules.pop() diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 6904e6bbce18f..c9f407b12cc0d 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -518,7 +518,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) = let finalCallee = generateInstance(c, s, x.bindings, a.info) a[0].sym = finalCallee a[0].typ = finalCallee.typ - #a.typ = finalCallee.typ[0] + #a.typ = finalCallee.typ.returnType proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) = assert n.kind in nkCallKinds @@ -735,7 +735,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = if formal.kind == tyStatic and arg.kind != tyStatic: let evaluated = c.semTryConstExpr(c, n[i]) if evaluated != nil: - arg = newTypeS(tyStatic, c, sons = @[evaluated.typ]) + arg = newTypeS(tyStatic, c, son = evaluated.typ) arg.n = evaluated let tm = typeRel(m, formal, arg) if tm in {isNone, isConvertible}: return nil @@ -821,7 +821,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS ]# t = skipTypes(param.typ, desiredTypes) isDistinct = t.kind == tyDistinct or param.typ.kind == tyDistinct - if t.kind == tyGenericInvocation and t[0].last.kind == tyDistinct: + if t.kind == tyGenericInvocation and t.genericHead.last.kind == tyDistinct: result.state = bsGeneric return if isDistinct: hasDistinct = true diff --git a/compiler/semdata.nim b/compiler/semdata.nim index e56cfc944399b..c066e3a7b5b89 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -396,12 +396,11 @@ proc addToLib*(lib: PLib, sym: PSym) = # LocalError(sym.info, errInvalidPragma) sym.annex = lib -proc newTypeS*(kind: TTypeKind, c: PContext, sons: seq[PType] = @[]): PType = - result = newType(kind, c.idgen, getCurrOwner(c), sons = sons) +proc newTypeS*(kind: TTypeKind; c: PContext; son: sink PType = nil): PType = + result = newType(kind, c.idgen, getCurrOwner(c), son = son) proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType = - result = newType(tyPtr, idgen, owner) - addSonSkipIntLit(result, baseType, idgen) + result = newType(tyPtr, idgen, owner, skipIntLit(baseType, idgen)) proc makePtrType*(c: PContext, baseType: PType): PType = makePtrType(getCurrOwner(c), baseType, c.idgen) @@ -414,15 +413,13 @@ proc makeTypeWithModifier*(c: PContext, if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier: result = baseType else: - result = newTypeS(modifier, c) - addSonSkipIntLit(result, baseType, c.idgen) + result = newTypeS(modifier, c, skipIntLit(baseType, c.idgen)) proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType = if baseType.kind == kind: result = baseType else: - result = newTypeS(kind, c) - addSonSkipIntLit(result, baseType, c.idgen) + result = newTypeS(kind, c, skipIntLit(baseType, c.idgen)) proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = newTypeS(tyTypeDesc, c) @@ -438,31 +435,35 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType = assert n != nil result.n = n -proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]; - idgen: IdGenerator): PType = - result = newType(kind, idgen, owner, sons = sons) +when false: + proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]; + idgen: IdGenerator): PType = + result = newType(kind, idgen, owner, sons = sons) -proc newTypeWithSons*(c: PContext, kind: TTypeKind, - sons: seq[PType]): PType = - result = newType(kind, c.idgen, getCurrOwner(c), sons = sons) + proc newTypeWithSons*(c: PContext, kind: TTypeKind, + sons: seq[PType]): PType = + result = newType(kind, c.idgen, getCurrOwner(c), sons = sons) proc makeStaticExpr*(c: PContext, n: PNode): PNode = result = newNodeI(nkStaticExpr, n.info) result.sons = @[n] result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ - else: newTypeWithSons(c, tyStatic, @[n.typ]) + else: newTypeS(tyStatic, c, n.typ) proc makeAndType*(c: PContext, t1, t2: PType): PType = - result = newTypeS(tyAnd, c, sons = @[t1, t2]) + result = newTypeS(tyAnd, c) + result.rawAddSon t1 + result.rawAddSon t2 propagateToOwner(result, t1) propagateToOwner(result, t2) result.flags.incl((t1.flags + t2.flags) * {tfHasStatic}) result.flags.incl tfHasMeta proc makeOrType*(c: PContext, t1, t2: PType): PType = - if t1.kind != tyOr and t2.kind != tyOr: - result = newTypeS(tyOr, c, sons = @[t1, t2]) + result = newTypeS(tyOr, c) + result.rawAddSon t1 + result.rawAddSon t2 else: result = newTypeS(tyOr, c) template addOr(t1) = @@ -478,7 +479,7 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType = result.flags.incl tfHasMeta proc makeNotType*(c: PContext, t1: PType): PType = - result = newTypeS(tyNot, c, sons = @[t1]) + result = newTypeS(tyNot, c, son = t1) propagateToOwner(result, t1) result.flags.incl(t1.flags * {tfHasStatic}) result.flags.incl tfHasMeta @@ -489,7 +490,7 @@ proc nMinusOne(c: PContext; n: PNode): PNode = # Remember to fix the procs below this one when you make changes! proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType = let intType = getSysType(c.graph, n.info, tyInt) - result = newTypeS(tyRange, c, sons = @[intType]) + result = newTypeS(tyRange, c, son = intType) if n.typ != nil and n.typ.n == nil: result.flags.incl tfUnresolved result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType), @@ -549,9 +550,8 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = if typ.kind == tyTypeDesc and not isSelf(typ): result = typ else: - result = newTypeS(tyTypeDesc, c) + result = newTypeS(tyTypeDesc, c, skipIntLit(typ, c.idgen)) incl result.flags, tfCheckedForDestructor - result.addSonSkipIntLit(typ, c.idgen) proc symFromType*(c: PContext; t: PType, info: TLineInfo): PSym = if t.sym != nil: return t.sym diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d20ac92caee7a..c39bbc68310cf 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -345,7 +345,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType if targetType.kind in {tySink, tyLent} or isOwnedSym(c, n[0]): let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc}) - let t = newTypeS(targetType.kind, c, @[baseType]) + let t = newTypeS(targetType.kind, c, baseType) if targetType.kind == tyOwned: t.flags.incl tfHasOwned result = newNodeI(nkType, n.info) @@ -467,7 +467,7 @@ proc fixupStaticType(c: PContext, n: PNode) = # apply this measure only in code that is enlightened to work # with static types. if n.typ.kind != tyStatic: - n.typ = newTypeWithSons(getCurrOwner(c), tyStatic, @[n.typ], c.idgen) + n.typ = newTypeS(tyStatic, c, n.typ) n.typ.n = n # XXX: cycles like the one here look dangerous. # Consider using `n.copyTree` @@ -901,7 +901,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if n[i].typ.isNil or n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags: break maybeLabelAsStatic - n.typ = newTypeWithSons(c, tyStatic, @[n.typ]) + n.typ = newTypeS(tyStatic, c, n.typ) n.typ.flags.incl tfUnresolved # optimization pass: not necessary for correctness of the semantic pass @@ -1032,7 +1032,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy result = magicsAfterOverloadResolution(c, result, flags, expectedType) when false: if result.typ != nil and - not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty): + not (result.typ.kind == tySequence and result.elementType.kind == tyEmpty): liftTypeBoundOps(c, result.typ, n.info) #result = patchResolvedTypeBoundOp(c, result) if c.matchedConcept == nil: @@ -1263,7 +1263,7 @@ proc readTypeParameter(c: PContext, typ: PType, discard if typ.kind != tyUserTypeClass: - let ty = if typ.kind == tyCompositeTypeClass: typ[1].skipGenericAlias + let ty = if typ.kind == tyCompositeTypeClass: typ.firstGenericParam.skipGenericAlias else: typ.skipGenericAlias let tbody = ty[0] for s in 0.. 2 and operand2.kind == tyGenericParam): return traitCall ## too early to evaluate let s = trait.sym.name.s case s of "or", "|": - return typeWithSonsResult(tyOr, @[operand, operand2]) + return buildBinaryPredicate(tyOr, c, context, operand, operand2).toNode(traitCall.info) of "and": - return typeWithSonsResult(tyAnd, @[operand, operand2]) + return buildBinaryPredicate(tyAnd, c, context, operand, operand2).toNode(traitCall.info) of "not": - return typeWithSonsResult(tyNot, @[operand]) + return buildNotPredicate(c, context, operand).toNode(traitCall.info) of "typeToString": var prefer = preferTypeName if traitCall.len >= 2: @@ -532,7 +537,7 @@ proc semNewFinalize(c: PContext; n: PNode): PNode = result = addDefaultFieldForNew(c, n) proc semPrivateAccess(c: PContext, n: PNode): PNode = - let t = n[1].typ[0].toObjectFromRefPtrGeneric + let t = n[1].typ.elementType.toObjectFromRefPtrGeneric if t.kind == tyObject: assert t.sym != nil c.currentScope.allowPrivateAccess.add t.sym @@ -668,7 +673,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = semPrivateAccess(c, n) of mArrToSeq: result = n - if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty: + if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and + expectedType.kind == tySequence and result.typ.elementType.kind == tyEmpty: result.typ = expectedType # type inference for empty sequence # bug #21377 of mEnsureMove: result = n diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index ae254f45bf38d..96f7658df73d8 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -413,7 +413,7 @@ proc semConstructTypeAux(c: PContext, result.defaults.add defaults if status in {initPartial, initNone, initUnknown}: discard collectMissingFields(c, t.n, constrCtx, result.defaults) - let base = t[0] + let base = t.baseClass if base == nil or base.id == t.id or base.kind in {tyRef, tyPtr} and base.elementType.id == t.id: break diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index d5fc72760a907..e9ba04e8b4475 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -406,7 +406,7 @@ proc transformSlices(g: ModuleGraph; idgen: IdGenerator; n: PNode): PNode = if op.name.s == "[]" and op.fromSystem: result = copyNode(n) var typ = newType(tyOpenArray, idgen, result.typ.owner) - typ.add result.typ[0] + typ.add result.typ.elementType result.typ = typ let opSlice = newSymNode(createMagic(g, idgen, "slice", mSlice)) opSlice.typ = getSysType(g, n.info, tyInt) @@ -441,7 +441,7 @@ proc transformSpawn(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier: if result.isNil: result = newNodeI(nkStmtList, n.info) result.add n - let t = b[1][0].typ[0] + let t = b[1][0].typ.returnType if spawnResult(t, true) == srByVar: result.add wrapProcForSpawn(g, idgen, owner, m, b.typ, barrier, it[0]) it[^1] = newNodeI(nkEmpty, it.info) @@ -450,7 +450,7 @@ proc transformSpawn(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier: if result.isNil: result = n of nkAsgn, nkFastAsgn, nkSinkAsgn: let b = n[1] - if getMagic(b) == mSpawn and (let t = b[1][0].typ[0]; + if getMagic(b) == mSpawn and (let t = b[1][0].typ.returnType; spawnResult(t, true) == srByVar): let m = transformSlices(g, idgen, b) return wrapProcForSpawn(g, idgen, owner, m, b.typ, barrier, n[0]) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 448f4d26a131c..8fc2189559bf5 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -24,9 +24,6 @@ when defined(useDfa): import liftdestructors include sinkparameter_inference - -import std/options as opt - #[ Second semantic checking pass over the AST. Necessary because the old way had some inherent problems. Performs: @@ -94,29 +91,26 @@ const errXCannotBeAssignedTo = "'$1' cannot be assigned to" errLetNeedsInit = "'let' symbol requires an initialization" -proc getObjDepth(t: PType): Option[tuple[depth: int, root: ItemId]] = +proc getObjDepth(t: PType): (int, ItemId) = var x = t - var res: tuple[depth: int, root: ItemId] - res.depth = -1 + result = (-1, default(ItemId)) var stack = newSeq[ItemId]() while x != nil: x = skipTypes(x, skipPtrs) if x.kind != tyObject: - return none(tuple[depth: int, root: ItemId]) + return (-3, default(ItemId)) stack.add x.itemId - x = x[0] - inc(res.depth) - res.root = stack[^2] - result = some(res) + x = x.baseClass + inc(result[0]) + result[1] = stack[^2] proc collectObjectTree(graph: ModuleGraph, n: PNode) = for section in n: if section.kind == nkTypeDef and section[^1].kind in {nkObjectTy, nkRefTy, nkPtrTy}: let typ = section[^1].typ.skipTypes(skipPtrs) - if typ.len > 0 and typ[0] != nil: - let depthItem = getObjDepth(typ) - if isSome(depthItem): - let (depthLevel, root) = depthItem.unsafeGet + if typ.kind == tyObject and typ.baseClass != nil: + let (depthLevel, root) = getObjDepth(typ) + if depthLevel != -3: if depthLevel == 1: graph.objectTree[root] = @[] else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 3104f3158d7c9..22e863c5cf066 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1343,7 +1343,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = inc i proc checkCovariantParamsUsages(c: PContext; genericType: PType) = - var body = genericType[^1] + var body = genericType.typeBodyImpl proc traverseSubTypes(c: PContext; t: PType): bool = template error(msg) = localError(c.config, genericType.sym.info, msg) @@ -1360,7 +1360,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) = for field in t.n: subresult traverseSubTypes(c, field.typ) of tyArray: - return traverseSubTypes(c, t[1]) + return traverseSubTypes(c, t.elementType) of tyProc: for subType in t: if subType != nil: @@ -1368,9 +1368,9 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) = if result: error("non-invariant type param used in a proc type: " & $t) of tySequence: - return traverseSubTypes(c, t[0]) + return traverseSubTypes(c, t.elementType) of tyGenericInvocation: - let targetBody = t[0] + let targetBody = t.genericHead for i in 1..= 2 and t[0] == nil + t.len >= 2 and t.returnType == nil if cond: - var obj = t[1].skipTypes({tyVar}) + var obj = t.firstParamType.skipTypes({tyVar}) while true: incl(obj.flags, tfHasAsgn) if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier - elif obj.kind == tyGenericInvocation: obj = obj[0] + elif obj.kind == tyGenericInvocation: obj = obj.genericHead else: break if obj.kind in {tyObject, tyDistinct, tySequence, tyString}: - if (not suppressVarDestructorWarning) and op == attachedDestructor and t[1].kind == tyVar: + if (not suppressVarDestructorWarning) and op == attachedDestructor and t.firstParamType.kind == tyVar: message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter") obj = canonType(c, obj) let ao = getAttachedOp(c.graph, obj, op) @@ -1976,7 +1980,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = var t = s.typ.firstParamType.skipTypes(abstractInst).elementType.skipTypes(abstractInst) while true: if t.kind == tyGenericBody: t = t.typeBodyImpl - elif t.kind == tyGenericInvocation: t = t[0] + elif t.kind == tyGenericInvocation: t = t.genericHead else: break if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}: if getAttachedOp(c.graph, t, attachedDeepCopy).isNil: @@ -2004,18 +2008,18 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if name == "=": message(c.config, n.info, warnDeprecated, "Overriding `=` hook is deprecated; Override `=copy` hook instead") let t = s.typ - if t.len == 3 and t[0] == nil and t[1].kind == tyVar: - var obj = t[1][0] + if t.len == 3 and t.returnType == nil and t.firstParamType.kind == tyVar: + var obj = t.firstParamType.elementType while true: incl(obj.flags, tfHasAsgn) if obj.kind == tyGenericBody: obj = obj.skipModifier - elif obj.kind == tyGenericInvocation: obj = obj[0] + elif obj.kind == tyGenericInvocation: obj = obj.genericHead else: break var objB = t[2] while true: if objB.kind == tyGenericBody: objB = objB.skipModifier elif objB.kind in {tyGenericInvocation, tyGenericInst}: - objB = objB[0] + objB = objB.genericHead else: break if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB): # attach these ops to the canonical tySequence @@ -2132,7 +2136,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = for col in 1.. 0: - let bound = result.typ[0].sym + let bound = result.typ.elementType.sym if bound != nil: return bound return result if result.typ.sym == nil: @@ -2296,7 +2296,7 @@ proc processMagicType(c: PContext, m: PSym) = else: localError(c.config, m.info, errTypeExpected) proc semGenericConstraints(c: PContext, x: PType): PType = - result = newTypeWithSons(c, tyGenericParam, @[x]) + result = newTypeS(tyGenericParam, c, x) proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = @@ -2322,8 +2322,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = typ = semTypeNode(c, constraint, nil) if typ.kind != tyStatic or typ.len == 0: if typ.kind == tyTypeDesc: - if typ[0].kind == tyNone: - typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)]) + if typ.elementType.kind == tyNone: + typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c)) incl typ.flags, tfCheckedForDestructor else: typ = semGenericConstraints(c, typ) @@ -2332,7 +2332,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = def = semConstExpr(c, def) if typ == nil: if def.typ.kind != tyTypeDesc: - typ = newTypeWithSons(c, tyStatic, @[def.typ]) + typ = newTypeS(tyStatic, c, def.typ) else: # the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]`` # from manyloc/named_argument_bug/triengine: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index b514cc8fa8fc8..58d684a8fbdac 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -343,7 +343,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # tyGenericInvocation[A, tyGenericInvocation[A, B]] # is difficult to handle: - var body = t[0] + var body = t.genericHead if body.kind != tyGenericBody: internalError(cl.c.config, cl.info, "no generic body") var header = t @@ -379,7 +379,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = else: header = instCopyType(cl, t) - result = newType(tyGenericInst, cl.c.idgen, t[0].owner, sons = @[header[0]]) + result = newType(tyGenericInst, cl.c.idgen, t.genericHead.owner, son = header.genericHead) result.flags = header.flags # be careful not to propagate unnecessary flags here (don't use rawAddSon) # ugh need another pass for deeply recursive generic types (e.g. PActor) @@ -469,8 +469,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = proc eraseVoidParams*(t: PType) = # transform '(): void' into '()' because old parts of the compiler really # don't deal with '(): void': - if t[0] != nil and t[0].kind == tyVoid: - t[0] = nil + if t.returnType != nil and t.returnType.kind == tyVoid: + t.setReturnType nil for i in 1.. 0 and t[0].kind == tyObject and t[0].n != nil: - discard replaceObjBranches(cl, t[0].n) + if t.kind == tyRef and t.len > 0 and t.elementType.kind == tyObject and t.elementType.n != nil: + discard replaceObjBranches(cl, t.elementType.n) elif result.n != nil and t.kind == tyObject: # Invalidate the type size as we may alter its structure @@ -703,8 +703,8 @@ when false: popInfoContext(p.config) proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) = - if t != nil and t.len > 0 and t[0] != nil: - let b = skipTypes(t[0], skipPtrs) + if t != nil and t.len > 0 and t.baseClass != nil: + let b = skipTypes(t.baseClass, skipPtrs) recomputeFieldPositions(b, b.n, currPosition) case obj.kind of nkRecList: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 1cfb630e3fc52..38cc666372367 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -361,7 +361,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType = if c.isNoCall: result = t else: result = nil of tySequence, tySet: - if t[0].kind == tyEmpty: result = nil + if t.elementType.kind == tyEmpty: result = nil else: result = t of tyGenericParam, tyAnything, tyConcept: result = t @@ -512,7 +512,7 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int = while t != nil and not sameObjectTypes(f, t): if t.kind != tyObject: # avoid entering generic params etc return -1 - t = t[0] + t = t.baseClass if t == nil: break last = t t = skipTypes(t, skipPtrs) @@ -563,7 +563,7 @@ proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin # XXX sameObjectType can return false here. Need to investigate # why that is but sameObjectType does way too much work here anyway. while t != nil and r.sym != t.sym and askip == fskip: - t = t[0] + t = t.baseClass if t == nil: break last = t t = t.skipToObject(askip) @@ -787,7 +787,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = else: param = paramSym skType param.typ = if typ.isMetaType: - c.newTypeWithSons(tyInferred, @[typ]) + newTypeS(tyInferred, c, typ) else: makeTypeDesc(c, typ) @@ -941,7 +941,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = else: discard elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil: - var inferred = newTypeWithSons(c.c, tyStatic, @[lhs.typ.elementType]) + var inferred = newTypeS(tyStatic, c.c, lhs.typ.elementType) inferred.n = newIntNode(nkIntLit, rhs) put(c, lhs.typ, inferred) if c.c.matchedConcept != nil: @@ -1868,7 +1868,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, typeRel(c, f.last, aOrig.n.typ, flags) else: isGeneric if result != isNone: - var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ]) + var boundType = newTypeS(tyStatic, c.c, aOrig.n.typ) boundType.n = aOrig.n put(c, f, boundType) else: @@ -2004,7 +2004,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv") result.add c.graph.emptyNode if arg.typ != nil and arg.typ.kind == tyLent: - let a = newNodeIT(nkHiddenDeref, arg.info, arg.typ[0]) + let a = newNodeIT(nkHiddenDeref, arg.info, arg.typ.elementType) a.add arg result.add a else: @@ -2117,8 +2117,8 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) = of isNone: discard template matchesVoidProc(t: PType): bool = - (t.kind == tyProc and t.len == 1 and t[0] == nil) or - (t.kind == tyBuiltInTypeClass and t[0].kind == tyProc) + (t.kind == tyProc and t.len == 1 and t.returnType == nil) or + (t.kind == tyBuiltInTypeClass and t.elementType.kind == tyProc) proc paramTypesMatchAux(m: var TCandidate, f, a: PType, argSemantized, argOrig: PNode): PNode = @@ -2151,7 +2151,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, if evaluated != nil: # Don't build the type in-place because `evaluated` and `arg` may point # to the same object and we'd end up creating recursive types (#9255) - let typ = newTypeS(tyStatic, c, sons = @[evaluated.typ]) + let typ = newTypeS(tyStatic, c, son = evaluated.typ) typ.n = evaluated arg = copyTree(arg) # fix #12864 arg.typ = typ @@ -2456,7 +2456,7 @@ proc arrayConstr(c: PContext, info: TLineInfo): PType = proc incrIndexType(t: PType) = assert t.kind == tyArray - inc t[0].n[1].intVal + inc t.indexType.n[1].intVal template isVarargsUntyped(x): untyped = x.kind == tyVarargs and x[0].kind == tyUntyped diff --git a/compiler/spawn.nim b/compiler/spawn.nim index b140729a889b2..972d49d3e2c52 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -16,7 +16,7 @@ from trees import getMagic, getRoot proc callProc(a: PNode): PNode = result = newNodeI(nkCall, a.info) result.add a - result.typ = a.typ[0] + result.typ = a.typ.returnType # we have 4 cases to consider: # - a void proc --> nothing to do @@ -141,10 +141,10 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; if spawnKind == srByVar: body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) elif fv != nil: - let fk = flowVarKind(g.config, fv.typ[1]) + let fk = flowVarKind(g.config, fv.typ.firstGenericParam) if fk == fvInvalid: localError(g.config, f.info, "cannot create a flowVar of type: " & - typeToString(fv.typ[1])) + typeToString(fv.typ.firstGenericParam)) body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, if fk == fvGC: "data" else: "blob", fv.info, g.cache), call) if fk == fvGC: @@ -193,7 +193,7 @@ proc createCastExpr(argsParam: PSym; objType: PType; idgen: IdGenerator): PNode result.typ.rawAddSon(objType) template checkMagicProcs(g: ModuleGraph, n: PNode, formal: PNode) = - if (formal.typ.kind == tyVarargs and formal.typ[0].kind in {tyTyped, tyUntyped}) or + if (formal.typ.kind == tyVarargs and formal.typ.elementType.kind in {tyTyped, tyUntyped}) or formal.typ.kind in {tyTyped, tyUntyped}: localError(g.config, n.info, "'spawn'ed function cannot have a 'typed' or 'untyped' parameter") diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 802da1c3e3665..4f90fe00b29e4 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -327,7 +327,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = proc getQuality(s: PSym): range[0..100] = result = 100 if s.typ != nil and s.typ.len > 1: - var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) + var exp = s.typ.firstParamType.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: result = 50 @@ -396,17 +396,17 @@ proc suggestVar(c: PContext, n: PNode, outputs: var Suggestions) = wholeSymTab(nameFits(c, it, n), ideCon) proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = - if s.typ != nil and s.typ.len > 1 and s.typ[1] != nil: + if s.typ != nil and s.typ.len > 1 and s.typ.firstParamType != nil: # special rule: if system and some weird generic match via 'tyUntyped' # or 'tyGenericParam' we won't list it either to reduce the noise (nobody # wants 'system.`-|` as suggestion let m = s.getModule() if m != nil and sfSystemModule in m.flags: if s.kind == skType: return - var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) + var exp = s.typ.firstParamType.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return - result = sigmatch.argtypeMatches(c, s.typ[1], firstArg) + result = sigmatch.argtypeMatches(c, s.typ.firstParamType, firstArg) else: result = false @@ -476,13 +476,13 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) var t = typ while t != nil: suggestSymList(c, t.n, field, n.info, outputs) - t = t[0] + t = t.baseClass elif typ.kind == tyObject: var t = typ while true: suggestObject(c, t.n, field, n.info, outputs) - if t[0] == nil: break - t = skipTypes(t[0], skipPtrs) + if t.baseClass == nil: break + t = skipTypes(t.baseClass, skipPtrs) elif typ.kind == tyTuple and typ.n != nil: # All tuple fields are in scope # So go through each field and add it to the suggestions (If it passes the filter) @@ -761,11 +761,11 @@ proc suggestPragmas*(c: PContext, n: PNode) = # Now show suggestions for user pragmas for pragma in c.userPragmas: - var pm = default(PrefixMatch) - if filterSym(pragma, n, pm): - outputs &= symToSuggest(c.graph, pragma, isLocal=true, ideSug, info, - pragma.getQuality, pm, c.inTypeContext > 0, 0, - extractDocs=false) + var pm = default(PrefixMatch) + if filterSym(pragma, n, pm): + outputs &= symToSuggest(c.graph, pragma, isLocal=true, ideSug, info, + pragma.getQuality, pm, c.inTypeContext > 0, 0, + extractDocs=false) produceOutput(outputs, c.config) if outputs.len > 0: diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index e82de29f3092b..04dbc69c59a52 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -73,7 +73,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, elif isOutParam(t) and kind != skParam: result = t else: - var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc, tySink}) + var t2 = skipTypes(t.elementType, abstractInst-{tyTypeDesc, tySink}) case t2.kind of tyVar, tyLent: if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap @@ -99,8 +99,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, for i in 1.. 1: result.add(", ") result.add(typeToString(t[i], preferGenericArg)) result.add(']') of tyGenericBody: - result = typeToString(t.last) & '[' + result = typeToString(t.typeBodyImpl) & '[' for i in 0.. 0: result.add(", ") result.add(typeToString(t[i], preferTypeName)) @@ -881,8 +881,8 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = case t.kind of tyBool: result = toInt128(1'u) of tyChar: result = toInt128(255'u) - of tySet, tyVar: result = lastOrd(conf, t[0]) - of tyArray: result = lastOrd(conf, t[0]) + of tySet, tyVar: result = lastOrd(conf, t.elementType) + of tyArray: result = lastOrd(conf, t.indexType) of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) @@ -1810,8 +1810,8 @@ proc isException*(t: PType): bool = var t = t.skipTypes(abstractInst) while t.kind == tyObject: if t.sym != nil and t.sym.magic == mException: return true - if t[0] == nil: break - t = skipTypes(t[0], abstractPtrs) + if t.baseClass == nil: break + t = skipTypes(t.baseClass, abstractPtrs) return false proc isDefectException*(t: PType): bool = diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 957497bb62552..44d38ebffd567 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -407,8 +407,8 @@ proc allRoots(n: PNode; result: var seq[(PSym, int)]; level: int) = if typ != nil and i < typ.len: assert(typ.n[i].kind == nkSym) let paramType = typ.n[i].typ - if not paramType.isCompileTimeOnly and not typ[0].isEmptyType and - canAlias(paramType, typ[0]): + if not paramType.isCompileTimeOnly and not typ.returnType.isEmptyType and + canAlias(paramType, typ.returnType): allRoots(it, result, RootEscapes) else: allRoots(it, result, RootEscapes) diff --git a/compiler/vm.nim b/compiler/vm.nim index 1584b289337bb..6b00ff9d36e97 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -507,7 +507,7 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) = setLen(node.sons, newLen) if oldLen < newLen: for i in oldLen.. 0: result.add objectNode(cache, t.n, idgen) @@ -217,19 +217,19 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyPtr: if inst: result = newNodeX(nkPtrTy) - result.add mapTypeToAst(t[0], info) + result.add mapTypeToAst(t.elementType, info) else: result = mapTypeToBracket("ptr", mPtr, t, info) of tyRef: if inst: result = newNodeX(nkRefTy) - result.add mapTypeToAst(t[0], info) + result.add mapTypeToAst(t.elementType, info) else: result = mapTypeToBracket("ref", mRef, t, info) of tyVar: if inst: result = newNodeX(nkVarTy) - result.add mapTypeToAst(t[0], info) + result.add mapTypeToAst(t.elementType, info) else: result = mapTypeToBracket("var", mVar, t, info) of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info) @@ -239,10 +239,10 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; if inst: result = newNodeX(nkProcTy) var fp = newNodeX(nkFormalParams) - if t[0] == nil: + if t.returnType == nil: fp.add newNodeI(nkEmpty, info) else: - fp.add mapTypeToAst(t[0], t.n[0].info) + fp.add mapTypeToAst(t.returnType, t.n[0].info) for i in 1..= y.depth: 1 - else: -1 - ) - - for item in g.objectTree[baseType.itemId]: - if item.value.itemId notin itemTable: - itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen) - - var mIndex = 0 # here is the correpsonding index - if baseType.itemId notin rootItemIdCount: - rootItemIdCount[baseType.itemId] = 1 - else: - mIndex = rootItemIdCount[baseType.itemId] - rootItemIdCount.inc(baseType.itemId) - for idx in 0..= y.depth: 1 - else: -1 - ) - - for item in g.objectTree[baseType.itemId]: - if item.value.itemId notin itemTable: - itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen) - - var mIndex = 0 # here is the correpsonding index - if baseType.itemId notin rootItemIdCount: - rootItemIdCount[baseType.itemId] = 1 - else: - mIndex = rootItemIdCount[baseType.itemId] - rootItemIdCount.inc(baseType.itemId) - for idx in 0..= y.depth: 1 + else: -1 + ) + + for item in g.objectTree[baseType.itemId]: + if item.value.itemId notin itemTable: + itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen) + + var mIndex = 0 # here is the correpsonding index + if baseType.itemId notin rootItemIdCount: + rootItemIdCount[baseType.itemId] = 1 + else: + mIndex = rootItemIdCount[baseType.itemId] + rootItemIdCount.inc(baseType.itemId) + for idx in 0..= y.depth: 1 + else: -1 + ) + + for item in g.objectTree[baseType.itemId]: + if item.value.itemId notin itemTable: + itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen) + + var mIndex = 0 # here is the correpsonding index + if baseType.itemId notin rootItemIdCount: + rootItemIdCount[baseType.itemId] = 1 + else: + mIndex = rootItemIdCount[baseType.itemId] + rootItemIdCount.inc(baseType.itemId) + for idx in 0.. Date: Wed, 13 Dec 2023 17:34:41 +0800 Subject: [PATCH 037/123] fixes #23060; `editDistance` wrongly compare the length of rune strings (#23062) fixes #23060 --- lib/std/editdistance.nim | 2 +- tests/errmsgs/t23060.nim | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/errmsgs/t23060.nim diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim index 6a25ca4b94e07..40c0017ae0633 100644 --- a/lib/std/editdistance.nim +++ b/lib/std/editdistance.nim @@ -18,7 +18,7 @@ proc editDistance*(a, b: string): int {.noSideEffect.} = ## This uses the `Levenshtein`:idx: distance algorithm with only a linear ## memory overhead. runnableExamples: static: doAssert editdistance("Kitten", "Bitten") == 1 - if len(a) > len(b): + if runeLen(a) > runeLen(b): # make `b` the longer string return editDistance(b, a) # strip common prefix diff --git a/tests/errmsgs/t23060.nim b/tests/errmsgs/t23060.nim new file mode 100644 index 0000000000000..abb79bcc32355 --- /dev/null +++ b/tests/errmsgs/t23060.nim @@ -0,0 +1,5 @@ +discard """ + errormsg: "undeclared identifier: '♔♕♖♗♘♙'" +""" + +♔♕♖♗♘♙ = 1 \ No newline at end of file From cd4ecddb30a64f5d2c3c6fdde955366c7976577f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 Dec 2023 10:39:10 +0100 Subject: [PATCH 038/123] nimpretty: check the rendered AST for wrong output (#23057) --- compiler/layouter.nim | 25 ++++++++++++++---------- compiler/parser.nim | 2 -- nimpretty/nimpretty.nim | 42 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/compiler/layouter.nim b/compiler/layouter.nim index 7cff98b11b7c2..0121b118581cb 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -9,7 +9,7 @@ ## Layouter for nimpretty. -import idents, lexer, lineinfos, llstream, options, msgs, strutils, pathutils +import idents, lexer, ast, lineinfos, llstream, options, msgs, strutils, pathutils const MinLineLen = 15 @@ -243,23 +243,28 @@ proc renderTokens*(em: var Emitter): string = return content -proc writeOut*(em: Emitter, content: string) = +type + FinalCheck = proc (content: string; origAst: PNode): bool {.nimcall.} + +proc writeOut*(em: Emitter; content: string; origAst: PNode; check: FinalCheck) = ## Write to disk let outFile = em.config.absOutFile if fileExists(outFile) and readFile(outFile.string) == content: discard "do nothing, see #9499" return - var f = llStreamOpen(outFile, fmWrite) - if f == nil: - rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string) - return - f.llStreamWrite content - llStreamClose(f) -proc closeEmitter*(em: var Emitter) = + if check(content, origAst): + var f = llStreamOpen(outFile, fmWrite) + if f == nil: + rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string) + return + f.llStreamWrite content + llStreamClose(f) + +proc closeEmitter*(em: var Emitter; origAst: PNode; check: FinalCheck) = ## Renders emitter tokens and write to a file let content = renderTokens(em) - em.writeOut(content) + em.writeOut(content, origAst, check) proc wr(em: var Emitter; x: string; lt: LayoutToken) = em.tokens.add x diff --git a/compiler/parser.nim b/compiler/parser.nim index 072540dba62ea..4ed38f739e1f1 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -155,8 +155,6 @@ proc openParser*(p: var Parser, filename: AbsoluteFile, inputStream: PLLStream, proc closeParser*(p: var Parser) = ## Close a parser, freeing up its resources. closeLexer(p.lex) - when defined(nimpretty): - closeEmitter(p.em) proc parMessage(p: Parser, msg: TMsgKind, arg = "") = ## Produce and emit the parser message `arg` to output. diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index e3b4c9a3a000c..8e8c585973eb6 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -12,7 +12,7 @@ when not defined(nimpretty): {.error: "This needs to be compiled with --define:nimPretty".} -import ../compiler / [idents, msgs, syntaxes, options, pathutils, layouter] +import ../compiler / [idents, llstream, ast, msgs, syntaxes, options, pathutils, layouter] import parseopt, strutils, os, sequtils @@ -48,6 +48,42 @@ type indWidth*: Natural maxLineLen*: Positive +proc goodEnough(a, b: PNode): bool = + if a.kind == b.kind and a.safeLen == b.safeLen: + case a.kind + of nkNone, nkEmpty, nkNilLit: result = true + of nkIdent: result = a.ident.id == b.ident.id + of nkSym: result = a.sym == b.sym + of nkType: result = true + of nkCharLit, nkIntLit..nkInt64Lit, nkUIntLit..nkUInt64Lit: + result = a.intVal == b.intVal + of nkFloatLit..nkFloat128Lit: + result = a.floatVal == b.floatVal + of nkStrLit, nkRStrLit, nkTripleStrLit: + result = a.strVal == b.strVal + else: + for i in 0 ..< a.len: + if not goodEnough(a[i], b[i]): return false + return true + elif a.kind == nkStmtList and a.len == 1: + result = goodEnough(a[0], b) + elif b.kind == nkStmtList and b.len == 1: + result = goodEnough(a, b[0]) + else: + result = false + +proc finalCheck(content: string; origAst: PNode): bool {.nimcall.} = + var conf = newConfigRef() + let oldErrors = conf.errorCounter + var parser: Parser + parser.em.indWidth = 2 + let fileIdx = fileInfoIdx(conf, AbsoluteFile "nimpretty_bug.nim") + + openParser(parser, fileIdx, llStreamOpen(content), newIdentCache(), conf) + let newAst = parseAll(parser) + closeParser(parser) + result = conf.errorCounter == oldErrors # and goodEnough(newAst, origAst) + proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) = var conf = newConfigRef() let fileIdx = fileInfoIdx(conf, AbsoluteFile infile) @@ -58,8 +94,10 @@ proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) = parser.em.indWidth = opt.indWidth if setupParser(parser, fileIdx, newIdentCache(), conf): parser.em.maxLineLen = opt.maxLineLen - discard parseAll(parser) + let fullAst = parseAll(parser) closeParser(parser) + when defined(nimpretty): + closeEmitter(parser.em, fullAst, finalCheck) proc main = var outfile, outdir: string From a3739751a8439908624815b02d8242515cb5e178 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Wed, 13 Dec 2023 22:13:36 +0200 Subject: [PATCH 039/123] Skip trailing asterisk when placing inlay type hints. Fixes #23067 (#23068) --- compiler/suggest.nim | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 4f90fe00b29e4..9e0fc13e44715 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -85,7 +85,16 @@ proc cmpSuggestions(a, b: Suggest): int = # independent of hashing order: result = cmp(a.name[], b.name[]) -proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int = +proc scanForTrailingAsterisk(line: string, start: int): int = + result = 0 + while start+result < line.len and line[start+result] in {' ', '\t'}: + inc result + if start+result < line.len and line[start+result] == '*': + inc result + else: + result = 0 + +proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo; skipTrailingAsterisk: bool = false): int = let line = sourceLine(conf, info) column = toColumn(info) @@ -109,6 +118,8 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int result = identLen(line, column) if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0: result = 0 + if skipTrailingAsterisk and result > 0: + result += scanForTrailingAsterisk(line, column + result) else: var sourceIdent: string = "" result = parseWhile(line, sourceIdent, @@ -184,7 +195,7 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info result.tokenLen = if section notin {ideHighlight, ideInlayHints}: s.name.s.len else: - getTokenLenFromSource(g.config, s.name.s, infox) + getTokenLenFromSource(g.config, s.name.s, infox, section == ideInlayHints) result.version = g.config.suggestVersion result.endLine = endLine result.endCol = endCol From 1b7b0d69db41b3c5a27cca643d66c0acabbe41df Mon Sep 17 00:00:00 2001 From: Pylgos <43234674+Pylgos@users.noreply.github.com> Date: Thu, 14 Dec 2023 17:55:04 +0900 Subject: [PATCH 040/123] fixes #9381; Fix double evaluation of types in generic objects (#23072) fixes https://github.com/nim-lang/Nim/issues/9381 --- compiler/semtypinst.nim | 19 ++++++++++++++----- tests/generics/tgenerics_various.nim | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 58d684a8fbdac..63941419c9c92 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -83,7 +83,7 @@ type recursionLimit: int proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType -proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym +proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable = @@ -123,7 +123,12 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode = else: t.n result = copyNode(n) result.typ = t - if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym) + if result.kind == nkSym: + result.sym = + if n.typ != nil and n.typ == n.sym.typ: + replaceTypeVarsS(cl, n.sym, result.typ) + else: + replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ)) let isCall = result.kind in nkCallKinds for i in 0.. Date: Thu, 14 Dec 2023 16:25:34 +0100 Subject: [PATCH 041/123] type graph refactor; part 3 (#23064) --- compiler/ast.nim | 82 +++++++++-- compiler/astalgo.nim | 69 ++++----- compiler/docgen.nim | 3 +- compiler/expanddefaults.nim | 2 +- compiler/ic/ic.nim | 2 +- compiler/isolation_check.nim | 16 +- compiler/semdata.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 12 +- compiler/semtypes.nim | 2 +- compiler/sigmatch.nim | 30 ++-- compiler/sizealignoffsetimpl.nim | 11 +- compiler/typeallowed.nim | 27 ++-- compiler/types.nim | 246 ++++++++++++------------------- compiler/varpartitions.nim | 3 +- compiler/vmdeps.nim | 2 +- tests/typerel/tregionptrs.nim | 16 -- 17 files changed, 257 insertions(+), 270 deletions(-) delete mode 100644 tests/typerel/tregionptrs.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index ab46a02d6e707..c880cb65178b5 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1199,9 +1199,6 @@ proc discardSons*(father: PNode) proc len*(n: PNode): int {.inline.} = result = n.sons.len -proc len*(n: PType): int {.inline.} = - result = n.sons.len - proc safeLen*(n: PNode): int {.inline.} = ## works even for leaves. if n.kind in {nkNone..nkNilLit}: result = 0 @@ -1576,11 +1573,74 @@ proc `$`*(s: PSym): string = else: result = "" -iterator items*(t: PType): PType = +when false: + iterator items*(t: PType): PType = + for i in 0.. 0 + +proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0 +proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0 +proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1 + +iterator genericInstParams*(t: PType): (bool, PType) = + for i in 1.. 0: - s.add $t.kind - s.add " " - t = t.last - echo s - template debug*(x: PSym|PType|PNode) {.deprecated.} = when compiles(c.config): debug(c.config, x) @@ -337,21 +328,18 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int, sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope( strutils.toHex(cast[int](n), sizeof(n) * 2))] else: - if n.len > 0: - sonsRope = rope("[") - for i in 0.. 0: sonsRope.add(",") - sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n[i], - marker, indent + 4, maxRecDepth - 1)]) - sonsRope.addf("$N$1]", [rspaces(indent + 2)]) - else: - sonsRope = rope("null") + sonsRope = rope("[") + for i, a in n.ikids: + if i > 0: sonsRope.add(",") + sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, a, + marker, indent + 4, maxRecDepth - 1)]) + sonsRope.addf("$N$1]", [rspaces(indent + 2)]) let istr = rspaces(indent + 2) result = rope("{") result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)]) result.addf("$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)]) - result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)]) + result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)]) if card(n.flags) > 0: result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)]) @@ -573,14 +561,12 @@ proc value(this: var DebugPrinter; value: PType) = this.key "n" this.value value.n - if value.len > 0: - this.key "sons" - this.openBracket - for i in 0.. 0: this.comma + this.value a + this.closeBracket if value.n != nil: this.key "n" @@ -649,30 +635,33 @@ proc value(this: var DebugPrinter; value: PNode) = proc debug(n: PSym; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - this.renderSymType = true - this.useColor = not defined(windows) + var this = DebugPrinter( + visited: initTable[pointer, int](), + renderSymType: true, + useColor: not defined(windows) + ) this.value(n) echo($this.res) proc debug(n: PType; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - this.renderSymType = true - this.useColor = not defined(windows) + var this = DebugPrinter( + visited: initTable[pointer, int](), + renderSymType: true, + useColor: not defined(windows) + ) this.value(n) echo($this.res) proc debug(n: PNode; conf: ConfigRef) = - var this: DebugPrinter - this.visited = initTable[pointer, int]() - #this.renderSymType = true - this.useColor = not defined(windows) + var this = DebugPrinter( + visited: initTable[pointer, int](), + renderSymType: false, + useColor: not defined(windows) + ) this.value(n) echo($this.res) -proc nextTry(h, maxHash: Hash): Hash = +proc nextTry(h, maxHash: Hash): Hash {.inline.} = result = ((5 * h) + 1) and maxHash # For any initial h in range(maxHash), repeating that maxHash times # generates each int in range(maxHash) exactly once (see any text on diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 29eeced9be67d..b53307ee02f2e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1199,8 +1199,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): var param = %{"name": %($genericParam)} if genericParam.sym.typ.len > 0: param["types"] = newJArray() - for kind in genericParam.sym.typ: - param["types"].add %($kind) + param["types"].add %($genericParam.sym.typ.elementType) result.json["signature"]["genericParams"].add param if optGenIndex in d.conf.globalOptions: genItem(d, n, nameNode, k, kForceExport) diff --git a/compiler/expanddefaults.nim b/compiler/expanddefaults.nim index 395d31cc8617f..86f87cd8474dc 100644 --- a/compiler/expanddefaults.nim +++ b/compiler/expanddefaults.nim @@ -118,7 +118,7 @@ proc expandDefault(t: PType; info: TLineInfo): PNode = expandDefaultObj(t, info, result) of tyTuple: result = newZero(t, info, nkTupleConstr) - for it in t: + for it in t.kids: result.add expandDefault(it, info) of tyVarargs, tyOpenArray, tySequence, tyUncheckedArray: result = newZero(t, info, nkBracket) diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 0085ea7485537..a7d3ed81c737b 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -370,7 +370,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI paddingAtEnd: t.paddingAtEnd) storeNode(p, t, n) p.typeInst = t.typeInst.storeType(c, m) - for kid in items t: + for kid in kids t: p.types.add kid.storeType(c, m) c.addMissing t.sym p.sym = t.sym.safeItemId(c, m) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 08a2cc6045fbc..17fbde29eeb4e 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -54,14 +54,14 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool = of tyObject: if isFinal(ret): result = canAliasN(arg, ret.n, marker) - if not result and ret.len > 0 and ret[0] != nil: - result = canAlias(arg, ret[0], marker) + if not result and ret.baseClass != nil: + result = canAlias(arg, ret.baseClass, marker) else: result = true of tyTuple: result = false - for i in 0.. maxBranch: maxBranch = branchSum inc result, maxBranch @@ -240,11 +240,16 @@ proc sumGeneric(t: PType): int = t = t.elementType if t.kind == tyEmpty: break inc result - of tyGenericInvocation, tyTuple, tyProc, tyAnd: + of tyGenericInvocation, tyTuple, tyAnd: result += ord(t.kind in {tyGenericInvocation, tyAnd}) - for i in 0..= isGeneric: isGeneric else: x @@ -1660,7 +1665,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyAnd: considerPreviousT: result = isEqual - for branch in f: + for branch in f.kids: let x = typeRel(c, branch, aOrig, flags) if x < isSubtype: return isNone # 'and' implies minimum matching result: @@ -1672,7 +1677,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNone let oldInheritancePenalty = c.inheritancePenalty var maxInheritance = 0 - for branch in f: + for branch in f.kids: c.inheritancePenalty = 0 let x = typeRel(c, branch, aOrig, flags) maxInheritance = max(maxInheritance, c.inheritancePenalty) @@ -1686,9 +1691,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, c.inheritancePenalty = oldInheritancePenalty + maxInheritance of tyNot: considerPreviousT: - for branch in f: - if typeRel(c, branch, aOrig, flags) != isNone: - return isNone + if typeRel(c, f.elementType, aOrig, flags) != isNone: + return isNone bindingRet isGeneric of tyAnything: @@ -1699,7 +1703,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return isGeneric of tyBuiltInTypeClass: considerPreviousT: - let target = f[0] + let target = f.genericHead let targetKind = target.kind var effectiveArgType = a.getObjectTypeOrNil() if effectiveArgType == nil: return isNone diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 7cc11f55f13a9..d114f59da53d6 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -332,8 +332,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = of tyTuple: try: var accum = OffsetAccum(maxAlign: 1) - for i in 0.. 0: + if typ.hasElementType: computeSizeAlign(conf, typ.last) typ.size = typ.last.size typ.align = typ.last.align typ.paddingAtEnd = typ.last.paddingAtEnd of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned: - computeSizeAlign(conf, typ.last) - typ.size = typ.last.size - typ.align = typ.last.align + computeSizeAlign(conf, typ.skipModifier) + typ.size = typ.skipModifier.size + typ.align = typ.skipModifier.align typ.paddingAtEnd = typ.last.paddingAtEnd of tyTypeClasses: diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 04dbc69c59a52..d226b2e063db0 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -96,9 +96,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, # only closure iterators may be assigned to anything. result = t let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags - for i in 1.. 0: + if t.hasElementType: result = classifyViewTypeAux(marker, skipModifier(t)) else: result = noView of tyTuple: result = noView - for i in 0.. 0: + if t.kind == tyGenericParam and t.genericParamHasConstraints: result.add ": " - var first = true - for son in t: - if not first: result.add " or " - result.add son.typeToString - first = false + result.add t.elementType.typeToString else: result = t.sym.owner.name.s & '.' & t.sym.name.s result.addTypeFlags(t) @@ -589,17 +552,23 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "int" else: result = "int literal(" & $t.n.intVal & ")" - of tyGenericInst, tyGenericInvocation: + of tyGenericInst: result = typeToString(t.genericHead) & '[' - for i in 1.. 1: result.add(", ") - result.add(typeToString(t[i], preferGenericArg)) + for needsComma, a in t.genericInstParams: + if needsComma: result.add(", ") + result.add(typeToString(a, preferGenericArg)) + result.add(']') + of tyGenericInvocation: + result = typeToString(t.genericHead) & '[' + for needsComma, a in t.genericInvocationParams: + if needsComma: result.add(", ") + result.add(typeToString(a, preferGenericArg)) result.add(']') of tyGenericBody: result = typeToString(t.typeBodyImpl) & '[' - for i in 0.. 0: result.add(", ") - result.add(typeToString(t[i], preferTypeName)) + for needsComma, a in t.genericBodyParams: + if needsComma: result.add(", ") + result.add(typeToString(a, preferTypeName)) result.add(']') of tyTypeDesc: if t.elementType.kind == tyNone: result = "typedesc" @@ -608,7 +577,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if prefer == preferGenericArg and t.n != nil: result = t.n.renderTree else: - result = "static[" & (if t.len > 0: typeToString(t.skipModifier) else: "") & "]" + result = "static[" & (if t.hasElementType: typeToString(t.skipModifier) else: "") & "]" if t.n != nil: result.add "(" & renderTree(t.n) & ")" of tyUserTypeClass: if t.sym != nil and t.sym.owner != nil: @@ -639,20 +608,18 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyUserTypeClassInst: let body = t.base result = body.sym.name.s & "[" - for i in 1.. 1: result.add(", ") - result.add(typeToString(t[i])) + for needsComma, a in t.userTypeClassInstParams: + if needsComma: result.add(", ") + result.add(typeToString(a)) result.add "]" of tyAnd: - for i, son in t: + for i, son in t.ikids: + if i > 0: result.add(" and ") result.add(typeToString(son)) - if i < t.len - 1: - result.add(" and ") of tyOr: - for i, son in t: + for i, son in t.ikids: + if i > 0: result.add(" or ") result.add(typeToString(son)) - if i < t.len - 1: - result.add(" or ") of tyNot: result = "not " & typeToString(t.elementType) of tyUntyped: @@ -665,7 +632,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "typeof(" & renderTree(t.n) & ")" of tyArray: result = "array" - if t.len > 0: + if t.hasElementType: if t.indexType.kind == tyRange: result &= "[" & rangeToStr(t.indexType.n) & ", " & typeToString(t.elementType) & ']' @@ -674,26 +641,26 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = typeToString(t.elementType) & ']' of tyUncheckedArray: result = "UncheckedArray" - if t.len > 0: + if t.hasElementType: result &= "[" & typeToString(t.elementType) & ']' of tySequence: if t.sym != nil and prefer != preferResolved: result = t.sym.name.s else: result = "seq" - if t.len > 0: + if t.hasElementType: result &= "[" & typeToString(t.elementType) & ']' of tyOrdinal: result = "ordinal" - if t.len > 0: + if t.hasElementType: result &= "[" & typeToString(t.skipModifier) & ']' of tySet: result = "set" - if t.len > 0: + if t.hasElementType: result &= "[" & typeToString(t.elementType) & ']' of tyOpenArray: result = "openArray" - if t.len > 0: + if t.hasElementType: result &= "[" & typeToString(t.elementType) & ']' of tyDistinct: result = "distinct " & typeToString(t.elementType, @@ -701,38 +668,33 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyIterable: # xxx factor this pattern result = "iterable" - if t.len > 0: + if t.hasElementType: result &= "[" & typeToString(t.skipModifier) & ']' of tyTuple: # we iterate over t.sons here, because t.n may be nil if t.n != nil: result = "tuple[" - assert(t.n.len == t.len) for i in 0.. 0: result.add ", " + result.add(typeToString(son)) result.add(')') of tyPtr, tyRef, tyVar, tyLent: result = if isOutParam(t): "out " else: typeToStr[t.kind] - if t.len >= 2: - setLen(result, result.len-1) - result.add '[' - for i in 0.. FirstParamAt: result.add(", ") + let j = paramTypeToNodeIndex(i) + if t.n != nil and j < t.n.len and t.n[j].kind == nkSym: + result.add(t.n[j].sym.name.s) result.add(": ") - result.add(typeToString(t[i])) - if i < t.len - 1: result.add(", ") + result.add(typeToString(a)) result.add(')') - if t.len > 0 and t.returnType != nil: result.add(": " & typeToString(t.returnType)) + if t.returnType != nil: result.add(": " & typeToString(t.returnType)) var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos: let pragmasNode = t.owner.ast[pragmasPos] @@ -813,7 +776,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = of tyUInt..tyUInt64: result = Zero of tyEnum: # if basetype <> nil then return firstOrd of basetype - if t.len > 0 and t.baseClass != nil: + if t.baseClass != nil: result = firstOrd(conf, t.baseClass) else: if t.n.len > 0: @@ -827,7 +790,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = of tyUserTypeClasses: result = firstOrd(conf, last(t)) of tyOrdinal: - if t.len > 0: result = firstOrd(conf, skipModifier(t)) + if t.hasElementType: result = firstOrd(conf, skipModifier(t)) else: result = Zero internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') @@ -923,7 +886,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = result = lastOrd(conf, last(t)) of tyProxy: result = Zero of tyOrdinal: - if t.len > 0: result = lastOrd(conf, skipModifier(t)) + if t.hasElementType: result = lastOrd(conf, skipModifier(t)) else: result = Zero internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') @@ -1093,11 +1056,11 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = # two tuples are equivalent iff the names, types and positions are the same; # however, both types may not have any field names (t.n may be nil) which # complicates the matter a bit. - if a.len == b.len: + if sameTupleLengths(a, b): result = true - for i in 0..= a.len or a[i] == nil: return false - a = a[i] - result = a.kind == last - include sizealignoffsetimpl @@ -1578,8 +1524,8 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} = proc containsCompileTimeOnly*(t: PType): bool = if isCompileTimeOnly(t): return true - for i in 0.. but expected 'APtr = ptr[RegionA, int]'" - line: 16 -""" - -type - RegionA = object - APtr = RegionA ptr int - RegionB = object - BPtr = RegionB ptr int - -var x,xx: APtr -var y: BPtr -x = nil -x = xx -x = y From 7e4060cb4a473617bc8ed6e289586bf793aed5b1 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 15 Dec 2023 00:04:09 +0800 Subject: [PATCH 042/123] fixes #23065; DocLike command defaults to ORC (#23075) fixes #23065 --- compiler/nim.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/nim.nim b/compiler/nim.nim index 184303f8eab7a..3473ea443c82c 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -117,7 +117,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = if conf.selectedGC == gcUnselected: if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or - (conf.cmd == cmdInteractive and isDefined(conf, "nir")): + (conf.cmd == cmdInteractive and isDefined(conf, "nir")) or + (conf.cmd in cmdDocLike and conf.backend != backendJs): initOrcDefines(conf) mainCommand(graph) From 91efa49550b377e677cb0ff0d10e0c1192955b63 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Thu, 14 Dec 2023 09:05:14 -0700 Subject: [PATCH 043/123] =?UTF-8?q?Overloads=20passed=20to=20static=20proc?= =?UTF-8?q?=20parameters=20now=20convert=20to=20the=20desired=E2=80=A6=20(?= =?UTF-8?q?#23063)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … type mirroring proc params --- compiler/semcall.nim | 14 ++++++++++---- compiler/semexprs.nim | 4 ++-- compiler/sigmatch.nim | 13 ++++++++++++- tests/statictypes/tstaticprocparams.nim | 9 ++++++++- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c9f407b12cc0d..f6beb1aebdef9 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -733,7 +733,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = # try transforming the argument into a static one before feeding it into # typeRel if formal.kind == tyStatic and arg.kind != tyStatic: - let evaluated = c.semTryConstExpr(c, n[i]) + let evaluated = c.semTryConstExpr(c, n[i], n[i].typ) if evaluated != nil: arg = newTypeS(tyStatic, c, son = evaluated.typ) arg.n = evaluated @@ -746,10 +746,16 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = onUse(info, s) result = newSymNode(newInst, info) -proc setGenericParams(c: PContext, n: PNode) = +proc setGenericParams(c: PContext, n, expectedParams: PNode) = ## sems generic params in subscript expression for i in 1.. Date: Fri, 15 Dec 2023 00:27:16 +0800 Subject: [PATCH 044/123] fixes #23051; don't generate documentation for exported symbols again (#23074) fixes #23051 Before ![image](https://github.com/nim-lang/Nim/assets/43030857/d402a837-281e-4035-8302-500f64dccdb5) After ![image](https://github.com/nim-lang/Nim/assets/43030857/de9a23f1-9e50-4551-b3fd-3311e1de378e) --- compiler/docgen.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index b53307ee02f2e..a8bbe5b64bed4 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1399,7 +1399,8 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags for it in n: traceDeps(d, it) of nkExportStmt: for it in n: - if it.kind == nkSym: + # bug #23051; don't generate documentation for exported symbols again + if it.kind == nkSym and sfExported notin it.sym.flags: if d.module != nil and d.module == it.sym.owner: generateDoc(d, it.sym.ast, orig, config, kForceExport) elif it.sym.ast != nil: From 94f7e9683fb5c9f643b7e4af367a3a6457d5ad7f Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Fri, 15 Dec 2023 06:48:34 +0000 Subject: [PATCH 045/123] Param match relax (#23033) #23032 --------- Co-authored-by: Nikolay Nikolov Co-authored-by: Pylgos <43234674+Pylgos@users.noreply.github.com> Co-authored-by: Andreas Rumpf Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> Co-authored-by: Jason Beetham --- compiler/ast.nim | 6 +- compiler/lookups.nim | 12 ++ compiler/sigmatch.nim | 137 +++++++++++++---------- lib/pure/sugar.nim | 5 +- testament/important_packages.nim | 2 +- tests/lookups/issue_23032/deep_scope.nim | 2 + tests/lookups/t23032.nim | 13 +++ tests/macros/t23032_1.nim | 19 ++++ tests/macros/t23032_2.nim | 20 ++++ tests/macros/tgetimpl.nim | 7 +- 10 files changed, 154 insertions(+), 69 deletions(-) create mode 100644 tests/lookups/issue_23032/deep_scope.nim create mode 100644 tests/lookups/t23032.nim create mode 100644 tests/macros/t23032_1.nim create mode 100644 tests/macros/t23032_2.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index c880cb65178b5..aa12c6421f446 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -2033,13 +2033,15 @@ proc skipGenericOwner*(s: PSym): PSym = ## Generic instantiations are owned by their originating generic ## symbol. This proc skips such owners and goes straight to the owner ## of the generic itself (the module or the enclosing proc). - result = if s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule: + result = if s.kind == skModule: + s + elif s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule: s.owner.owner else: s.owner proc originatingModule*(s: PSym): PSym = - result = s.owner + result = s while result.kind != skModule: result = result.owner proc isRoutine*(s: PSym): bool {.inline.} = diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 1a60de7e532b1..cfefe764ba3b0 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -256,6 +256,18 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy if s.kind in filter: result.add s +proc cmpScopes*(ctx: PContext, s: PSym): int = + # Do not return a negative number + if s.originatingModule == ctx.module: + result = 2 + var owner = s + while true: + owner = owner.skipGenericOwner + if owner.kind == skModule: break + inc result + else: + result = 1 + proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool = result = false block outer: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 8e4dba0904da9..ceb3f5a516abd 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -135,15 +135,7 @@ proc initCandidate*(ctx: PContext, callee: PSym, result = initCandidateAux(ctx, callee.typ) result.calleeSym = callee if callee.kind in skProcKinds and calleeScope == -1: - if callee.originatingModule == ctx.module: - result.calleeScope = 2 - var owner = callee - while true: - owner = owner.skipGenericOwner - if owner.kind == skModule: break - inc result.calleeScope - else: - result.calleeScope = 1 + result.calleeScope = cmpScopes(ctx, callee) else: result.calleeScope = calleeScope result.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil @@ -297,7 +289,7 @@ proc writeMatches*(c: TCandidate) = echo " conv matches: ", c.convMatches echo " inheritance: ", c.inheritancePenalty -proc cmpCandidates*(a, b: TCandidate): int = +proc cmpCandidates*(a, b: TCandidate, isFormal=true): int = result = a.exactMatches - b.exactMatches if result != 0: return result = a.genericMatches - b.genericMatches @@ -311,13 +303,14 @@ proc cmpCandidates*(a, b: TCandidate): int = # the other way round because of other semantics: result = b.inheritancePenalty - a.inheritancePenalty if result != 0: return - # check for generic subclass relation - result = checkGeneric(a, b) + if isFormal: + # check for generic subclass relation + result = checkGeneric(a, b) + if result != 0: return + # prefer more specialized generic over more general generic: + result = complexDisambiguation(a.callee, b.callee) if result != 0: return - # prefer more specialized generic over more general generic: - result = complexDisambiguation(a.callee, b.callee) # only as a last resort, consider scoping: - if result != 0: return result = a.calleeScope - b.calleeScope proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string = @@ -2353,56 +2346,76 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, if arg == nil or arg.kind notin nkSymChoices: result = paramTypesMatchAux(m, f, a, arg, argOrig) else: - # CAUTION: The order depends on the used hashing scheme. Thus it is - # incorrect to simply use the first fitting match. However, to implement - # this correctly is inefficient. We have to copy `m` here to be able to - # roll back the side effects of the unification algorithm. - let c = m.c - var - x = newCandidate(c, m.callee) - y = newCandidate(c, m.callee) - z = newCandidate(c, m.callee) - x.calleeSym = m.calleeSym - y.calleeSym = m.calleeSym - z.calleeSym = m.calleeSym + let matchSet = {skProc, skFunc, skMethod, skConverter,skIterator, skMacro, + skTemplate, skEnumField} + var best = -1 - for i in 0.. bestScope: best = i - of csMatch: - let cmp = cmpCandidates(x, z) - if cmp < 0: - best = i - x = z - elif cmp == 0: - y = z # z is as good as x - - if x.state == csEmpty: - result = nil - elif y.state == csMatch and cmpCandidates(x, y) == 0: - if x.state != csMatch: - internalError(m.c.graph.config, arg.info, "x.state is not csMatch") - # ambiguous: more than one symbol fits! - # See tsymchoice_for_expr as an example. 'f.kind == tyUntyped' should match - # anyway: - if f.kind in {tyUntyped, tyTyped}: result = arg - else: result = nil + bestScope = thisScope + counts = 0 + elif thisScope == bestScope: + inc counts + if best == -1: + result = nil + elif counts > 0: + best = -1 else: + # CAUTION: The order depends on the used hashing scheme. Thus it is + # incorrect to simply use the first fitting match. However, to implement + # this correctly is inefficient. We have to copy `m` here to be able to + # roll back the side effects of the unification algorithm. + let c = m.c + var + x = newCandidate(c, m.callee) + y = newCandidate(c, m.callee) + z = newCandidate(c, m.callee) + x.calleeSym = m.calleeSym + y.calleeSym = m.calleeSym + z.calleeSym = m.calleeSym + + for i in 0.. -1 and result != nil: # only one valid interpretation found: markUsed(m.c, arg.info, arg[best].sym) onUse(arg.info, arg[best].sym) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index cfa04a8376205..7833ed0633345 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -345,9 +345,10 @@ proc collectImpl(init, body: NimNode): NimNode {.since: (1, 1).} = let res = genSym(nskVar, "collectResult") var bracketExpr: NimNode if init != nil: - expectKind init, {nnkCall, nnkIdent, nnkSym} + expectKind init, {nnkCall, nnkIdent, nnkSym, nnkClosedSymChoice, nnkOpenSymChoice} bracketExpr = newTree(nnkBracketExpr, - if init.kind == nnkCall: freshIdentNodes(init[0]) else: freshIdentNodes(init)) + if init.kind in {nnkCall, nnkClosedSymChoice, nnkOpenSymChoice}: + freshIdentNodes(init[0]) else: freshIdentNodes(init)) else: bracketExpr = newTree(nnkBracketExpr) let (resBody, keyType, valueType) = trans(body, res, bracketExpr) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index c2b2476e7042d..d3d3f06437881 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -60,7 +60,7 @@ pkg "compactdict" pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension" pkg "cowstrings" pkg "criterion", allowFailure = true # needs testing binary -pkg "datamancer" +pkg "datamancer", url="https://github.com/Graveflo/Datamancer.git" pkg "dashing", "nim c tests/functional.nim" pkg "delaunay" pkg "docopt" diff --git a/tests/lookups/issue_23032/deep_scope.nim b/tests/lookups/issue_23032/deep_scope.nim new file mode 100644 index 0000000000000..3e25809a7076a --- /dev/null +++ b/tests/lookups/issue_23032/deep_scope.nim @@ -0,0 +1,2 @@ +type A*[T] = object +proc foo*(a: A[int]): bool = false diff --git a/tests/lookups/t23032.nim b/tests/lookups/t23032.nim new file mode 100644 index 0000000000000..144abcb05924c --- /dev/null +++ b/tests/lookups/t23032.nim @@ -0,0 +1,13 @@ +discard """ +action: "run" +outputsub: "proc (a: A[system.float]): bool{.noSideEffect, gcsafe.}" +""" + +import issue_23032/deep_scope + +proc foo(a: A[float]):bool = true + +let p: proc = foo +echo p.typeof +doAssert p(A[float]()) == true +doAssert compiles(doAssert p(A[int]()) == true) == false diff --git a/tests/macros/t23032_1.nim b/tests/macros/t23032_1.nim new file mode 100644 index 0000000000000..4e1707414a894 --- /dev/null +++ b/tests/macros/t23032_1.nim @@ -0,0 +1,19 @@ +import std/macros + +type A[T, H] = object + +proc `%*`(a: A): bool = true +proc `%*`[T](a: A[int, T]): bool = false + +macro collapse(s: untyped) = + result = newStmtList() + result.add quote do: + doAssert(`s`(A[float, int]()) == true) + +macro startHere(n: untyped): untyped = + result = newStmtList() + let s = n[0] + result.add quote do: + `s`.collapse() + +startHere(`a` %* `b`) diff --git a/tests/macros/t23032_2.nim b/tests/macros/t23032_2.nim new file mode 100644 index 0000000000000..cb8e772e70382 --- /dev/null +++ b/tests/macros/t23032_2.nim @@ -0,0 +1,20 @@ +discard """ + action: "reject" + errormsg: "ambiguous identifier '%*'" +""" +import std/macros + +type A[T, H] = object + +proc `%*`[T](a: A) = discard +proc `%*`[T](a: A[int, T]) = discard + +macro collapse(s: typed) = discard + +macro startHere(n: untyped): untyped = + result = newStmtList() + let s = n[0] + result.add quote do: + collapse(`s`.typeof()) + +startHere(`a` %* `b`) diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index 66722a234400c..3989576729b62 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -44,8 +44,11 @@ static: doAssert checkOwner(poo, 2) == "nskProc" doAssert checkOwner(poo, 3) == "nskModule" doAssert isSameOwner(foo, poo) - doAssert isSameOwner(foo, echo) == false - doAssert isSameOwner(poo, len) == false + proc wrappedScope() = + proc dummyproc() = discard + doAssert isSameOwner(foo, dummyproc) == false + doAssert isSameOwner(poo, dummyproc) == false + wrappedScope() #--------------------------------------------------------------- From a4628532b27857d095e69b7b162b453fc2b8373c Mon Sep 17 00:00:00 2001 From: shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> Date: Fri, 15 Dec 2023 06:49:07 +0000 Subject: [PATCH 046/123] rationals: support Rational[SomeUnsignedInt] (#23046) fixes #22227 rationale: - `3u - 4u` is supported why not`3u.toRational - 4u.toRational` - all of rationals' api is on SomeInteger, looks like unsigned is declared as supported - math on unsigned rationals is meaningful and useful. --- lib/pure/rationals.nim | 12 ++++++------ tests/stdlib/trationals.nim | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index ab05bcc252d90..45902b7cd4405 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -40,16 +40,16 @@ func reduce*[T: SomeInteger](x: var Rational[T]) = reduce(r) doAssert r.num == 1 doAssert r.den == 2 - + if x.den == 0: + raise newException(DivByZeroDefect, "division by zero") let common = gcd(x.num, x.den) if x.den > 0: x.num = x.num div common x.den = x.den div common - elif x.den < 0: - x.num = -x.num div common - x.den = -x.den div common - else: - raise newException(DivByZeroDefect, "division by zero") + when T isnot SomeUnsignedInt: + if x.den < 0: + x.num = -x.num div common + x.den = -x.den div common func initRational*[T: SomeInteger](num, den: T): Rational[T] = ## Creates a new rational number with numerator `num` and denominator `den`. diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim index cd9954f61dc73..22d7f5c2d4ac3 100644 --- a/tests/stdlib/trationals.nim +++ b/tests/stdlib/trationals.nim @@ -10,6 +10,7 @@ template main() = z = Rational[int](num: 0, den: 1) o = initRational(num = 1, den = 1) a = initRational(1, 2) + u = 3u // 2 b = -1 // -2 m1 = -1 // 1 tt = 10 // 2 @@ -104,5 +105,13 @@ template main() = when sizeof(int) == 8: doAssert almostEqual(PI.toRational.toFloat, PI) + # unsigned + doAssert u == u + doAssert u + u == 3u // 1 + doAssert 3u.toRational - u == u + doAssert u * 2 == 3u // 1 + + + static: main() main() From cca5684a17e654a13ddac046f1e76873d8c19f55 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 15 Dec 2023 15:13:25 +0800 Subject: [PATCH 047/123] fixes yet another strictdefs bug (#23069) --- compiler/ccgcalls.nim | 6 ++---- compiler/ccgexprs.nim | 9 +++++---- compiler/ccgtrav.nim | 13 +++++++------ compiler/closureiters.nim | 7 ++----- compiler/docgen.nim | 10 ++++++---- compiler/evaltempl.nim | 16 ++++++++-------- compiler/guards.nim | 2 +- compiler/ic/ic.nim | 7 +++---- compiler/ic/packed_ast.nim | 2 +- compiler/importer.nim | 3 ++- compiler/int128.nim | 16 ++++++++++++++++ compiler/lexer.nim | 3 +-- compiler/modulegraphs.nim | 28 +++++++++++++++------------- compiler/msgs.nim | 14 ++++++-------- compiler/nilcheck.nim | 18 +++++++++--------- compiler/nimblecmd.nim | 2 ++ compiler/nimconf.nim | 2 +- compiler/parser.nim | 2 +- compiler/patterns.nim | 5 +---- compiler/procfind.nim | 2 +- compiler/semfields.nim | 25 +++++++++++++------------ compiler/semgnrc.nim | 14 ++++++++------ compiler/semobjconstr.nim | 2 +- compiler/semparallel.nim | 8 ++++---- compiler/sempass2.nim | 3 +++ compiler/semtempl.nim | 26 ++++++++++++++------------ compiler/sigmatch.nim | 2 +- compiler/sourcemap.nim | 5 +---- lib/pure/collections/tables.nim | 3 +++ 29 files changed, 138 insertions(+), 117 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 175100ff4571a..53c147024163a 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -237,8 +237,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) if ntyp.kind in {tyVar} and not compileToCpp(p.module): - var t: TLoc - t.r = "(*$1)" % [a.rdLoc] + var t = TLoc(r: "(*$1)" % [a.rdLoc]) result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" % [a.rdLoc, lenExpr(p, t), dataField(p), dataFieldAccessor(p, "*" & a.rdLoc)] @@ -250,8 +249,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = of tyPtr, tyRef: case elementType(a.t).kind of tyString, tySequence: - var t: TLoc - t.r = "(*$1)" % [a.rdLoc] + var t = TLoc(r: "(*$1)" % [a.rdLoc]) result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" % [a.rdLoc, lenExpr(p, t), dataField(p), dataFieldAccessor(p, "*" & a.rdLoc)] diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7757c9419ba1b..28f75f994874c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -221,10 +221,11 @@ proc asgnComplexity(n: PNode): int = proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc = assert field != "" - result.k = locField - result.storage = a.storage - result.lode = lodeTyp t - result.r = rdLoc(a) & "." & field + result = TLoc(k: locField, + storage: a.storage, + lode: lodeTyp t, + r: rdLoc(a) & "." & field + ) proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let newflags = diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index d4db16018b7fd..a7470c44f317b 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -134,7 +134,6 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = lineF(p, cpsStmts, "}$n", []) proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = - var c: TTraversalClosure var p = newProc(nil, m) result = "Marker_" & getTypeName(m, origTyp, sig) let @@ -147,8 +146,9 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = lineF(p, cpsLocals, "$1 a;$n", [t]) lineF(p, cpsInit, "a = ($1)p;$n", [t]) - c.p = p - c.visitorFrmt = "op" # "#nimGCvisit((void*)$1, op);$n" + var c = TTraversalClosure(p: p, + visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n" + ) assert typ.kind != tyTypeDesc if typ.kind == tySequence: @@ -174,7 +174,6 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope = discard genTypeInfoV1(m, s.loc.t, info) - var c: TTraversalClosure var p = newProc(nil, m) var sLoc = rdLoc(s.loc) result = getTempName(m) @@ -183,8 +182,10 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope = accessThreadLocalVar(p, s) sLoc = "NimTV_->" & sLoc - c.visitorFrmt = "0" # "#nimGCvisit((void*)$1, 0);$n" - c.p = p + var c = TTraversalClosure(p: p, + visitorFrmt: "0" # "#nimGCvisit((void*)$1, 0);$n" + ) + let header = "static N_NIMCALL(void, $1)(void)" % [result] genTraverseProc(c, sLoc, s.loc.t) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 122a69da6ebc9..9e97fbf4d89de 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -413,7 +413,7 @@ proc hasYieldsInExpressions(n: PNode): bool = proc exprToStmtList(n: PNode): tuple[s, res: PNode] = assert(n.kind == nkStmtListExpr) - result.s = newNodeI(nkStmtList, n.info) + result = (newNodeI(nkStmtList, n.info), nil) result.s.sons = @[] var n = n @@ -1431,10 +1431,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode = result[i] = preprocess(c, n[i]) proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: PNode): PNode = - var ctx: Ctx - ctx.g = g - ctx.fn = fn - ctx.idgen = idgen + var ctx = Ctx(g: g, fn: fn, idgen: idgen) if getEnvParam(fn).isNil: # Lambda lifting was not done yet. Use temporary :state sym, which will diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a8bbe5b64bed4..bf8bdde143a49 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -289,7 +289,7 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) = let outDirPath: RelativeFile = presentationPath(conf, AbsoluteFile(basedir / targetRelPath)) # use presentationPath because `..` path can be be mangled to `_._` - result.targetPath = string(conf.outDir / outDirPath) + result = (string(conf.outDir / outDirPath), "") if not fileExists(result.targetPath): # this can happen if targetRelPath goes to parent directory `OUTDIR/..`. # Trying it, this may cause ambiguities, but allows us to insert @@ -1000,8 +1000,9 @@ proc getTypeKind(n: PNode): string = proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol = ## Converts symbol info (names/types/parameters) in `n` into format ## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``. - result.name = baseName.nimIdentNormalize - result.symKind = k.toHumanStr + result = LangSymbol(name: baseName.nimIdentNormalize, + symKind: k.toHumanStr + ) if k in routineKinds: var paramTypes: seq[string] = @[] @@ -1166,8 +1167,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): if nonExports: renderFlags.incl renderNonExportedFields r = initTokRender(n, renderFlags) - result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int, + result = JsonItem(json: %{ "name": %name, "type": %($k), "line": %n.info.line.int, "col": %n.info.col} + ) if comm != nil: result.rst = comm result.rstField = "description" diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 5ebb4fa553403..d875051020504 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -182,14 +182,14 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; # replace each param by the corresponding node: var args = evalTemplateArgs(n, tmpl, conf, fromHlo) - var ctx: TemplCtx - ctx.owner = tmpl - ctx.genSymOwner = genSymOwner - ctx.config = conf - ctx.ic = ic - ctx.mapping = initIdTable() - ctx.instID = instID[] - ctx.idgen = idgen + var ctx = TemplCtx(owner: tmpl, + genSymOwner: genSymOwner, + config: conf, + ic: ic, + mapping: initIdTable(), + instID: instID[], + idgen: idgen + ) let body = tmpl.ast[bodyPos] #echo "instantion of ", renderTree(body, {renderIds}) diff --git a/compiler/guards.nim b/compiler/guards.nim index 87dbfdf6f2849..bbb23986741f1 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -1063,7 +1063,7 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = let b = fact[2] if a.kind == nkSym: replacements.add((a,b)) else: replacements.add((b,a)) - var m: TModel + var m = TModel() var a = aa var b = bb if replacements.len > 0: diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index a7d3ed81c737b..e856219107a91 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -383,10 +383,9 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib = ## the plib hangs off the psym via the .annex field if l.isNil: return - result.kind = l.kind - result.generated = l.generated - result.isOverridden = l.isOverridden - result.name = toLitId($l.name, m) + result = PackedLib(kind: l.kind, generated: l.generated, + isOverridden: l.isOverridden, name: toLitId($l.name, m) + ) storeNode(result, l, path) proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId = diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 8971d72beedb7..2599e07d11d9a 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -124,7 +124,7 @@ proc `==`*(a, b: NodePos): bool {.borrow.} proc `==`*(a, b: NodeId): bool {.borrow.} proc newTreeFrom*(old: PackedTree): PackedTree = - result.nodes = @[] + result = PackedTree(nodes: @[]) when false: result.sh = old.sh proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) = diff --git a/compiler/importer.nim b/compiler/importer.nim index a8de1e8bcf533..57cbbb8475830 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -251,7 +251,8 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool) c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] = - var ret: typeof(result) + result = (nil, false) + var ret = default(typeof(result)) proc processPragma(n2: PNode): PNode = let (result2, kws) = splitPragmas(c, n2) result = result2 diff --git a/compiler/int128.nim b/compiler/int128.nim index ca06a3a9743b9..74e581cd51cc1 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -34,6 +34,7 @@ proc `$`*(a: Int128): string proc toInt128*[T: SomeInteger | bool](arg: T): Int128 = {.noSideEffect.}: + result = Zero when T is bool: result.sdata(0) = int32(arg) elif T is SomeUnsignedInt: when sizeof(arg) <= 4: @@ -208,30 +209,35 @@ proc `==`*(a, b: Int128): bool = return true proc bitnot*(a: Int128): Int128 = + result = Zero result.udata[0] = not a.udata[0] result.udata[1] = not a.udata[1] result.udata[2] = not a.udata[2] result.udata[3] = not a.udata[3] proc bitand*(a, b: Int128): Int128 = + result = Zero result.udata[0] = a.udata[0] and b.udata[0] result.udata[1] = a.udata[1] and b.udata[1] result.udata[2] = a.udata[2] and b.udata[2] result.udata[3] = a.udata[3] and b.udata[3] proc bitor*(a, b: Int128): Int128 = + result = Zero result.udata[0] = a.udata[0] or b.udata[0] result.udata[1] = a.udata[1] or b.udata[1] result.udata[2] = a.udata[2] or b.udata[2] result.udata[3] = a.udata[3] or b.udata[3] proc bitxor*(a, b: Int128): Int128 = + result = Zero result.udata[0] = a.udata[0] xor b.udata[0] result.udata[1] = a.udata[1] xor b.udata[1] result.udata[2] = a.udata[2] xor b.udata[2] result.udata[3] = a.udata[3] xor b.udata[3] proc `shr`*(a: Int128, b: int): Int128 = + result = Zero let b = b and 127 if b < 32: result.sdata(3) = a.sdata(3) shr b @@ -258,6 +264,7 @@ proc `shr`*(a: Int128, b: int): Int128 = result.sdata(0) = a.sdata(3) shr (b and 31) proc `shl`*(a: Int128, b: int): Int128 = + result = Zero let b = b and 127 if b < 32: result.udata[0] = a.udata[0] shl b @@ -281,6 +288,7 @@ proc `shl`*(a: Int128, b: int): Int128 = result.udata[3] = a.udata[0] shl (b and 31) proc `+`*(a, b: Int128): Int128 = + result = Zero let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0]) result.udata[0] = cast[uint32](tmp0) let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32) @@ -313,6 +321,7 @@ proc abs(a: int32): int = if a < 0: -a else: a proc `*`(a: Int128, b: uint32): Int128 = + result = Zero let tmp0 = uint64(a.udata[0]) * uint64(b) let tmp1 = uint64(a.udata[1]) * uint64(b) let tmp2 = uint64(a.udata[2]) * uint64(b) @@ -335,6 +344,7 @@ proc `*=`(a: var Int128, b: int32) = a = a * b proc makeInt128(high, low: uint64): Int128 = + result = Zero result.udata[0] = cast[uint32](low) result.udata[1] = cast[uint32](low shr 32) result.udata[2] = cast[uint32](high) @@ -373,6 +383,8 @@ proc fastLog2*(a: Int128): int = proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = assert(divisor != Zero) + result = (Zero, Zero) + let isNegativeA = isNegative(dividend) let isNegativeB = isNegative(divisor) @@ -539,24 +551,28 @@ proc toInt128*(arg: float64): Int128 = return res proc maskUInt64*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] result.udata[1] = arg.udata[1] result.udata[2] = 0 result.udata[3] = 0 proc maskUInt32*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] result.udata[1] = 0 result.udata[2] = 0 result.udata[3] = 0 proc maskUInt16*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] and 0xffff result.udata[1] = 0 result.udata[2] = 0 result.udata[3] = 0 proc maskUInt8*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] and 0xff result.udata[1] = 0 result.udata[2] = 0 diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 1ef0ce879e21d..ad5dd560c0f4d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -300,8 +300,7 @@ proc getNumber(L: var Lexer, result: var Token) = # Used to get slightly human friendlier err messages. const literalishChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '.', '\''} var msgPos = L.bufpos - var t: Token - t.literal = "" + var t = Token(literal: "") L.bufpos = startpos # Use L.bufpos as pos because of matchChars matchChars(L, t, literalishChars) # We must verify +/- specifically so that we're not past the literal diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 95fa193dc9896..89ed4967f9e73 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -477,19 +477,21 @@ proc registerModuleById*(g: ModuleGraph; m: FileIndex) = proc initOperators*(g: ModuleGraph): Operators = # These are safe for IC. # Public because it's used by DrNim. - result.opLe = createMagic(g, "<=", mLeI) - result.opLt = createMagic(g, "<", mLtI) - result.opAnd = createMagic(g, "and", mAnd) - result.opOr = createMagic(g, "or", mOr) - result.opIsNil = createMagic(g, "isnil", mIsNil) - result.opEq = createMagic(g, "==", mEqI) - result.opAdd = createMagic(g, "+", mAddI) - result.opSub = createMagic(g, "-", mSubI) - result.opMul = createMagic(g, "*", mMulI) - result.opDiv = createMagic(g, "div", mDivI) - result.opLen = createMagic(g, "len", mLengthSeq) - result.opNot = createMagic(g, "not", mNot) - result.opContains = createMagic(g, "contains", mInSet) + result = Operators( + opLe: createMagic(g, "<=", mLeI), + opLt: createMagic(g, "<", mLtI), + opAnd: createMagic(g, "and", mAnd), + opOr: createMagic(g, "or", mOr), + opIsNil: createMagic(g, "isnil", mIsNil), + opEq: createMagic(g, "==", mEqI), + opAdd: createMagic(g, "+", mAddI), + opSub: createMagic(g, "-", mSubI), + opMul: createMagic(g, "*", mMulI), + opDiv: createMagic(g, "div", mDivI), + opLen: createMagic(g, "len", mLengthSeq), + opNot: createMagic(g, "not", mNot), + opContains: createMagic(g, "contains", mInSet) + ) proc initModuleGraphFields(result: ModuleGraph) = # A module ID of -1 means that the symbol is not attached to a module at all, diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5c30acff3cec3..1d67811829f56 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -61,14 +61,12 @@ proc makeCString*(s: string): Rope = result.add('\"') proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo = - result.fullPath = fullPath - #shallow(result.fullPath) - result.projPath = projPath - #shallow(result.projPath) - result.shortName = fullPath.extractFilename + result = TFileInfo(fullPath: fullPath, projPath: projPath, + shortName: fullPath.extractFilename, + quotedFullName: fullPath.string.makeCString, + lines: @[] + ) result.quotedName = result.shortName.makeCString - result.quotedFullName = fullPath.string.makeCString - result.lines = @[] when defined(nimpretty): if not result.fullPath.isEmpty: try: @@ -136,7 +134,7 @@ proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex = fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy) proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = - result.fileIndex = fileInfoIdx + result = TLineInfo(fileIndex: fileInfoIdx) if line < int high(uint16): result.line = uint16(line) else: diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 6261c8fda9091..932cffba89911 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -498,7 +498,7 @@ proc checkCall(n, ctx, map): Check = # check args and handle possible mutations var isNew = false - result.map = map + result = Check(map: map) for i, child in n: discard check(child, ctx, map) @@ -753,6 +753,7 @@ proc checkReturn(n, ctx, map): Check = proc checkIf(n, ctx, map): Check = ## check branches based on condition + result = default(Check) var mapIf: NilMap = map # first visit the condition @@ -825,7 +826,7 @@ proc checkFor(n, ctx, map): Check = var check2 = check(n.sons[2], ctx, m) var map2 = check2.map - result.map = ctx.union(map0, m) + result = Check(map: ctx.union(map0, m)) result.map = ctx.union(result.map, map2) result.nilability = Safe @@ -853,7 +854,7 @@ proc checkWhile(n, ctx, map): Check = var check2 = check(n.sons[1], ctx, m) var map2 = check2.map - result.map = ctx.union(map0, map1) + result = Check(map: ctx.union(map0, map1)) result.map = ctx.union(result.map, map2) result.nilability = Safe @@ -899,7 +900,7 @@ proc checkInfix(n, ctx, map): Check = proc checkIsNil(n, ctx, map; isElse: bool = false): Check = ## check isNil calls ## update the map depending on if it is not isNil or isNil - result.map = newNilMap(map) + result = Check(map: newNilMap(map)) let value = n[1] result.map.store(ctx, ctx.index(n[1]), if not isElse: Nil else: Safe, TArg, n.info, n) @@ -947,7 +948,7 @@ proc checkCase(n, ctx, map): Check = # c2 # also a == true is a , a == false is not a let base = n[0] - result.map = map.copyMap() + result = Check(map: map.copyMap()) result.nilability = Safe var a: PNode = nil for child in n: @@ -1219,7 +1220,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = result = check(n.sons[1], ctx, map) of nkStmtList, nkStmtListExpr, nkChckRangeF, nkChckRange64, nkChckRange, nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkElse: - result.map = map + result = Check(map: map) if n.kind in {nkObjConstr, nkTupleConstr}: # TODO deeper nested elements? # A(field: B()) # @@ -1247,7 +1248,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = of nkAsgn, nkFastAsgn, nkSinkAsgn: result = checkAsgn(n[0], n[1], ctx, map) of nkVarSection: - result.map = map + result = Check(map: map) for child in n: result = checkAsgn(child[0], child[2], ctx, result.map) of nkForStmt: @@ -1273,8 +1274,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = else: var elementMap = map.copyMap() - var elementCheck: Check - elementCheck.map = elementMap + var elementCheck = Check(map: elementMap) for element in n: elementCheck = check(element, ctx, elementCheck.map) diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 4b6e22bc9d775..a5324ea76c93f 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -79,6 +79,8 @@ proc getPathVersionChecksum*(p: string): tuple[name, version, checksum: string] ## ``/home/user/.nimble/pkgs/package-0.1-febadeaea2345e777f0f6f8433f7f0a52edd5d1b`` into ## ``("/home/user/.nimble/pkgs/package", "0.1", "febadeaea2345e777f0f6f8433f7f0a52edd5d1b")`` + result = ("", "", "") + const checksumSeparator = '-' const versionSeparator = '-' const specialVersionSepartator = "-#" diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 1e7d62b4da425..5417cd1e93aaa 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -223,7 +223,7 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache; stream = llStreamOpen(filename, fmRead) if stream != nil: openLexer(L, filename, stream, cache, config) - tok.tokType = tkEof # to avoid a pointless warning + tok = Token(tokType: tkEof) # to avoid a pointless warning var condStack: seq[bool] = @[] confTok(L, tok, config, condStack) # read in the first token while tok.tokType != tkEof: parseAssignment(L, tok, config, filename, condStack) diff --git a/compiler/parser.nim b/compiler/parser.nim index 4ed38f739e1f1..1017759a91622 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -2574,7 +2574,7 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef; var stream = llStreamOpen(s) stream.lineOffset = line - var p: Parser + var p = Parser() p.lex.errorHandler = errorHandler openParser(p, AbsoluteFile filename, stream, cache, config) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 7b0d7e4fb43d2..04d8593ccba89 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -276,10 +276,7 @@ proc addToArgList(result, n: PNode) = proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = ## returns a tree to semcheck if the rule triggered; nil otherwise - var ctx: TPatternContext - ctx.owner = s - ctx.c = c - ctx.formals = s.typ.len-1 + var ctx = TPatternContext(owner: s, c: c, formals: s.typ.len-1) var m = matchStmtList(ctx, s.ast[patternPos], n) if isNil(m): return nil # each parameter should have been bound; we simply setup a call and diff --git a/compiler/procfind.nim b/compiler/procfind.nim index 468879ba2ddba..65266201ab323 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -54,7 +54,7 @@ proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym = proc searchForProc*(c: PContext, scope: PScope, fn: PSym): tuple[proto: PSym, comesFromShadowScope: bool] = var scope = scope - result.proto = searchForProcAux(c, scope, fn) + result = (searchForProcAux(c, scope, fn), false) while result.proto == nil and scope.isShadowScope: scope = scope.parent result.proto = searchForProcAux(c, scope, fn) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index d1637e1f28704..874055cdcde96 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -64,10 +64,12 @@ type proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = case typ.kind of nkSym: - var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid - fc.c = c.c - fc.field = typ.sym - fc.replaceByFieldName = c.m == mFieldPairs + # either 'tup[i]' or 'field' is valid + var fc = TFieldInstCtx( + c: c.c, + field: typ.sym, + replaceByFieldName: c.m == mFieldPairs + ) openScope(c.c) inc c.c.inUnrolledContext let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) @@ -139,20 +141,19 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var loopBody = n[^1] for i in 0..`_ ## * `newCountTable proc<#newCountTable>`_ for creating a ## `CountTableRef` + result = default(CountTable[A]) initImpl(result, initialSize) proc toCountTable*[A](keys: openArray[A]): CountTable[A] = From 91ad6a740bad84f76ecfba253d12f07d6abbd3eb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 15 Dec 2023 10:20:57 +0100 Subject: [PATCH 048/123] type refactor: part 4 (#23077) --- compiler/aliases.nim | 4 +-- compiler/ast.nim | 9 +++++- compiler/ccgcalls.nim | 16 ++++------- compiler/ccgexprs.nim | 11 ++++---- compiler/ccgreset.nim | 11 ++++---- compiler/ccgstmts.nim | 3 +- compiler/ccgtrav.nim | 15 +++++----- compiler/ccgtypes.nim | 37 ++++++++++++------------- compiler/cgmeth.nim | 22 ++++++++------- compiler/concepts.nim | 50 ++++++++++++++++++---------------- compiler/dfa.nim | 2 +- compiler/evaltempl.nim | 4 +-- compiler/expanddefaults.nim | 2 +- compiler/injectdestructors.nim | 4 +-- compiler/liftdestructors.nim | 18 ++++++------ compiler/semmacrosanity.nim | 2 +- compiler/sempass2.nim | 12 ++++---- compiler/semtypinst.nim | 35 ++++++++++++------------ compiler/sighashes.nim | 32 ++++++++++++---------- compiler/sigmatch.nim | 44 +++++++++++++++--------------- compiler/varpartitions.nim | 4 +-- compiler/vm.nim | 17 ++++++------ compiler/vmdeps.nim | 22 +++++++-------- compiler/vmgen.nim | 8 +++--- compiler/vmmarshal.nim | 7 +++-- 25 files changed, 197 insertions(+), 194 deletions(-) diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 3910ecb9dc68d..fa1167753f78a 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -59,8 +59,8 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = of tySet, tyArray: result = isPartOfAux(a.elementType, b, marker) of tyTuple: - for i in 0.. 0: result.add ", " genArgNoParam(p, ri[i][0], result) inc argsCounter @@ -584,7 +582,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) = # for better or worse c2nim translates the 'this' argument to a 'var T'. # However manual wrappers may also use 'ptr T'. In any case we support both # for convenience. - internalAssert p.config, i < typ.len + internalAssert p.config, i < typ.n.len assert(typ.n[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: @@ -674,7 +672,6 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) assert(typ.kind == tyProc) - assert(typ.len == typ.n.len) # don't call '$' here for efficiency: let pat = $ri[0].sym.loc.r internalAssert p.config, pat.len > 0 @@ -708,7 +705,6 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = pl.add(op.r) var params = newRopeAppender() for i in 2..= typ.len: + if i >= typ.n.len: internalError(p.config, ri.info, "varargs for objective C method?") assert(typ.n[i].kind == nkSym) var param = typ.n[i].sym diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 28f75f994874c..8cb9e208a488c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -236,8 +236,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: flags let t = skipTypes(dest.t, abstractInst).getUniqueType() - for i in 0.. 0: result.add ", " - getDefaultValue(p, t[i], info, result) + getDefaultValue(p, a, info, result) result.add "}" of tyArray: result.add "{" diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index da7f373988a70..e4abcfc8c6ebf 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -63,15 +63,14 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ.elementType) lineF(p, cpsStmts, "}$n", []) of tyObject: - for i in 0.. 0: result.add "," diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index a7470c44f317b..3fd269bc664e2 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -87,15 +87,14 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = else: lineF(p, cpsStmts, "}$n", []) of tyObject: - for i in 0..= typ.len: + if idx >= typ.kidsLen: raiseAssert "invalid apostrophe type parameter index" result = typ[idx] for i in 1..stars: - if result != nil and result.len > 0: - result = if result.kind == tyGenericInst: result[1] + if result != nil and result.kidsLen > 0: + result = if result.kind == tyGenericInst: result[FirstGenericParamAt] else: result.elemType proc getOpenArrayDesc(m: BModule; t: PType, check: var IntSet; kind: TypeDescKind): Rope = @@ -1079,9 +1079,9 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes result.add cppName.substr(chunkStart) else: result = cppNameAsRope & "<" - for i in 1.. 1: result.add(" COMMA ") - addResultType(tt[i]) + for needsComma, a in tt.genericInstParams: + if needsComma: result.add(" COMMA ") + addResultType(a) result.add("> ") # always call for sideeffects: assert t.kind != tyTuple @@ -1333,7 +1333,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; proc genTypeInfoAux(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = var base: Rope - if typ.len > 0 and typ.last != nil: + if typ.hasElementType and typ.last != nil: var x = typ.last if typ.kind == tyObject: x = x.skipTypes(skipPtrs) if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x): @@ -1457,11 +1457,10 @@ proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo proc genTupleInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info) var expr = getNimNode(m) - if typ.len > 0: - var tmp = getTempName(m) & "_" & $typ.len - genTNimNodeArray(m, tmp, rope(typ.len)) - for i in 0.. 0 and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions: + if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = @@ -1779,7 +1778,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn addf(typeEntry, ", .flags = $1};$n", [rope(flags)]) m.s[cfsVars].add typeEntry - if t.kind == tyObject and t.len > 0 and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions: + if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope = diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 6bfa6d7892d9c..6c3db7ad68f07 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -69,12 +69,14 @@ type proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult = result = No if a.name.id != b.name.id: return - if a.typ.len != b.typ.len: + if a.typ.signatureLen != b.typ.signatureLen: return - for i in 1.. 0 and f[0].kind != tyNone: + if f.hasElementType and f.elementType.kind != tyNone: # also check the generic's constraints: let oldLen = m.inferred.len - result = matchType(c, f[0], a, m) + result = matchType(c, f.elementType, a, m) m.inferred.setLen oldLen if result: when logBindings: echo "A adding ", f, " ", ak @@ -155,9 +156,9 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = # modifiers in the concept must be there in the actual implementation # too but not vice versa. if a.kind == f.kind: - result = matchType(c, f[0], a[0], m) + result = matchType(c, f.elementType, a.elementType, m) elif m.magic == mArrPut: - result = matchType(c, f[0], a, m) + result = matchType(c, f.elementType, a, m) else: result = false of tyEnum, tyObject, tyDistinct: @@ -167,7 +168,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = of tyBool, tyChar, tyInt..tyUInt64: let ak = a.skipTypes(ignorableForArgType) result = ak.kind == f.kind or ak.kind == tyOrdinal or - (ak.kind == tyGenericParam and ak.len > 0 and ak[0].kind == tyOrdinal) + (ak.kind == tyGenericParam and ak.hasElementType and ak.elementType.kind == tyOrdinal) of tyConcept: let oldLen = m.inferred.len let oldPotentialImplementation = m.potentialImplementation @@ -178,10 +179,11 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = m.inferred.setLen oldLen of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr, tyGenericInst: + # ^ XXX Rewrite this logic, it's more complex than it needs to be. result = false let ak = a.skipTypes(ignorableForArgType - {f.kind}) - if ak.kind == f.kind and f.len == ak.len: - for i in 0..= a.len + result = covered >= a.kidsLen if not result: m.inferred.setLen oldLen else: result = false - for i in 0.. 0: + if t.hasElementType: result = expandDefault(t.skipModifier, info) else: result = newZero(t, info, nkEmpty) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b8d6d5f636aa2..a6620de2a811c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -221,7 +221,7 @@ proc makePtrType(c: var Con, baseType: PType): PType = proc genOp(c: var Con; op: PSym; dest: PNode): PNode = var addrExp: PNode - if op.typ != nil and op.typ.len > 1 and op.typ.firstParamType.kind != tyVar: + if op.typ != nil and op.typ.signatureLen > 1 and op.typ.firstParamType.kind != tyVar: addrExp = dest else: addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) @@ -877,7 +877,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing c.inSpawn.dec let parameters = n[0].typ - let L = if parameters != nil: parameters.len else: 0 + let L = if parameters != nil: parameters.signatureLen else: 0 when false: var isDangerous = false diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 2987a04a84125..a3ca88dd50e8b 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -56,10 +56,10 @@ proc destructorOverridden(g: ModuleGraph; t: PType): bool = op != nil and sfOverridden in op.flags proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = - for i in 0.. 0 and t.baseClass != nil: + if t.baseClass != nil: fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, x, y) fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false) proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = var hasCase = isCaseObj(t.n) var obj = t - while obj.len > 0 and obj[0] != nil: - obj = skipTypes(obj[0], abstractPtrs) + while obj.baseClass != nil: + obj = skipTypes(obj.baseClass, abstractPtrs) hasCase = hasCase or isCaseObj(obj.n) if hasCase and c.kind in {attachedAsgn, attachedDeepCopy}: @@ -288,7 +288,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode = proc getCycleParam(c: TLiftCtx): PNode = assert c.kind in {attachedAsgn, attachedDup} - if c.fn.typ.len == 4: + if c.fn.typ.signatureLen == 4: result = c.fn.typ.n.lastSon assert result.kind == nkSym assert result.sym.name.s == "cyclic" @@ -308,9 +308,9 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result.add x if y != nil: result.add y - if op.typ.len == 4: + if op.typ.signatureLen == 4: assert y != nil - if c.fn.typ.len == 4: + if c.fn.typ.signatureLen == 4: result.add getCycleParam(c) else: # assume the worst: A cycle is created: diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 01b79c1bc6567..4aab216c7fd77 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -63,7 +63,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = if x.kind == tyTuple: n.typ = t for i in 0..= x.len: globalError conf, n.info, "invalid field at index " & $i + if i >= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i else: annotateType(n[i], x[i], conf) elif x.kind == tyProc and x.callConv == ccClosure: n.typ = t diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 9b386cf5cadac..e2d45a3884910 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -660,7 +660,7 @@ proc isTrival(caller: PNode): bool {.inline.} = proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; argIndex: int; caller: PNode) = let a = skipConvCastAndClosure(n) let op = a.typ - let param = if formals != nil and argIndex < formals.len and formals.n != nil: formals.n[argIndex].sym else: nil + let param = if formals != nil and formals.n != nil and argIndex < formals.n.len: formals.n[argIndex].sym else: nil # assume indirect calls are taken here: if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and not isTrival(caller) and @@ -695,7 +695,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags: markSideEffect(tracked, a, n.info) - let paramType = if formals != nil and argIndex < formals.len: formals[argIndex] else: nil + let paramType = if formals != nil and argIndex < formals.signatureLen: formals[argIndex] else: nil if paramType != nil and paramType.kind in {tyVar}: invalidateFacts(tracked.guards, n) if n.kind == nkSym and isLocalSym(tracked, n.sym): @@ -979,7 +979,7 @@ proc trackCall(tracked: PEffects; n: PNode) = # may not look like an assignment, but it is: let arg = n[1] initVarViaNew(tracked, arg) - if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.elementType.flags != {}: + if arg.typ.hasElementType and {tfRequiresInit} * arg.typ.elementType.flags != {}: if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and n[2].intVal == 0: # var s: seq[notnil]; newSeq(s, 0) is a special case! @@ -988,7 +988,7 @@ proc trackCall(tracked: PEffects; n: PNode) = message(tracked.config, arg.info, warnProveInit, $arg) # check required for 'nim check': - if n[1].typ.len > 0: + if n[1].typ.hasElementType: createTypeBoundOps(tracked, n[1].typ.elementType, n.info) createTypeBoundOps(tracked, n[1].typ, n.info) # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? @@ -1012,11 +1012,11 @@ proc trackCall(tracked: PEffects; n: PNode) = n[0].sym = op if op != nil and op.kind == tyProc: - for i in 1.. 0 and t.elementType.kind == tyObject and t.elementType.n != nil: + if t.kind == tyRef and t.hasElementType and t.elementType.kind == tyObject and t.elementType.n != nil: discard replaceObjBranches(cl, t.elementType.n) elif result.n != nil and t.kind == tyObject: @@ -712,7 +711,7 @@ when false: popInfoContext(p.config) proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) = - if t != nil and t.len > 0 and t.baseClass != nil: + if t != nil and t.baseClass != nil: let b = skipTypes(t.baseClass, skipPtrs) recomputeFieldPositions(b, b.n, currPosition) case obj.kind diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index ca1b74604faa5..a058ffee99051 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -104,8 +104,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi case t.kind of tyGenericInvocation: - for i in 0.. 0 and t.baseClass != nil: + if t.hasElementType and t.baseClass != nil: hashType c, t.baseClass, flags, conf of tyRef, tyPtr, tyVar: c &= char(t.kind) - if t.len > 0: + if t.hasElementType: c.hashType t.elementType, flags, conf if tfVarIsPtr in t.flags: c &= ".varisptr" of tyGenericBody: c &= char(t.kind) - if t.len > 0: + if t.hasElementType: c.hashType t.typeBodyImpl, flags, conf of tyFromExpr: c &= char(t.kind) @@ -201,15 +203,14 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi of tyTuple: c &= char(t.kind) if t.n != nil and CoType notin flags: - assert(t.n.len == t.len) for i in 0.. y: winner = 1 @@ -276,8 +276,8 @@ proc complexDisambiguation(a, b: PType): int = result = winner when false: var x, y: int - for i in 1.. 0 and f[0].skipTypes({tyBuiltInTypeClass, tyOr}).kind == tyProc: + if f != nil and f.hasElementType and f.elementType.skipTypes({tyBuiltInTypeClass, tyOr}).kind == tyProc: result = t.skipModifier else: result = t @@ -468,10 +468,10 @@ proc getObjectTypeOrNil(f: PType): PType = if f == nil: return nil case f.kind: of tyGenericInvocation, tyCompositeTypeClass, tyAlias: - if f.len <= 0 or f[0] == nil: + if not f.hasElementType or f.elementType == nil: result = nil else: - result = getObjectTypeOrNil(f[0]) + result = getObjectTypeOrNil(f.elementType) of tyGenericInst: result = getObjectTypeOrNil(f.skipModifier) of tyGenericBody: @@ -496,8 +496,8 @@ proc getObjectTypeOrNil(f: PType): PType = proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) = if fGenericOrigin != nil and last.kind == tyGenericInst and - last.len-1 == fGenericOrigin.len: - for i in 1.. 0: typ = typ.skipModifier + while typ.kind == tyTypeDesc and typ.hasElementType: typ = typ.skipModifier createStr regs[ra] regs[ra].node.strVal = typ.typeToString(preferExported) @@ -2280,11 +2280,11 @@ proc execute(c: PCtx, start: int): PNode = proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = c.loopIterations = c.config.maxLoopIterationsVM if sym.kind in routineKinds: - if sym.typ.len-1 != args.len: + if sym.typ.paramsLen != args.len: result = nil localError(c.config, sym.info, "NimScript: expected $# arguments, but got $#" % [ - $(sym.typ.len-1), $args.len]) + $(sym.typ.paramsLen), $args.len]) else: let start = genProc(c, sym) @@ -2296,8 +2296,8 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = if not isEmptyType(sym.typ.returnType) or sym.kind == skMacro: putIntoReg(tos.slots[0], getNullValue(sym.typ.returnType, sym.info, c.config)) # XXX We could perform some type checking here. - for i in 1.. n.safeLen and sym.typ.len > 1: + let sl = sym.typ.signatureLen + if sl > n.safeLen and sl > 1: globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [ - n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) + n.renderTree, $(n.safeLen-1), $(sym.typ.paramsLen)]) setupGlobalCtx(module, g, idgen) var c = PCtx g.vm diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 6d0e038139139..e293ab7b203dd 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -49,13 +49,13 @@ proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; inf inst=false): PNode = result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) result.add atomicTypeX(cache, name, m, t, info, idgen) - for i in 0.. 0: t.n[0][pragmasEffects].copyTree diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 9667daa3d0441..9bbea2b08e62c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -620,7 +620,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = for i in 0..= fntyp.len: + if i >= fntyp.signatureLen: internalAssert c.config, tfVarargs in fntyp.flags c.gABx(n, opcSetType, r, c.genType(n[i].typ)) if dest < 0: @@ -1874,7 +1874,7 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = genArrAccessOpcode(c, n, dest, opc, flags) proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) = - if t != nil and t.len > 0 and t.baseClass != nil: + if t != nil and t.baseClass != nil: let b = skipTypes(t.baseClass, skipPtrs) getNullValueAux(b, b.n, result, conf, currPosition) case obj.kind @@ -1929,8 +1929,8 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = result.add getNullValue(elemType(t), info, conf) of tyTuple: result = newNodeIT(nkTupleConstr, info, t) - for i in 0.. 0: s.add(", ") s.add("\"Field" & $i) s.add("\": ") - storeAny(s, t[i], a[i].skipColon, stored, conf) + storeAny(s, ti, a[i].skipColon, stored, conf) s.add("}") of tyObject: s.add("{") @@ -208,11 +208,12 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkTupleConstr) var i = 0 + let tupleLen = t.kidsLen while p.kind != jsonObjectEnd and p.kind != jsonEof: if p.kind != jsonString: raiseParseErr(p, "string expected for a field name") next(p) - if i >= t.len: + if i >= tupleLen: raiseParseErr(p, "too many fields to tuple type " & typeToString(t)) result.add loadAny(p, t[i], tab, cache, conf, idgen) inc i From 315b59e824fc8fc473439fb0cb23ff7ac61c0563 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Fri, 15 Dec 2023 12:59:56 +0100 Subject: [PATCH 049/123] make treeToYaml print yaml (and not json) (#23082) less verbose - used in nph --- compiler/astalgo.nim | 173 +------------------------------------ compiler/astyaml.nim | 200 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 170 deletions(-) create mode 100644 compiler/astyaml.nim diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 238aa6776a4a1..0fd13de00cace 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -12,24 +12,18 @@ # the data structures here are used in various places of the compiler. import - ast, options, lineinfos, ropes, idents, rodutils, + ast, astyaml, options, lineinfos, idents, rodutils, msgs import std/[hashes, intsets] import std/strutils except addf +export astyaml.treeToYaml, astyaml.typeToYaml, astyaml.symToYaml, astyaml.lineInfoToStr + when defined(nimPreviewSlimSystem): import std/assertions proc hashNode*(p: RootRef): Hash -proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope - # Convert a tree into its YAML representation; this is used by the - # YAML code generator and it is invaluable for debugging purposes. - # If maxRecDepht <> -1 then it won't print the whole graph. -proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope -proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope -proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope - # these are for debugging only: They are not really deprecated, but I want # the warning so that release versions do not contain debugging statements: @@ -236,167 +230,6 @@ proc mustRehash(length, counter: int): bool = assert(length > counter) result = (length * 2 < counter * 3) or (length - counter < 4) -proc rspaces(x: int): Rope = - # returns x spaces - result = rope(spaces(x)) - -proc toYamlChar(c: char): string = - case c - of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4) - of '\'', '\"', '\\': result = '\\' & c - else: result = $c - -proc makeYamlString*(s: string): Rope = - # We have to split long strings into many ropes. Otherwise - # this could trigger InternalError(111). See the ropes module for - # further information. - const MaxLineLength = 64 - result = "" - var res = "\"" - for i in 0.. 0: - result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) - result.addf("$N$1\"magic\": $2", [istr, makeYamlString($n.magic)]) - result.addf("$N$1\"ast\": $2", [istr, ast]) - result.addf("$N$1\"options\": $2", [istr, flagsToStr(n.options)]) - result.addf("$N$1\"position\": $2", [istr, rope(n.position)]) - result.addf("$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)]) - result.addf("$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)]) - if card(n.loc.flags) > 0: - result.addf("$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)]) - result.addf("$N$1\"r\": $2", [istr, n.loc.r]) - result.addf("$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)]) - result.addf("$N$1}", [rspaces(indent)]) - -proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int, - maxRecDepth: int): Rope = - var sonsRope: Rope - if n == nil: - result = "" - sonsRope = rope("null") - elif containsOrIncl(marker, n.id): - result = "" - sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope( - strutils.toHex(cast[int](n), sizeof(n) * 2))] - else: - sonsRope = rope("[") - for i, a in n.ikids: - if i > 0: sonsRope.add(",") - sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, a, - marker, indent + 4, maxRecDepth - 1)]) - sonsRope.addf("$N$1]", [rspaces(indent + 2)]) - - let istr = rspaces(indent + 2) - result = rope("{") - result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)]) - result.addf("$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)]) - result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)]) - if card(n.flags) > 0: - result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) - result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)]) - result.addf("$N$1\"size\": $2", [istr, rope(n.size)]) - result.addf("$N$1\"align\": $2", [istr, rope(n.align)]) - result.addf("$N$1\"sons\": $2", [istr, sonsRope]) - -proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int, - maxRecDepth: int): Rope = - if n == nil: - result = rope("null") - else: - var istr = rspaces(indent + 2) - result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)] - if maxRecDepth != 0: - if conf != nil: - result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)]) - case n.kind - of nkCharLit..nkUInt64Lit: - result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) - of nkFloatLit, nkFloat32Lit, nkFloat64Lit: - result.addf(",$N$1\"floatVal\": $2", - [istr, rope(n.floatVal.toStrMaxPrecision)]) - of nkStrLit..nkTripleStrLit: - result.addf(",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) - of nkSym: - result.addf(",$N$1\"sym\": $2", - [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)]) - of nkIdent: - if n.ident != nil: - result.addf(",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) - else: - result.addf(",$N$1\"ident\": null", [istr]) - else: - if n.len > 0: - result.addf(",$N$1\"sons\": [", [istr]) - for i in 0.. 0: result.add(",") - result.addf("$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n[i], - marker, indent + 4, maxRecDepth - 1)]) - result.addf("$N$1]", [istr]) - result.addf(",$N$1\"typ\": $2", - [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)]) - result.addf("$N$1}", [rspaces(indent)]) - -proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope = - var marker = initIntSet() - result = treeToYamlAux(conf, n, marker, indent, maxRecDepth) - -proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope = - var marker = initIntSet() - result = typeToYamlAux(conf, n, marker, indent, maxRecDepth) - -proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope = - var marker = initIntSet() - result = symToYamlAux(conf, n, marker, indent, maxRecDepth) - import std/tables const backrefStyle = "\e[90m" diff --git a/compiler/astyaml.nim b/compiler/astyaml.nim new file mode 100644 index 0000000000000..b098d92b93d6c --- /dev/null +++ b/compiler/astyaml.nim @@ -0,0 +1,200 @@ +# +# +# The Nim Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# AST YAML printing + +import "."/[ast, lineinfos, msgs, options, rodutils] +import std/[intsets, strutils] + +proc addYamlString*(res: var string; s: string) = + res.add "\"" + for c in s: + case c + of '\0' .. '\x1F', '\x7F' .. '\xFF': + res.add("\\u" & strutils.toHex(ord(c), 4)) + of '\"', '\\': + res.add '\\' & c + else: + res.add c + + res.add('\"') + +proc makeYamlString(s: string): string = + result = "" + result.addYamlString(s) + +proc flagsToStr[T](flags: set[T]): string = + if flags == {}: + result = "[]" + else: + result = "" + for x in items(flags): + if result != "": + result.add(", ") + result.addYamlString($x) + result = "[" & result & "]" + +proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): string = + result = "[" + result.addYamlString(toFilename(conf, info)) + result.addf ", $1, $2]", [toLinenumber(info), toColumn(info)] + +proc treeToYamlAux( + res: var string; + conf: ConfigRef; + n: PNode; + marker: var IntSet; + indent, maxRecDepth: int; +) + +proc symToYamlAux( + res: var string; + conf: ConfigRef; + n: PSym; + marker: var IntSet; + indent, maxRecDepth: int; +) + +proc typeToYamlAux( + res: var string; + conf: ConfigRef; + n: PType; + marker: var IntSet; + indent, maxRecDepth: int; +) + +proc symToYamlAux( + res: var string; + conf: ConfigRef; + n: PSym; + marker: var IntSet; + indent: int; + maxRecDepth: int; +) = + if n == nil: + res.add("null") + elif containsOrIncl(marker, n.id): + res.addYamlString(n.name.s) + else: + let istr = spaces(indent * 4) + + res.addf("kind: $1", [makeYamlString($n.kind)]) + res.addf("\n$1name: $2", [istr, makeYamlString(n.name.s)]) + res.addf("\n$1typ: ", [istr]) + res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth - 1) + if conf != nil: + # if we don't pass the config, we probably don't care about the line info + res.addf("\n$1info: $2", [istr, lineInfoToStr(conf, n.info)]) + if card(n.flags) > 0: + res.addf("\n$1flags: $2", [istr, flagsToStr(n.flags)]) + res.addf("\n$1magic: $2", [istr, makeYamlString($n.magic)]) + res.addf("\n$1ast: ", [istr]) + res.treeToYamlAux(conf, n.ast, marker, indent + 1, maxRecDepth - 1) + res.addf("\n$1options: $2", [istr, flagsToStr(n.options)]) + res.addf("\n$1position: $2", [istr, $n.position]) + res.addf("\n$1k: $2", [istr, makeYamlString($n.loc.k)]) + res.addf("\n$1storage: $2", [istr, makeYamlString($n.loc.storage)]) + if card(n.loc.flags) > 0: + res.addf("\n$1flags: $2", [istr, makeYamlString($n.loc.flags)]) + res.addf("\n$1r: $2", [istr, n.loc.r]) + res.addf("\n$1lode: $2", [istr]) + res.treeToYamlAux(conf, n.loc.lode, marker, indent + 1, maxRecDepth - 1) + +proc typeToYamlAux( + res: var string; + conf: ConfigRef; + n: PType; + marker: var IntSet; + indent: int; + maxRecDepth: int; +) = + if n == nil: + res.add("null") + elif containsOrIncl(marker, n.id): + res.addf "\"$1 @$2\"" % [$n.kind, strutils.toHex(cast[uint](n), sizeof(n) * 2)] + else: + let istr = spaces(indent * 4) + res.addf("kind: $2", [istr, makeYamlString($n.kind)]) + res.addf("\n$1sym: ") + res.symToYamlAux(conf, n.sym, marker, indent + 1, maxRecDepth - 1) + res.addf("\n$1n: ") + res.treeToYamlAux(conf, n.n, marker, indent + 1, maxRecDepth - 1) + if card(n.flags) > 0: + res.addf("\n$1flags: $2", [istr, flagsToStr(n.flags)]) + res.addf("\n$1callconv: $2", [istr, makeYamlString($n.callConv)]) + res.addf("\n$1size: $2", [istr, $(n.size)]) + res.addf("\n$1align: $2", [istr, $(n.align)]) + if n.len > 0: + res.addf("\n$1sons:") + for i in 0.. 0: + res.addf("\n$1sons: ", [istr]) + for i in 0 ..< n.len: + res.addf("\n$1 - ", [istr]) + res.treeToYamlAux(conf, n[i], marker, indent + 1, maxRecDepth - 1) + if n.typ != nil: + res.addf("\n$1typ: ", [istr]) + res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth) + +proc treeToYaml*( + conf: ConfigRef; n: PNode; indent: int = 0; maxRecDepth: int = -1 +): string = + var marker = initIntSet() + result = newStringOfCap(1024) + result.treeToYamlAux(conf, n, marker, indent, maxRecDepth) + +proc typeToYaml*( + conf: ConfigRef; n: PType; indent: int = 0; maxRecDepth: int = -1 +): string = + var marker = initIntSet() + result = newStringOfCap(1024) + result.typeToYamlAux(conf, n, marker, indent, maxRecDepth) + +proc symToYaml*( + conf: ConfigRef; n: PSym; indent: int = 0; maxRecDepth: int = -1 +): string = + var marker = initIntSet() + result = newStringOfCap(1024) + result.symToYamlAux(conf, n, marker, indent, maxRecDepth) From 0c3e7039609deddd3567ce36c841b1c3f22f8fe7 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 15 Dec 2023 21:12:28 +0800 Subject: [PATCH 050/123] fixes not nil examples (#23080) --- doc/manual_experimental.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index d20695933c109..f5e39b768bc01 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -566,6 +566,7 @@ All types for which `nil` is a valid value can be annotated with the {.experimental: "notnil".} type + TObj = object PObject = ref TObj not nil TProc = (proc (x, y: int)) not nil From 9648d97a8dab053067e2c50b2f5b0d7c3650d5e3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:05:57 +0800 Subject: [PATCH 051/123] fixes #22637; now `--experimental:strictNotNil` can be enabled globally (#23079) fixes #22637 --- compiler/nilcheck.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 932cffba89911..7e0efc34bbe91 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -1247,10 +1247,10 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = result = checkIf(n, ctx, map) of nkAsgn, nkFastAsgn, nkSinkAsgn: result = checkAsgn(n[0], n[1], ctx, map) - of nkVarSection: + of nkVarSection, nkLetSection: result = Check(map: map) for child in n: - result = checkAsgn(child[0], child[2], ctx, result.map) + result = checkAsgn(child[0].skipPragmaExpr, child[2], ctx, result.map) of nkForStmt: result = checkFor(n, ctx, map) of nkCaseStmt: From 0bd4d802383518cfbb43fa02375602abdfb6114f Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sun, 17 Dec 2023 19:01:00 +1100 Subject: [PATCH 052/123] Allow `parseAll` to parse statements separated by semicolons (#23088) Fixes the second issue listed in #9918. Fixed by replacing the logic used in `parseAll` with just a continious loop to `complexOrSimpleStmt` like what the [normal parser does](https://github.com/nim-lang/Nim/blob/devel/compiler/passes.nim#L143-L146). `complexOrSimpleStmt` [guarantees progress](https://github.com/nim-lang/Nim/blob/devel/compiler/parser.nim#L2541) so we don't need to check progress ourselves. Also allows `nimpretty` to parse more valid Nim code such as ```nim proc foo(); # Would complain about indention here # ... proc foo() = # ... ``` --- compiler/parser.nim | 26 ++++++++++---------------- tests/macros/ttryparseexpr.nim | 4 ++++ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 1017759a91622..024807a8a6590 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -2514,22 +2514,6 @@ proc parseStmt(p: var Parser): PNode = if err and p.tok.tokType == tkEof: break setEndInfo() -proc parseAll*(p: var Parser): PNode = - ## Parses the rest of the input stream held by the parser into a PNode. - result = newNodeP(nkStmtList, p) - while p.tok.tokType != tkEof: - p.hasProgress = false - var a = complexOrSimpleStmt(p) - if a.kind != nkEmpty and p.hasProgress: - result.add(a) - else: - parMessage(p, errExprExpected, p.tok) - # bugfix: consume a token here to prevent an endless loop: - getTok(p) - if p.tok.indent != 0: - parMessage(p, errInvalidIndentation) - setEndInfo() - proc checkFirstLineIndentation*(p: var Parser) = if p.tok.indent != 0 and tsLeading in p.tok.spacing: parMessage(p, errInvalidIndentation) @@ -2564,6 +2548,16 @@ proc parseTopLevelStmt*(p: var Parser): PNode = break setEndInfo() +proc parseAll*(p: var Parser): PNode = + ## Parses the rest of the input stream held by the parser into a PNode. + result = newNodeP(nkStmtList, p) + while true: + let nextStmt = p.parseTopLevelStmt() + if nextStmt.kind == nkEmpty: + break + result &= nextStmt + setEndInfo() + proc parseString*(s: string; cache: IdentCache; config: ConfigRef; filename: string = ""; line: int = 0; errorHandler: ErrorHandler = nil): PNode = diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim index fc0ee61d0b54c..e6e9e9880ab3c 100644 --- a/tests/macros/ttryparseexpr.nim +++ b/tests/macros/ttryparseexpr.nim @@ -18,3 +18,7 @@ const c = test("\"") # bug #2504 echo a, " ", b + +static: + # Issue #9918 + discard parseStmt("echo(1+1);") From b3b87f0f8a8091c88461953d686f9772dfb3c4bc Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sun, 17 Dec 2023 22:29:46 +1100 Subject: [PATCH 053/123] Mark `macros.error` as `.noreturn.` (#23081) Closes #14329 Marks `macros.error` as `.noreturn` so that it can be used in expressions. This also fixes the issue that occurred in #19659 where a stmt that could be an expression (Due to having `discardable` procs at the end of other branches) would believe a `noreturn` proc is returning the same type e.g. ```nim proc bar(): int {.discardable.} = discard if true: bar() else: quit(0) # Says that quit is of type `int` and needs to be used/discarded except it actually has no return type ``` --- compiler/condsyms.nim | 1 + compiler/semstmts.nim | 5 +++++ lib/core/macros.nim | 7 ++++++- tests/casestmt/tcasestmt.nim | 14 ++++++++++++++ tests/macros/t14329.nim | 4 ++++ 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/macros/t14329.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 5865e5310e02d..085576c6b2f40 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -157,6 +157,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimAllowNonVarDestructor") defineSymbol("nimHasQuirky") defineSymbol("nimHasEnsureMove") + defineSymbol("nimHasNoReturnError") defineSymbol("nimUseStrictDefs") defineSymbol("nimHasNolineTooLong") diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index eacda7f9b7c1c..a0eda36d1eada 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -169,6 +169,11 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) = while n.kind in skipForDiscardable: if n.kind == nkTryStmt: n = n[0] else: n = n.lastSon + + # Ignore noreturn procs since they don't have a type + if n.endsInNoReturn: + return + var s = "expression '" & $n & "' is of type '" & result.typ.typeToString & "' and has to be used (or discarded)" if result.info.line != n.info.line or diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 01a654b6c675a..fe911ffbf6319 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -427,7 +427,12 @@ proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} = let x = 12 echo x -proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.} +when defined(nimHasNoReturnError): + {.pragma: errorNoReturn, noreturn.} +else: + {.pragma: errorNoReturn.} + +proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign, errorNoReturn.} ## Writes an error message at compile time. The optional `n: NimNode` ## parameter is used as the source for file and line number information in ## the compilation error message. diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 3a4907494ad51..aea0c96a42beb 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -298,3 +298,17 @@ proc main(a: uint64) = static: main(10) main(10) + +block: + # Just needs to compile + proc bar(): int {.discardable.} = discard + + proc foo() {.noreturn.} = discard + + case "*" + of "*": + bar() + else: + # Make sure this noreturn doesn't + # cause the discardable to not discard + foo() diff --git a/tests/macros/t14329.nim b/tests/macros/t14329.nim new file mode 100644 index 0000000000000..b5606424ae92f --- /dev/null +++ b/tests/macros/t14329.nim @@ -0,0 +1,4 @@ +import macros + +macro myMacro(n) = + let x = if true: newLit"test" else: error "error", n From 9b08abaa0574c32f414c09bb4ef183739003884d Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sun, 17 Dec 2023 22:30:11 +1100 Subject: [PATCH 054/123] Show the name of the unexpected exception that was thrown in `std/unittest` (#23087) Show name of error that wasn't expected in an `expect` block --- lib/pure/unittest.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 2f3437ac7ceee..cfb762258590c 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -773,7 +773,8 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = except errorTypes: discard except: - checkpoint(lineInfoLit & ": Expect Failed, unexpected exception was thrown.") + let err = getCurrentException() + checkpoint(lineInfoLit & ": Expect Failed, " & $err.name & " was thrown.") fail() {.pop.} From fe18ec5dc089831c6ea634ade211d8d0dadfec86 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 17 Dec 2023 18:43:52 +0100 Subject: [PATCH 055/123] types refactoring; WIP (#23086) --- compiler/ast.nim | 36 ++++++++++++++++++-- compiler/astyaml.nim | 76 +++++++++--------------------------------- compiler/enumtostr.nim | 2 +- compiler/patterns.nim | 2 +- compiler/sem.nim | 14 ++++---- compiler/semcall.nim | 11 +++--- compiler/seminst.nim | 21 ++++++------ compiler/suggest.nim | 4 +-- compiler/types.nim | 4 +-- compiler/vm.nim | 6 ++-- compiler/vtables.nim | 2 +- 11 files changed, 81 insertions(+), 97 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index ce86d7369cf1e..06b6cd3573a0a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1602,6 +1602,14 @@ proc signatureLen*(t: PType): int {.inline.} = proc paramsLen*(t: PType): int {.inline.} = result = t.sons.len - 1 +proc genericParamsLen*(t: PType): int {.inline.} = + assert t.kind == tyGenericInst + result = t.sons.len - 2 # without 'head' and 'body' + +proc genericInvocationParamsLen*(t: PType): int {.inline.} = + assert t.kind == tyGenericInvocation + result = t.sons.len - 1 # without 'head' + proc kidsLen*(t: PType): int {.inline.} = result = t.sons.len @@ -1611,17 +1619,34 @@ proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0 proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0 proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1 +proc genericConstraint*(t: PType): PType {.inline.} = t.sons[0] + iterator genericInstParams*(t: PType): (bool, PType) = for i in 1..= b.sons.len: + yield (false, nil, nil) + else: + yield (true, a.sons[i], b.sons[i]) + +iterator genericBodyParams*(t: PType): (int, PType) = for i in 0.. 1: + setLen(t.sons, 1) + proc assignType*(dest, src: PType) = dest.kind = src.kind dest.flags = src.flags @@ -2041,7 +2071,7 @@ proc skipGenericOwner*(s: PSym): PSym = ## symbol. This proc skips such owners and goes straight to the owner ## of the generic itself (the module or the enclosing proc). result = if s.kind == skModule: - s + s elif s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule: s.owner.owner else: diff --git a/compiler/astyaml.nim b/compiler/astyaml.nim index b098d92b93d6c..c7e090cd3bef5 100644 --- a/compiler/astyaml.nim +++ b/compiler/astyaml.nim @@ -45,38 +45,11 @@ proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): string = result.addYamlString(toFilename(conf, info)) result.addf ", $1, $2]", [toLinenumber(info), toColumn(info)] -proc treeToYamlAux( - res: var string; - conf: ConfigRef; - n: PNode; - marker: var IntSet; - indent, maxRecDepth: int; -) - -proc symToYamlAux( - res: var string; - conf: ConfigRef; - n: PSym; - marker: var IntSet; - indent, maxRecDepth: int; -) - -proc typeToYamlAux( - res: var string; - conf: ConfigRef; - n: PType; - marker: var IntSet; - indent, maxRecDepth: int; -) - -proc symToYamlAux( - res: var string; - conf: ConfigRef; - n: PSym; - marker: var IntSet; - indent: int; - maxRecDepth: int; -) = +proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent, maxRecDepth: int) +proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent, maxRecDepth: int) +proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent, maxRecDepth: int) + +proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent: int; maxRecDepth: int) = if n == nil: res.add("null") elif containsOrIncl(marker, n.id): @@ -106,14 +79,7 @@ proc symToYamlAux( res.addf("\n$1lode: $2", [istr]) res.treeToYamlAux(conf, n.loc.lode, marker, indent + 1, maxRecDepth - 1) -proc typeToYamlAux( - res: var string; - conf: ConfigRef; - n: PType; - marker: var IntSet; - indent: int; - maxRecDepth: int; -) = +proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent: int; maxRecDepth: int) = if n == nil: res.add("null") elif containsOrIncl(marker, n.id): @@ -130,20 +96,14 @@ proc typeToYamlAux( res.addf("\n$1callconv: $2", [istr, makeYamlString($n.callConv)]) res.addf("\n$1size: $2", [istr, $(n.size)]) res.addf("\n$1align: $2", [istr, $(n.align)]) - if n.len > 0: + if n.hasElementType: res.addf("\n$1sons:") - for i in 0.. 0: + if result == nil and t.baseClass != nil: result = searchObjCase(t.baseClass.skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field) doAssert result != nil diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 04d8593ccba89..32ec7fb537dd4 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -276,7 +276,7 @@ proc addToArgList(result, n: PNode) = proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = ## returns a tree to semcheck if the rule triggered; nil otherwise - var ctx = TPatternContext(owner: s, c: c, formals: s.typ.len-1) + var ctx = TPatternContext(owner: s, c: c, formals: s.typ.paramsLen) var m = matchStmtList(ctx, s.ast[patternPos], n) if isNil(m): return nil # each parameter should have been bound; we simply setup a call and diff --git a/compiler/sem.nim b/compiler/sem.nim index 47b9600f51ddb..1ae7d4626489f 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -144,7 +144,7 @@ proc commonType*(c: PContext; x, y: PType): PType = elif b.kind == tyTyped: result = b elif a.kind == tyTypeDesc: # turn any concrete typedesc into the abstract typedesc type - if a.len == 0: result = a + if not a.hasElementType: result = a else: result = newType(tyTypeDesc, c.idgen, a.owner) rawAddSon(result, newType(tyNone, c.idgen, a.owner)) @@ -153,17 +153,17 @@ proc commonType*(c: PContext; x, y: PType): PType = # check for seq[empty] vs. seq[int] let idx = ord(b.kind == tyArray) if a[idx].kind == tyEmpty: return y - elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len: + elif a.kind == tyTuple and b.kind == tyTuple and sameTupleLengths(a, b): var nt: PType = nil - for i in 0.. 0: let (t, u) = typeStack.pop() @@ -608,10 +608,11 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = continue case t.kind of ConcreteTypes, tyGenericInvocation, tyUncheckedArray: + # XXX This logic makes no sense for `tyUncheckedArray` # nested, add all the types to stack let startIdx = if u.kind in ConcreteTypes: 0 else: 1 - endIdx = min(u.len() - startIdx, t.len()) + endIdx = min(u.kidsLen() - startIdx, t.kidsLen()) for i in startIdx ..< endIdx: # early exit with current impl @@ -749,7 +750,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = proc setGenericParams(c: PContext, n, expectedParams: PNode) = ## sems generic params in subscript expression for i in 1.. 1: + if i > FirstParamAt: resetIdTable(cl.symMap) resetIdTable(cl.localCache) # take a note of the original type. If't a free type or static parameter # we'll need to keep it unbound for the `fitNode` operation below... - var typeToFit = result[i] + var typeToFit = resulti - let needsStaticSkipping = result[i].kind == tyFromExpr - result[i] = replaceTypeVarsT(cl, result[i]) + let needsStaticSkipping = resulti.kind == tyFromExpr + result[i] = replaceTypeVarsT(cl, resulti) if needsStaticSkipping: result[i] = result[i].skipTypes({tyStatic}) @@ -295,7 +294,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, resetIdTable(cl.symMap) resetIdTable(cl.localCache) cl.isReturnType = true - result[0] = replaceTypeVarsT(cl, result[0]) + result.setReturnType replaceTypeVarsT(cl, result.returnType) cl.isReturnType = false result.n[0] = originalParams[0].copyTree if result[0] != nil: @@ -377,15 +376,15 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # generic[void](), generic[int]() # see ttypeor.nim test. var i = 0 - newSeq(entry.concreteTypes, fn.typ.len+gp.len-1) + newSeq(entry.concreteTypes, fn.typ.paramsLen+gp.len) for s in instantiateGenericParamList(c, gp, pt): addDecl(c, s) entry.concreteTypes[i] = s.typ inc i pushProcCon(c, result) instantiateProcType(c, pt, result, info) - for j in 1.. 1: + if s.typ != nil and s.typ.paramsLen > 0: var exp = s.typ.firstParamType.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: result = 50 @@ -407,7 +407,7 @@ proc suggestVar(c: PContext, n: PNode, outputs: var Suggestions) = wholeSymTab(nameFits(c, it, n), ideCon) proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = - if s.typ != nil and s.typ.len > 1 and s.typ.firstParamType != nil: + if s.typ != nil and s.typ.paramsLen > 0 and s.typ.firstParamType != nil: # special rule: if system and some weird generic match via 'tyUntyped' # or 'tyGenericParam' we won't list it either to reduce the noise (nobody # wants 'system.`-|` as suggestion diff --git a/compiler/types.nim b/compiler/types.nim index 7d7d3349dbd97..04f953f79d1cb 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -566,8 +566,8 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(']') of tyGenericBody: result = typeToString(t.typeBodyImpl) & '[' - for needsComma, a in t.genericBodyParams: - if needsComma: result.add(", ") + for i, a in t.genericBodyParams: + if i > 0: result.add(", ") result.add(typeToString(a, preferTypeName)) result.add(']') of tyTypeDesc: diff --git a/compiler/vm.nim b/compiler/vm.nim index 7063a72688334..88419d5ddfea2 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2486,12 +2486,12 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC tos.slots[0] = TFullReg(kind: rkNode, node: newNodeI(nkEmpty, n.info)) # setup parameters: - for i in 1.. Date: Sun, 17 Dec 2023 23:25:49 -0600 Subject: [PATCH 056/123] Fix grammar (#23090) --- lib/pure/strscans.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index cf3f3116bf087..16ef9e64287cc 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -94,7 +94,7 @@ which we then use in our scanf pattern to help us in the matching process: ... ``` -It also possible to pass arguments to a user definable matcher: +It is also possible to pass arguments to a user definable matcher: ```nim proc ndigits(input: string; intVal: var int; start: int; n: int): int = From 941659581add605e8a4ddfc9ff00662aa6234d26 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 18 Dec 2023 19:40:30 +0300 Subject: [PATCH 057/123] allow replacing captured syms in macro calls in generics (#23091) fixes #22605, separated from #22744 This marks symbol captures in macro calls in generic contexts as `nfOpenSym`, which means if there is a new symbol in the local instantiatied body during instantiation time, this symbol replaces the captured symbol. We have to be careful not to consider symbols outside of the instantiation body during instantiation, because this will leak symbols from the instantiation context scope rather than the original declaration scope. This is done by checking if the local context owner (maybe should be the symbol of the proc currently getting instantiated instead? not sure how to get this) is the same as or a parent owner of the owner of the replacement candidate symbol. This solution is distinct from the symchoice mechanisms which we originally assumed had to be related, if this assumption was wrong it would explain why this solution took so long to arrive at. --- compiler/ast.nim | 4 +- compiler/ic/ic.nim | 10 ++-- compiler/semexprs.nim | 20 ++++++- compiler/semgnrc.nim | 13 +++++ tests/generics/tmacroinjectedsym.nim | 86 ++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 tests/generics/tmacroinjectedsym.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 06b6cd3573a0a..732763f0fe61b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -520,6 +520,7 @@ type nfFirstWrite # this node is a first write nfHasComment # node has a comment nfSkipFieldChecking # node skips field visable checking + nfOpenSym # node is a captured sym but can be overriden by local symbols TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47) @@ -1095,7 +1096,8 @@ const nfIsRef, nfIsPtr, nfPreventCg, nfLL, nfFromTemplate, nfDefaultRefsParam, nfExecuteOnReload, nfLastRead, - nfFirstWrite, nfSkipFieldChecking} + nfFirstWrite, nfSkipFieldChecking, + nfOpenSym} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index e856219107a91..c9f546c76a952 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -433,11 +433,11 @@ proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pac let info = n.info.toPackedInfo(c, m) if n.typ != n.sym.typ: ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total - info = info, + info = info, flags = n.flags, typeId = storeTypeLater(n.typ, c, m)) else: ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total - info = info) + info = info, flags = n.flags) ir.addNode(kind = nkNone, info = info, operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32) ir.addNode(kind = nkNone, info = info, @@ -829,7 +829,8 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId]) of nkSym: result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand)) - if result.typ == nil: result.typ = result.sym.typ + if result.typ == nil and nfOpenSym notin result.flags: + result.typ = result.sym.typ of externIntLit: result.intVal = g[thisModule].fromDisk.numbers[n.litId] of nkStrLit..nkTripleStrLit: @@ -842,7 +843,8 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; assert n2.kind == nkNone transitionNoneToSym(result) result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand)) - if result.typ == nil: result.typ = result.sym.typ + if result.typ == nil and nfOpenSym notin result.flags: + result.typ = result.sym.typ else: for n0 in sonsReadonly(tree, n): result.addAllowNil loadNodes(c, g, thisModule, tree, n0) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b3b8c27fc405a..93574e217ffea 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1024,7 +1024,10 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType) of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType) else: - semFinishOperands(c, result) + if callee.magic notin {mArrGet, mArrPut, mNBindSym}: + # calls to `[]` can be explicit generic instantiations, + # don't sem every operand now, leave it to semmagic + semFinishOperands(c, result) activate(c, result) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) @@ -3063,9 +3066,22 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType of nkClosedSymChoice, nkOpenSymChoice: result = semSymChoice(c, result, flags, expectedType) of nkSym: + let s = n.sym + if nfOpenSym in n.flags: + let id = newIdentNode(s.name, n.info) + c.isAmbiguous = false + let s2 = qualifiedLookUp(c, id, {}) + if s2 != nil and s2 != s and not c.isAmbiguous: + # only consider symbols defined under current proc: + var o = s2.owner + while o != nil: + if o == c.p.owner: + result = semExpr(c, id, flags, expectedType) + return + o = o.owner # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! - result = semSym(c, n, n.sym, flags) + result = semSym(c, n, s, flags) of nkEmpty, nkNone, nkCommentStmt, nkType: discard of nkNilLit: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index cae823a8f0cae..a96bc484bb294 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -69,6 +69,9 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result.transitionSonsKind(nkClosedSymChoice) else: result = symChoice(c, n, s, scOpen) + if {withinMixin, withinConcept} * flags == {withinMixin} and result.kind == nkSym: + result.flags.incl nfOpenSym + result.typ = nil case s.kind of skUnknown: # Introduced in this pass! Leave it as an identifier. @@ -96,6 +99,9 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = n else: result = newSymNodeTypeDesc(s, c.idgen, n.info) + if {withinMixin, withinConcept} * flags == {withinMixin}: + result.flags.incl nfOpenSym + result.typ = nil onUse(n.info, s) of skParam: result = n @@ -104,11 +110,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, if (s.typ != nil) and (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}): result = newSymNodeTypeDesc(s, c.idgen, n.info) + if {withinMixin, withinConcept} * flags == {withinMixin}: + result.flags.incl nfOpenSym + result.typ = nil else: result = n onUse(n.info, s) else: result = newSymNode(s, n.info) + if {withinMixin, withinConcept} * flags == {withinMixin}: + result.flags.incl nfOpenSym + result.typ = nil onUse(n.info, s) proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, @@ -148,6 +160,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, var s = qualifiedLookUp(c, n, luf) if s != nil: + isMacro = s.kind in {skTemplate, skMacro} result = semGenericStmtSymbol(c, n, s, ctx, flags) else: n[0] = semGenericStmt(c, n[0], flags, ctx) diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim new file mode 100644 index 0000000000000..a98c1edb11c4a --- /dev/null +++ b/tests/generics/tmacroinjectedsym.nim @@ -0,0 +1,86 @@ +block: # issue #22605, normal call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + proc g(T: type): string = + let x = valueOr 123: + return $error + + "ok" + + doAssert g(int) == "good" + +block: # issue #22605, method call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + proc g(T: type): string = + let x = 123.valueOr: + return $error + + "ok" + + doAssert g(int) == "good" + +block: # issue #22605, original complex example + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + + proc g(T: type): string = + let x = f().valueOr: + return $error + + "ok" + + doAssert g(int) == "f" From 0613537ca0804e61e6fc9ba3fee5ff68408553a0 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 18 Dec 2023 22:34:21 +0300 Subject: [PATCH 058/123] add tuple unpacking changes to changelog (#23093) closes #23042 Adds changes from #22537 and #22611 to changelog (I believe both are set for 2.2). --- changelog.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/changelog.md b/changelog.md index f21ab39da5c55..db85e25a12c4e 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,12 @@ - The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/` instead of `Nim httpclient/` which was incorrect according to the HTTP spec. - Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined. - With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default. +- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like: + ```nim + var a, b: int + (a, b) = (1, 2, 3, 4) + ``` + will no longer compile. ## Standard library additions and changes @@ -38,6 +44,19 @@ slots when enlarging a sequence. - `member` can be used to attach a procedure to a C++ type. - C++ `constructor` now reuses `result` instead creating `this`. +- Tuple unpacking changes: + - Tuple unpacking assignment now supports using underscores to discard values. + ```nim + var a, c: int + (a, _, c) = (1, 2, 3) + ``` + - Tuple unpacking variable declarations now support type annotations, but + only for the entire tuple. + ```nim + let (a, b): (int, int) = (1, 2) + let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc")) + ``` + ## Compiler changes - `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory. From d3b9711c5e3be9b05fb15c4e39bc7607c606287d Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 18 Dec 2023 22:38:34 +0300 Subject: [PATCH 059/123] retain postfix node in type section typed AST (#23096) fixes #22933 --- compiler/semstmts.nim | 22 +++++++++++++++++++--- testament/important_packages.nim | 3 ++- tests/macros/tastrepr.nim | 5 +++++ tests/macros/tgetimpl.nim | 4 +++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a0eda36d1eada..5a0968ba55cb5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1259,6 +1259,9 @@ proc typeSectionTypeName(c: PContext; n: PNode): PNode = result = n[0] else: result = n + if result.kind == nkPostfix: + if result.len != 2: illFormedAst(n, c.config) + result = result[1] if result.kind != nkSym: illFormedAst(n, c.config) proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = @@ -1326,9 +1329,15 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = elif s.owner == nil: s.owner = getCurrOwner(c) if name.kind == nkPragmaExpr: - typeDef[0][0] = newSymNode(s) + if name[0].kind == nkPostfix: + typeDef[0][0][1] = newSymNode(s) + else: + typeDef[0][0] = newSymNode(s) else: - typeDef[0] = newSymNode(s) + if name.kind == nkPostfix: + typeDef[0][1] = newSymNode(s) + else: + typeDef[0] = newSymNode(s) proc typeSectionLeftSidePass(c: PContext, n: PNode) = # process the symbols on the left side for the whole type section, before @@ -1538,8 +1547,15 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = of nkSym: obj.ast[0] = symNode of nkPragmaExpr: obj.ast[0] = a[0].shallowCopy - obj.ast[0][0] = symNode + if a[0][0].kind == nkPostfix: + obj.ast[0][0] = a[0][0].shallowCopy + obj.ast[0][0][1] = symNode + else: + obj.ast[0][0] = symNode obj.ast[0][1] = a[0][1] + of nkPostfix: + obj.ast[0] = a[0].shallowCopy + obj.ast[0][1] = symNode else: assert(false) obj.ast[1] = a[1] obj.ast[2] = a[2][0] diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d3d3f06437881..d056dac69db9f 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -97,7 +97,8 @@ pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim", url = "https://github.com/nim-lang/neo" -pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true +pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true, allowFailure = true + # inactive, tests not adapted to #23096 pkg "netty" pkg "nico", allowFailure = true pkg "nicy", "nim c -r src/nicy.nim" diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim index c04498a25b37e..668904caec226 100644 --- a/tests/macros/tastrepr.nim +++ b/tests/macros/tastrepr.nim @@ -11,6 +11,8 @@ for i, (x, y) in pairs(data): var a = 1 b = 2 +type + A* = object var data = @[(1, "one"), (2, "two")] for (i, d) in pairs(data): @@ -20,6 +22,8 @@ for i, d in pairs(data): for i, (x, y) in pairs(data): discard var (a, b) = (1, 2) +type + A* = object ''' """ @@ -44,3 +48,4 @@ echoTypedAndUntypedRepr: for i, (x,y) in pairs(data): discard var (a,b) = (1,2) + type A* = object # issue #22933 diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index 3989576729b62..e215d26968497 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -75,7 +75,9 @@ assert: check_gen_proc(len(a)) == (false, true) macro check(x: type): untyped = let z = getType(x) let y = getImpl(z[1]) - let sym = if y[0].kind == nnkSym: y[0] else: y[0][0] + var sym = y[0] + if sym.kind == nnkPragmaExpr: sym = sym[0] + if sym.kind == nnkPostfix: sym = sym[1] expectKind(z[1], nnkSym) expectKind(sym, nnkSym) expectKind(y[2], nnkObjectTy) From 8614f35dc2801bc8a24b393bd526370099404095 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 19 Dec 2023 02:07:20 +0300 Subject: [PATCH 060/123] Revert "retain postfix node in type section typed AST" (#23098) Reverts nim-lang/Nim#23096 --- compiler/semstmts.nim | 22 +++------------------- testament/important_packages.nim | 3 +-- tests/macros/tastrepr.nim | 5 ----- tests/macros/tgetimpl.nim | 4 +--- 4 files changed, 5 insertions(+), 29 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5a0968ba55cb5..a0eda36d1eada 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1259,9 +1259,6 @@ proc typeSectionTypeName(c: PContext; n: PNode): PNode = result = n[0] else: result = n - if result.kind == nkPostfix: - if result.len != 2: illFormedAst(n, c.config) - result = result[1] if result.kind != nkSym: illFormedAst(n, c.config) proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = @@ -1329,15 +1326,9 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = elif s.owner == nil: s.owner = getCurrOwner(c) if name.kind == nkPragmaExpr: - if name[0].kind == nkPostfix: - typeDef[0][0][1] = newSymNode(s) - else: - typeDef[0][0] = newSymNode(s) + typeDef[0][0] = newSymNode(s) else: - if name.kind == nkPostfix: - typeDef[0][1] = newSymNode(s) - else: - typeDef[0] = newSymNode(s) + typeDef[0] = newSymNode(s) proc typeSectionLeftSidePass(c: PContext, n: PNode) = # process the symbols on the left side for the whole type section, before @@ -1547,15 +1538,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = of nkSym: obj.ast[0] = symNode of nkPragmaExpr: obj.ast[0] = a[0].shallowCopy - if a[0][0].kind == nkPostfix: - obj.ast[0][0] = a[0][0].shallowCopy - obj.ast[0][0][1] = symNode - else: - obj.ast[0][0] = symNode + obj.ast[0][0] = symNode obj.ast[0][1] = a[0][1] - of nkPostfix: - obj.ast[0] = a[0].shallowCopy - obj.ast[0][1] = symNode else: assert(false) obj.ast[1] = a[1] obj.ast[2] = a[2][0] diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d056dac69db9f..d3d3f06437881 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -97,8 +97,7 @@ pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim", url = "https://github.com/nim-lang/neo" -pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true, allowFailure = true - # inactive, tests not adapted to #23096 +pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true pkg "netty" pkg "nico", allowFailure = true pkg "nicy", "nim c -r src/nicy.nim" diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim index 668904caec226..c04498a25b37e 100644 --- a/tests/macros/tastrepr.nim +++ b/tests/macros/tastrepr.nim @@ -11,8 +11,6 @@ for i, (x, y) in pairs(data): var a = 1 b = 2 -type - A* = object var data = @[(1, "one"), (2, "two")] for (i, d) in pairs(data): @@ -22,8 +20,6 @@ for i, d in pairs(data): for i, (x, y) in pairs(data): discard var (a, b) = (1, 2) -type - A* = object ''' """ @@ -48,4 +44,3 @@ echoTypedAndUntypedRepr: for i, (x,y) in pairs(data): discard var (a,b) = (1,2) - type A* = object # issue #22933 diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index e215d26968497..3989576729b62 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -75,9 +75,7 @@ assert: check_gen_proc(len(a)) == (false, true) macro check(x: type): untyped = let z = getType(x) let y = getImpl(z[1]) - var sym = y[0] - if sym.kind == nnkPragmaExpr: sym = sym[0] - if sym.kind == nnkPostfix: sym = sym[1] + let sym = if y[0].kind == nnkSym: y[0] else: y[0][0] expectKind(z[1], nnkSym) expectKind(sym, nnkSym) expectKind(y[2], nnkObjectTy) From 0f54554213af767e6bec25250fc9c902316b5266 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:47:39 +0800 Subject: [PATCH 061/123] allow non var deinit for locks and conds: alternative way (#23099) alternative to https://github.com/nim-lang/Nim/pull/23092 --- lib/core/locks.nim | 4 ++-- lib/core/rlocks.nim | 2 +- lib/std/private/syslocks.nim | 28 ++++++++++++++-------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index ad0bff44d093d..5237274792f8a 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -37,7 +37,7 @@ proc initLock*(lock: var Lock) {.inline.} = when not defined(js): initSysLock(lock) -proc deinitLock*(lock: var Lock) {.inline.} = +proc deinitLock*(lock: Lock) {.inline.} = ## Frees the resources associated with the lock. deinitSys(lock) @@ -60,7 +60,7 @@ proc initCond*(cond: var Cond) {.inline.} = ## Initializes the given condition variable. initSysCond(cond) -proc deinitCond*(cond: var Cond) {.inline.} = +proc deinitCond*(cond: Cond) {.inline.} = ## Frees the resources associated with the condition variable. deinitSysCond(cond) diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index bee5c16556301..8cb0cef055e16 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -31,7 +31,7 @@ proc initRLock*(lock: var RLock) {.inline.} = else: initSysLock(lock) -proc deinitRLock*(lock: var RLock) {.inline.} = +proc deinitRLock*(lock: RLock) {.inline.} = ## Frees the resources associated with the lock. deinitSys(lock) diff --git a/lib/std/private/syslocks.nim b/lib/std/private/syslocks.nim index ca8897dc2a601..e19ec2c04d5a7 100644 --- a/lib/std/private/syslocks.nim +++ b/lib/std/private/syslocks.nim @@ -16,7 +16,7 @@ when defined(windows): Handle = int SysLock* {.importc: "CRITICAL_SECTION", - header: "", final, pure.} = object # CRITICAL_SECTION in WinApi + header: "", final, pure, byref.} = object # CRITICAL_SECTION in WinApi DebugInfo: pointer LockCount: int32 RecursionCount: int32 @@ -24,7 +24,7 @@ when defined(windows): LockSemaphore: int SpinCount: int - SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "".} = object + SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "", byref.} = object thePtr {.importc: "Ptr".} : Handle proc initSysLock*(L: var SysLock) {.importc: "InitializeCriticalSection", @@ -46,7 +46,7 @@ when defined(windows): header: "".} ## Releases the lock `L`. - proc deinitSys*(L: var SysLock) {.importc: "DeleteCriticalSection", + proc deinitSys*(L: SysLock) {.importc: "DeleteCriticalSection", header: "".} proc initializeConditionVariable( @@ -68,7 +68,7 @@ when defined(windows): proc initSysCond*(cond: var SysCond) {.inline.} = initializeConditionVariable(cond) - proc deinitSysCond*(cond: var SysCond) {.inline.} = + proc deinitSysCond*(cond: SysCond) {.inline.} = discard proc waitSysCond*(cond: var SysCond, lock: var SysLock) = discard sleepConditionVariableCS(cond, lock, -1'i32) @@ -83,13 +83,13 @@ elif defined(genode): header: Header.} = object proc initSysLock*(L: var SysLock) = discard - proc deinitSys*(L: var SysLock) = discard + proc deinitSys*(L: SysLock) = discard proc acquireSys*(L: var SysLock) {.noSideEffect, importcpp.} proc tryAcquireSys*(L: var SysLock): bool {.noSideEffect, importcpp.} proc releaseSys*(L: var SysLock) {.noSideEffect, importcpp.} proc initSysCond*(L: var SysCond) = discard - proc deinitSysCond*(L: var SysCond) = discard + proc deinitSysCond*(L: SysCond) = discard proc waitSysCond*(cond: var SysCond, lock: var SysLock) {. noSideEffect, importcpp.} proc signalSysCond*(cond: var SysCond) {. @@ -101,7 +101,7 @@ else: type SysLockObj {.importc: "pthread_mutex_t", pure, final, header: """#include - #include """.} = object + #include """, byref.} = object when defined(linux) and defined(amd64): abi: array[40 div sizeof(clong), clong] @@ -113,7 +113,7 @@ else: SysCondObj {.importc: "pthread_cond_t", pure, final, header: """#include - #include """.} = object + #include """, byref.} = object when defined(linux) and defined(amd64): abi: array[48 div sizeof(clonglong), clonglong] @@ -127,7 +127,7 @@ else: proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {. importc: "pthread_mutex_init", header: "", noSideEffect.} - proc deinitSysAux(L: var SysLockObj) {.noSideEffect, + proc deinitSysAux(L: SysLockObj) {.noSideEffect, importc: "pthread_mutex_destroy", header: "".} proc acquireSysAux(L: var SysLockObj) {.noSideEffect, @@ -156,7 +156,7 @@ else: L = cast[SysLock](c_malloc(csize_t(sizeof(SysLockObj)))) initSysLockAux(L[], attr) - proc deinitSys*(L: var SysLock) = + proc deinitSys*(L: SysLock) = deinitSysAux(L[]) c_free(L) @@ -173,7 +173,7 @@ else: template initSysLock*(L: var SysLock, attr: ptr SysLockAttr = nil) = initSysLockAux(L, attr) - template deinitSys*(L: var SysLock) = + template deinitSys*(L: SysLock) = deinitSysAux(L) template acquireSys*(L: var SysLock) = acquireSysAux(L) @@ -193,7 +193,7 @@ else: # locks proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {. importc: "pthread_cond_init", header: "", noSideEffect.} - proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect, + proc deinitSysCondAux(cond: SysCondObj) {.noSideEffect, importc: "pthread_cond_destroy", header: "".} proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj): cint {. @@ -208,7 +208,7 @@ else: cond = cast[SysCond](c_malloc(csize_t(sizeof(SysCondObj)))) initSysCondAux(cond[], cond_attr) - proc deinitSysCond*(cond: var SysCond) = + proc deinitSysCond*(cond: SysCond) = deinitSysCondAux(cond[]) c_free(cond) @@ -221,7 +221,7 @@ else: else: template initSysCond*(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = initSysCondAux(cond, cond_attr) - template deinitSysCond*(cond: var SysCond) = + template deinitSysCond*(cond: SysCond) = deinitSysCondAux(cond) template waitSysCond*(cond: var SysCond, lock: var SysLock) = From 434e062e82b21ace37abb16f7388c07df74a0729 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:24:22 +0800 Subject: [PATCH 062/123] =?UTF-8?q?fixes=20#18073;=20fixes=20#14730;=20doc?= =?UTF-8?q?ument=20notnil=20is=20only=20applied=20to=20local=20=E2=80=A6?= =?UTF-8?q?=20(#23084)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …symbols fixes #18073 fixes #14730 --- doc/manual_experimental.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index f5e39b768bc01..3b552ef8e571f 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -560,7 +560,8 @@ Not nil annotation `{.experimental: "notnil".}`. All types for which `nil` is a valid value can be annotated with the -`not nil` annotation to exclude `nil` as a valid value: +`not nil` annotation to exclude `nil` as a valid value. Note that only local +symbols are checked. ```nim {.experimental: "notnil".} @@ -577,8 +578,11 @@ All types for which `nil` is a valid value can be annotated with the p(nil) # and also this: - var x: PObject - p(x) + proc foo = + var x: PObject + p(x) + + foo() ``` The compiler ensures that every code path initializes variables which contain From 6618448ced6f4f6d65d830d355e819996f654b57 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:24:36 +0800 Subject: [PATCH 063/123] fixes strictnotnil for func, method, converter (#23083) --- compiler/sempass2.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e2d45a3884910..48a6b9d1c3be0 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1667,7 +1667,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = dataflowAnalysis(s, body) when false: trackWrites(s, body) - if strictNotNil in c.features and s.kind == skProc: + if strictNotNil in c.features and s.kind in {skProc, skFunc, skMethod, skConverter}: checkNil(s, body, g.config, c.idgen) proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = From db9d8003b074cb6d150f7ece467f29006ccefde7 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Wed, 20 Dec 2023 03:27:24 +1100 Subject: [PATCH 064/123] Don't crash for invalid toplevel parseStmt/Expr calls (#23089) This code will crash `check`/`nimsuggest` since the `ra` register is uninitialised ```nim import macros static: discard parseExpr("'") ``` Now it assigns an empty node so that it has something Testament changes were so I could properly write a test. It would pass even with a segfault since it could find the error --- compiler/vm.nim | 3 +++ testament/testament.nim | 13 +++++++++---- tests/macros/tfail_parse.nim | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/macros/tfail_parse.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 88419d5ddfea2..d74a649088bc4 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1925,6 +1925,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) + + regs[ra].node = newNode(nkEmpty) if error.len > 0: c.errorFlag = error elif ast.len != 1: @@ -1942,6 +1944,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = error = formatMsg(conf, info, msg, arg)) if error.len > 0: c.errorFlag = error + regs[ra].node = newNode(nkEmpty) else: regs[ra].node = ast of opcQueryErrorFlag: diff --git a/testament/testament.nim b/testament/testament.nim index 5f443ffba0ce8..e0a200e29b8bb 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -193,7 +193,6 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, foundSuccessMsg = true elif not running(p): break - close(p) result.msg = "" result.file = "" result.output = "" @@ -201,8 +200,9 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.column = 0 result.err = reNimcCrash - let exitCode = p.peekExitCode - case exitCode + result.exitCode = p.peekExitCode + close p + case result.exitCode of 0: if foundErrorMsg: result.debugInfo.add " compiler exit code was 0 but some Error's were found." @@ -214,7 +214,7 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, if foundSuccessMsg: result.debugInfo.add " compiler exit code was 1 but no `isSuccess` was true." else: - result.debugInfo.add " expected compiler exit code 0 or 1, got $1." % $exitCode + result.debugInfo.add " expected compiler exit code 0 or 1, got $1." % $result.exitCode if err =~ pegLineError: result.file = extractFilename(matches[0]) @@ -521,7 +521,12 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, r.addResult(test, target, extraOptions, expected.output, bufB, reOutputsDiffer) compilerOutputTests(test, target, extraOptions, given, expected, r) of actionReject: + # Make sure its the compiler rejecting and not the system (e.g. segfault) cmpMsgs(r, expected, given, test, target, extraOptions) + if given.exitCode != QuitFailure: + r.addResult(test, target, extraOptions, "exitcode: " & $QuitFailure, + "exitcode: " & $given.exitCode & "\n\nOutput:\n" & + given.nimout, reExitcodesDiffer) proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: string) = for target in expected.targets: diff --git a/tests/macros/tfail_parse.nim b/tests/macros/tfail_parse.nim new file mode 100644 index 0000000000000..1925f2b69281b --- /dev/null +++ b/tests/macros/tfail_parse.nim @@ -0,0 +1,15 @@ +discard """ +action: "reject" +cmd: "nim check $file" +errormsg: "expected expression, but got multiple statements [ValueError]" +file: "macros.nim" +""" + +import macros +static: + discard parseStmt("'") + discard parseExpr("'") + discard parseExpr(""" +proc foo() +proc foo() = discard +""") From 12d847550abf8adb53052975e7c98be916128d81 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 21 Dec 2023 02:12:05 +0300 Subject: [PATCH 065/123] update mac CI to macos 12 (#23108) closes #23107 Could also change to `macos-latest` but nothing else in CI uses `latest` OS versions. --- .github/workflows/ci_packages.yml | 2 +- azure-pipelines.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 91ac83aecd141..2ea5092e3edd0 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, macos-11] + os: [ubuntu-20.04, macos-12] cpu: [amd64] batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num` name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3f20fb86690ce..9ef202948f576 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,10 +29,10 @@ jobs: # vmImage: 'ubuntu-18.04' # CPU: i386 OSX_amd64: - vmImage: 'macOS-11' + vmImage: 'macOS-12' CPU: amd64 OSX_amd64_cpp: - vmImage: 'macOS-11' + vmImage: 'macOS-12' CPU: amd64 NIM_COMPILE_TO_CPP: true Windows_amd64_batch0_3: From 02a1a083ed41867514b3499a0b3a8addb4b01ed4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:15:44 +0800 Subject: [PATCH 066/123] update action versions (#23109) --- .github/workflows/ci_docs.yml | 4 ++-- .github/workflows/ci_publish.yml | 2 +- .github/workflows/stale.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 32e8e050e4a00..2faa37ce0abba 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -45,7 +45,7 @@ jobs: - target: windows os: windows-2019 - target: osx - os: macos-11 + os: macos-12 name: ${{ matrix.target }} runs-on: ${{ matrix.os }} @@ -109,7 +109,7 @@ jobs: if: | github.event_name == 'push' && github.ref == 'refs/heads/devel' && matrix.target == 'linux' - uses: crazy-max/ghaction-github-pages@v3 + uses: crazy-max/ghaction-github-pages@v4 with: build_dir: doc/html env: diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml index 58da92206dea5..decfe953ecc9e 100644 --- a/.github/workflows/ci_publish.yml +++ b/.github/workflows/ci_publish.yml @@ -71,7 +71,7 @@ jobs: run: nim c -r -d:release ci/action.nim - name: 'Comment' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const fs = require('fs'); diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index d89a4888a1b7e..0c5a533e1d5d9 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v8 + - uses: actions/stale@v9 with: days-before-pr-stale: 365 days-before-pr-close: 30 From 4321ce2635cc91a975580e8a74bff70cf5d8aadf Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:58:17 +0800 Subject: [PATCH 067/123] fixes nimdoc warnings (#23110) --- doc/manual_experimental.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 3b552ef8e571f..87381f6559654 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2450,7 +2450,7 @@ main() Will produce: -```c++ +```cpp struct Test { Foo foo; From b15463948c6f78a546742fc5c521fa2f6e8f9312 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:56:02 +0800 Subject: [PATCH 068/123] document `--experimental:vtables` (#23111) --- doc/manual_experimental.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 87381f6559654..fc5ff19599aeb 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2520,3 +2520,38 @@ NimFunctor()(1) ``` Notice we use the overload of `()` to have the same semantics in Nim, but on the `importcpp` we import the functor as a function. This allows to easy interop with functions that accepts for example a `const` operator in its signature. + +VTable for methods +================== + +Methods now support implementations based on a VTable by using `--experimental:vtables`. Note that the option needs to enabled +globally. The virtual method table is stored in the type info of +an object, which is an array of function pointers. + +```nim +method foo(x: Base, ...) {.base.} +method foo(x: Derived, ...) {.base.} +``` + +It roughly generates a dispatcher like + +```nim +proc foo_dispatch(x: Base, ...) = + x.typeinfo.vtable[method_index](x, ...) # method_index is the index of the sorted order of a method +``` + +Methods are required to be in the same module where their type has been defined. + +```nim +# types.nim +type + Base* = ref object +``` + +```nim +import types + +method foo(x: Base) {.base.} = discard +``` + +It gives an error: method `foo` can be defined only in the same module with its type (Base). From df3c95d8af7bfd1e61e6b06eec21f57781dff9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Fri, 22 Dec 2023 04:38:40 +0000 Subject: [PATCH 069/123] makes nimsuggest `con` work under v3 (#23113) Co-authored-by: Jake Leahy --- nimsuggest/nimsuggest.nim | 9 ++++++--- nimsuggest/tests/tv3_con.nim | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 nimsuggest/tests/tv3_con.nim diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 03a6e32e19007..1d48bf653d9c0 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -984,10 +984,10 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, graph.unmarkAllDirty() # these commands require partially compiled project - elif cmd in {ideSug, ideOutline, ideHighlight, ideDef, ideChkFile, ideType, ideDeclaration, ideExpand} and - (graph.needsCompilation(fileIndex) or cmd == ideSug): + elif cmd in {ideSug, ideCon, ideOutline, ideHighlight, ideDef, ideChkFile, ideType, ideDeclaration, ideExpand} and + (graph.needsCompilation(fileIndex) or cmd in {ideSug, ideCon}): # for ideSug use v2 implementation - if cmd == ideSug: + if cmd in {ideSug, ideCon}: conf.m.trackPos = newLineInfo(fileIndex, line, col) conf.m.trackPosAttached = false else: @@ -1033,6 +1033,9 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, # ideSug performs partial build of the file, thus mark it dirty for the # future calls. graph.markDirtyIfNeeded(file.string, fileIndex) + of ideCon: + graph.markDirty fileIndex + graph.markClientsDirty fileIndex of ideOutline: let n = parseFile(fileIndex, graph.cache, graph.config) graph.iterateOutlineNodes(n, graph.fileSymbols(fileIndex).deduplicateSymInfoPair) diff --git a/nimsuggest/tests/tv3_con.nim b/nimsuggest/tests/tv3_con.nim new file mode 100644 index 0000000000000..4714c366ba765 --- /dev/null +++ b/nimsuggest/tests/tv3_con.nim @@ -0,0 +1,13 @@ +# tests v3 + +proc test(a: string, b:string) = discard +proc test(a: int) = discard + +test(#[!]# + +discard """ +$nimsuggest --v3 --tester $file +>con $1 +con;;skProc;;tv3_con.test;;proc (a: string, b: string);;$file;;3;;5;;"";;100 +con;;skProc;;tv3_con.test;;proc (a: int);;$file;;4;;5;;"";;100 +""" From 4b1a84170786653f60313f7bdf56efa3928c2a3a Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 22 Dec 2023 10:49:51 +0300 Subject: [PATCH 070/123] add switch, warning, and `bind` support for new generic injection behavior (#23102) refs #23091, especially post merge comments Unsure if `experimental` and `bind` are the perfect constructs to use but they seem to get the job done here. Symbol nodes do not get marked `nfOpenSym` if the `bind` statement is used for their symbol, and `nfOpenSym` nodes do not get replaced by new local symbols if the experimental switch is not enabled in the local context (meaning it also works with `push experimental`). However this incurs a warning as the fact that the node is marked `nfOpenSym` means we did not `bind` it, so we might want to do that or turn on the experimental switch if we didn't intend to bind it. The experimental switch name is arbitrary and could be changed. --------- Co-authored-by: Andreas Rumpf --- changelog.md | 35 +++++++++++++++ compiler/lineinfos.nim | 2 + compiler/options.nim | 1 + compiler/semexprs.nim | 14 +++++- compiler/semgnrc.nim | 11 +++-- doc/manual_experimental.md | 40 +++++++++++++++++ tests/generics/tmacroinjectedsym.nim | 29 ++++++++++++ tests/generics/tmacroinjectedsymwarning.nim | 50 +++++++++++++++++++++ 8 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 tests/generics/tmacroinjectedsymwarning.nim diff --git a/changelog.md b/changelog.md index db85e25a12c4e..1bedb1cd60034 100644 --- a/changelog.md +++ b/changelog.md @@ -57,6 +57,41 @@ slots when enlarging a sequence. let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc")) ``` +- An experimental option `genericsOpenSym` has been added to allow captured + symbols in generic routine bodies to be replaced by symbols injected locally + by templates/macros at instantiation time. `bind` may be used to keep the + captured symbols over the injected ones regardless of enabling the option. + + Since this change may affect runtime behavior, the experimental switch + `genericsOpenSym` needs to be enabled, and a warning is given in the case + where an injected symbol would replace a captured symbol not bound by `bind` + and the experimental switch isn't enabled. + + ```nim + const value = "captured" + template foo(x: int, body: untyped) = + let value {.inject.} = "injected" + body + + proc old[T](): string = + foo(123): + return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym` + echo old[int]() # "captured" + + {.experimental: "genericsOpenSym".} + + proc bar[T](): string = + foo(123): + return value + assert bar[int]() == "injected" # previously it would be "captured" + + proc baz[T](): string = + bind value + foo(123): + return value + assert baz[int]() == "captured" + ``` + ## Compiler changes - `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory. diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index d21825be767ac..dc0b6c360f584 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -92,6 +92,7 @@ type warnStmtListLambda = "StmtListLambda", warnBareExcept = "BareExcept", warnImplicitDefaultValue = "ImplicitDefaultValue", + warnGenericsIgnoredInjection = "GenericsIgnoredInjection", warnStdPrefix = "StdPrefix" warnUser = "User", # hints @@ -196,6 +197,7 @@ const warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead", warnBareExcept: "$1", warnImplicitDefaultValue: "$1", + warnGenericsIgnoredInjection: "$1", warnStdPrefix: "$1 needs the 'std' prefix", warnUser: "$1", hintSuccess: "operation successful: $#", diff --git a/compiler/options.nim b/compiler/options.nim index 45ed8c23e725e..1ef096601fe72 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -227,6 +227,7 @@ type strictDefs, strictCaseObjects, inferGenericTypes, + genericsOpenSym, vtables LegacyFeature* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 93574e217ffea..b469658757d54 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -3076,8 +3076,18 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType var o = s2.owner while o != nil: if o == c.p.owner: - result = semExpr(c, id, flags, expectedType) - return + if genericsOpenSym in c.features: + result = semExpr(c, id, flags, expectedType) + return + else: + message(c.config, n.info, warnGenericsIgnoredInjection, + "a new symbol '" & s.name.s & "' has been injected during " & + "instantiation of " & c.p.owner.name.s & ", " & + "however " & getSymRepr(c.config, s) & " captured at " & + "the proc declaration will be used instead; " & + "either enable --experimental:genericsOpenSym to use the " & + "injected symbol or `bind` this captured symbol explicitly") + break o = o.owner # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index a96bc484bb294..03af12df2109c 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -56,6 +56,9 @@ template isMixedIn(sym): bool = s.magic == mNone and s.kind in OverloadableSyms) +template canOpenSym(s): bool = + {withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind + proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, ctx: var GenericCtx; flags: TSemGenericFlags, fromDotExpr=false): PNode = @@ -69,7 +72,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result.transitionSonsKind(nkClosedSymChoice) else: result = symChoice(c, n, s, scOpen) - if {withinMixin, withinConcept} * flags == {withinMixin} and result.kind == nkSym: + if result.kind == nkSym and canOpenSym(result.sym): result.flags.incl nfOpenSym result.typ = nil case s.kind @@ -99,7 +102,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = n else: result = newSymNodeTypeDesc(s, c.idgen, n.info) - if {withinMixin, withinConcept} * flags == {withinMixin}: + if canOpenSym(result.sym): result.flags.incl nfOpenSym result.typ = nil onUse(n.info, s) @@ -110,7 +113,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, if (s.typ != nil) and (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}): result = newSymNodeTypeDesc(s, c.idgen, n.info) - if {withinMixin, withinConcept} * flags == {withinMixin}: + if canOpenSym(result.sym): result.flags.incl nfOpenSym result.typ = nil else: @@ -118,7 +121,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, onUse(n.info, s) else: result = newSymNode(s, n.info) - if {withinMixin, withinConcept} * flags == {withinMixin}: + if canOpenSym(result.sym): result.flags.incl nfOpenSym result.typ = nil onUse(n.info, s) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index fc5ff19599aeb..765a69a0fab42 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2521,6 +2521,46 @@ NimFunctor()(1) Notice we use the overload of `()` to have the same semantics in Nim, but on the `importcpp` we import the functor as a function. This allows to easy interop with functions that accepts for example a `const` operator in its signature. + +Injected symbols in generic procs +================================= + +With the experimental option `genericsOpenSym`, captured symbols in generic +routine bodies may be replaced by symbols injected locally by templates/macros +at instantiation time. `bind` may be used to keep the captured symbols over +the injected ones regardless of enabling the option. + +Since this change may affect runtime behavior, the experimental switch +`genericsOpenSym` needs to be enabled, and a warning is given in the case +where an injected symbol would replace a captured symbol not bound by `bind` +and the experimental switch isn't enabled. + +```nim +const value = "captured" +template foo(x: int, body: untyped) = + let value {.inject.} = "injected" + body + +proc old[T](): string = + foo(123): + return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym` +echo old[int]() # "captured" + +{.experimental: "genericsOpenSym".} + +proc bar[T](): string = + foo(123): + return value +assert bar[int]() == "injected" # previously it would be "captured" + +proc baz[T](): string = + bind value + foo(123): + return value +assert baz[int]() == "captured" +``` + + VTable for methods ================== diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim index a98c1edb11c4a..d36d34cdd86f6 100644 --- a/tests/generics/tmacroinjectedsym.nim +++ b/tests/generics/tmacroinjectedsym.nim @@ -1,3 +1,5 @@ +{.experimental: "genericsOpenSym".} + block: # issue #22605, normal call syntax const error = "bad" @@ -16,6 +18,15 @@ block: # issue #22605, normal call syntax doAssert g(int) == "good" + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = valueOr 123: + return $error + + "ok" + + doAssert g2(int) == "bad" + block: # issue #22605, method call syntax const error = "bad" @@ -34,6 +45,15 @@ block: # issue #22605, method call syntax doAssert g(int) == "good" + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = 123.valueOr: + return $error + + "ok" + + doAssert g2(int) == "bad" + block: # issue #22605, original complex example type Xxx = enum error @@ -84,3 +104,12 @@ block: # issue #22605, original complex example "ok" doAssert g(int) == "f" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = f().valueOr: + return $error + + "ok" + + doAssert g2(int) == "error" diff --git a/tests/generics/tmacroinjectedsymwarning.nim b/tests/generics/tmacroinjectedsymwarning.nim new file mode 100644 index 0000000000000..7adb759e88a6c --- /dev/null +++ b/tests/generics/tmacroinjectedsymwarning.nim @@ -0,0 +1,50 @@ +type Xxx = enum + error + value + +type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + +template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + +proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + +proc g(T: type): string = + let x = f().valueOr: + return $error #[tt.Warning + ^ a new symbol 'error' has been injected during instantiation of g, however 'error' [enumField declared in tmacroinjectedsymwarning.nim(2, 3)] captured at the proc declaration will be used instead; either enable --experimental:genericsOpenSym to use the injected symbol or `bind` this captured symbol explicitly [GenericsIgnoredInjection]]# + + "ok" + +discard g(int) From c0acf3ce286f92d41e6b280ba9a1b729019bae12 Mon Sep 17 00:00:00 2001 From: metagn Date: Sat, 23 Dec 2023 11:22:49 +0300 Subject: [PATCH 071/123] retain postfix node in type section typed AST, with docgen fix (#23101) Continued from #23096 which was reverted due to breaking a package and failing docgen tests. Docgen should now work, but ~~a PR is still pending for the package: https://github.com/SciNim/Unchained/pull/45~~ has been merged --- compiler/docgen.nim | 31 ++++++++++++++++++------------- compiler/renderer.nim | 25 ++++++++++++++++++------- compiler/semstmts.nim | 22 +++++++++++++++++++--- testament/important_packages.nim | 3 ++- tests/macros/tastrepr.nim | 5 +++++ tests/macros/tgetimpl.nim | 4 +++- 6 files changed, 65 insertions(+), 25 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index bf8bdde143a49..b4c4baa2b6731 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1031,7 +1031,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol = if genNode != nil: var literal = "" var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments, - renderNoPragmas, renderNoProcDefs, renderExpandUsing}) + renderNoPragmas, renderNoProcDefs, renderExpandUsing, renderNoPostfix}) var kind = tkEof while true: getNextTok(r, kind, literal) @@ -1059,7 +1059,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx # Obtain the plain rendered string for hyperlink titles. var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments, - renderNoPragmas, renderNoProcDefs, renderExpandUsing}) + renderNoPragmas, renderNoProcDefs, renderExpandUsing, renderNoPostfix}) while true: getNextTok(r, kind, literal) if kind == tkEof: @@ -1086,6 +1086,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx symbolOrIdEnc = encodeUrl(symbolOrId, usePlus = false) deprecationMsg = genDeprecationMsg(d, pragmaNode) rstLangSymbol = toLangSymbol(k, n, cleanPlainSymbol) + symNameNode = + if nameNode.kind == nkPostfix: nameNode[1] + else: nameNode # we generate anchors automatically for subsequent use in doc comments let lineinfo = rstast.TLineInfo( @@ -1096,10 +1099,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx priority = symbolPriority(k), info = lineinfo, module = addRstFileIndex(d, FileIndex d.module.position)) - let renderFlags = - if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms, - renderExpandUsing, renderNonExportedFields} - else: {renderNoBody, renderNoComments, renderDocComments, renderSyms, renderExpandUsing} + var renderFlags = {renderNoBody, renderNoComments, renderDocComments, + renderSyms, renderExpandUsing, renderNoPostfix} + if nonExports: + renderFlags.incl renderNonExportedFields nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc) let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int) @@ -1122,18 +1125,19 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string var attype = "" - if k in routineKinds and nameNode.kind == nkSym: + if k in routineKinds and symNameNode.kind == nkSym: let att = attachToType(d, nameNode.sym) if att != nil: attype = esc(d.target, att.name.s) - elif k == skType and nameNode.kind == nkSym and nameNode.sym.typ.kind in {tyEnum, tyBool}: - let etyp = nameNode.sym.typ + elif k == skType and symNameNode.kind == nkSym and + symNameNode.sym.typ.kind in {tyEnum, tyBool}: + let etyp = symNameNode.sym.typ for e in etyp.n: if e.sym.kind != skEnumField: continue let plain = renderPlainSymbolName(e) let symbolOrId = d.newUniquePlainSymbol(plain) setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, - term = plain, linkTitle = nameNode.sym.name.s & '.' & plain, + term = plain, linkTitle = symNameNode.sym.name.s & '.' & plain, linkDesc = xmltree.escape(getPlainDocstring(e).docstringSummary), line = n.info.line.int) @@ -1154,8 +1158,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx linkTitle = detailedName, linkDesc = xmltree.escape(plainDocstring.docstringSummary), line = n.info.line.int) - if k == skType and nameNode.kind == nkSym: - d.types.strTableAdd nameNode.sym + if k == skType and symNameNode.kind == nkSym: + d.types.strTableAdd symNameNode.sym proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem = if not isVisible(d, nameNode): return @@ -1163,7 +1167,8 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): name = getNameEsc(d, nameNode) comm = genRecComment(d, n) r: TSrcGen - renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing} + renderFlags = {renderNoBody, renderNoComments, renderDocComments, + renderExpandUsing, renderNoPostfix} if nonExports: renderFlags.incl renderNonExportedFields r = initTokRender(n, renderFlags) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index bc1cbd65e908d..e9f0d2be9ef56 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -25,7 +25,7 @@ type TRenderFlag* = enum renderNone, renderNoBody, renderNoComments, renderDocComments, renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples, - renderIr, renderNonExportedFields, renderExpandUsing + renderIr, renderNonExportedFields, renderExpandUsing, renderNoPostfix TRenderFlags* = set[TRenderFlag] TRenderTok* = object @@ -546,7 +546,11 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkInfix: result = lsons(g, n) + 2 of nkPrefix: result = lsons(g, n)+1+(if n.len > 0 and n[1].kind == nkInfix: 2 else: 0) - of nkPostfix: result = lsons(g, n) + of nkPostfix: + if renderNoPostfix notin g.flags: + result = lsons(g, n) + else: + result = lsub(g, n[1]) of nkCallStrLit: result = lsons(g, n) of nkPragmaExpr: result = lsub(g, n[0]) + lcomma(g, n, 1) of nkRange: result = lsons(g, n) + 2 @@ -1330,14 +1334,20 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = put(g, tkColon, ":") gsub(g, n, bodyPos) of nkIdentDefs: - # Skip if this is a property in a type and its not exported - # (While also not allowing rendering of non exported fields) - if ObjectDef in g.inside and (not n[0].isExported() and renderNonExportedFields notin g.flags): - return + var exclFlags: TRenderFlags = {} + if ObjectDef in g.inside: + if not n[0].isExported() and renderNonExportedFields notin g.flags: + # Skip if this is a property in a type and its not exported + # (While also not allowing rendering of non exported fields) + return + # render postfix for object fields: + exclFlags = g.flags * {renderNoPostfix} # We render the identDef without being inside the section incase we render something like # y: proc (x: string) # (We wouldn't want to check if x is exported) g.outside(ObjectDef): + g.flags.excl(exclFlags) gcomma(g, n, 0, -3) + g.flags.incl(exclFlags) if n.len >= 2 and n[^2].kind != nkEmpty: putWithSpace(g, tkColon, ":") gsub(g, n[^2], c) @@ -1416,7 +1426,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = postStatements(g, n, i, fromStmtList) of nkPostfix: gsub(g, n, 1) - gsub(g, n, 0) + if renderNoPostfix notin g.flags: + gsub(g, n, 0) of nkRange: gsub(g, n, 0) put(g, tkDotDot, "..") diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a0eda36d1eada..5a0968ba55cb5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1259,6 +1259,9 @@ proc typeSectionTypeName(c: PContext; n: PNode): PNode = result = n[0] else: result = n + if result.kind == nkPostfix: + if result.len != 2: illFormedAst(n, c.config) + result = result[1] if result.kind != nkSym: illFormedAst(n, c.config) proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = @@ -1326,9 +1329,15 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = elif s.owner == nil: s.owner = getCurrOwner(c) if name.kind == nkPragmaExpr: - typeDef[0][0] = newSymNode(s) + if name[0].kind == nkPostfix: + typeDef[0][0][1] = newSymNode(s) + else: + typeDef[0][0] = newSymNode(s) else: - typeDef[0] = newSymNode(s) + if name.kind == nkPostfix: + typeDef[0][1] = newSymNode(s) + else: + typeDef[0] = newSymNode(s) proc typeSectionLeftSidePass(c: PContext, n: PNode) = # process the symbols on the left side for the whole type section, before @@ -1538,8 +1547,15 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = of nkSym: obj.ast[0] = symNode of nkPragmaExpr: obj.ast[0] = a[0].shallowCopy - obj.ast[0][0] = symNode + if a[0][0].kind == nkPostfix: + obj.ast[0][0] = a[0][0].shallowCopy + obj.ast[0][0][1] = symNode + else: + obj.ast[0][0] = symNode obj.ast[0][1] = a[0][1] + of nkPostfix: + obj.ast[0] = a[0].shallowCopy + obj.ast[0][1] = symNode else: assert(false) obj.ast[1] = a[1] obj.ast[2] = a[2][0] diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d3d3f06437881..d056dac69db9f 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -97,7 +97,8 @@ pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim", url = "https://github.com/nim-lang/neo" -pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true +pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true, allowFailure = true + # inactive, tests not adapted to #23096 pkg "netty" pkg "nico", allowFailure = true pkg "nicy", "nim c -r src/nicy.nim" diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim index c04498a25b37e..668904caec226 100644 --- a/tests/macros/tastrepr.nim +++ b/tests/macros/tastrepr.nim @@ -11,6 +11,8 @@ for i, (x, y) in pairs(data): var a = 1 b = 2 +type + A* = object var data = @[(1, "one"), (2, "two")] for (i, d) in pairs(data): @@ -20,6 +22,8 @@ for i, d in pairs(data): for i, (x, y) in pairs(data): discard var (a, b) = (1, 2) +type + A* = object ''' """ @@ -44,3 +48,4 @@ echoTypedAndUntypedRepr: for i, (x,y) in pairs(data): discard var (a,b) = (1,2) + type A* = object # issue #22933 diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index 3989576729b62..e215d26968497 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -75,7 +75,9 @@ assert: check_gen_proc(len(a)) == (false, true) macro check(x: type): untyped = let z = getType(x) let y = getImpl(z[1]) - let sym = if y[0].kind == nnkSym: y[0] else: y[0][0] + var sym = y[0] + if sym.kind == nnkPragmaExpr: sym = sym[0] + if sym.kind == nnkPostfix: sym = sym[1] expectKind(z[1], nnkSym) expectKind(sym, nnkSym) expectKind(y[2], nnkObjectTy) From 6fee2240cd327fbe65548eaed9ca21355a1a24b5 Mon Sep 17 00:00:00 2001 From: "Eric N. Vander Weele" Date: Sun, 24 Dec 2023 09:21:22 -0500 Subject: [PATCH 072/123] Add `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` (#22952) Allow for conversion from `openArray`s, similar to `toSinglyLinkedList` and `toDoublyLinkedList`. --- changelog.md | 1 + lib/pure/collections/lists.nim | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/changelog.md b/changelog.md index 1bedb1cd60034..f4a9d627cf671 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ slots when enlarging a sequence. - Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value. - Added Viewport API for the JavaScript targets in the `dom` module. +- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s. [//]: # "Deprecations:" diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index b9d5c48eb5cdd..9b89fe9f8bf21 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -983,6 +983,17 @@ func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: ( for elem in elems.items: result.add(elem) +func toSinglyLinkedRing*[T](elems: openArray[T]): SinglyLinkedRing[T] = + ## Creates a new `SinglyLinkedRing` from the members of `elems`. + runnableExamples: + from std/sequtils import toSeq + let a = [1, 2, 3, 4, 5].toSinglyLinkedRing + assert a.toSeq == [1, 2, 3, 4, 5] + + result = initSinglyLinkedRing[T]() + for elem in elems.items: + result.add(elem) + func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = ## Creates a new `DoublyLinkedList` from the members of `elems`. runnableExamples: @@ -993,3 +1004,14 @@ func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: ( result = initDoublyLinkedList[T]() for elem in elems.items: result.add(elem) + +func toDoublyLinkedRing*[T](elems: openArray[T]): DoublyLinkedRing[T] = + ## Creates a new `DoublyLinkedRing` from the members of `elems`. + runnableExamples: + from std/sequtils import toSeq + let a = [1, 2, 3, 4, 5].toDoublyLinkedRing + assert a.toSeq == [1, 2, 3, 4, 5] + + result = initDoublyLinkedRing[T]() + for elem in elems.items: + result.add(elem) From fc49c6e3ba5081593e4d9af7e04bfb84e97a39f5 Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 24 Dec 2023 17:22:10 +0300 Subject: [PATCH 073/123] fix spurious indent and newlines in rendering of nkRecList (#23121) Rendering of `nkRecList` produces an indent and adds a new line at the end. However for things like case object `of`/`else` branches or `when` branches this is already done, so this produces 2 indents and an extra new line. Instead, just add an indent in the place where the indent that `nkRecList` produces is needed, for the rendering of the final node of `nkObjectTy`. There doesn't seem to be a need to add the newline. Before: ```nim case x*: bool of true: y*: int of false: nil ``` After: ```nim case x*: bool of true: y*: int of false: nil ``` --- compiler/renderer.nim | 5 ++--- lib/core/macros.nim | 3 +-- nimdoc/extlinks/project/expected/main.html | 3 +-- .../expected/subdir/subdir_b/utils.html | 3 +-- nimdoc/testproject/expected/testproject.html | 16 +++++----------- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index e9f0d2be9ef56..3a7c60953ac60 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1531,17 +1531,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = gsub(g, n[0]) gsub(g, n[1]) gcoms(g) + indentNL(g) gsub(g, n[2]) + dedent(g) else: put(g, tkObject, "object") of nkRecList: - indentNL(g) for i in 0..Imports

Types

-
A = object
-  
+
A = object
diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index ba9512d5a9d78..5969e48bba066 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -253,8 +253,7 @@

Types

-
G[T] = object
-  
+
G[T] = object
diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index db49102f85aa0..dfd10390a5146 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -59,8 +59,7 @@

testproject

  • AnotherObject
  • B
  • @@ -380,11 +379,8 @@

    Types

    AnotherObject = object
       case x*: bool
       of true:
    -      y*: proc (x: string)
    -
    -  of false:
    -    
    -  
    + y*: proc (x: string) + of false:
    @@ -423,8 +419,7 @@

    Types

    MyObject = object
       someString*: string        ## This is a string
    -  annotated* {.somePragma.}: string ## This is an annotated string
    -  
    + annotated* {.somePragma.}: string ## This is an annotated string
    @@ -444,8 +439,7 @@

    Types

    T19396 = object
    -  a*: int
    -  
    + a*: int
    From 53855a9fa387f07dbf42c82879d00fbc15b59c10 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:30:35 +0800 Subject: [PATCH 074/123] make `-d:debugHeapLinks` compile again (#23126) I have made `realloc` absorb unused adjacent memory, which improves the performance. I'm investigating whether `deallocOsPages` can be used to improve memory comsumption. --- lib/system/alloc.nim | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index edb094f3349a0..9c7c83aab03fa 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -334,7 +334,7 @@ when not defined(gcDestructors): n.link[0] = a.freeAvlNodes a.freeAvlNodes = n -proc addHeapLink(a: var MemRegion; p: PBigChunk, size: int) = +proc addHeapLink(a: var MemRegion; p: PBigChunk, size: int): ptr HeapLinks = var it = addr(a.heapLinks) while it != nil and it.len >= it.chunks.len: it = it.next if it == nil: @@ -343,10 +343,12 @@ proc addHeapLink(a: var MemRegion; p: PBigChunk, size: int) = a.heapLinks.next = n n.chunks[0] = (p, size) n.len = 1 + result = n else: let L = it.len it.chunks[L] = (p, size) inc it.len + result = it when not defined(gcDestructors): include "system/avltree" @@ -490,10 +492,10 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = incCurrMem(a, size) inc(a.freeMem, size) - a.addHeapLink(result, size) + let heapLink = a.addHeapLink(result, size) when defined(debugHeapLinks): cprintf("owner: %p; result: %p; next pointer %p; size: %ld\n", addr(a), - result, result.heapLink, result.size) + result, heapLink, size) when defined(memtracker): trackLocation(addr result.size, sizeof(int)) @@ -1091,7 +1093,7 @@ proc deallocOsPages(a: var MemRegion) = let (p, size) = it.chunks[i] when defined(debugHeapLinks): cprintf("owner %p; dealloc A: %p size: %ld; next: %p\n", addr(a), - it, it.size, next) + it, size, next) sysAssert size >= PageSize, "origSize too small" osDeallocPages(p, size) it = next From 6f3d3fdf9f4a718a7365ab98455903a7b18dade8 Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Mon, 25 Dec 2023 03:25:05 +0000 Subject: [PATCH 075/123] CI entry may be reset to default (#23127) --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d056dac69db9f..b9f891dadf1d5 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -60,7 +60,7 @@ pkg "compactdict" pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension" pkg "cowstrings" pkg "criterion", allowFailure = true # needs testing binary -pkg "datamancer", url="https://github.com/Graveflo/Datamancer.git" +pkg "datamancer" pkg "dashing", "nim c tests/functional.nim" pkg "delaunay" pkg "docopt" From 1324d2e04cb11aaa96e9ba9efc69aee47ed6c1d8 Mon Sep 17 00:00:00 2001 From: ASVIEST <71895914+ASVIEST@users.noreply.github.com> Date: Mon, 25 Dec 2023 09:12:54 +0300 Subject: [PATCH 076/123] Asm syntax pragma (#23119) (Inspired by this pragma in nir asm PR) `inlineAsmSyntax` pragma allowing specify target inline assembler syntax in `asm` stmt. It prevents compiling code with different of the target CC inline asm syntax, i.e. it will not allow gcc inline asm code to be compiled with vcc. ```nim proc nothing() = asm {.inlineAsmSyntax: "gcc".} """ nop """ ``` The current C(C++) backend implementation cannot generate code for gcc and for vcc at the same time. For example, `{.inlineAsmSyntax: "vcc".}` with the ICC compiler will not generate code with intel asm syntax, even though ICC can use both gcc-like asm and vcc-like. For implement support for gcc and for vcc at the same time in ICC compiler, we need to refactor extccomp --------- Co-authored-by: Andreas Rumpf --- compiler/ccgstmts.nim | 15 +++++++++++++++ compiler/pragmas.nim | 32 ++++++++++++++++++-------------- compiler/wordrecg.nim | 2 +- doc/manual_experimental.md | 17 +++++++++++++++++ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 7bbc408902d2d..28c0851aa6b0e 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1537,6 +1537,21 @@ proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) genLineDir(p, t) var s = newRopeAppender() + + var asmSyntax = "" + if (let p = t[0]; p.kind == nkPragma): + for i in p: + if whichPragma(i) == wAsmSyntax: + asmSyntax = i[1].strVal + + if asmSyntax != "" and + not ( + asmSyntax == "gcc" and hasGnuAsm in CC[p.config.cCompiler].props or + asmSyntax == "vcc" and hasGnuAsm notin CC[p.config.cCompiler].props): + localError( + p.config, t.info, + "Your compiler does not support the specified inline assembler") + genAsmOrEmitStmt(p, t, isAsmStmt=true, s) # see bug #2362, "top level asm statements" seem to be a mis-feature # but even if we don't do this, the example in #2362 cannot possibly diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 001af6ae7fec8..a4c5397992794 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -153,20 +153,6 @@ proc pragmaEnsures(c: PContext, n: PNode) = n[1] = c.semExpr(c, n[1]) closeScope(c) -proc pragmaAsm*(c: PContext, n: PNode): char = - result = '\0' - if n != nil: - for i in 0.. Date: Thu, 28 Dec 2023 23:41:58 +0100 Subject: [PATCH 077/123] Fix cmpRunesIgnoreCase on system where sizeof(int) < 4. Fixes #23125. (#23138) Fixes an issue where importing the `strutils` module, or any other importing the `strutils` module, ends up with a compile time error on platforms where ints are less then 32-bit wide. The fix follows the suggestions made in #23125. --- lib/pure/unicode.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index c8d18831a3171..4b557e16eec9f 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -846,7 +846,12 @@ proc cmpRunesIgnoreCase*(a, b: openArray[char]): int {.rtl, extern: "nuc$1".} = # slow path: fastRuneAt(a, i, ar) fastRuneAt(b, j, br) - result = RuneImpl(toLower(ar)) - RuneImpl(toLower(br)) + when sizeof(int) < 4: + const lo = low(int).int32 + const hi = high(int).int32 + result = clamp(RuneImpl(toLower(ar)) - RuneImpl(toLower(br)), lo, hi).int + else: + result = RuneImpl(toLower(ar)) - RuneImpl(toLower(br)) if result != 0: return result = a.len - b.len From d8a5cf422722698cb3c871653a02ca4bd995fd79 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 29 Dec 2023 13:36:03 +0800 Subject: [PATCH 078/123] fixes a typo in the test (#23140) --- tests/metatype/tmetatype_various.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/metatype/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim index be70f37a7d60d..30169aa1e3b07 100644 --- a/tests/metatype/tmetatype_various.nim +++ b/tests/metatype/tmetatype_various.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:refc" + matrix: "--mm:refc; --mm:orc" output: '''[1, 0, 0, 0, 0, 0, 0, 0] CTBool[Ct[system.uint32]]''' """ From fd253a08b1a58816d3224d3b91603c37232897b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Fri, 29 Dec 2023 12:47:08 +0000 Subject: [PATCH 079/123] Adds info:capabilities to NimSuggest (#23134) --- nimsuggest/nimsuggest.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 1d48bf653d9c0..df59bc6fa98cd 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -68,6 +68,7 @@ Options: --info:X information --info:nimVer return the Nim compiler version that nimsuggest uses internally --info:protocolVer return the newest protocol version that is supported + --info:capabilities return the capabilities supported by nimsuggest --refresh perform automatic refreshes to keep the analysis precise --maxresults:N limit the number of suggestions to N --tester implies --stdin and outputs a line @@ -124,6 +125,10 @@ const "type 'quit' to quit\n" & "type 'debug' to toggle debug mode on/off\n" & "type 'terse' to toggle terse mode on/off" + #List of currently supported capabilities. So lang servers/ides can iterate over and check for what's enabled + Capabilities = [ + "con" #current NimSuggest supports the `con` commmand + ] proc parseQuoted(cmd: string; outp: var string; start: int): int = var i = start @@ -689,6 +694,9 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = of "nimver": stdout.writeLine(system.NimVersion) quit 0 + of "capabilities": + stdout.writeLine(Capabilities.toSeq.mapIt($it).join(" ")) + quit 0 else: processSwitch(pass, p, conf) of "tester": From b92163180d94d31e2027f57de6656dca1b42cbd3 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Sat, 30 Dec 2023 18:05:55 +0900 Subject: [PATCH 080/123] Fix typo in pegs.nim (#23143) wether -> whether --- lib/pure/pegs.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index d0c449bdd97f1..935cea5e62486 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -314,21 +314,21 @@ func capture*(a: Peg = Peg(kind: pkEmpty)): Peg {.rtl, extern: "npegsCapture".} func backref*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. `reverse` specifies wether indexing starts from the end of the + ## from 1. `reverse` specifies whether indexing starts from the end of the ## capture list. result = Peg(kind: pkBackRef, index: (if reverse: -index else: index - 1)) func backrefIgnoreCase*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. `reverse` specifies wether indexing starts from the end of the + ## from 1. `reverse` specifies whether indexing starts from the end of the ## capture list. Ignores case for matching. result = Peg(kind: pkBackRefIgnoreCase, index: (if reverse: -index else: index - 1)) func backrefIgnoreStyle*(index: range[1..MaxSubpatterns], reverse: bool = false): Peg {. rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. `reverse` specifies wether indexing starts from the end of the + ## from 1. `reverse` specifies whether indexing starts from the end of the ## capture list. Ignores style for matching. result = Peg(kind: pkBackRefIgnoreStyle, index: (if reverse: -index else: index - 1)) From 9483b11267bfede119f7d3e5aa3b7f86d5a15af3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 31 Dec 2023 22:56:48 +0800 Subject: [PATCH 081/123] Update copyright year 2024 (#23144) --- compiler/options.nim | 2 +- copying.txt | 2 +- readme.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 1ef096601fe72..3be1758ebaac0 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -25,7 +25,7 @@ const useEffectSystem* = true useWriteTracking* = false hasFFI* = defined(nimHasLibFFI) - copyrightYear* = "2023" + copyrightYear* = "2024" nimEnableCovariance* = defined(nimEnableCovariance) diff --git a/copying.txt b/copying.txt index ae3a162a742b0..819330be30666 100644 --- a/copying.txt +++ b/copying.txt @@ -1,7 +1,7 @@ ===================================================== Nim -- a Compiler for Nim. https://nim-lang.org/ -Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved. +Copyright (C) 2006-2024 Andreas Rumpf. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/readme.md b/readme.md index cbe902c5235c9..6556ee302b9e0 100644 --- a/readme.md +++ b/readme.md @@ -204,7 +204,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2023 Andreas Rumpf, all rights reserved. +Copyright © 2006-2024 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org From 9659da903fcb28b96bc06cd9b18bd8f99a8d9aad Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 1 Jan 2024 00:25:14 +0800 Subject: [PATCH 082/123] fixes wrong indentation (#23145) 4 spaces => 2 spaces --- lib/packages/docutils/rst.nim | 208 +++++++++++++++++----------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 342ce01082482..73d4ba47b6774 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -3652,114 +3652,114 @@ proc preparePass2*(s: var PRstSharedState, mainNode: PRstNode, importdoc = true) loadIdxFile(s, origFilename) proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode = - # Associate this link alias with its target and change node kind to - # rnHyperlink or rnInternalRef appropriately. - var desc, alias: PRstNode - if n.kind == rnPandocRef: # link like [desc][alias] - desc = n.sons[0] - alias = n.sons[1] - else: # n.kind == rnRstRef, link like `desc=alias`_ - desc = n - alias = n - type LinkDef = object - ar: AnchorRule - priority: int - tooltip: string - target: PRstNode - info: TLineInfo - externFilename: string - # when external anchor: origin filename where anchor was defined - isTitle: bool - proc cmp(x, y: LinkDef): int = - result = cmp(x.priority, y.priority) - if result == 0: - result = cmp(x.target, y.target) - var foundLinks: seq[LinkDef] - let refn = rstnodeToRefname(alias) - var hyperlinks = findRef(s, refn) - for y in hyperlinks: - foundLinks.add LinkDef(ar: arHyperlink, priority: refPriority(y.kind), - target: y.value, info: y.info, - tooltip: "(" & $y.kind & ")") - let substRst = findMainAnchorRst(s, alias.addNodes, n.info) - template getExternFilename(subst: AnchorSubst): string = - if subst.kind == arExternalRst or - (subst.kind == arNim and subst.external): - getFilename(s, subst) - else: "" - for subst in substRst: - var refname, fullRefname: string - if subst.kind == arInternalRst: - refname = subst.target.anchor - fullRefname = refname - else: # arExternalRst - refname = subst.refnameExt - fullRefname = s.idxImports[getFilename(s, subst)].linkRelPath & - "/" & refname - let anchorType = - if subst.kind == arInternalRst: subst.anchorType - else: subst.anchorTypeExt # arExternalRst + # Associate this link alias with its target and change node kind to + # rnHyperlink or rnInternalRef appropriately. + var desc, alias: PRstNode + if n.kind == rnPandocRef: # link like [desc][alias] + desc = n.sons[0] + alias = n.sons[1] + else: # n.kind == rnRstRef, link like `desc=alias`_ + desc = n + alias = n + type LinkDef = object + ar: AnchorRule + priority: int + tooltip: string + target: PRstNode + info: TLineInfo + externFilename: string + # when external anchor: origin filename where anchor was defined + isTitle: bool + proc cmp(x, y: LinkDef): int = + result = cmp(x.priority, y.priority) + if result == 0: + result = cmp(x.target, y.target) + var foundLinks: seq[LinkDef] + let refn = rstnodeToRefname(alias) + var hyperlinks = findRef(s, refn) + for y in hyperlinks: + foundLinks.add LinkDef(ar: arHyperlink, priority: refPriority(y.kind), + target: y.value, info: y.info, + tooltip: "(" & $y.kind & ")") + let substRst = findMainAnchorRst(s, alias.addNodes, n.info) + template getExternFilename(subst: AnchorSubst): string = + if subst.kind == arExternalRst or + (subst.kind == arNim and subst.external): + getFilename(s, subst) + else: "" + for subst in substRst: + var refname, fullRefname: string + if subst.kind == arInternalRst: + refname = subst.target.anchor + fullRefname = refname + else: # arExternalRst + refname = subst.refnameExt + fullRefname = s.idxImports[getFilename(s, subst)].linkRelPath & + "/" & refname + let anchorType = + if subst.kind == arInternalRst: subst.anchorType + else: subst.anchorTypeExt # arExternalRst + foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority, + target: newLeaf(fullRefname), + info: subst.info, + externFilename: getExternFilename(subst), + isTitle: isDocumentationTitle(refname), + tooltip: "(" & $anchorType & ")") + # find anchors automatically generated from Nim symbols + if roNimFile in s.options or s.nimFileImported: + let substNim = findMainAnchorNim(s, signature=alias, n.info) + for subst in substNim: + let fullRefname = + if subst.external: + s.idxImports[getFilename(s, subst)].linkRelPath & + "/" & subst.refname + else: subst.refname foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority, target: newLeaf(fullRefname), - info: subst.info, externFilename: getExternFilename(subst), - isTitle: isDocumentationTitle(refname), - tooltip: "(" & $anchorType & ")") - # find anchors automatically generated from Nim symbols - if roNimFile in s.options or s.nimFileImported: - let substNim = findMainAnchorNim(s, signature=alias, n.info) - for subst in substNim: - let fullRefname = - if subst.external: - s.idxImports[getFilename(s, subst)].linkRelPath & - "/" & subst.refname - else: subst.refname - foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority, - target: newLeaf(fullRefname), - externFilename: getExternFilename(subst), - isTitle: isDocumentationTitle(subst.refname), - info: subst.info, tooltip: subst.tooltip) - foundLinks.sort(cmp = cmp, order = Descending) - let aliasStr = addNodes(alias) - if foundLinks.len >= 1: + isTitle: isDocumentationTitle(subst.refname), + info: subst.info, tooltip: subst.tooltip) + foundLinks.sort(cmp = cmp, order = Descending) + let aliasStr = addNodes(alias) + if foundLinks.len >= 1: + if foundLinks[0].externFilename != "": + s.idxImports[foundLinks[0].externFilename].used = true + let kind = if foundLinks[0].ar in {arHyperlink, arExternalRst}: rnHyperlink + elif foundLinks[0].ar == arNim: + if foundLinks[0].externFilename == "": rnNimdocRef + else: rnHyperlink + else: rnInternalRef + result = newRstNode(kind) + let documentName = # filename without ext for `.nim`, title for `.md` + if foundLinks[0].ar == arNim: + changeFileExt(foundLinks[0].externFilename.extractFilename, "") + elif foundLinks[0].externFilename != "": + s.idxImports[foundLinks[0].externFilename].title + else: foundLinks[0].externFilename.extractFilename + let linkText = if foundLinks[0].externFilename != "": - s.idxImports[foundLinks[0].externFilename].used = true - let kind = if foundLinks[0].ar in {arHyperlink, arExternalRst}: rnHyperlink - elif foundLinks[0].ar == arNim: - if foundLinks[0].externFilename == "": rnNimdocRef - else: rnHyperlink - else: rnInternalRef - result = newRstNode(kind) - let documentName = # filename without ext for `.nim`, title for `.md` - if foundLinks[0].ar == arNim: - changeFileExt(foundLinks[0].externFilename.extractFilename, "") - elif foundLinks[0].externFilename != "": - s.idxImports[foundLinks[0].externFilename].title - else: foundLinks[0].externFilename.extractFilename - let linkText = - if foundLinks[0].externFilename != "": - if foundLinks[0].isTitle: newLeaf(addNodes(desc)) - else: newLeaf(documentName & ": " & addNodes(desc)) - else: - newRstNode(rnInner, desc.sons) - result.sons = @[linkText, foundLinks[0].target] - if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip - if foundLinks.len > 1: # report ambiguous link - var targets = newSeq[string]() - for l in foundLinks: - var t = " " - if s.filenames.len > 1: - t.add getFilename(s.filenames, l.info.fileIndex) - let n = l.info.line - let c = l.info.col + ColRstOffset - t.add "($1, $2): $3" % [$n, $c, l.tooltip] - targets.add t - rstMessage(s.filenames, s.msgHandler, n.info, mwAmbiguousLink, - "`$1`\n clash:\n$2" % [ - aliasStr, targets.join("\n")]) - else: # nothing found - result = n - rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, aliasStr) + if foundLinks[0].isTitle: newLeaf(addNodes(desc)) + else: newLeaf(documentName & ": " & addNodes(desc)) + else: + newRstNode(rnInner, desc.sons) + result.sons = @[linkText, foundLinks[0].target] + if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip + if foundLinks.len > 1: # report ambiguous link + var targets = newSeq[string]() + for l in foundLinks: + var t = " " + if s.filenames.len > 1: + t.add getFilename(s.filenames, l.info.fileIndex) + let n = l.info.line + let c = l.info.col + ColRstOffset + t.add "($1, $2): $3" % [$n, $c, l.tooltip] + targets.add t + rstMessage(s.filenames, s.msgHandler, n.info, mwAmbiguousLink, + "`$1`\n clash:\n$2" % [ + aliasStr, targets.join("\n")]) + else: # nothing found + result = n + rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, aliasStr) proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode = ## Makes pass 2 of RST parsing. From ccc7c45d718c13714e8e9e1040c29b9b286d2448 Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Sun, 31 Dec 2023 16:52:52 +0000 Subject: [PATCH 083/123] `typRel` and `sumGeneric` adjustments (#23137) Filling in some more logic in `typeRel` that I came across when poking the compiler in another PR. Some of the cases where `typeRel` returns an "incorrect" result are actually common, but `sumGeneric` ends up breaking the tie correctly. There isn't anything wrong with that necessarily, but I assume that it's preferred these functions behave just as well in isolation as they do when integrated. I will be following up this description with specific examples. --- compiler/sigmatch.nim | 100 +++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 54 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 127ed4a6884ad..df70ff3b4e570 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -162,19 +162,19 @@ proc newCandidate*(ctx: PContext, callee: PSym, proc newCandidate*(ctx: PContext, callee: PType): TCandidate = result = initCandidate(ctx, callee) -proc copyCandidate(a: var TCandidate, b: TCandidate) = - a.c = b.c - a.exactMatches = b.exactMatches - a.subtypeMatches = b.subtypeMatches - a.convMatches = b.convMatches - a.intConvMatches = b.intConvMatches - a.genericMatches = b.genericMatches - a.state = b.state - a.callee = b.callee - a.calleeSym = b.calleeSym - a.call = copyTree(b.call) - a.baseTypeMatch = b.baseTypeMatch - copyIdTable(a.bindings, b.bindings) +proc copyCandidate(dest: var TCandidate, src: TCandidate) = + dest.c = src.c + dest.exactMatches = src.exactMatches + dest.subtypeMatches = src.subtypeMatches + dest.convMatches = src.convMatches + dest.intConvMatches = src.intConvMatches + dest.genericMatches = src.genericMatches + dest.state = src.state + dest.callee = src.callee + dest.calleeSym = src.calleeSym + dest.call = copyTree(src.call) + dest.baseTypeMatch = src.baseTypeMatch + copyIdTable(dest.bindings, src.bindings) proc typeRel*(c: var TCandidate, f, aOrig: PType, flags: TTypeRelFlags = {}): TTypeRelation @@ -189,10 +189,10 @@ proc checkGeneric(a, b: TCandidate): int = let tra = typeRel(ma, bbi, aai, {trDontBind}) var mb = newCandidate(c, aai) let trb = typeRel(mb, aai, bbi, {trDontBind}) - if tra == isGeneric and trb == isNone: + if tra == isGeneric and trb in {isNone, isInferred, isInferredConvertible}: if winner == -1: return 0 winner = 1 - if trb == isGeneric and tra == isNone: + if trb == isGeneric and tra in {isNone, isInferred, isInferredConvertible}: if winner == 1: return 0 winner = -1 result = winner @@ -203,19 +203,24 @@ proc sumGeneric(t: PType): int = # specific than Foo[T]. result = 0 var t = t - var isvar = 0 while true: case t.kind + of tyAlias, tySink, tyNot: t = t.skipModifier of tyArray, tyRef, tyPtr, tyDistinct, tyUncheckedArray, tyOpenArray, tyVarargs, tySet, tyRange, tySequence, - tyLent, tyOwned: + tyLent, tyOwned, tyVar: t = t.elementType inc result - of tyGenericInst: - t = t.skipModifier + of tyBool, tyChar, tyEnum, tyObject, tyPointer, tyVoid, + tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, + tyUInt..tyUInt64, tyCompositeTypeClass, tyBuiltInTypeClass, + tyGenericParam: inc result + break of tyGenericBody: t = t.typeBodyImpl + of tyGenericInst, tyStatic: + t = t.skipModifier inc result of tyOr: var maxBranch = 0 @@ -224,16 +229,13 @@ proc sumGeneric(t: PType): int = if branchSum > maxBranch: maxBranch = branchSum inc result, maxBranch break - of tyVar: - t = t.elementType - inc result - inc isvar of tyTypeDesc: t = t.elementType if t.kind == tyEmpty: break inc result + of tyUntyped, tyTyped: break of tyGenericInvocation, tyTuple, tyAnd: - result += ord(t.kind in {tyGenericInvocation, tyAnd}) + result += ord(t.kind == tyAnd) for a in t.kids: if a != nil: result += sumGeneric(a) @@ -243,18 +245,8 @@ proc sumGeneric(t: PType): int = for _, a in t.paramTypes: result += sumGeneric(a) break - of tyStatic: - return sumGeneric(t.skipModifier) + 1 - of tyGenericParam, tyUntyped, tyTyped: break - of tyAlias, tySink: t = t.skipModifier - of tyBool, tyChar, tyEnum, tyObject, tyPointer, - tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, - tyUInt..tyUInt64, tyCompositeTypeClass: - return isvar + 1 - of tyBuiltInTypeClass: - return isvar else: - return 0 + break proc complexDisambiguation(a, b: PType): int = # 'a' matches better if *every* argument matches better or equal than 'b'. @@ -459,23 +451,24 @@ proc handleFloatRange(f, a: PType): TTypeRelation = else: result = isIntConv else: result = isNone -proc getObjectTypeOrNil(f: PType): PType = +proc getObjectType(f: PType): PType = #[ Returns a type that is f's effective typeclass. This is usually just one level deeper in the hierarchy of generality for a type. `object`, `ref object`, `enum` and user defined tyObjects are common return values. ]# - if f == nil: return nil case f.kind: - of tyGenericInvocation, tyCompositeTypeClass, tyAlias: + of tyGenericInvocation: + result = getObjectType(f.baseClass) + of tyCompositeTypeClass, tyAlias: if not f.hasElementType or f.elementType == nil: - result = nil + result = f else: - result = getObjectTypeOrNil(f.elementType) + result = getObjectType(f.elementType) of tyGenericInst: - result = getObjectTypeOrNil(f.skipModifier) + result = getObjectType(f.skipModifier) of tyGenericBody: - result = getObjectTypeOrNil(f.typeBodyImpl) + result = getObjectType(f.typeBodyImpl) of tyUserTypeClass: if f.isResolvedUserTypeClass: @@ -483,12 +476,12 @@ proc getObjectTypeOrNil(f: PType): PType = else: result = f.skipModifier of tyStatic, tyOwned, tyVar, tyLent, tySink: - result = getObjectTypeOrNil(f.base) + result = getObjectType(f.base) of tyInferred: # This is not true "After a candidate type is selected" - result = getObjectTypeOrNil(f.base) + result = getObjectType(f.base) of tyTyped, tyUntyped, tyFromExpr: - result = nil + result = f of tyRange: result = f.elementType else: @@ -577,7 +570,7 @@ proc minRel(a, b: TTypeRelation): TTypeRelation = if a <= b: result = a else: result = b -proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = +proc recordRel(c: var TCandidate, f, a: PType, flags: TTypeRelFlags): TTypeRelation = result = isNone if sameType(f, a): result = isEqual @@ -586,7 +579,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = let firstField = if f.kind == tyTuple: 0 else: 1 for _, ff, aa in tupleTypePairs(f, a): - var m = typeRel(c, ff, aa) + var m = typeRel(c, ff, aa, flags) if m < isSubtype: return isNone result = minRel(result, m) if f.n != nil and a.n != nil: @@ -597,7 +590,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = else: var x = f.n[i].sym var y = a.n[i].sym - if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype: + if f.kind == tyObject and typeRel(c, x.typ, y.typ, flags) < isSubtype: return isNone if x.name.id != y.name.id: return isNone @@ -1251,6 +1244,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = typeRel(c, f.base, aOrig, flags + {trNoCovariance}) subtypeCheck() of tyArray: + a = getObjectType(a) case a.kind of tyArray: var fRange = f.indexType @@ -1371,13 +1365,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, skipOwned(a) if a.kind == f.kind: result = isEqual of tyTuple: - if a.kind == tyTuple: result = recordRel(c, f, a) + if a.kind == tyTuple: result = recordRel(c, f, a, flags) of tyObject: let effectiveArgType = if useTypeLoweringRuleInTypeClass: a else: - getObjectTypeOrNil(a) - if effectiveArgType == nil: return isNone + getObjectType(a) if effectiveArgType.kind == tyObject: if sameObjectTypes(f, effectiveArgType): result = isEqual @@ -1407,7 +1400,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # set constructors are a bit special... result = isNone of tyPtr, tyRef: - skipOwned(a) + a = getObjectType(a) if a.kind == f.kind: # ptr[R, T] can be passed to ptr[T], but not the other way round: if a.len < f.len: return isNone @@ -1698,8 +1691,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, considerPreviousT: let target = f.genericHead let targetKind = target.kind - var effectiveArgType = a.getObjectTypeOrNil() - if effectiveArgType == nil: return isNone + var effectiveArgType = getObjectType(a) effectiveArgType = effectiveArgType.skipTypes({tyBuiltInTypeClass}) if targetKind == effectiveArgType.kind: if effectiveArgType.isEmptyContainer: From b280100499fafe43657c860e3c79d9347be5b4b6 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 1 Jan 2024 14:21:19 +0300 Subject: [PATCH 084/123] ambiguous identifier resolution (#23123) fixes #23002, fixes #22841, refs comments in #23097 When an identifier is ambiguous in scope (i.e. multiple imports contain symbols with the same name), attempt resolving it through type inference (by creating a symchoice). To do this efficiently, `qualifiedLookUp` had to be broken up so that `semExpr` can access the ambiguous candidates directly (now obtained directly via `lookUpCandidates`). This fixes the linked issues, but an example like: ```nim let on = 123 {.warning[ProveInit]: on.} ``` will still fail, since `on` is unambiguously the local `let` symbol here (this is also true for `proc on` but `proc` symbols generate symchoices anyway). Type symbols are not considered to not confuse the type inference. This includes the change in sigmatch, up to this point symchoices with nonoverloadable symbols could be created, they just wouldn't be considered during disambiguation. Now every proper symbol except types are considered in disambiguation, so the correct symbols must be picked during the creation of the symchoice node. I remember there being a violating case of this in the compiler, but this was very likely fixed by excluding type symbols as CI seems to have found no issues. The pure enum ambiguity test was disabled because ambiguous pure enums now behave like overloadable enums with this behavior, so we get a longer error message for `echo amb` like `type mismatch: got but expected T` --- compiler/lookups.nim | 64 +++++++++------- compiler/semexprs.nim | 109 +++++++++++++++++++--------- compiler/sigmatch.nim | 4 +- tests/enum/tambiguousoverloads.nim | 4 +- tests/enum/tpure_enums_conflict.nim | 1 + tests/errmsgs/t8064.nim | 2 +- tests/lookups/tambiguousemit.nim | 2 +- tests/lookups/tambprocvar.nim | 4 +- tests/lookups/tambsym3.nim | 2 +- tests/macros/t23032_2.nim | 2 +- tests/pragmas/monoff1.nim | 1 + tests/pragmas/tonoff1.nim | 8 ++ tests/pragmas/tonoff2.nim | 14 ++++ 13 files changed, 146 insertions(+), 71 deletions(-) create mode 100644 tests/pragmas/monoff1.nim create mode 100644 tests/pragmas/tonoff1.nim create mode 100644 tests/pragmas/tonoff2.nim diff --git a/compiler/lookups.nim b/compiler/lookups.nim index cfefe764ba3b0..52296644dd10a 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -303,8 +303,16 @@ proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): boo # imports had a candidate but wasn't ambiguous return false -proc errorSym*(c: PContext, n: PNode): PSym = +proc errorSym*(c: PContext, ident: PIdent, info: TLineInfo): PSym = ## creates an error symbol to avoid cascading errors (for IDE support) + result = newSym(skError, ident, c.idgen, getCurrOwner(c), info, {}) + result.typ = errorType(c) + incl(result.flags, sfDiscardable) + # pretend it's from the top level scope to prevent cascading errors: + if c.config.cmd != cmdInteractive and c.compilesContextId == 0: + c.moduleScope.addSym(result) + +proc errorSym*(c: PContext, n: PNode): PSym = var m = n # ensure that 'considerQuotedIdent' can't fail: if m.kind == nkDotExpr: m = m[1] @@ -312,12 +320,7 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(c, m) else: getIdent(c.cache, "err:" & renderTree(m)) - result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {}) - result.typ = errorType(c) - incl(result.flags, sfDiscardable) - # pretend it's from the top level scope to prevent cascading errors: - if c.config.cmd != cmdInteractive and c.compilesContextId == 0: - c.moduleScope.addSym(result) + result = errorSym(c, ident, n.info) type TOverloadIterMode* = enum @@ -499,7 +502,7 @@ proc mustFixSpelling(c: PContext): bool {.inline.} = result = c.config.spellSuggestMax != 0 and c.compilesContextId == 0 # don't slowdown inside compiles() -proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) = +proc fixSpelling(c: PContext, ident: PIdent, result: var string) = ## when we cannot find the identifier, suggest nearby spellings var list = initHeapQueue[SpellCandidate]() let name0 = ident.s.nimIdentNormalize @@ -558,7 +561,7 @@ proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) = var amb: bool discard errorUseQualifier(c, info, s, amb) -proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") = +proc errorUseQualifier*(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") = var err = "ambiguous identifier: '" & candidates[0].name.s & "'" var i = 0 for candidate in candidates: @@ -589,11 +592,11 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr c.recursiveDep = "" localError(c.config, info, errGenerated, err) -proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym = +proc errorUndeclaredIdentifierHint*(c: PContext; ident: PIdent; info: TLineInfo): PSym = var extra = "" - if c.mustFixSpelling: fixSpelling(c, n, ident, extra) - errorUndeclaredIdentifier(c, n.info, ident.s, extra) - result = errorSym(c, n) + if c.mustFixSpelling: fixSpelling(c, ident, extra) + errorUndeclaredIdentifier(c, info, ident.s, extra) + result = errorSym(c, ident, info) proc lookUp*(c: PContext, n: PNode): PSym = # Looks up a symbol. Generates an error in case of nil. @@ -601,13 +604,13 @@ proc lookUp*(c: PContext, n: PNode): PSym = case n.kind of nkIdent: result = searchInScopes(c, n.ident, amb) - if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident) + if result == nil: result = errorUndeclaredIdentifierHint(c, n.ident, n.info) of nkSym: result = n.sym of nkAccQuoted: var ident = considerQuotedIdent(c, n) result = searchInScopes(c, ident, amb) - if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident) + if result == nil: result = errorUndeclaredIdentifierHint(c, ident, n.info) else: internalError(c.config, n.info, "lookUp") return nil @@ -621,16 +624,29 @@ type TLookupFlag* = enum checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields +const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage} + +proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind]): seq[PSym] = + result = searchInScopesFilterBy(c, ident, filter) + if result.len == 0: + result.add allPureEnumFields(c, ident) + proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = - const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage} case n.kind of nkIdent, nkAccQuoted: var amb = false var ident = considerQuotedIdent(c, n) if checkModule in flags: result = searchInScopes(c, ident, amb) + if result == nil: + let candidates = allPureEnumFields(c, ident) + if candidates.len > 0: + result = candidates[0] + amb = candidates.len > 1 + if amb and checkAmbiguity in flags: + errorUseQualifier(c, n.info, candidates) else: - let candidates = searchInScopesFilterBy(c, ident, allExceptModule) + let candidates = lookUpCandidates(c, ident, allExceptModule) if candidates.len > 0: result = candidates[0] amb = candidates.len > 1 @@ -638,16 +654,8 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = errorUseQualifier(c, n.info, candidates) else: result = nil - if result == nil: - let candidates = allPureEnumFields(c, ident) - if candidates.len > 0: - result = candidates[0] - amb = candidates.len > 1 - if amb and checkAmbiguity in flags: - errorUseQualifier(c, n.info, candidates) - if result == nil and checkUndeclared in flags: - result = errorUndeclaredIdentifierHint(c, n, ident) + result = errorUndeclaredIdentifierHint(c, ident, n.info) elif checkAmbiguity in flags and result != nil and amb: result = errorUseQualifier(c, n.info, result, amb) c.isAmbiguous = amb @@ -672,12 +680,12 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = else: result = someSym(c.graph, m, ident) if result == nil and checkUndeclared in flags: - result = errorUndeclaredIdentifierHint(c, n[1], ident) + result = errorUndeclaredIdentifierHint(c, ident, n[1].info) elif n[1].kind == nkSym: result = n[1].sym if result.owner != nil and result.owner != m and checkUndeclared in flags: # dotExpr in templates can end up here - result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1])) + result = errorUndeclaredIdentifierHint(c, result.name, n[1].info) elif checkUndeclared in flags and n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}: localError(c.config, n[1].info, "identifier expected, but got: " & diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b469658757d54..67eee3a19a407 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -131,11 +131,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode proc isSymChoice(n: PNode): bool {.inline.} = result = n.kind in nkSymChoices -proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode = - result = n +proc resolveSymChoice(c: PContext, n: var PNode, flags: TExprFlags = {}, expectedType: PType = nil) = + ## Attempts to resolve a symchoice `n`, `n` remains a symchoice if + ## it cannot be resolved (this is the case even when `n.len == 1`). if expectedType != nil: - result = fitNode(c, expectedType, result, n.info) - if isSymChoice(result) and efAllowSymChoice notin flags: + # resolve from type inference, see paramTypesMatch + n = fitNode(c, expectedType, n, n.info) + if isSymChoice(n) and efAllowSymChoice notin flags: # some contexts might want sym choices preserved for later disambiguation # in general though they are ambiguous let first = n[0].sym @@ -145,17 +147,24 @@ proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: P foundSym == first: # choose the first resolved enum field, i.e. the latest in scope # to mirror behavior before overloadable enums - result = n[0] - else: - var err = "ambiguous identifier '" & first.name.s & - "' -- use one of the following:\n" - for child in n: - let candidate = child.sym - err.add " " & candidate.owner.name.s & "." & candidate.name.s - err.add ": " & typeToString(candidate.typ) & "\n" - localError(c.config, n.info, err) - n.typ = errorType(c) - result = n + n = n[0] + +proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode = + result = n + resolveSymChoice(c, result, flags, expectedType) + if isSymChoice(result) and result.len == 1: + # resolveSymChoice can leave 1 sym + result = result[0] + if isSymChoice(result) and efAllowSymChoice notin flags: + var err = "ambiguous identifier: '" & result[0].sym.name.s & + "' -- use one of the following:\n" + for child in n: + let candidate = child.sym + err.add " " & candidate.owner.name.s & "." & candidate.name.s + err.add ": " & typeToString(candidate.typ) & "\n" + localError(c.config, n.info, err) + n.typ = errorType(c) + result = n if result.kind == nkSym: result = semSym(c, result, result.sym, flags) @@ -2989,6 +2998,55 @@ proc semPragmaStmt(c: PContext; n: PNode) = else: pragma(c, c.p.owner, n, stmtPragmas, true) +proc resolveIdentToSym(c: PContext, n: PNode, resultNode: var PNode, + flags: TExprFlags, expectedType: PType): PSym = + # result is nil on error or if a node that can't produce a sym is resolved + let ident = considerQuotedIdent(c, n) + if expectedType != nil and ( + let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); + expected.kind == tyEnum): + let nameId = ident.id + for f in expected.n: + if f.kind == nkSym and f.sym.name.id == nameId: + return f.sym + var filter = {low(TSymKind)..high(TSymKind)} + if efNoEvaluateGeneric in flags: + # `a[...]` where `a` is a module or package is not possible + filter.excl {skModule, skPackage} + let candidates = lookUpCandidates(c, ident, filter) + if candidates.len == 0: + result = errorUndeclaredIdentifierHint(c, ident, n.info) + elif candidates.len == 1 or {efNoEvaluateGeneric, efInCall} * flags != {}: + # unambiguous, or we don't care about ambiguity + result = candidates[0] + else: + # ambiguous symbols have 1 last chance as a symchoice, + # but type symbols cannot participate in symchoices + var choice = newNodeIT(nkClosedSymChoice, n.info, newTypeS(tyNone, c)) + for c in candidates: + if c.kind notin {skType, skModule, skPackage}: + choice.add newSymNode(c, n.info) + if choice.len == 0: + # we know candidates.len > 1, we just couldn't put any in a symchoice + errorUseQualifier(c, n.info, candidates) + return nil + resolveSymChoice(c, choice, flags, expectedType) + # choice.len == 1 can be true here but as long as it's a symchoice + # it's still not resolved + if isSymChoice(choice): + result = nil + if efAllowSymChoice in flags: + resultNode = choice + else: + errorUseQualifier(c, n.info, candidates) + else: + if choice.kind == nkSym: + result = choice.sym + else: + # resolution could have generated nkHiddenStdConv etc + resultNode = semExpr(c, choice, flags, expectedType) + result = nil + proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind @@ -3026,25 +3084,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: - var s: PSym = nil - if expectedType != nil and ( - let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); - expected.kind == tyEnum): - let nameId = considerQuotedIdent(c, n).id - for f in expected.n: - if f.kind == nkSym and f.sym.name.id == nameId: - s = f.sym - break + let s = resolveIdentToSym(c, n, result, flags, expectedType) if s == nil: - let checks = if efNoEvaluateGeneric in flags: - {checkUndeclared, checkPureEnumFields} - elif efInCall in flags: - {checkUndeclared, checkModule, checkPureEnumFields} - else: - {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields} - s = qualifiedLookUp(c, n, checks) - if s == nil: - return + # resolveIdentToSym either errored or gave a result node + return if c.matchedConcept == nil: semCaptureSym(s, c.p.owner) case s.kind of skProc, skFunc, skMethod, skConverter, skIterator: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index df70ff3b4e570..2dfab4d17760b 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2338,8 +2338,8 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, if arg == nil or arg.kind notin nkSymChoices: result = paramTypesMatchAux(m, f, a, arg, argOrig) else: - let matchSet = {skProc, skFunc, skMethod, skConverter,skIterator, skMacro, - skTemplate, skEnumField} + # symbol kinds that don't participate in symchoice type disambiguation: + let matchSet = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage, skType} var best = -1 result = arg diff --git a/tests/enum/tambiguousoverloads.nim b/tests/enum/tambiguousoverloads.nim index aa75eaa91f731..12c78c848c1b0 100644 --- a/tests/enum/tambiguousoverloads.nim +++ b/tests/enum/tambiguousoverloads.nim @@ -9,7 +9,7 @@ block: # bug #21887 EnumC = enum C doAssert typeof(EnumC(A)) is EnumC #[tt.Error - ^ ambiguous identifier 'A' -- use one of the following: + ^ ambiguous identifier: 'A' -- use one of the following: EnumA.A: EnumA EnumB.A: EnumB]# @@ -21,6 +21,6 @@ block: # issue #22598 red let a = red #[tt.Error - ^ ambiguous identifier 'red' -- use one of the following: + ^ ambiguous identifier: 'red' -- use one of the following: A.red: A B.red: B]# diff --git a/tests/enum/tpure_enums_conflict.nim b/tests/enum/tpure_enums_conflict.nim index 3c7528a7257eb..4411fd2a618da 100644 --- a/tests/enum/tpure_enums_conflict.nim +++ b/tests/enum/tpure_enums_conflict.nim @@ -1,4 +1,5 @@ discard """ + disabled: true # pure enums behave like overloaded enums on ambiguity now which gives a different error message errormsg: "ambiguous identifier: 'amb'" line: 19 """ diff --git a/tests/errmsgs/t8064.nim b/tests/errmsgs/t8064.nim index 6be83fd1ae193..c35a3abcc0cf8 100644 --- a/tests/errmsgs/t8064.nim +++ b/tests/errmsgs/t8064.nim @@ -5,5 +5,5 @@ values discard """ # either this or "expression has no type": - errormsg: "ambiguous identifier 'values' -- use one of the following:" + errormsg: "ambiguous identifier: 'values' -- use one of the following:" """ diff --git a/tests/lookups/tambiguousemit.nim b/tests/lookups/tambiguousemit.nim index 0ebd0a2551799..4f4bacce41a9a 100644 --- a/tests/lookups/tambiguousemit.nim +++ b/tests/lookups/tambiguousemit.nim @@ -7,6 +7,6 @@ proc foo(x: int) = discard proc foo(x: float) = discard {.emit: ["// ", foo].} #[tt.Error - ^ ambiguous identifier 'foo' -- use one of the following: + ^ ambiguous identifier: 'foo' -- use one of the following: tambiguousemit.foo: proc (x: int){.noSideEffect, gcsafe.} tambiguousemit.foo: proc (x: float){.noSideEffect, gcsafe.}]# diff --git a/tests/lookups/tambprocvar.nim b/tests/lookups/tambprocvar.nim index 33323fbb2a457..f5c3fde4f8f05 100644 --- a/tests/lookups/tambprocvar.nim +++ b/tests/lookups/tambprocvar.nim @@ -2,7 +2,7 @@ discard """ action: reject cmd: "nim check $file" nimout: ''' -tambprocvar.nim(15, 11) Error: ambiguous identifier 'foo' -- use one of the following: +tambprocvar.nim(15, 11) Error: ambiguous identifier: 'foo' -- use one of the following: tambprocvar.foo: proc (x: int){.noSideEffect, gcsafe.} tambprocvar.foo: proc (x: float){.noSideEffect, gcsafe.} ''' @@ -16,4 +16,4 @@ block: block: let x = `+` #[tt.Error - ^ ambiguous identifier '+' -- use one of the following:]# + ^ ambiguous identifier: '+' -- use one of the following:]# diff --git a/tests/lookups/tambsym3.nim b/tests/lookups/tambsym3.nim index 6e7589cd8a6d8..6bbebca103a0a 100644 --- a/tests/lookups/tambsym3.nim +++ b/tests/lookups/tambsym3.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "ambiguous identifier 'mDec' -- use one of the following:" + errormsg: "ambiguous identifier: 'mDec' -- use one of the following:" file: "tambsym3.nim" line: 11 """ diff --git a/tests/macros/t23032_2.nim b/tests/macros/t23032_2.nim index cb8e772e70382..8dde29e1041af 100644 --- a/tests/macros/t23032_2.nim +++ b/tests/macros/t23032_2.nim @@ -1,6 +1,6 @@ discard """ action: "reject" - errormsg: "ambiguous identifier '%*'" + errormsg: "ambiguous identifier: '%*'" """ import std/macros diff --git a/tests/pragmas/monoff1.nim b/tests/pragmas/monoff1.nim new file mode 100644 index 0000000000000..85d6c57b3b132 --- /dev/null +++ b/tests/pragmas/monoff1.nim @@ -0,0 +1 @@ +proc on*() = discard diff --git a/tests/pragmas/tonoff1.nim b/tests/pragmas/tonoff1.nim new file mode 100644 index 0000000000000..20ba7def2374f --- /dev/null +++ b/tests/pragmas/tonoff1.nim @@ -0,0 +1,8 @@ +# issue #23002 + +import monoff1 + +proc test() = + {.warning[ProveInit]: on.} + +test() diff --git a/tests/pragmas/tonoff2.nim b/tests/pragmas/tonoff2.nim new file mode 100644 index 0000000000000..9dff5ef11a695 --- /dev/null +++ b/tests/pragmas/tonoff2.nim @@ -0,0 +1,14 @@ +discard """ + action: compile +""" + +# issue #22841 + +import unittest + +proc on() = + discard + +suite "some suite": + test "some test": + discard From c7d742e484e06cdc8d87443a76ec03f1f1724bee Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:49:16 +0800 Subject: [PATCH 085/123] fixes #23148; restricts infix path concatenation to what starts with `/` (#23150) fixes #23148 --- compiler/modulepaths.nim | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index c29ed6793c2e9..73e0ef7849271 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -38,11 +38,14 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = localError(n.info, "only '/' supported with $package notation") result = "" else: - let modname = getModuleName(conf, n[2]) - # hacky way to implement 'x / y /../ z': - result = getModuleName(conf, n1) - result.add renderTree(n0, {renderNoComments}).replace(" ") - result.add modname + if n0.kind == nkIdent and n0.ident.s[0] == '/': + let modname = getModuleName(conf, n[2]) + # hacky way to implement 'x / y /../ z': + result = getModuleName(conf, n1) + result.add renderTree(n0, {renderNoComments}).replace(" ") + result.add modname + else: + result = "" of nkPrefix: when false: if n[0].kind == nkIdent and n[0].ident.s == "$": From 20d79c9fb0cd2e72473f5fb08134cf72d0fdd9e7 Mon Sep 17 00:00:00 2001 From: ASVIEST <71895914+ASVIEST@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:49:54 +0300 Subject: [PATCH 086/123] Deprecate asm stmt for js target (#23149) why ? - We already have an emit that does the same thing - The name asm itself is a bit confusing, you might think it's an alias for asm.js or something else. - The asm keyword is used differently on different compiler targets (it makes it inexpressive). - Does anyone (other than some compiler libraries) use asm instead of emit ? If yes, it's a bit strange to use asm somewhere and emit somewhere. By making the asm keyword for js target deprecated, there would be even less use of the asm keyword for js target, reducing the amount of confusion. - New users might accidentally use a non-universal approach via the asm keyword instead of emit, and then when they learn about asm, try to figure out what the differences are. see https://forum.nim-lang.org/t/10821 --------- Co-authored-by: Andreas Rumpf --- compiler/jsgen.nim | 12 ++- lib/js/asyncjs.nim | 4 +- lib/js/jsre.nim | 2 +- lib/pure/hashes.nim | 6 +- lib/pure/json.nim | 13 +-- lib/pure/math.nim | 4 +- lib/std/exitprocs.nim | 16 ++-- lib/std/formatfloat.nim | 4 +- lib/system.nim | 4 +- lib/system/comparisons.nim | 2 +- lib/system/jssys.nim | 168 ++++++++++++++++++------------------- 11 files changed, 121 insertions(+), 114 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index fb1145360ca6c..471d51c0f9873 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1136,10 +1136,14 @@ proc genBreakStmt(p: PProc, n: PNode) = p.blocks[idx].id = abs(p.blocks[idx].id) # label is used lineF(p, "break Label$1;$n", [rope(p.blocks[idx].id)]) -proc genAsmOrEmitStmt(p: PProc, n: PNode) = +proc genAsmOrEmitStmt(p: PProc, n: PNode; isAsmStmt = false) = genLineDir(p, n) p.body.add p.indentLine("") - for i in 0..".} @@ -72,16 +72,16 @@ proc addExitProc*(cl: proc() {.noconv.}) = when not defined(nimscript) and (not defined(js) or defined(nodejs)): proc getProgramResult*(): int = when defined(js) and defined(nodejs): - asm """ + {.emit: """ `result` = process.exitCode; -""" +""".} else: result = programResult proc setProgramResult*(a: int) = when defined(js) and defined(nodejs): - asm """ + {.emit: """ process.exitCode = `a`; -""" +""".} else: programResult = a diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim index 872549c3b1ea3..7103b58637a61 100644 --- a/lib/std/formatfloat.nim +++ b/lib/std/formatfloat.nim @@ -104,7 +104,7 @@ when defined(js): proc nimFloatToString(a: float): cstring = ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2 # print `-0.0` properly - asm """ + {.emit: """ function nimOnlyDigitsOrMinus(n) { return n.toString().match(/^-?\d+$/); } @@ -116,7 +116,7 @@ when defined(js): `result` = `a`+".0" } } - """ + """.} proc addFloat*(result: var string; x: float | float32) {.inline.} = ## Converts float to its string representation and appends it to `result`. diff --git a/lib/system.nim b/lib/system.nim index 8c17afaa026bf..9ca9da3027f30 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1871,14 +1871,14 @@ when defined(js) or defined(nimdoc): tmp.add(cstring("ab")) tmp.add(cstring("cd")) doAssert tmp == "abcd" - asm """ + {.emit: """ if (`x` === null) { `x` = []; } var off = `x`.length; `x`.length += `y`.length; for (var i = 0; i < `y`.length; ++i) { `x`[off+i] = `y`.charCodeAt(i); } - """ + """.} proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} = ## Appends `y` to `x` in place. ## Only implemented for JS backend. diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 9759c3c99adb1..ce5e486f71a74 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -324,7 +324,7 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = return true else: var sameObject = false - asm """`sameObject` = `x` === `y`""" + {.emit: """`sameObject` = `x` === `y`""".} if sameObject: return true if x.len != y.len: diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 1c8ea9d88867d..868abfd53b822 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -49,7 +49,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} = result[0] = x proc isNimException(): bool {.asmNoStackFrame.} = - asm "return `lastJSError` && `lastJSError`.m_type;" + {.emit: "return `lastJSError` && `lastJSError`.m_type;".} proc getCurrentException*(): ref Exception {.compilerRtl, benign.} = if isNimException(): result = cast[ref Exception](lastJSError) @@ -148,7 +148,7 @@ proc raiseException(e: ref Exception, ename: cstring) {. unhandledException(e) when NimStackTrace: e.trace = rawWriteStackTrace() - asm "throw `e`;" + {.emit: "throw `e`;".} proc reraiseException() {.compilerproc, asmNoStackFrame.} = if lastJSError == nil: @@ -158,7 +158,7 @@ proc reraiseException() {.compilerproc, asmNoStackFrame.} = if isNimException(): unhandledException(cast[ref Exception](lastJSError)) - asm "throw lastJSError;" + {.emit: "throw lastJSError;".} proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerproc.} = raise newException(OverflowDefect, "over- or underflow") @@ -176,7 +176,7 @@ proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} = raise newException(FieldDefect, formatFieldDefect(f, discVal)) proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = {}; for (var i = 0; i < arguments.length; ++i) { var x = arguments[i]; @@ -189,7 +189,7 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = } } return result; - """ + """.} proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ @@ -277,64 +277,64 @@ proc toJSStr(s: string): cstring {.compilerproc.} = result = join(res) proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = new Array(`len`); for (var i = 0; i < `len`; i++) {result[i] = 0;} return result; - """ + """.} proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = # argument type is a fake - asm """ + {.emit: """ var result = 0; for (var elem in `a`) { ++result; } return result; - """ + """.} proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ for (var elem in `a`) { if (!`b`[elem]) return false; } for (var elem in `b`) { if (!`a`[elem]) return false; } return true; - """ + """.} proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ for (var elem in `a`) { if (!`b`[elem]) return false; } return true; - """ + """.} proc SetLt(a, b: int): bool {.compilerproc.} = result = SetLe(a, b) and not SetEq(a, b) proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ var result = {}; for (var elem in `a`) { if (`b`[elem]) { result[elem] = true; } } return result; - """ + """.} proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ var result = {}; for (var elem in `a`) { result[elem] = true; } for (var elem in `b`) { result[elem] = true; } return result; - """ + """.} proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ var result = {}; for (var elem in `a`) { if (!`b`[elem]) { result[elem] = true; } } return result; - """ + """.} proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`a` == `b`) return 0; if (!`a`) return -1; if (!`b`) return 1; @@ -343,7 +343,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} = if (result != 0) return result; } return `a`.length - `b`.length; - """ + """.} proc cmp(x, y: string): int = when nimvm: @@ -354,7 +354,7 @@ proc cmp(x, y: string): int = result = cmpStrings(x, y) proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`a` == `b`) return true; if (`a` === null && `b`.length == 0) return true; if (`b` === null && `a`.length == 0) return true; @@ -364,29 +364,29 @@ proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} = for (var i = 0; i < alen; ++i) if (`a`[i] != `b`[i]) return false; return true; - """ + """.} when defined(kwin): proc rawEcho {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ var buf = ""; for (var i = 0; i < arguments.length; ++i) { buf += `toJSStr`(arguments[i]); } print(buf); - """ + """.} elif not defined(nimOldEcho): proc ewriteln(x: cstring) = log(x) proc rawEcho {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ var buf = ""; for (var i = 0; i < arguments.length; ++i) { buf += `toJSStr`(arguments[i]); } console.log(buf); - """ + """.} else: proc ewriteln(x: cstring) = @@ -414,84 +414,84 @@ else: # Arithmetic: proc checkOverflowInt(a: int) {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`a` > 2147483647 || `a` < -2147483648) `raiseOverflow`(); - """ + """.} proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` + `b`; `checkOverflowInt`(result); return result; - """ + """.} proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` - `b`; `checkOverflowInt`(result); return result; - """ + """.} proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` * `b`; `checkOverflowInt`(result); return result; - """ + """.} proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`b` == 0) `raiseDivByZero`(); if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); return Math.trunc(`a` / `b`); - """ + """.} proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`b` == 0) `raiseDivByZero`(); if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); return Math.trunc(`a` % `b`); - """ + """.} proc checkOverflowInt64(a: int64) {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`a` > 9223372036854775807n || `a` < -9223372036854775808n) `raiseOverflow`(); - """ + """.} proc addInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` + `b`; `checkOverflowInt64`(result); return result; - """ + """.} proc subInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` - `b`; `checkOverflowInt64`(result); return result; - """ + """.} proc mulInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` * `b`; `checkOverflowInt64`(result); return result; - """ + """.} proc divInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`b` == 0n) `raiseDivByZero`(); if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); return `a` / `b`; - """ + """.} proc modInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`b` == 0n) `raiseDivByZero`(); if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); return `a` % `b`; - """ + """.} proc negInt(a: int): int {.compilerproc.} = result = a*(-1) @@ -526,22 +526,22 @@ proc nimCopyAux(dest, src: JSRef, n: ptr TNimNode) {.compilerproc.} = case n.kind of nkNone: sysAssert(false, "nimCopyAux") of nkSlot: - asm """ + {.emit: """ `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ); - """ + """.} of nkList: - asm """ + {.emit: """ for (var i = 0; i < `n`.sons.length; i++) { nimCopyAux(`dest`, `src`, `n`.sons[i]); } - """ + """.} of nkCase: - asm """ + {.emit: """ `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ); for (var i = 0; i < `n`.sons.length; ++i) { nimCopyAux(`dest`, `src`, `n`.sons[i][1]); } - """ + """.} proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = case ti.kind @@ -549,9 +549,9 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = if not isFatPointer(ti): result = src else: - asm "`result` = [`src`[0], `src`[1]];" + {.emit: "`result` = [`src`[0], `src`[1]];".} of tySet: - asm """ + {.emit: """ if (`dest` === null || `dest` === undefined) { `dest` = {}; } @@ -560,18 +560,18 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = } for (var key in `src`) { `dest`[key] = `src`[key]; } `result` = `dest`; - """ + """.} of tyTuple, tyObject: if ti.base != nil: result = nimCopy(dest, src, ti.base) elif ti.kind == tyObject: - asm "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;" + {.emit: "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;".} else: - asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;" + {.emit: "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;".} nimCopyAux(result, src, ti.node) of tyArrayConstr, tyArray: # In order to prevent a type change (TypedArray -> Array) and to have better copying performance, # arrays constructors are considered separately - asm """ + {.emit: """ if(ArrayBuffer.isView(`src`)) { if(`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { `dest` = new `src`.constructor(`src`); @@ -593,9 +593,9 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = } } } - """ + """.} of tySequence, tyOpenArray: - asm """ + {.emit: """ if (`src` === null) { `result` = null; } @@ -608,55 +608,55 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base); } } - """ + """.} of tyString: - asm """ + {.emit: """ if (`src` !== null) { `result` = `src`.slice(0); } - """ + """.} else: result = src proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} = - asm "`result` = null;" + {.emit: "`result` = null;".} case ti.kind of tyPtr, tyRef, tyVar, tyNil: if isFatPointer(ti): - asm """ + {.emit: """ `result` = [null, 0]; - """ + """.} of tySet: - asm """ + {.emit: """ `result` = {}; - """ + """.} of tyTuple, tyObject: if ti.kind == tyObject: - asm "`result` = {m_type: `ti`};" + {.emit: "`result` = {m_type: `ti`};".} else: - asm "`result` = {};" + {.emit: "`result` = {};".} of tySequence, tyOpenArray, tyString: - asm """ + {.emit: """ `result` = []; - """ + """.} of tyArrayConstr, tyArray: - asm """ + {.emit: """ `result` = new Array(`x`.length); for (var i = 0; i < `x`.length; ++i) { `result`[i] = genericReset(`x`[i], `ti`.base); } - """ + """.} else: discard proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {. asmNoStackFrame, compilerproc.} = # types are fake - asm """ + {.emit: """ var result = new Array(`len`); for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`); return result; - """ + """.} proc chckIndx(i, a, b: int): int {.compilerproc.} = if i >= a and i <= b: return i @@ -685,7 +685,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = return true proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = - asm "`x`.push(`c`);" + {.emit: "`x`.push(`c`);".} {.pop.} @@ -712,9 +712,9 @@ proc parseFloatNative(a: openarray[char]): float = let cstr = cstring str - asm """ + {.emit: """ `result` = Number(`cstr`); - """ + """.} proc nimParseBiggestFloat(s: openarray[char], number: var BiggestFloat): int {.compilerproc.} = var sign: bool From c4f98b7696ce74c9952c973b0f09e59234f84917 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 3 Jan 2024 14:06:39 +0100 Subject: [PATCH 087/123] Recommend hanging indent in NEP1 (#23105) This PR modernises the NEP1 style guide to prefer hanging indent over vertial alignment for long code statements while still allowing alignment in legacy code. The change is based on research and study of existing style guides for both braced and indented languages that have seen wide adoption as well as working with a large Nim codebase with several teams touching the same code regularly. The research was done as part of due diligence leading up to [nph](https://github.com/arnetheduck/nph) which uses this style throughout. There are several reasons why hanging indent works well for collaboration, good code practices and modern Nim features: * as NEP1 itself points out, alignment causes unnecessary friction when refactoring, adding/removing items to lists and otherwise improving code style or due to the need for realignment - the new recommendation aligns NEP1 with itself * When collaborating, alignment leads to unnecessary git conflicts and blame changes - with hanging indent, such conflicts are minimised. * Vertical alignment pushes much of the code to the right where often there is little space - when using modern features such as generics where types may be composed of several (descriptively named) components, there is simply no more room for parameters or comments * The space to the left of the alignemnt cannot productively be used for anything (unlike on the right, where comments may be placed) * Double hanging indent maintaines visual separation between parameters / condition and the body that follows. This may seem like a drastic change, but in reality, it is not: * the most popular editor for Nim (vscode) already promotes this style by default (if you press enter after `(`, it will jump to an indent on the next line) * although orthogonal to these changes, tools such as `nph` can be used to reformat existing code should this be desired - when done in a single commit, `git blame` is not lost and neither are exsting PRs (they can simply be reformatted deterministically) - `nph` is also integrated with vscode. * It only affects long lines - ie most code remains unchanged Examples of vertical alignment in the wild, for wildly successful languages and formatters: * [PEP-8](https://peps.python.org/pep-0008/#indentation) * [black](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#how-black-wraps-lines) * [prettier](https://prettier.io/docs/en/) The above examples are useful mainly to show that hanging-indent _generally_ is no impediment to efficient code reading and on the whole is an uncontroversial choice as befits the standard library. --- doc/nep1.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/doc/nep1.md b/doc/nep1.md index 0c62e3f9c6062..3d2a0cef3ee93 100644 --- a/doc/nep1.md +++ b/doc/nep1.md @@ -256,36 +256,46 @@ Coding Conventions Conventions for multi-line statements and expressions ----------------------------------------------------- -- Tuples which are longer than one line should indent their parameters to - align with the parameters above it. +- Tuples which are longer than one line should indent their parameters. ```nim type - LongTupleA = tuple[wordyTupleMemberOne: int, wordyTupleMemberTwo: string, - wordyTupleMemberThree: float] + LongTupleA = tuple[ + wordyTupleMemberOne: int, wordyTupleMemberTwo: string, + wordyTupleMemberThree: float] ``` - Similarly, any procedure and procedure type declarations that are longer - than one line should do the same thing. + than one line should do the same thing. Double indent may be used to + distinguish them from the body that follows - this applies to all constructs + with a body (if, while, etc). ```nim type - EventCallback = proc (timeReceived: Time, errorCode: int, event: Event, - output: var string) - - proc lotsOfArguments(argOne: string, argTwo: int, argThree: float, - argFour: proc(), argFive: bool): int - {.heyLookALongPragma.} = + EventCallback = proc( + timeReceived: Time, errorCode: int, event: Event, + output: var string) + + proc lotsOfArguments( + argOne: string, argTwo: int, argThree: float, + argFour: proc(), argFive: bool, argSix: int + ): GenericType[int, string] {.heyLookALongPragma.} = + discard ``` -- Multi-line procedure calls should continue on the same column as the opening - parenthesis (like multi-line procedure declarations). +- Multi-line procedure calls should continue indented (like multi-line procedure + declarations). ```nim - startProcess(nimExecutable, currentDirectory, compilerArguments - environment, processOptions) + startProcess( + nimExecutable, currentDirectory, compilerArguments + environment, processOptions) ``` +Previous versions of this guide advocated vertical alignment along the opening +brace / parenthesis - both styles are permissible with a preference for the +current style in new code. + Miscellaneous ------------- From 4eaa3b028cd8963799a637c8a4f7f553386fe395 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 5 Jan 2024 15:17:08 +0800 Subject: [PATCH 088/123] fixes #23167; take `nkOpenSymChoice` into consideration caused by templates [backport] (#23168) fixes #23167 --- compiler/modulepaths.nim | 16 ++++++++++------ tests/import/t23167.nim | 5 +++++ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 tests/import/t23167.nim diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 73e0ef7849271..c9e6060e5eaf3 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -38,12 +38,16 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = localError(n.info, "only '/' supported with $package notation") result = "" else: - if n0.kind == nkIdent and n0.ident.s[0] == '/': - let modname = getModuleName(conf, n[2]) - # hacky way to implement 'x / y /../ z': - result = getModuleName(conf, n1) - result.add renderTree(n0, {renderNoComments}).replace(" ") - result.add modname + if n0.kind in nkIdentKinds: + let ident = n0.getPIdent + if ident != nil and ident.s[0] == '/': + let modname = getModuleName(conf, n[2]) + # hacky way to implement 'x / y /../ z': + result = getModuleName(conf, n1) + result.add renderTree(n0, {renderNoComments}).replace(" ") + result.add modname + else: + result = "" else: result = "" of nkPrefix: diff --git a/tests/import/t23167.nim b/tests/import/t23167.nim new file mode 100644 index 0000000000000..0891ee2afacb0 --- /dev/null +++ b/tests/import/t23167.nim @@ -0,0 +1,5 @@ +# bug #23167 +template sharedImport() = + import std / os + +sharedImport() From 74fa8ed59a15caa2ee91f9e559b37728618c3865 Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Fri, 5 Jan 2024 08:42:21 +0000 Subject: [PATCH 089/123] Changing generic weight of `tyGenericParam` (#22143) This is in reference to a [feature request](https://github.com/nim-lang/Nim/issues/22142) that I posted. I'm making this PR to demonstrate the suggested change and expect that this should be scrutinized --------- Co-authored-by: Bung Co-authored-by: Andreas Rumpf --- compiler/sigmatch.nim | 63 +++++++++-------- doc/manual.md | 38 ++++++++--- tests/concepts/t976.nim | 57 ++++++++++++++++ tests/concepts/tconcepts_issues.nim | 50 -------------- tests/macros/tgetimpl.nim | 2 - .../issue22142/tfail_implicit_ambiguous.nim | 10 +++ .../issue22142/tfail_nested_pointers.nim | 12 ++++ .../issue22142/tfail_object_is_generic.nim | 16 +++++ .../issue22142/tfail_typeclass_var_invar.nim | 9 +++ .../issue22142/tissue22142_shouldpass.nim | 68 +++++++++++++++++++ tests/overload/tor_isnt_better.nim | 1 - 11 files changed, 237 insertions(+), 89 deletions(-) create mode 100644 tests/concepts/t976.nim create mode 100644 tests/overload/issue22142/tfail_implicit_ambiguous.nim create mode 100644 tests/overload/issue22142/tfail_nested_pointers.nim create mode 100644 tests/overload/issue22142/tfail_object_is_generic.nim create mode 100644 tests/overload/issue22142/tfail_typeclass_var_invar.nim create mode 100644 tests/overload/issue22142/tissue22142_shouldpass.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2dfab4d17760b..afbff1b38b5f8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -213,8 +213,7 @@ proc sumGeneric(t: PType): int = inc result of tyBool, tyChar, tyEnum, tyObject, tyPointer, tyVoid, tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, - tyUInt..tyUInt64, tyCompositeTypeClass, tyBuiltInTypeClass, - tyGenericParam: + tyUInt..tyUInt64, tyCompositeTypeClass, tyBuiltInTypeClass: inc result break of tyGenericBody: @@ -233,6 +232,12 @@ proc sumGeneric(t: PType): int = t = t.elementType if t.kind == tyEmpty: break inc result + of tyGenericParam: + if t.len > 0: + t = t.skipModifier + else: + inc result + break of tyUntyped, tyTyped: break of tyGenericInvocation, tyTuple, tyAnd: result += ord(t.kind == tyAnd) @@ -451,37 +456,40 @@ proc handleFloatRange(f, a: PType): TTypeRelation = else: result = isIntConv else: result = isNone -proc getObjectType(f: PType): PType = +proc reduceToBase(f: PType): PType = #[ - Returns a type that is f's effective typeclass. This is usually just one level deeper - in the hierarchy of generality for a type. `object`, `ref object`, `enum` and user defined - tyObjects are common return values. + Returns the lowest order (most general) type that that is compatible with the input. + E.g. + A[T] = ptr object ... A -> ptr object + A[N: static[int]] = array[N, int] ... A -> array ]# case f.kind: + of tyGenericParam: + if f.len <= 0 or f.skipModifier == nil: + result = f + else: + result = reduceToBase(f.skipModifier) of tyGenericInvocation: - result = getObjectType(f.baseClass) + result = reduceToBase(f.baseClass) of tyCompositeTypeClass, tyAlias: if not f.hasElementType or f.elementType == nil: result = f else: - result = getObjectType(f.elementType) + result = reduceToBase(f.elementType) of tyGenericInst: - result = getObjectType(f.skipModifier) + result = reduceToBase(f.skipModifier) of tyGenericBody: - result = getObjectType(f.typeBodyImpl) - + result = reduceToBase(f.typeBodyImpl) of tyUserTypeClass: if f.isResolvedUserTypeClass: result = f.base # ?? idk if this is right else: result = f.skipModifier of tyStatic, tyOwned, tyVar, tyLent, tySink: - result = getObjectType(f.base) + result = reduceToBase(f.base) of tyInferred: # This is not true "After a candidate type is selected" - result = getObjectType(f.base) - of tyTyped, tyUntyped, tyFromExpr: - result = f + result = reduceToBase(f.base) of tyRange: result = f.elementType else: @@ -1244,7 +1252,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = typeRel(c, f.base, aOrig, flags + {trNoCovariance}) subtypeCheck() of tyArray: - a = getObjectType(a) + a = reduceToBase(a) case a.kind of tyArray: var fRange = f.indexType @@ -1370,7 +1378,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, let effectiveArgType = if useTypeLoweringRuleInTypeClass: a else: - getObjectType(a) + reduceToBase(a) if effectiveArgType.kind == tyObject: if sameObjectTypes(f, effectiveArgType): result = isEqual @@ -1400,7 +1408,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # set constructors are a bit special... result = isNone of tyPtr, tyRef: - a = getObjectType(a) + a = reduceToBase(a) if a.kind == f.kind: # ptr[R, T] can be passed to ptr[T], but not the other way round: if a.len < f.len: return isNone @@ -1691,7 +1699,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, considerPreviousT: let target = f.genericHead let targetKind = target.kind - var effectiveArgType = getObjectType(a) + var effectiveArgType = reduceToBase(a) effectiveArgType = effectiveArgType.skipTypes({tyBuiltInTypeClass}) if targetKind == effectiveArgType.kind: if effectiveArgType.isEmptyContainer: @@ -1785,7 +1793,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)' if f.len > 0 and f[0].kind != tyNone: let oldInheritancePenalty = c.inheritancePenalty - result = typeRel(c, f[0], a, flags + {trDontBind,trBindGenericParam}) + result = typeRel(c, f[0], a, flags + {trDontBind, trBindGenericParam}) if doBindGP and result notin {isNone, isGeneric}: let concrete = concreteType(c, a, f) if concrete == nil: return isNone @@ -1811,10 +1819,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, a.sym.transitionGenericParamToType() a.flags.excl tfWildcard elif doBind: - # The mechanics of `doBind` being a flag that also denotes sig cmp via - # negation is potentially problematic. `IsNone` is appropriate for - # preventing illegal bindings, but it is not necessarily appropriate - # before the bindings have been finalized. + # careful: `trDontDont` (set by `checkGeneric`) is not always respected in this call graph. + # typRel having two different modes (binding and non-binding) can make things harder to + # reason about and maintain. Refactoring typeRel to not be responsible for setting, or + # at least validating, bindings can have multiple benefits. This is debatable. I'm not 100% sure. + # A design that allows a proper complexity analysis of types like `tyOr` would be ideal. concrete = concreteType(c, a, f) if concrete == nil: return isNone @@ -2368,9 +2377,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, # roll back the side effects of the unification algorithm. let c = m.c var - x = newCandidate(c, m.callee) - y = newCandidate(c, m.callee) - z = newCandidate(c, m.callee) + x = newCandidate(c, m.callee) # potential "best" + y = newCandidate(c, m.callee) # potential competitor with x + z = newCandidate(c, m.callee) # buffer for copies of m x.calleeSym = m.calleeSym y.calleeSym = m.calleeSym z.calleeSym = m.calleeSym diff --git a/doc/manual.md b/doc/manual.md index 0e167be042024..f2c8edd1f282d 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2635,7 +2635,9 @@ of the argument. range. 3. Generic match: `f` is a generic type and `a` matches, for instance `a` is `int` and `f` is a generic (constrained) parameter - type (like in `[T]` or `[T: int|char]`). + type (like in `[T]` or `[T: int|char]`). Constraints given an alias (as in `T`) + shall be used to define `f`, when `f` is composed of `T`, following simple variable + substitution. 4. Subrange or subtype match: `a` is a `range[T]` and `T` matches `f` exactly. Or: `a` is a subtype of `f`. 5. Integral conversion match: `a` is convertible to `f` and `f` and `a` @@ -2647,9 +2649,8 @@ of the argument. There are two major methods of selecting the best matching candidate, namely counting and disambiguation. Counting takes precedence to disambiguation. In counting, each parameter is given a category and the number of parameters in each category is counted. -The categories are listed above and are in order of precedence. For example, if -a candidate with one exact match is compared to a candidate with multiple generic matches -and zero exact matches, the candidate with an exact match will win. +For example, if a candidate with one exact match is compared to a candidate with multiple +generic matches and zero exact matches, the candidate with an exact match will win. In the following, `count(p, m)` counts the number of matches of the matching category `m` for the routine `p`. @@ -2669,10 +2670,12 @@ algorithm returns true: return "ambiguous" ``` -When counting is ambiguous, disambiguation begins. Parameters are iterated -by position and these parameter pairs are compared for their type relation. The general goal -of this comparison is to determine which parameter is more specific. The types considered are -not of the inputs from the callsite, but of the competing candidates' parameters. +When counting is ambiguous, disambiguation begins. Disambiguation also has two stages, first a +hierarchical type relation comparison, and if that is inconclusive, a complexity comparison. +Where counting relates the type of the operand to the formal parameter, disambiguation relates the +formal parameters with each other to find the most competitive choice. +Parameters are iterated by position and these parameter pairs are compared for their type +relation. The general goal of this comparison is to determine which parameter is least general. Some examples: @@ -2692,7 +2695,6 @@ Some examples: ``` -If this algorithm returns "ambiguous" further disambiguation is performed: If the argument `a` matches both the parameter type `f` of `p` and `g` of `q` via a subtyping relation, the inheritance depth is taken into account: @@ -2734,6 +2736,23 @@ matches) is preferred: gen(ri) # "ref T" ``` +Type variables match +---------------------- + +When overload resolution is considering candidates, the type variable's definition +is not overlooked as it is used to define the formal parameter's type via variable substitution. + +For example: +```nim +type A +proc p[T: A](param: T) +proc p[T: object](param: T) +``` + +These signatures are not ambiguous for an instance of `A` even though the formal parameters match ("T" == "T"). +Instead `T` is treated as a variable in that (`T` ?= `T`) depending on the bound type of `T` at the time of +overload resolution. + Overloading based on 'var T' -------------------------------------- @@ -5424,6 +5443,7 @@ Generics are Nim's means to parametrize procs, iterators or types with `type parameters`:idx:. Depending on the context, the brackets are used either to introduce type parameters or to instantiate a generic proc, iterator, or type. + The following example shows how a generic binary tree can be modeled: ```nim test = "nim c $1" diff --git a/tests/concepts/t976.nim b/tests/concepts/t976.nim new file mode 100644 index 0000000000000..776d5382712ed --- /dev/null +++ b/tests/concepts/t976.nim @@ -0,0 +1,57 @@ +discard """ + output: ''' +Printable +''' +joinable: false +""" + +#[ + The converter is a proper example of a confounding variable + Moved to an isolated file +]# + +type + Obj1[T] = object + v: T +converter toObj1[T](t: T): Obj1[T] = + return Obj1[T](v: t) +block t976: + type + int1 = distinct int + int2 = distinct int + int1g = concept x + x is int1 + int2g = concept x + x is int2 + + proc take[T: int1g](value: int1) = + when T is int2: + static: error("killed in take(int1)") + + proc take[T: int2g](vale: int2) = + when T is int1: + static: error("killed in take(int2)") + + var i1: int1 = 1.int1 + var i2: int2 = 2.int2 + + take[int1](i1) + take[int2](i2) + + template reject(e) = + static: assert(not compiles(e)) + + reject take[string](i2) + reject take[int1](i2) + + # bug #6249 + type + Obj2 = ref object + PrintAble = concept x + $x is string + + proc `$`[T](nt: Obj1[T]): string = + when T is PrintAble: result = "Printable" + else: result = "Non Printable" + + echo Obj2() \ No newline at end of file diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index 83f3085c3990c..1d5e415dd2d55 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -1,7 +1,6 @@ discard """ output: ''' 20.0 USD -Printable true true true @@ -78,55 +77,6 @@ block t3414: let s2 = s1.find(10) - -type - Obj1[T] = object - v: T -converter toObj1[T](t: T): Obj1[T] = - return Obj1[T](v: t) -block t976: - type - int1 = distinct int - int2 = distinct int - int1g = concept x - x is int1 - int2g = concept x - x is int2 - - proc take[T: int1g](value: int1) = - when T is int2: - static: error("killed in take(int1)") - - proc take[T: int2g](vale: int2) = - when T is int1: - static: error("killed in take(int2)") - - var i1: int1 = 1.int1 - var i2: int2 = 2.int2 - - take[int1](i1) - take[int2](i2) - - template reject(e) = - static: assert(not compiles(e)) - - reject take[string](i2) - reject take[int1](i2) - - # bug #6249 - type - Obj2 = ref object - PrintAble = concept x - $x is string - - proc `$`[T](nt: Obj1[T]): string = - when T is PrintAble: result = "Printable" - else: result = "Non Printable" - - echo Obj2() - - - block t1128: type TFooContainer[T] = object diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index e215d26968497..ab33131b0d279 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -50,8 +50,6 @@ static: doAssert isSameOwner(poo, dummyproc) == false wrappedScope() -#--------------------------------------------------------------- - macro check_gen_proc(ex: typed): (bool, bool) = let lenChoice = bindsym"len" var is_equal = false diff --git a/tests/overload/issue22142/tfail_implicit_ambiguous.nim b/tests/overload/issue22142/tfail_implicit_ambiguous.nim new file mode 100644 index 0000000000000..2586e08777bd9 --- /dev/null +++ b/tests/overload/issue22142/tfail_implicit_ambiguous.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "ambiguous call" +""" +type + A[T] = object + C = object + +proc test[T: A](param: T): bool = false +proc test(param: A): bool = true +doAssert test(A[C]()) == true # previously would pass diff --git a/tests/overload/issue22142/tfail_nested_pointers.nim b/tests/overload/issue22142/tfail_nested_pointers.nim new file mode 100644 index 0000000000000..1603d98cbeb65 --- /dev/null +++ b/tests/overload/issue22142/tfail_nested_pointers.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "ambiguous call" +""" + +type + A[T] = object + C = object + x:int +proc p[T: A[ptr]](x:ptr[T]):bool = false +proc p(x: ptr[A[ptr]]):bool = true +var a: A[ptr[C]] +doAssert p(a.addr) == true diff --git a/tests/overload/issue22142/tfail_object_is_generic.nim b/tests/overload/issue22142/tfail_object_is_generic.nim new file mode 100644 index 0000000000000..b46795bd5396e --- /dev/null +++ b/tests/overload/issue22142/tfail_object_is_generic.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "ambiguous call" +""" + +#[ +As of the time of writing `object` needs some special +treament in order to be considered "generic" in the right +context when used implicitly +]# + +type + C = object + +proc test[T: object](param: T): bool = false +proc test(param: object): bool = true +doAssert test(C()) == true # previously would pass diff --git a/tests/overload/issue22142/tfail_typeclass_var_invar.nim b/tests/overload/issue22142/tfail_typeclass_var_invar.nim new file mode 100644 index 0000000000000..07db65fefdcb4 --- /dev/null +++ b/tests/overload/issue22142/tfail_typeclass_var_invar.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "ambiguous call" +""" + +type C = object +proc test[T: ptr](param: var T): bool = false +proc test(param: var ptr): bool = true +var d: ptr[C] +doAssert test(d) == true # previously would pass diff --git a/tests/overload/issue22142/tissue22142_shouldpass.nim b/tests/overload/issue22142/tissue22142_shouldpass.nim new file mode 100644 index 0000000000000..90d4efe51c59f --- /dev/null +++ b/tests/overload/issue22142/tissue22142_shouldpass.nim @@ -0,0 +1,68 @@ +type + A[T] = object of RootObj + B[T] = object + C = object + x:int + +# change (previously true) +block: + proc test[J;H: A[J];T: B[H]](param: T): bool = false + proc test[T](param: B[T]): bool = true + doAssert test(B[A[int]]()) == false +block: # object is more specific then `T` + proc p[H:object;T:ptr[H]](param:T):bool = false + proc p[T](param:ptr[T]):bool= true + var l: ptr[C] + doAssert p(l) == false +block: + proc p[T:A[object]](param:T):bool = false + proc p[T](param: A[T]):bool= true + doAssert p(A[C]()) == false +block: + proc test[H;T: A[H]](param: T): bool = false + proc test(param: A): bool = true + doAssert test(A[C]()) == false + +# change (previously ambiguous) +block: + proc p[T](a: A[T]): bool = false + proc p[T: object](a: T): bool = true + doAssert p(A[int]()) == false +block: # A is more specific than `object` + proc test[T: A](param: T): bool = false + proc test[T: object](param: T): bool = true + doAssert test(A[int]()) == false +block: + proc test[T: A](param: T): bool = false + proc test(param: object): bool = true + doAssert test(A[int]()) == false +block: + proc test[H;T: A[H]](param: T): bool = false + proc test(param: object): bool = true + doAssert test(A[C]()) == false +block: + proc test[H;T: A[B[H]]](param: T): bool = false + proc test[T: object](param: T): bool = true + doAssert test(A[B[int]]()) == false +block: + #[ + This was referenced in the nim compiler source (`sumGeneric`) as a case + that was supposed to not be ambiguous, yet it was + ]# + proc test[J;H:A[J]; T: A[H]](param: T): bool = false + proc test[H;T: A[H]](param: T): bool = true + doAssert test(A[A[C]]()) == false +block: + proc test[J;T:A[J]](param: A[T]): bool = false + proc test[T](param: A[T]): bool = true + doAssert test(A[A[C]]()) == false +block: + proc test[T](param: A[T]): bool = false + proc test[T: object](param: A[T]): bool = true + doAssert test(A[C]()) == true + + +block: #anti-regression (object is more specific then `T`) + proc test[J;T:A[J]](param: A[T]): bool = false + proc test(param: A[A[object]]): bool = true + doAssert test(A[A[C]]()) == true \ No newline at end of file diff --git a/tests/overload/tor_isnt_better.nim b/tests/overload/tor_isnt_better.nim index ce92009d03fb0..be1ad67bf68e3 100644 --- a/tests/overload/tor_isnt_better.nim +++ b/tests/overload/tor_isnt_better.nim @@ -7,7 +7,6 @@ block: # PR #22261 proc d(x: int | D[SomeInteger]):bool= true doAssert d(D[5]()) == false - block: # bug #8568 #[ Since PR #22261 and amendment has been made. Since D is a subset of D | E but From 3dee1a3e4c81448b67b75068fef06a121f320758 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 5 Jan 2024 18:07:27 +0800 Subject: [PATCH 090/123] fixes #23139; Cannot get repr of range type of enum (#23164) fixes #23139 --- lib/system/repr_v2.nim | 2 +- tests/metatype/tmetatype_various.nim | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index f81c615e91f63..a486cb224e830 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -99,7 +99,7 @@ proc repr*(p: proc | iterator {.closure.}): string = ## repr of a proc as its address repr(cast[ptr pointer](unsafeAddr p)[]) -template repr*[T: distinct|range](x: T): string = +template repr*[T: distinct|(range and not enum)](x: T): string = when T is range: # add a branch to handle range repr(rangeBase(typeof(x))(x)) elif T is distinct: diff --git a/tests/metatype/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim index 30169aa1e3b07..45c74432da3ee 100644 --- a/tests/metatype/tmetatype_various.nim +++ b/tests/metatype/tmetatype_various.nim @@ -66,3 +66,8 @@ var x: array[8, CTBool[Ct[uint32]]] x[0] = (CTBool[Ct[uint32]])(1) echo x.repr, " ", typeof(x[0]) +block: # bug #23139 + type Foo = enum a, b + + var x: range[a..b] + doAssert (repr x) == "a" From a4f3bf374238df96f0982b7106e3702da6b485b1 Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Sat, 6 Jan 2024 05:50:09 +0000 Subject: [PATCH 091/123] Fixes #23172 (#23173) #23172 --- compiler/sigmatch.nim | 2 +- tests/lookups/issue_23172/m23172.nim | 6 ++++++ tests/lookups/t23172.nim | 9 +++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/lookups/issue_23172/m23172.nim create mode 100644 tests/lookups/t23172.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index afbff1b38b5f8..8f383013090e7 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1710,7 +1710,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if tfExplicitCallConv in target.flags and target.callConv != effectiveArgType.callConv: return isNone - put(c, f, a) + if doBind: put(c, f, a) return isGeneric else: return isNone diff --git a/tests/lookups/issue_23172/m23172.nim b/tests/lookups/issue_23172/m23172.nim new file mode 100644 index 0000000000000..36af48761cb82 --- /dev/null +++ b/tests/lookups/issue_23172/m23172.nim @@ -0,0 +1,6 @@ +type + Foo* = object + Bar* = object + +func `$`*(x: Foo | Bar): string = + "X" diff --git a/tests/lookups/t23172.nim b/tests/lookups/t23172.nim new file mode 100644 index 0000000000000..9edf9905a4301 --- /dev/null +++ b/tests/lookups/t23172.nim @@ -0,0 +1,9 @@ +import issue_23172/m23172 + +type FooX = distinct Foo + +func `$`*(x: FooX): string = + $m23172.Foo(x) + +var a: FooX +doAssert $a == "X" From 62d8ca43063197272968b4acf8c7a1ef27874c54 Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 7 Jan 2024 09:48:32 +0300 Subject: [PATCH 092/123] don't transform typed bracket exprs to `[]` calls in templates (#23175) fixes #22775 It's pre-existing that [`prepareOperand` doesn't typecheck expressions which have types](https://github.com/nim-lang/Nim/blob/a4f3bf374238df96f0982b7106e3702da6b485b1/compiler/sigmatch.nim#L2444). Templates can take typed subscript expressions, transform them into calls to `[]`, and then have this `[]` not be resolved later if the expression is nested inside of a call argument, which leaks an untyped expression past semantic analysis. To prevent this, don't transform any typed subscript expressions into calls to `[]` in templates. Ditto for curly subscripts (with `{}`) and assignments to subscripts and curly subscripts (with `[]=` and `{}=`). --- compiler/semtempl.nim | 39 ++++++++++++++++++++++++-------------- tests/template/tnested.nim | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 tests/template/tnested.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index e572efdc0bec0..10440614d904b 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -507,14 +507,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = if x.kind == nkExprColonExpr: x[1] = semTemplBody(c, x[1]) of nkBracketExpr: - result = newNodeI(nkCall, n.info) - result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info) - for i in 0.. Date: Mon, 8 Jan 2024 10:23:24 +0300 Subject: [PATCH 094/123] Docs:strutils. Expand `multiReplace` docs, add runnableExamples (#23181) - Clarified the implications of order of operation. - Mentioned overlapping isn't handled - Added the runnableExamples block Fixes #23160, which supposedly should have been fixed in an earlier PR #23022, but the wording was still not clear enough to my liking, which the raised issue kind of confirms. --- lib/pure/strutils.nim | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 479acc0753de2..85ba802611502 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -2281,18 +2281,31 @@ func replaceWord*(s, sub: string, by = ""): string {.rtl, add result, substr(s, i) func multiReplace*(s: string, replacements: varargs[(string, string)]): string = - ## Same as replace, but specialized for doing multiple replacements in a single - ## pass through the input string. + ## Same as `replace<#replace,string,string,string>`_, but specialized for + ## doing multiple replacements in a single pass through the input string. ## - ## `multiReplace` performs all replacements in a single pass, this means it - ## can be used to swap the occurrences of "a" and "b", for instance. + ## `multiReplace` scans the input string from left to right and replaces the + ## matching substrings in the same order as passed in the argument list. + ## + ## The implications of the order of scanning the string and matching the + ## replacements: + ## - In case of multiple matches at a given position, the earliest + ## replacement is applied. + ## - Overlaps are not handled. After performing a replacement, the scan + ## continues from the character after the matched substring. If the + ## resulting string then contains a possible match starting in a newly + ## placed substring, the additional replacement is not performed. ## ## If the resulting string is not longer than the original input string, ## only a single memory allocation is required. ## - ## Replacements are done left to right in the string. If at a given position - ## multiple replacements match, earlier replacements are preferred over - ## later replacements in the argument list. + runnableExamples: + # Swapping occurrences of 'a' and 'b': + doAssert multireplace("abba", [("a", "b"), ("b", "a")]) == "baab" + + # The second replacement ("ab") is matched and performed first, the scan then + # continues from 'c', so the "bc" replacement is never matched and thus skipped. + doAssert multireplace("abc", [("bc", "x"), ("ab", "_b")]) == "_bc" result = newStringOfCap(s.len) var i = 0 var fastChk: set[char] = {} From e20a2b1f2bd2a55f16ed5d66f37bbb562c27f7cd Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Wed, 10 Jan 2024 01:37:41 +0900 Subject: [PATCH 095/123] Nim manual: better byref pragma explanation (#23192) Nim manual says: > When using the Cpp backend, params marked as byref will translate to cpp references `&` But how `byref` pragma translate to depends on whether it is used with `importc` or `importcpp`. When `byref` pragma used with `importc` types and compiled with the Cpp backend, it is not traslated to cpp reference `&`. --------- Co-authored-by: Andreas Rumpf --- doc/manual.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index f2c8edd1f282d..268d04f67245b 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -8573,8 +8573,62 @@ Byref pragma The `byref` pragma can be applied to an object or tuple type or a proc param. When applied to a type it instructs the compiler to pass the type by reference (hidden pointer) to procs. When applied to a param it will take precedence, even -if the the type was marked as `bycopy`. When using the Cpp backend, params marked -as byref will translate to cpp references `&`. +if the the type was marked as `bycopy`. When an `importc` type has a `byref` pragma or +parameters are marked as `byref` in an `importc` proc, these params translate to pointers. +When an `importcpp` type has a `byref` pragma, these params translate to +C++ references `&`. + + ```Nim + {.emit: """/*TYPESECTION*/ + typedef struct { + int x; + } CStruct; + """.} + + {.emit: """ + #ifdef __cplusplus + extern "C" + #endif + int takesCStruct(CStruct* x) { + return x->x; + } + """.} + + type + CStruct {.importc, byref.} = object + x: cint + + proc takesCStruct(x: CStruct): cint {.importc.} + ``` + + or + + + ```Nim + type + CStruct {.importc.} = object + x: cint + + proc takesCStruct(x {.byref.}: CStruct): cint {.importc.} + ``` + + ```Nim + {.emit: """/*TYPESECTION*/ + struct CppStruct { + int x; + + int takesCppStruct(CppStruct& y) { + return x + y.x; + } + }; + """.} + + type + CppStruct {.importcpp, byref.} = object + x: cint + + proc takesCppStruct(x, y: CppStruct): cint {.importcpp.} + ``` Varargs pragma -------------- From e8092a54704be254cd7ccb4f5ecfca7cb059fe5c Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 11 Jan 2024 09:45:11 +0300 Subject: [PATCH 096/123] delay resolved procvar check for proc params + acknowledge unresolved statics (#23188) fixes #23186 As explained in #23186, generics can transform `genericProc[int]` into a call `` `[]`(genericProc, int) `` which causes a problem when `genericProc` is resemmed, since it is not a resolved generic proc. `[]` needs unresolved generic procs since `mArrGet` also handles explicit generic instantiations, so delay the resolved generic proc check to `semFinishOperands` which is intentionally not called for `mArrGet`. The root issue for [t6137](https://github.com/nim-lang/Nim/blob/devel/tests/generics/t6137.nim) is also fixed (because this change breaks it otherwise), the compiler doesn't consider the possibility that an assigned generic param can be an unresolved static value (note the line `if t.kind == tyStatic: s.ast = t.n` below the change in sigmatch), now it properly errors that it couldn't instantiate it as it would for a type param. ~~The change in semtypinst is just for symmetry with the code above it which also gives a `cannot instantiate` error, it may or may not be necessary/correct.~~ Now removed, I don't think it was correct. Still possible that this has unintended consequences. --- compiler/semexprs.nim | 35 +++-- compiler/seminst.nim | 9 ++ compiler/sigmatch.nim | 6 - tests/errmsgs/t5167_5.nim | 4 +- tests/generics/t23186.nim | 155 ++++++++++++++++++++++ tests/generics/t6137.nim | 4 +- tests/generics/timplicit_and_explicit.nim | 3 +- tests/misc/t8545.nim | 3 +- 8 files changed, 196 insertions(+), 23 deletions(-) create mode 100644 tests/generics/t23186.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 009458089b8dd..70206c6f99e07 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -54,17 +54,6 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # same as 'semExprWithType' but doesn't check for proc vars result = semExpr(c, n, flags + {efOperand, efAllowSymChoice}) if result.typ != nil: - # XXX tyGenericInst here? - if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}): - #and tfUnresolved in result.typ.flags: - let owner = result.typ.owner - let err = - # consistent error message with evaltempl/semMacroExpr - if owner != nil and owner.kind in {skTemplate, skMacro}: - errMissingGenericParamsForTemplate % n.renderTree - else: - errProcHasNoConcreteType % n.renderTree - localError(c.config, n.info, err) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) @@ -1013,6 +1002,30 @@ proc bracketedMacro(n: PNode): PSym = else: result = nil +proc finishOperand(c: PContext, a: PNode): PNode = + if a.typ.isNil: + result = c.semOperand(c, a, {efDetermineType}) + else: + result = a + # XXX tyGenericInst here? + if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}): + #and tfUnresolved in result.typ.flags: + let owner = result.typ.owner + let err = + # consistent error message with evaltempl/semMacroExpr + if owner != nil and owner.kind in {skTemplate, skMacro}: + errMissingGenericParamsForTemplate % a.renderTree + else: + errProcHasNoConcreteType % a.renderTree + localError(c.config, a.info, err) + considerGenSyms(c, result) + +proc semFinishOperands(c: PContext; n: PNode) = + # this needs to be called to ensure that after overloading resolution every + # argument has been sem'checked: + for i in 1..]# let y = m #[tt.Error ^ 'm' has unspecified generic parameters]# bar m #[tt.Error - ^ 'm' has unspecified generic parameters]# +^ type mismatch: got ]# diff --git a/tests/generics/t23186.nim b/tests/generics/t23186.nim new file mode 100644 index 0000000000000..76f38da6be3fd --- /dev/null +++ b/tests/generics/t23186.nim @@ -0,0 +1,155 @@ +# issue #23186 + +block: # simplified + template typedTempl(x: int, body): untyped = + body + proc generic1[T]() = + discard + proc generic2[T]() = + typedTempl(1): + let x = generic1[T] + generic2[int]() + +import std/macros + +when not compiles(len((1, 2))): + import std/typetraits + + func len(x: tuple): int = + arity(type(x)) + +block: # full issue example + type FieldDescription = object + name: NimNode + func isTuple(t: NimNode): bool = + t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple") + proc collectFieldsFromRecList(result: var seq[FieldDescription], + n: NimNode, + parentCaseField: NimNode = nil, + parentCaseBranch: NimNode = nil, + isDiscriminator = false) = + case n.kind + of nnkRecList: + for entry in n: + collectFieldsFromRecList result, entry, + parentCaseField, parentCaseBranch + of nnkIdentDefs: + for i in 0 ..< n.len - 2: + var field: FieldDescription + field.name = n[i] + if field.name.kind == nnkPragmaExpr: + field.name = field.name[0] + if field.name.kind == nnkPostfix: + field.name = field.name[1] + result.add field + of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty: + discard + else: + doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr + proc collectFieldsInHierarchy(result: var seq[FieldDescription], + objectType: NimNode) = + var objectType = objectType + if objectType.kind == nnkRefTy: + objectType = objectType[0] + let recList = objectType[2] + collectFieldsFromRecList result, recList + proc recordFields(typeImpl: NimNode): seq[FieldDescription] = + let objectType = case typeImpl.kind + of nnkObjectTy: typeImpl + of nnkTypeDef: typeImpl[2] + else: + macros.error("object type expected", typeImpl) + return + collectFieldsInHierarchy(result, objectType) + proc skipPragma(n: NimNode): NimNode = + if n.kind == nnkPragmaExpr: n[0] + else: n + func declval(T: type): T = + doAssert false, + "declval should be used only in `typeof` expressions and concepts" + default(ptr T)[] + macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = + var typeAst = getType(T)[1] + var typeImpl: NimNode + let isSymbol = not typeAst.isTuple + if not isSymbol: + typeImpl = typeAst + else: + typeImpl = getImpl(typeAst) + result = newStmtList() + var i = 0 + for field in recordFields(typeImpl): + let + fieldIdent = field.name + realFieldName = newLit($fieldIdent.skipPragma) + fieldName = realFieldName + fieldIndex = newLit(i) + let fieldNameDefs = + if isSymbol: + quote: + const fieldName {.inject, used.} = `fieldName` + const realFieldName {.inject, used.} = `realFieldName` + else: + quote: + const fieldName {.inject, used.} = $`fieldIndex` + const realFieldName {.inject, used.} = $`fieldIndex` + # we can't access .Fieldn, so our helper knows + # to parseInt this + let field = + if isSymbol: + quote do: declval(`T`).`fieldIdent` + else: + quote do: declval(`T`)[`fieldIndex`] + result.add quote do: + block: + `fieldNameDefs` + type FieldType {.inject, used.} = type(`field`) + `body` + i += 1 + template enumAllSerializedFields(T: type, body): untyped = + when T is ref|ptr: + type TT = type(default(T)[]) + enumAllSerializedFieldsImpl(TT, body) + else: + enumAllSerializedFieldsImpl(T, body) + type + MemRange = object + startAddr: ptr byte + length: int + SszNavigator[T] = object + m: MemRange + func sszMount(data: openArray[byte], T: type): SszNavigator[T] = + let startAddr = unsafeAddr data[0] + SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) + func sszMount(data: openArray[char], T: type): SszNavigator[T] = + let startAddr = cast[ptr byte](unsafeAddr data[0]) + SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) + template sszMount(data: MemRange, T: type): SszNavigator[T] = + SszNavigator[T](m: data) + func navigateToField[T]( + n: SszNavigator[T], + FieldType: type): SszNavigator[FieldType] = + default(SszNavigator[FieldType]) + type + FieldInfo = ref object + navigator: proc (m: MemRange): MemRange {. + gcsafe, noSideEffect, raises: [IOError] .} + func fieldNavigatorImpl[RecordType; FieldType; fieldName: static string]( + m: MemRange): MemRange = + var typedNavigator = sszMount(m, RecordType) + discard navigateToField(typedNavigator, FieldType) + default(MemRange) + func genTypeInfo(T: type) = + when T is object: + enumAllSerializedFields(T): + discard FieldInfo(navigator: fieldNavigatorImpl[T, FieldType, fieldName]) + type + Foo = object + bar: Bar + BarList = seq[uint64] + Bar = object + b: BarList + baz: Baz + Baz = object + i: uint64 + genTypeInfo(Foo) diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim index 991f39dd157f1..fb7db22f81dab 100644 --- a/tests/generics/t6137.nim +++ b/tests/generics/t6137.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "\'vectFunc\' doesn't have a concrete type, due to unspecified generic parameters." - line: 28 + errormsg: "cannot instantiate: 'T'" + line: 19 """ type diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim index fe61004e4cb4f..ad0d1e88f3f8a 100644 --- a/tests/generics/timplicit_and_explicit.nim +++ b/tests/generics/timplicit_and_explicit.nim @@ -34,7 +34,8 @@ block: #15622 proc test1[T](a: T, b: static[string] = "") = discard test1[int64](123) proc test2[T](a: T, b: static[string] = "") = discard - test2[int64, static[string]](123) + doAssert not (compiles do: + test2[int64, static[string]](123)) block: #4688 proc convertTo[T](v: int or float): T = (T)(v) diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim index 89957e1d31a99..48b886cb89a47 100644 --- a/tests/misc/t8545.nim +++ b/tests/misc/t8545.nim @@ -1,5 +1,6 @@ discard """ - targets: "c cpp js" + # just tests that this doesn't crash the compiler + errormsg: "cannot instantiate: 'a:type'" """ # bug #8545 From 62c5b8b2873caac3e56d15738f503e953840e6ca Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 Jan 2024 14:47:33 +0800 Subject: [PATCH 097/123] fixes #23129; fixes generated hooks raise unlisted Exception, which never raise (#23195) fixes #23129 --- compiler/liftdestructors.nim | 7 ++++++- tests/effects/thooks.nim | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/effects/thooks.nim diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index a3ca88dd50e8b..1180c29119c1f 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -1179,7 +1179,12 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; # bug #19205: Do not forget to also copy the hidden type field: genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src) - if not a.canRaise: incl result.flags, sfNeverRaises + if not a.canRaise: + incl result.flags, sfNeverRaises + result.ast[pragmasPos] = newNodeI(nkPragma, info) + result.ast[pragmasPos].add newTree(nkExprColonExpr, + newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info)) + completePartialOp(g, idgen.module, typ, kind, result) diff --git a/tests/effects/thooks.nim b/tests/effects/thooks.nim new file mode 100644 index 0000000000000..23cc005cd155f --- /dev/null +++ b/tests/effects/thooks.nim @@ -0,0 +1,16 @@ +discard """ + matrix: "--warningAsError:Effect" +""" + +import std/isolation + +# bug #23129 +type + Thing = object + x: string + +proc send(x: string) = + let wrapper = Thing(x: x) + discard isolate(wrapper) + +send("la") \ No newline at end of file From 29ac3c9986de5731a32beaf015e81a18dd6bd498 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 Jan 2024 18:23:42 +0800 Subject: [PATCH 098/123] fixes #22923; fixes `=dup` issues (#23182) fixes #22923 --- compiler/ccgexprs.nim | 2 ++ compiler/liftdestructors.nim | 10 +++++++++- compiler/semmagic.nim | 10 ++++++++++ lib/system.nim | 3 ++- tests/arc/tarcmisc.nim | 26 ++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 8cb9e208a488c..17e0da57558bc 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2587,6 +2587,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mTrace: discard "no code to generate" of mEnsureMove: expr(p, e[1], d) + of mDup: + expr(p, e[1], d) else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 1180c29119c1f..aba1aa38c7020 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -288,7 +288,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode = proc getCycleParam(c: TLiftCtx): PNode = assert c.kind in {attachedAsgn, attachedDup} - if c.fn.typ.signatureLen == 4: + if c.fn.typ.len == 3 + ord(c.kind == attachedAsgn): result = c.fn.typ.n.lastSon assert result.kind == nkSym assert result.sym.name.s == "cyclic" @@ -323,6 +323,14 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = if sfNeverRaises notin op.flags: c.canRaise = true + if c.kind == attachedDup and op.typ.len == 3: + assert x != nil + if c.fn.typ.len == 3: + result.add getCycleParam(c) + else: + # assume the worst: A cycle is created: + result.add boolLit(c.g, x.info, true) + proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result = newAsgnStmt(x, newOpCall(c, op, y)) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index c36a9ede1825e..d1cd4d5daa358 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -635,6 +635,16 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, let op = getAttachedOp(c.graph, t, attachedTrace) if op != nil: result[0] = newSymNode(op) + of mDup: + result = n + let t = n[1].typ.skipTypes(abstractVar) + let op = getAttachedOp(c.graph, t, attachedDup) + if op != nil: + result[0] = newSymNode(op) + if op.typ.len == 3: + let boolLit = newIntLit(c.graph, n.info, 1) + boolLit.typ = getSysType(c.graph, n.info, tyBool) + result.add boolLit of mWasMoved: result = n let t = n[1].typ.skipTypes(abstractVar) diff --git a/lib/system.nim b/lib/system.nim index 9ca9da3027f30..1d08c70b4e16d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2926,4 +2926,5 @@ proc arrayWith*[T](y: T, size: static int): array[size, T] {.raises: [].} = when nimvm: result[i] = y else: - result[i] = `=dup`(y) + {.cast(raises: []).}: # TODO: fixme bug #23129 + result[i] = `=dup`(y) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 3b60fcd020232..d02db545a16e5 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -688,3 +688,29 @@ block: # bug #22259 f(wrapper) main() + +block: + block: # bug #22923 + block: + let + a: int = 100 + b: int32 = 200'i32 + + let + x = arrayWith(a, 8) # compiles + y = arrayWith(b, 8) # internal error + z = arrayWith(14, 8) # integer literal also results in a crash + + doAssert x == [100, 100, 100, 100, 100, 100, 100, 100] + doAssert $y == "[200, 200, 200, 200, 200, 200, 200, 200]" + doAssert z == [14, 14, 14, 14, 14, 14, 14, 14] + + block: + let a: string = "nim" + doAssert arrayWith(a, 3) == ["nim", "nim", "nim"] + + let b: char = 'c' + doAssert arrayWith(b, 3) == ['c', 'c', 'c'] + + let c: uint = 300'u + doAssert $arrayWith(c, 3) == "[300, 300, 300]" From 6650b417779d61a895da23d24ab32ee1388216c2 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 11 Jan 2024 14:39:51 +0300 Subject: [PATCH 099/123] document the new ambiguous identifier resolution (#23166) refs #23123 Not sure if detailed enough. --- doc/manual.md | 30 ++++++++++++++++++++++++++---- tests/lookups/mambsym3.nim | 4 ++++ tests/lookups/mambsym4.nim | 4 ++++ tests/lookups/tambsymmanual.nim | 25 +++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 tests/lookups/mambsym3.nim create mode 100644 tests/lookups/mambsym4.nim create mode 100644 tests/lookups/tambsymmanual.nim diff --git a/doc/manual.md b/doc/manual.md index 268d04f67245b..9ffd9b2cd9aa0 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -6976,25 +6976,47 @@ All identifiers of a module are valid from the point of declaration until the end of the module. Identifiers from indirectly dependent modules are *not* available. The `system`:idx: module is automatically imported in every module. -If a module imports an identifier by two different modules, each occurrence of -the identifier has to be qualified unless it is an overloaded procedure or -iterator in which case the overloading resolution takes place: +If a module imports the same identifier from two different modules, the +identifier is considered ambiguous, which can be resolved in the following ways: + +* Qualifying the identifier as `module.identifier` resolves ambiguity + between modules. (See below for the case that the module name itself + is ambiguous.) +* Calling the identifier as a routine makes overload resolution take place, + which resolves ambiguity in the case that one overload matches stronger + than the others. +* Using the identifier in a context where the compiler can infer the type + of the identifier resolves ambiguity in the case that one definition + matches the type stronger than the others. ```nim # Module A var x*: string + proc foo*(a: string) = + echo "A: ", a ``` ```nim # Module B var x*: int + proc foo*(b: int) = + echo "B: ", b ``` ```nim # Module C import A, B + + foo("abc") # A: abc + foo(123) # B: 123 + let inferred: proc (x: string) = foo + foo("def") # A: def + write(stdout, x) # error: x is ambiguous write(stdout, A.x) # no error: qualifier used + + proc bar(a: int): int = a + 1 + assert bar(x) == x + 1 # no error: only A.x of type int matches var x = 4 write(stdout, x) # not ambiguous: uses the module C's x @@ -7018,7 +7040,7 @@ proc fb* = echo "buzz" import A/C import B/C -C.fb() # Error: ambiguous identifier: 'fb' +C.fb() # Error: ambiguous identifier: 'C' ``` diff --git a/tests/lookups/mambsym3.nim b/tests/lookups/mambsym3.nim new file mode 100644 index 0000000000000..946a5ff294960 --- /dev/null +++ b/tests/lookups/mambsym3.nim @@ -0,0 +1,4 @@ +# Module A +var x*: string +proc foo*(a: string) = + echo "A: ", a diff --git a/tests/lookups/mambsym4.nim b/tests/lookups/mambsym4.nim new file mode 100644 index 0000000000000..ed66cc16d9d1f --- /dev/null +++ b/tests/lookups/mambsym4.nim @@ -0,0 +1,4 @@ +# Module B +var x*: int +proc foo*(b: int) = + echo "B: ", b diff --git a/tests/lookups/tambsymmanual.nim b/tests/lookups/tambsymmanual.nim new file mode 100644 index 0000000000000..3ad91b8cc721d --- /dev/null +++ b/tests/lookups/tambsymmanual.nim @@ -0,0 +1,25 @@ +discard """ + output: ''' +A: abc +B: 123 +A: def +4 +''' +""" +# Module C +import mambsym3, mambsym4 + +foo("abc") # A: abc +foo(123) # B: 123 +let inferred: proc (x: string) = foo +foo("def") # A: def + +doAssert not compiles(write(stdout, x)) # error: x is ambiguous +write(stdout, mambsym3.x) # no error: qualifier used + +proc bar(a: int): int = a + 1 +doAssert bar(x) == x + 1 # no error: only A.x of type int matches + +var x = 4 +write(stdout, x) # not ambiguous: uses the module C's x +echo() # for test output From 30cb6826c01d880b852b56e0d0d69e79a2105115 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 Jan 2024 22:38:23 +0800 Subject: [PATCH 100/123] patches for #23129 (#23198) fixes it in the normal situation --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 1d08c70b4e16d..38e3728974064 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -376,7 +376,7 @@ else: discard when defined(nimAllowNonVarDestructor) and arcLikeMem: - proc `=destroy`*(x: string) {.inline, magic: "Destroy".} = + proc `=destroy`*(x: string) {.inline, magic: "Destroy", enforceNoRaises.} = discard proc `=destroy`*[T](x: seq[T]) {.inline, magic: "Destroy".} = From ade5295fd56f632fc6fbdcfef42b1bb827574be6 Mon Sep 17 00:00:00 2001 From: Ethosa <49402667+Ethosa@users.noreply.github.com> Date: Fri, 12 Jan 2024 19:50:20 +0700 Subject: [PATCH 101/123] fix link to `jsfetch` stdlib (#23203) --- doc/lib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lib.md b/doc/lib.md index a76b29151f54f..1507bbaac7a44 100644 --- a/doc/lib.md +++ b/doc/lib.md @@ -578,7 +578,7 @@ Modules for the JavaScript backend The wrapper of core JavaScript functions. For most purposes, you should be using the `math`, `json`, and `times` stdlib modules instead of this module. -* [jsfetch](jshttp.html) +* [jsfetch](jsfetch.html) Wrapper for `fetch`. * [jsffi](jsffi.html) From 8484abc2e498bd9738097c06362d442c615a8264 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:00:55 +0800 Subject: [PATCH 102/123] fixes #15924; Tuple destructuring is broken with closure iterators (#23205) fixes #15924 --- compiler/lambdalifting.nim | 13 ++++++++----- tests/iter/titer.nim | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 38fdf5b92c80e..4db7471f14f84 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -994,12 +994,15 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): # gather vars in a tuple: var v2 = newNodeI(nkLetSection, body.info) var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info) - for i in 0.. Date: Sat, 13 Jan 2024 21:09:34 +0800 Subject: [PATCH 103/123] fixes #23180; fixes #19805; prohibits invalid tuple unpacking code in for loop (#23185) fixes #23180 fixes #19805 --- compiler/semstmts.nim | 5 ++++- tests/errmsgs/t17460.nim | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5a0968ba55cb5..d62ad8305be27 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -930,7 +930,10 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if iterAfterVarLent.kind != tyTuple or n.len == 3: if n.len == 3: if n[0].kind == nkVarTuple: - if n[0].len-1 != iterAfterVarLent.len: + if iterAfterVarLent.kind != tyTuple: + return localErrorNode(c, n, n[0].info, errTupleUnpackingTupleExpected % + [typeToString(n[1].typ, preferDesc)]) + elif n[0].len-1 != iterAfterVarLent.len: return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables) for i in 0.. Date: Mon, 15 Jan 2024 17:06:43 +0800 Subject: [PATCH 104/123] remove unnecessary workaround from `arrayWith` (#23208) The problem was fixed by https://github.com/nim-lang/Nim/pull/23195 --- lib/system.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 38e3728974064..0602d8fa42714 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2926,5 +2926,4 @@ proc arrayWith*[T](y: T, size: static int): array[size, T] {.raises: [].} = when nimvm: result[i] = y else: - {.cast(raises: []).}: # TODO: fixme bug #23129 - result[i] = `=dup`(y) + result[i] = `=dup`(y) From 18b5fb256d4647efa6a64df451d37129d36e96f3 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Mon, 15 Jan 2024 19:36:03 +0200 Subject: [PATCH 105/123] + show the inferred exception list (as part of the type) for functions that don't have an explicit `.raises` pragma (#23193) --- compiler/suggest.nim | 2 +- compiler/types.nim | 22 ++++++++++++++++++--- nimsuggest/tests/tdef1.nim | 6 +++--- nimsuggest/tests/tdot4.nim | 2 +- nimsuggest/tests/tinclude.nim | 2 +- nimsuggest/tests/tsug_pragmas.nim | 10 +++++----- nimsuggest/tests/tsug_template.nim | 2 +- nimsuggest/tests/tuse.nim | 8 ++++---- nimsuggest/tests/tv3.nim | 2 +- nimsuggest/tests/tv3_forward_definition.nim | 18 ++++++++--------- nimsuggest/tests/tv3_globalSymbols.nim | 8 ++++---- nimsuggest/tests/tv3_outline.nim | 14 ++++++------- nimsuggest/tests/twithin_macro.nim | 4 ++-- nimsuggest/tests/twithin_macro_prefix.nim | 2 +- 14 files changed, 59 insertions(+), 43 deletions(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 5eb2c03ab62db..720418466e4cb 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -172,7 +172,7 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info if section == ideInlayHints: result.forth = typeToString(s.typ, preferInlayHint) else: - result.forth = typeToString(s.typ) + result.forth = typeToString(s.typ, preferInferredEffects) else: result.forth = "" when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): diff --git a/compiler/types.nim b/compiler/types.nim index 04f953f79d1cb..8c447ddbfbae2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -31,6 +31,7 @@ type # most useful, shows: symbol + resolved symbols if it differs, e.g.: # tuple[a: MyInt{int}, b: float] preferInlayHint, + preferInferredEffects, TTypeRelation* = enum # order is important! isNone, isConvertible, @@ -477,7 +478,7 @@ const "void", "iterable"] const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo, - preferGenericArg, preferResolved, preferMixed, preferInlayHint} + preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects} template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) = tc.add concrete @@ -530,7 +531,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = t.sym.name.s if prefer == preferMixed and result != t.sym.name.s: result = t.sym.name.s & "{" & result & "}" - elif prefer in {preferName, preferTypeName, preferInlayHint} or t.sym.owner.isNil: + elif prefer in {preferName, preferTypeName, preferInlayHint, preferInferredEffects} or t.sym.owner.isNil: # note: should probably be: {preferName, preferTypeName, preferGenericArg} result = t.sym.name.s if t.kind == tyGenericParam and t.genericParamHasConstraints: @@ -723,6 +724,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(')') if t.returnType != nil: result.add(": " & typeToString(t.returnType)) var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv + var hasImplicitRaises = false if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos: let pragmasNode = t.owner.ast[pragmasPos] let raisesSpec = effectSpec(pragmasNode, wRaises) @@ -730,13 +732,27 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = addSep(prag) prag.add("raises: ") prag.add($raisesSpec) - + hasImplicitRaises = true if tfNoSideEffect in t.flags: addSep(prag) prag.add("noSideEffect") if tfThread in t.flags: addSep(prag) prag.add("gcsafe") + if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0): + let effects = t.owner.typ.n[0] + if effects.kind == nkEffectList and effects.len == effectListLen: + var inferredRaisesStr = "" + let effs = effects[exceptionEffects] + if not isNil(effs): + for eff in items(effs): + if not isNil(eff): + addSep(inferredRaisesStr) + inferredRaisesStr.add($eff.typ) + addSep(prag) + prag.add("raises: [") + prag.add(inferredRaisesStr) + prag.add("]") if prag.len != 0: result.add("{." & prag & ".}") of tyVarargs: result = typeToStr[t.kind] % typeToString(t.elementType) diff --git a/nimsuggest/tests/tdef1.nim b/nimsuggest/tests/tdef1.nim index 46d7c0b5d716e..49265bbc13857 100644 --- a/nimsuggest/tests/tdef1.nim +++ b/nimsuggest/tests/tdef1.nim @@ -1,11 +1,11 @@ discard """ $nimsuggest --tester $file >def $1 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;11;;5;;"Return hello";;100 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, raises: [].};;$file;;11;;5;;"Return hello";;100 >def $2 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;11;;5;;"Return hello";;100 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, raises: [].};;$file;;11;;5;;"Return hello";;100 >def $2 -def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;11;;5;;"Return hello";;100 +def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, raises: [].};;$file;;11;;5;;"Return hello";;100 """ proc hel#[!]#lo(): string = diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim index 8681d045add70..f2c6c765f5919 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -15,7 +15,7 @@ discard """ $nimsuggest --tester --maxresults:2 $file >sug $1 sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;6;;5;;"";;100;;None -sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe.};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None +sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, raises: [].};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None """ # TODO - determine appropriate behaviour for further suggest output and test it diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 66726f907ef21..f5cbabf053445 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -11,7 +11,7 @@ go() discard """ $nimsuggest --tester $file >def $path/tinclude.nim:7:14 -def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe.};;*fixtures/minclude_include.nim;;3;;5;;"";;100 +def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, raises: [].};;*fixtures/minclude_include.nim;;3;;5;;"";;100 >def $path/fixtures/minclude_include.nim:3:71 def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100 >def $path/fixtures/minclude_include.nim:3:71 diff --git a/nimsuggest/tests/tsug_pragmas.nim b/nimsuggest/tests/tsug_pragmas.nim index 03a9cba4c67f3..ce9c4e8f8dca4 100644 --- a/nimsuggest/tests/tsug_pragmas.nim +++ b/nimsuggest/tests/tsug_pragmas.nim @@ -18,23 +18,23 @@ $nimsuggest --tester $file >sug $1 sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix -sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe, raises: [].};;$file;;3;;6;;"";;50;;Prefix >sug $2 sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix -sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe, raises: [].};;$file;;3;;6;;"";;50;;Prefix >sug $3 sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix -sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe, raises: [].};;$file;;3;;6;;"";;50;;Prefix >sug $4 sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix -sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe, raises: [].};;$file;;3;;6;;"";;50;;Prefix >sug $5 sug;;skTemplate;;fooBar4;;;;$file;;4;;8;;"";;100;;Prefix sug;;skTemplate;;tsug_pragmas.fooBar1;;template ();;$file;;1;;9;;"";;100;;Prefix -sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe.};;$file;;3;;6;;"";;50;;Prefix +sug;;skMacro;;tsug_pragmas.fooBar3;;macro (x: untyped){.noSideEffect, gcsafe, raises: [].};;$file;;3;;6;;"";;50;;Prefix """ diff --git a/nimsuggest/tests/tsug_template.nim b/nimsuggest/tests/tsug_template.nim index a2558c81c7331..da494d279d896 100644 --- a/nimsuggest/tests/tsug_template.nim +++ b/nimsuggest/tests/tsug_template.nim @@ -6,7 +6,7 @@ tmp#[!]# discard """ $nimsuggest --tester $file >sug $1 -sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe.};;$file;;2;;6;;"";;100;;Prefix +sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, raises: [].};;$file;;2;;6;;"";;100;;Prefix sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;100;;Prefix sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;100;;Prefix """ diff --git a/nimsuggest/tests/tuse.nim b/nimsuggest/tests/tuse.nim index deaf81ef2ec68..7c1d1ad0c800f 100644 --- a/nimsuggest/tests/tuse.nim +++ b/nimsuggest/tests/tuse.nim @@ -14,9 +14,9 @@ proc #[!]#someProc*() = discard """ $nimsuggest --tester $file >use $1 -def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;9;;5;;"";;100 -use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;12;;0;;"";;100 +def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, raises: [].};;$file;;9;;5;;"";;100 +use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, raises: [].};;$file;;12;;0;;"";;100 >use $2 -def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;9;;5;;"";;100 -use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;12;;0;;"";;100 +def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, raises: [].};;$file;;9;;5;;"";;100 +use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, raises: [].};;$file;;12;;0;;"";;100 """ diff --git a/nimsuggest/tests/tv3.nim b/nimsuggest/tests/tv3.nim index fd736a1d8cc80..80e51e3644918 100644 --- a/nimsuggest/tests/tv3.nim +++ b/nimsuggest/tests/tv3.nim @@ -19,7 +19,7 @@ def skField tv3.Foo.bar string $file 5 4 "" 100 >sug $1 sug skField bar string $file 5 4 "" 100 Prefix >globalSymbols test -def skProc tv3.test proc (f: Foo){.gcsafe.} $file 7 5 "" 100 +def skProc tv3.test proc (f: Foo){.gcsafe, raises: [].} $file 7 5 "" 100 >globalSymbols Foo def skType tv3.Foo Foo $file 4 2 "" 100 >def $2 diff --git a/nimsuggest/tests/tv3_forward_definition.nim b/nimsuggest/tests/tv3_forward_definition.nim index 392e019ff910e..7a16ea331c249 100644 --- a/nimsuggest/tests/tv3_forward_definition.nim +++ b/nimsuggest/tests/tv3_forward_definition.nim @@ -7,17 +7,17 @@ let a = de#[!]#mo() discard """ $nimsuggest --v3 --tester $file >use $1 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 -def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 5 8 "" 100 +use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 1 5 "" 100 +def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 3 5 "" 100 +use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 5 8 "" 100 >use $2 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 -def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 -use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 5 8 "" 100 +use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 1 5 "" 100 +def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 3 5 "" 100 +use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 5 8 "" 100 >declaration $1 -declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 +declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 3 5 "" 100 >declaration $2 -declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 +declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 1 5 "" 100 >declaration $3 -declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe.} $file 1 5 "" 100 +declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, raises: [].} $file 1 5 "" 100 """ diff --git a/nimsuggest/tests/tv3_globalSymbols.nim b/nimsuggest/tests/tv3_globalSymbols.nim index f965a07aa9c13..c3bb9933b6cbc 100644 --- a/nimsuggest/tests/tv3_globalSymbols.nim +++ b/nimsuggest/tests/tv3_globalSymbols.nim @@ -7,8 +7,8 @@ proc BBtokenA(): int = 5 discard """ $nimsuggest --v3 --tester $file >globalSymbols token -def skProc tv3_globalSymbols.token proc (): int{.noSideEffect, gcsafe.} $file 4 5 "" 100 -def skProc tv3_globalSymbols.tokenA proc (): int{.noSideEffect, gcsafe.} $file 3 5 "" 100 -def skProc tv3_globalSymbols.Btoken proc (): int{.noSideEffect, gcsafe.} $file 2 5 "" 100 -def skProc tv3_globalSymbols.BBtokenA proc (): int{.noSideEffect, gcsafe.} $file 5 5 "" 100 +def skProc tv3_globalSymbols.token proc (): int{.noSideEffect, gcsafe, raises: [].} $file 4 5 "" 100 +def skProc tv3_globalSymbols.tokenA proc (): int{.noSideEffect, gcsafe, raises: [].} $file 3 5 "" 100 +def skProc tv3_globalSymbols.Btoken proc (): int{.noSideEffect, gcsafe, raises: [].} $file 2 5 "" 100 +def skProc tv3_globalSymbols.BBtokenA proc (): int{.noSideEffect, gcsafe, raises: [].} $file 5 5 "" 100 """ diff --git a/nimsuggest/tests/tv3_outline.nim b/nimsuggest/tests/tv3_outline.nim index 6370948d9a4e3..518620c871167 100644 --- a/nimsuggest/tests/tv3_outline.nim +++ b/nimsuggest/tests/tv3_outline.nim @@ -33,13 +33,13 @@ outline skType tv3_outline.FooEnum FooEnum $file 6 2 "" 100 6 31 outline skEnumField tv3_outline.FooEnum.value1 FooEnum $file 6 17 "" 100 6 23 outline skEnumField tv3_outline.FooEnum.value2 FooEnum $file 6 25 "" 100 6 31 outline skType tv3_outline.FooPrivate FooPrivate $file 7 2 "" 100 8 22 -outline skMacro tv3_outline.m macro (arg: untyped): untyped{.noSideEffect, gcsafe.} $file 10 6 "" 100 10 40 +outline skMacro tv3_outline.m macro (arg: untyped): untyped{.noSideEffect, gcsafe, raises: [].} $file 10 6 "" 100 10 40 outline skTemplate tv3_outline.t template (arg: untyped): untyped $file 11 9 "" 100 11 43 -outline skProc tv3_outline.p proc (){.noSideEffect, gcsafe.} $file 12 5 "" 100 12 24 -outline skConverter tv3_outline.c converter (s: string): int{.noSideEffect, gcsafe.} $file 14 10 "" 100 14 37 -outline skFunc tv3_outline.f proc (){.noSideEffect, gcsafe.} $file 16 5 "" 100 16 24 +outline skProc tv3_outline.p proc (){.noSideEffect, gcsafe, raises: [].} $file 12 5 "" 100 12 24 +outline skConverter tv3_outline.c converter (s: string): int{.noSideEffect, gcsafe, raises: [].} $file 14 10 "" 100 14 37 +outline skFunc tv3_outline.f proc (){.noSideEffect, gcsafe, raises: [].} $file 16 5 "" 100 16 24 outline skConst tv3_outline.con int literal(2) $file 20 6 "" 100 20 13 -outline skProc tv3_outline.outer proc (){.noSideEffect, gcsafe.} $file 22 5 "" 100 23 24 -outline skProc tv3_outline.outer.inner proc (){.noSideEffect, gcsafe.} $file 23 7 "" 100 23 24 -outline skProc tv3_outline.procWithLocal proc (){.noSideEffect, gcsafe.} $file 25 5 "" 100 26 16 +outline skProc tv3_outline.outer proc (){.noSideEffect, gcsafe, raises: [].} $file 22 5 "" 100 23 24 +outline skProc tv3_outline.outer.inner proc (){.noSideEffect, gcsafe, raises: [].} $file 23 7 "" 100 23 24 +outline skProc tv3_outline.procWithLocal proc (){.noSideEffect, gcsafe, raises: [].} $file 25 5 "" 100 26 16 """ diff --git a/nimsuggest/tests/twithin_macro.nim b/nimsuggest/tests/twithin_macro.nim index d79dae1be009c..98d58381f0fbf 100644 --- a/nimsuggest/tests/twithin_macro.nim +++ b/nimsuggest/tests/twithin_macro.nim @@ -45,7 +45,7 @@ $nimsuggest --tester --maxresults:5 $file >sug $1 sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;None sug;;skField;;name;;string;;$file;;5;;6;;"";;100;;None -sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;None -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;7;;9;;"";;100;;None +sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int{.raises: [].};;$file;;8;;9;;"";;100;;None +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string{.raises: [].};;$file;;7;;9;;"";;100;;None sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;23;;9;;"";;100;;None """ diff --git a/nimsuggest/tests/twithin_macro_prefix.nim b/nimsuggest/tests/twithin_macro_prefix.nim index dd38108183d61..e89c8b94231d1 100644 --- a/nimsuggest/tests/twithin_macro_prefix.nim +++ b/nimsuggest/tests/twithin_macro_prefix.nim @@ -44,5 +44,5 @@ discard """ $nimsuggest --tester $file >sug $1 sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;Prefix -sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;Prefix +sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int{.raises: [].};;$file;;8;;9;;"";;100;;Prefix """ From f46f26e79aada7195f4d83d8601f0d856520763d Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 17 Jan 2024 13:59:54 +0300 Subject: [PATCH 106/123] don't use previous bindings of `auto` for routine return types (#23207) fixes #23200, fixes #18866 #21065 made it so `auto` proc return types remained as `tyAnything` and not turned to `tyUntyped`. This had the side effect that anything previously bound to `tyAnything` in the proc type match was then bound to the proc return type, which is wrong since we don't know the proc return type even if we know the expected parameter types (`tyUntyped` also [does not care about its previous bindings in `typeRel`](https://github.com/nim-lang/Nim/blob/ab4278d2179639f19967431a7aa1be858046f7a7/compiler/sigmatch.nim#L1059-L1061) maybe for this reason). Now we mark `tyAnything` return types for routines as `tfRetType` [as done for other meta return types](https://github.com/nim-lang/Nim/blob/18b5fb256d4647efa6a64df451d37129d36e96f3/compiler/semtypes.nim#L1451), and ignore bindings to `tyAnything` + `tfRetType` types in `semtypinst`. On top of this, we reset the type relation in `paramTypesMatch` only after creating the instantiation (instead of trusting `isInferred`/`isInferredConvertible` before creating the instantiation), using the same mechanism that `isBothMetaConvertible` uses. This fixes the issues as well as making the disabled t15386_2 test introduced in #21065 work. As seen in the changes for the other tests, the error messages give an obscure `proc (a: GenericParam): auto` now, but it does give the correct error that the overload doesn't match instead of matching the overload pre-emptively and expecting a specific return type. tsugar had to be changed due to #16906, which is the problem where `void` is not inferred in the case where `result` was never touched. --- compiler/semtypes.nim | 3 +- compiler/semtypinst.nim | 7 ++- compiler/sigmatch.nim | 82 ++++++++++++++--------------- tests/concepts/tconcepts_issues.nim | 2 +- tests/errmsgs/t16654.nim | 2 +- tests/misc/t12869.nim | 2 +- tests/proc/tinferlambdareturn.nim | 36 +++++++++++++ tests/stdlib/tsugar.nim | 3 +- tests/types/t15836.nim | 2 +- tests/types/t15836_2.nim | 5 -- 10 files changed, 91 insertions(+), 53 deletions(-) create mode 100644 tests/proc/tinferlambdareturn.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index fe87c29731ade..1f671effa1132 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1436,7 +1436,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, "' is only valid for macros and templates") # 'auto' as a return type does not imply a generic: elif r.kind == tyAnything: - discard + r = copyType(r, c.idgen, r.owner) + r.flags.incl tfRetType elif r.kind == tyStatic: # type allowed should forbid this type discard diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 1510a3f9c52aa..d1327a3aee240 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -315,6 +315,9 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym = result.ast = replaceTypeVarsN(cl, s.ast) proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = + if tfRetType in t.flags and t.kind == tyAnything: + # don't bind `auto` return type to a previous binding of `auto` + return nil result = cl.typeMap.lookup(t) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return @@ -551,7 +554,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = t if t == nil: return - if t.kind in {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses: + const lookupMetas = {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses - {tyAnything} + if t.kind in lookupMetas or + (t.kind == tyAnything and tfRetType notin t.flags): let lookup = cl.typeMap.lookup(t) if lookup != nil: return lookup diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 557d4c44772ba..9e99353d10af4 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2120,6 +2120,7 @@ template matchesVoidProc(t: PType): bool = proc paramTypesMatchAux(m: var TCandidate, f, a: PType, argSemantized, argOrig: PNode): PNode = + result = nil var fMaybeStatic = f.skipTypes({tyDistinct}) arg = argSemantized @@ -2182,28 +2183,33 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, else: return argSemantized # argOrig - # If r == isBothMetaConvertible then we rerun typeRel. - # bothMetaCounter is for safety to avoid any infinite loop, - # I don't have any example when it is needed. - # lastBindingsLenth is used to check whether m.bindings remains the same, - # because in that case there is no point in continuing. - var bothMetaCounter = 0 - var lastBindingsLength = -1 - while r == isBothMetaConvertible and - lastBindingsLength != m.bindings.counter and - bothMetaCounter < 100: - lastBindingsLength = m.bindings.counter - inc(bothMetaCounter) - if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds: - result = c.semInferredLambda(c, m.bindings, arg) - elif arg.kind != nkSym: - return nil - else: - let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info) - result = newSymNode(inferred, arg.info) - inc(m.convMatches) - arg = result - r = typeRel(m, f, arg.typ) + block instantiateGenericRoutine: + # In the case where the matched value is a generic proc, we need to + # fully instantiate it and then rerun typeRel to make sure it matches. + # instantiationCounter is for safety to avoid any infinite loop, + # I don't have any example when it is needed. + # lastBindingCount is used to check whether m.bindings remains the same, + # because in that case there is no point in continuing. + var instantiationCounter = 0 + var lastBindingCount = -1 + while r in {isBothMetaConvertible, isInferred, isInferredConvertible} and + lastBindingCount != m.bindings.counter and + instantiationCounter < 100: + lastBindingCount = m.bindings.counter + inc(instantiationCounter) + if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds: + result = c.semInferredLambda(c, m.bindings, arg) + elif arg.kind != nkSym: + return nil + elif arg.sym.kind in {skMacro, skTemplate}: + return nil + else: + if arg.sym.ast == nil: + return nil + let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info) + result = newSymNode(inferred, arg.info) + arg = result + r = typeRel(m, f, arg.typ) case r of isConvertible: @@ -2230,23 +2236,15 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, result = arg else: result = implicitConv(nkHiddenStdConv, f, arg, m, c) - of isInferred, isInferredConvertible: - if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds: - result = c.semInferredLambda(c, m.bindings, arg) - elif arg.kind != nkSym: - return nil - elif arg.sym.kind in {skMacro, skTemplate}: - return nil - else: - if arg.sym.ast == nil: - return nil - let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info) - result = newSymNode(inferred, arg.info) - if r == isInferredConvertible: - inc(m.convMatches) - result = implicitConv(nkHiddenStdConv, f, result, m, c) - else: - inc(m.genericMatches) + of isInferred: + # result should be set in above while loop: + assert result != nil + inc(m.genericMatches) + of isInferredConvertible: + # result should be set in above while loop: + assert result != nil + inc(m.convMatches) + result = implicitConv(nkHiddenStdConv, f, result, m, c) of isGeneric: inc(m.genericMatches) if arg.typ == nil: @@ -2260,8 +2258,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, else: result = arg of isBothMetaConvertible: - # This is the result for the 101th time. - result = nil + # result should be set in above while loop: + assert result != nil + inc(m.convMatches) + result = arg of isFromIntLit: # too lazy to introduce another ``*matches`` field, so we conflate # ``isIntConv`` and ``isIntLit`` here: diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index 1d5e415dd2d55..d6c8674fd8f29 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -510,7 +510,7 @@ proc depthOf*[V](orderType: typedesc[BreadthOrder], tree: AnyTree[V], root, goal if root == goal: return 0 var order = init[LevelNode[V]](orderType) - order.expand(tree, root, (leaf) => (1, leaf)) + order.expand(tree, root, (leaf) => (1.uint, leaf)) while order.hasNext(): let depthNode: LevelNode[V] = order.popNext() if depthNode.node == goal: diff --git a/tests/errmsgs/t16654.nim b/tests/errmsgs/t16654.nim index 749707c069c15..b2b57619bd120 100644 --- a/tests/errmsgs/t16654.nim +++ b/tests/errmsgs/t16654.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim check $options $file" - errormsg: "type mismatch: got but expected 'float'" + errormsg: "type mismatch: got " """ when true: # bug #16654 diff --git a/tests/misc/t12869.nim b/tests/misc/t12869.nim index 731a4e95ec586..054e28a038576 100644 --- a/tests/misc/t12869.nim +++ b/tests/misc/t12869.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got but expected 'int'" + errormsg: "type mismatch: got " line: 12 """ diff --git a/tests/proc/tinferlambdareturn.nim b/tests/proc/tinferlambdareturn.nim new file mode 100644 index 0000000000000..e9e592871996e --- /dev/null +++ b/tests/proc/tinferlambdareturn.nim @@ -0,0 +1,36 @@ +import std/[sugar, sequtils] + +block: # issue #23200 + proc dosomething(iter: int -> (iterator: int)) = + discard + proc dosomething(iter: int -> seq[int]) = + discard + proc makeSeq(x: int): seq[int] = + @[x] + # Works fine with 1.6.12 and 1.6.14 + dosomething(makeSeq) + # Works with 1.6.12, fails with 1.6.14 + dosomething((y) => makeSeq(y)) + dosomething(proc (y: auto): auto = makeSeq(y)) + proc foo(y: auto): auto = makeSeq(y) + dosomething(foo) + +block: # issue #18866 + proc somefn[T](list: openarray[T], op: proc (v: T): float) = + discard op(list[0]) + + type TimeD = object + year: Natural + month: 1..12 + day: 1..31 + + doAssert not compiles(@[TimeD()].somefn(proc (v: auto): auto = + v + )) + @[TimeD()].somefn(proc (v: auto): auto = + v.year.float + ) + proc foo(v: auto): auto = v + doAssert not compiles(@[TimeD()].somefn(foo)) + proc bar(v: auto): auto = v.year.float + @[TimeD()].somefn(bar) diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index b9cbdd3e378f6..2ea96cfbbf6e7 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -295,7 +295,8 @@ template main() = for i in 0..5: xs.add(i) - xs.apply(d => ys.add(d)) + xs.apply(proc (d: auto) = ys.add(d)) + # ^ can be turned into d => ys.add(d) when we can infer void return type, #16906 doAssert ys == @[0, 1, 2, 3, 4, 5] test() diff --git a/tests/types/t15836.nim b/tests/types/t15836.nim index 9c0c26decf084..27d3ad0d0d716 100644 --- a/tests/types/t15836.nim +++ b/tests/types/t15836.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got but expected 'int'" + errormsg: "type mismatch: got " line: 11 """ diff --git a/tests/types/t15836_2.nim b/tests/types/t15836_2.nim index 9afef416a88db..6a16e2d2227e7 100644 --- a/tests/types/t15836_2.nim +++ b/tests/types/t15836_2.nim @@ -1,8 +1,3 @@ - -discard """ - action: "compile" - disabled: true -""" import std/sugar type Tensor[T] = object From 3379d26629f30e6be8d303a36e220d1039eb4551 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:20:54 +0800 Subject: [PATCH 107/123] fixes #23223; prevents `insert` self-assignment (#23225) fixes #23223 --- lib/system.nim | 2 ++ tests/system/tsystem_misc.nim | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index 0602d8fa42714..8aa1cc34c2ed1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2520,6 +2520,8 @@ when hasAlloc or defined(nimscript): ## var a = "abc" ## a.insert("zz", 0) # a <- "zzabc" ## ``` + if item.len == 0: # prevents self-assignment + return var xl = x.len setLen(x, xl+item.len) var j = xl-1 diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 7f5914725452a..c8e2b2a9df384 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -212,3 +212,10 @@ block: doAssert not compiles(echo p.rawProc.repr) doAssert not compiles(echo p.rawEnv.repr) doAssert not compiles(echo p.finished) + +proc bug23223 = # bug #23223 + var stuff = "hello" + stuff.insert "" + doAssert stuff == "hello" + +bug23223() From 2425f4559cc5e8a96cf0dccea72817a782918de0 Mon Sep 17 00:00:00 2001 From: Angel Ezquerra Date: Thu, 18 Jan 2024 14:32:22 +0100 Subject: [PATCH 108/123] Add `^` operator support for Rational numbers (#23219) Since pow() cannot be supported for rationals, we support negative integer exponents instead. --- lib/pure/rationals.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 45902b7cd4405..5f806bd701bcb 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -318,3 +318,23 @@ func hash*[T](x: Rational[T]): Hash = h = h !& hash(copy.num) h = h !& hash(copy.den) result = !$h + +func `^`*[T: SomeInteger](x: Rational[T], y: T): Rational[T] = + ## Computes `x` to the power of `y`. + ## + ## The exponent `y` must be an integer. Negative exponents are supported + ## but floating point exponents are not. + runnableExamples: + doAssert (-3 // 5) ^ 0 == (1 // 1) + doAssert (-3 // 5) ^ 1 == (-3 // 5) + doAssert (-3 // 5) ^ 2 == (9 // 25) + doAssert (-3 // 5) ^ -2 == (25 // 9) + + if y >= 0: + result.num = x.num ^ y + result.den = x.den ^ y + else: + result.num = x.den ^ -y + result.den = x.num ^ -y + # Note that all powers of reduced rationals are already reduced, + # so we don't need to call reduce() here From 473f259268d03f87874c674c08c74cf32da11d4a Mon Sep 17 00:00:00 2001 From: Giuliano Mega Date: Thu, 18 Jan 2024 10:40:22 -0300 Subject: [PATCH 109/123] Fix reset code gen for range types (#22462, #23214) (#23215) This PR modifies `specializeResetT` so that it generates the proper reset code for range types. I've tested it in the examples for issues #23214 and #22462 as well as our codebase, and it seems to fix the issues I had been experiencing. --- compiler/ccgreset.nim | 4 ++-- tests/ccgbugs/t22462.nim | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/ccgbugs/t22462.nim diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index e4abcfc8c6ebf..4af690e350a25 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -81,7 +81,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor]) else: lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) - of tyChar, tyBool, tyEnum, tyInt..tyUInt64: + of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64: lineCg(p, cpsStmts, "$1 = 0;$n", [accessor]) of tyCstring, tyPointer, tyPtr, tyVar, tyLent: lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) @@ -95,7 +95,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = else: raiseAssert "unexpected set type kind" of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation, - tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs, + tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs, tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable: diff --git a/tests/ccgbugs/t22462.nim b/tests/ccgbugs/t22462.nim new file mode 100644 index 0000000000000..9adfbb19ba2cb --- /dev/null +++ b/tests/ccgbugs/t22462.nim @@ -0,0 +1,20 @@ +discard """ + action: "run" + output: ''' +1 +1 +1 +''' + matrix: "--mm:refc" + targets: "c cpp" +""" + +type Object = object + someComplexType: seq[int] + index: Natural + +func newObject(): Object = result.index.inc + +for i in 1..3: + let o = newObject() + echo o.index From 322433755058eae481f4e92b2070e886f097bd9f Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 18 Jan 2024 16:50:36 +0300 Subject: [PATCH 110/123] give typedesc param nodes type T not typedesc[T] [backport:2.0] (#23115) fixes https://github.com/nim-lang/Nim/issues/23112, fixes a mistake in https://github.com/nim-lang/Nim/pull/22581 This makes `getType(t)` where `t` is a typedesc param with value `T` equal to `getType(T)`. --- compiler/vmgen.nim | 2 +- tests/vm/ttypedesc.nim | 13 +++++++++++++ tests/vm/tvmmisc.nim | 3 +-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 9bbea2b08e62c..b7dd193be63f2 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2124,7 +2124,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = genRdVar(c, n, dest, flags) of skParam: if s.typ.kind == tyTypeDesc: - genTypeLit(c, s.typ, dest) + genTypeLit(c, s.typ.skipTypes({tyTypeDesc}), dest) else: genRdVar(c, n, dest, flags) of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator: diff --git a/tests/vm/ttypedesc.nim b/tests/vm/ttypedesc.nim index a112584c544a6..d799e5adb04e6 100644 --- a/tests/vm/ttypedesc.nim +++ b/tests/vm/ttypedesc.nim @@ -16,3 +16,16 @@ block: # issue #15760 doAssert x[SpecialBanana]() == "SpecialBanana" doAssert y(SpecialBanana) == "SpecialBanana" + +import macros + +block: # issue #23112 + type Container = object + foo: string + + proc canBeImplicit(t: typedesc) {.compileTime.} = + let tDesc = getType(t) + doAssert tDesc.kind == nnkObjectTy + + static: + canBeImplicit(Container) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index cade68577cd9d..f277c20d8b8c6 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -4,8 +4,7 @@ import os # bug #4462 block: proc foo(t: typedesc) {.compileTime.} = - assert sameType(getType(t), getType(typedesc[int])) - assert sameType(getType(t), getType(type int)) + assert sameType(getType(t), getType(int)) static: foo(int) From fe98032d3d25490bb731dde20e7111c071ca1caa Mon Sep 17 00:00:00 2001 From: daylin <47667941+daylinmorgan@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:12:13 -0600 Subject: [PATCH 111/123] fix(#23231): add nimdoc.cls to installer script (#23232) Change to `compiler/installer.ini` to add `nimdoc.cls` to files copied by installer script. Closes #23231 --- compiler/installer.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/installer.ini b/compiler/installer.ini index d12127bde91c9..8569d0ef81f57 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -147,4 +147,4 @@ licenses: "bin/nim,MIT;lib/*,MIT;" [nimble] pkgName: "nim" -pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css" +pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css;doc/nimdoc.cls" From 8a38880ef7962fe4a3155449eb161eeffda0cda5 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 19 Jan 2024 04:13:39 +0800 Subject: [PATCH 112/123] workaround arrayWith issues (#23230) I'm working on it, but it's quite tricky. I will fix it soon --- lib/system.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 8aa1cc34c2ed1..61a0a9f2d484a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2928,4 +2928,5 @@ proc arrayWith*[T](y: T, size: static int): array[size, T] {.raises: [].} = when nimvm: result[i] = y else: - result[i] = `=dup`(y) + # TODO: fixme it should be `=dup` + result[i] = y From 3ab8b6b2cf4488c114284aa5ad5b7af0d4055312 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 18 Jan 2024 23:14:27 +0300 Subject: [PATCH 113/123] error on large integer types as array index range (#23229) fixes #17163, refs #23204 Types that aren't `tyRange` and are bigger than 16 bits, so `int32`, `uint64`, `int` etc, are disallowed as array index range types. `tyRange` is excluded because the max array size is backend independent (except for the specific size of `high(uint64)` which crashes the compiler) and so there should still be an escape hatch for people who want bigger arrays. --- compiler/semtypes.nim | 9 ++++++--- tests/array/tlargeindex.nim | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 tests/array/tlargeindex.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 1f671effa1132..ebc0b1dbc8e57 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -415,13 +415,16 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = skipModifier(indxB) if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and tfUnresolved notin indxB.flags: - if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}: - discard - elif not isOrdinalType(indxB): + if not isOrdinalType(indxB): localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(indxB, preferDesc)) elif enumHasHoles(indxB): localError(c.config, n[1].info, "enum '$1' has holes" % typeToString(indxB.skipTypes({tyRange}))) + elif indxB.kind != tyRange and + lengthOrd(c.config, indxB) > high(uint16).int: + # assume range type is intentional + localError(c.config, n[1].info, + "index type '$1' for array is too large" % typeToString(indxB)) base = semTypeNode(c, n[2], nil) # ensure we only construct a tyArray when there was no error (bug #3048): # bug #6682: Do not propagate initialization requirements etc for the diff --git a/tests/array/tlargeindex.nim b/tests/array/tlargeindex.nim new file mode 100644 index 0000000000000..61bcbd61d5fa6 --- /dev/null +++ b/tests/array/tlargeindex.nim @@ -0,0 +1,18 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +# issue #17163 +var e: array[int32, byte] #[tt.Error + ^ index type 'int32' for array is too large]# +var f: array[uint32, byte] #[tt.Error + ^ index type 'uint32' for array is too large]# +var g: array[int64, byte] #[tt.Error + ^ index type 'int64' for array is too large]# +var h: array[uint64, byte] #[tt.Error + ^ index type 'uint64' for array is too large]# + +# crash in issue #23204 +proc y[N](): array[N, int] = default(array[N, int]) #[tt.Error + ^ index type 'int' for array is too large]# +discard y[int]() From cfd69bad1a1071345cfcd145a7e7f906304f265f Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 18 Jan 2024 23:19:29 +0300 Subject: [PATCH 114/123] fix wrong subtype relation in tuples & infer some conversions (#23228) fixes #18125 Previously a tuple type like `(T, int)` would match an expected tuple type `(U, int)` if `T` is a subtype of `U`. This is wrong since the codegen does not handle type conversions of individual tuple elements in a type conversion of an entire tuple. For this reason the compiler already does not accept `(float, int)` for a matched type `(int, int)`, however the code that checked for which relations are unacceptable checked for `< isSubtype` rather than `<= isSubtype`, so subtypes were not included in the unacceptable relations. Update: Now only considered unacceptable when inheritance is used, as in [`paramTypesMatch`](https://github.com/nim-lang/Nim/blob/3379d26629f30e6be8d303a36e220d1039eb4551/compiler/sigmatch.nim#L2252-L2254). Ideally subtype relations that don't need conversions, like `nil`, `seq[empty]`, `range[0..5]` etc would be their own relation `isConcreteSubtype` (which would also allow us to differentiate with `openArray[T]`), but this is too big of a refactor for now. To compensate for this making things like `let x: (Parent, int) = (Child(), 0)` not compile (they would crash codegen before anyway but should still work in principle), type inference for tuple constructors is updated such that they call `fitNode` on the fields and their expected types, so a type conversion is generated for the individual subtype element. --- compiler/semexprs.nim | 18 +++++++++++++++--- compiler/sigmatch.nim | 6 ++++++ tests/tuples/t18125_1.nim | 14 ++++++++++++++ tests/tuples/t18125_2.nim | 20 ++++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 tests/tuples/t18125_1.nim create mode 100644 tests/tuples/t18125_2.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 70206c6f99e07..beb3719e8f524 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2074,12 +2074,10 @@ proc semYield(c: PContext, n: PNode): PNode = if c.p.owner == nil or c.p.owner.kind != skIterator: localError(c.config, n.info, errYieldNotAllowedHere) elif n[0].kind != nkEmpty: - n[0] = semExprWithType(c, n[0]) # check for type compatibility: var iterType = c.p.owner.typ let restype = iterType[0] + n[0] = semExprWithType(c, n[0], {}, restype) # check for type compatibility: if restype != nil: - if restype.kind != tyUntyped: - n[0] = fitNode(c, restype, n[0], n.info) if n[0].typ == nil: internalError(c.config, n.info, "semYield") if resultTypeIsInferrable(restype): @@ -2087,6 +2085,8 @@ proc semYield(c: PContext, n: PNode): PNode = iterType[0] = inferred if c.p.resultSym != nil: c.p.resultSym.typ = inferred + else: + n[0] = fitNode(c, restype, n[0], n.info) semYieldVarResult(c, n, restype) else: @@ -2767,6 +2767,12 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType # can check if field name matches expected type here let expectedElemType = if expected != nil: expected[i] else: nil n[i][1] = semExprWithType(c, n[i][1], {}, expectedElemType) + if expectedElemType != nil and + (expectedElemType.kind != tyNil and not hasEmpty(expectedElemType)): + # hasEmpty/nil check is to not break existing code like + # `const foo = [(1, {}), (2, {false})]`, + # `const foo = if true: (0, nil) else: (1, new(int))` + n[i][1] = fitNode(c, expectedElemType, n[i][1], n[i][1].info) if n[i][1].typ.kind == tyTypeDesc: localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.") @@ -2793,6 +2799,12 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT for i in 0.. oldInheritancePenalty: + # we can't process individual element type conversions from a + # type conversion for the whole tuple + # subtype relations need type conversions when inheritance is used + return isNone result = minRel(result, m) if f.n != nil and a.n != nil: for i in 0.. but expected '(Parent, int)'" + line: 17 +""" + +# issue #18125 solved with correct type relation + +type + Parent = ref object of RootObj + + Child = ref object of Parent + c: char + +func foo(c: char): (Parent, int) = + # Works if you use (Parent(Child(c: c)), 0) + let x = (Child(c: c), 0) + x + +let x = foo('x')[0] +doAssert Child(x).c == 'x' From 527d1e197731803c4c03b15b6ac0ba2d461eb7f3 Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Fri, 19 Jan 2024 05:25:31 +0900 Subject: [PATCH 115/123] Nim Compiler User Guide: Add explanations about lto and strip (#23227) --- doc/nimc.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/nimc.md b/doc/nimc.md index 08bd016e114b3..1136bef092bb8 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -552,6 +552,13 @@ Define Effect `globalSymbols` Load all `{.dynlib.}` libraries with the `RTLD_GLOBAL`:c: flag on Posix systems to resolve symbols in subsequently loaded libraries. +`lto` Enable link-time optimization in the backend compiler and + linker. +`lto_incremental` Enable link-time optimization and additionally enable + incremental linking for compilers that support it. + Currently only clang and vcc. +`strip` Strip debug symbols added by the backend compiler from + the executable. ====================== ========================================================= @@ -677,11 +684,11 @@ additional flags to both the Nim compiler and the C compiler and/or linker to optimize the build for size. For example, the following flags can be used when targeting a gcc compiler: -`--opt:size --passC:-flto --passL:-flto`:option: +`--opt:size -d:lto -d:strip`:option: The `--opt:size`:option: flag instructs Nim to optimize code generation for small -size (with the help of the C compiler), the `-flto`:option: flags enable link-time -optimization in the compiler and linker. +size (with the help of the C compiler), the `-d:lto`:option: flags enable link-time +optimization in the compiler and linker, the `-d:strip`:option: strips debug symbols. Check the [Cross-compilation] section for instructions on how to compile the program for your target. From 3fb46fac32b8a1fcf36ac52d09983297251d1213 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 19 Jan 2024 04:31:49 +0800 Subject: [PATCH 116/123] fixes #12334; keeps `nkHiddenStdConv` for cstring conversions (#23216) fixes #12334 `nkHiddenStdConv` shouldn't be removed if the sources aren't literals, viz. constant symbols. --- compiler/semstmts.nim | 2 ++ tests/vm/tconst.nim | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d62ad8305be27..59dc94f36a562 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -339,6 +339,8 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result.typ = typ if not floatRangeCheck(result.floatVal, typ): localError(c.config, n.info, errFloatToString % [$result.floatVal, typeToString(typ)]) + elif r1.kind == nkSym and typ.skipTypes(abstractRange).kind == tyCstring: + discard "keep nkHiddenStdConv for cstring conversions" else: changeType(c, r1, typ, check=true) result = r1 diff --git a/tests/vm/tconst.nim b/tests/vm/tconst.nim index c2bcf78b59793..5cfe7533edf60 100644 --- a/tests/vm/tconst.nim +++ b/tests/vm/tconst.nim @@ -42,6 +42,16 @@ template main() = discard (x, increment, a) mytemp() + block: # bug #12334 + block: + const b: cstring = "foo" + var c = b + doAssert c == "foo" + block: + const a = "foo" + const b: cstring = a + var c = b + doAssert c == "foo" static: main() From b2f79df81cc1fb2cfd4566ffa868043e286eba5c Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 19 Jan 2024 04:47:13 +0800 Subject: [PATCH 117/123] fixes #22218; avoids cursor when copy is disabled (#23209) fixes #22218 --- compiler/varpartitions.nim | 4 +++- tests/arc/t22218.nim | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/arc/t22218.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 9b5ad009d1534..6b2f677a7e7b8 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -985,7 +985,9 @@ proc computeCursors*(s: PSym; n: PNode; g: ModuleGraph) = if v.flags * {ownsData, preventCursor, isConditionallyReassigned} == {} and v.sym.kind notin {skParam, skResult} and v.sym.flags * {sfThread, sfGlobal} == {} and hasDestructor(v.sym.typ) and - v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned: + v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned and + (getAttachedOp(g, v.sym.typ, attachedAsgn) == nil or + sfError notin getAttachedOp(g, v.sym.typ, attachedAsgn).flags): let rid = root(par, i) if par.s[rid].con.kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].con.graphIndex], par.s[i]): discard "cannot cursor into a graph that is mutated" diff --git a/tests/arc/t22218.nim b/tests/arc/t22218.nim new file mode 100644 index 0000000000000..7837ed1d0d032 --- /dev/null +++ b/tests/arc/t22218.nim @@ -0,0 +1,25 @@ +discard """ + cmd: "nim c --mm:arc $file" + errormsg: "'=copy' is not available for type ; requires a copy because it's not the last read of 'chan[]'; routine: test" +""" + +# bug #22218 +type Obj[T] = object + v: T + +proc `=copy`[T]( + dest: var Obj[T], + source: Obj[T] + ) {.error: "A channel cannot be copied".} + +from system/ansi_c import c_calloc + +proc test() = + var v: bool = true + var chan = cast[ptr Obj[int]](c_calloc(1, csize_t sizeof(Obj[int]))) + var copy = chan[] + + echo chan.v + echo v + +test() \ No newline at end of file From 38f9ee0e5850ac9987fe612edcf48cddd1835091 Mon Sep 17 00:00:00 2001 From: Angel Ezquerra Date: Thu, 18 Jan 2024 21:59:16 +0100 Subject: [PATCH 118/123] Make std/math classify work without `--passc:-fast-math`. (#23211) By using the existing isNaN function we can make std/math's classify function work even if `--passc:-fast-math` is used. --- lib/pure/math.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index a90aef54c5ef8..1ca4825a2de79 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -200,7 +200,7 @@ func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = template fn: untyped = result = x != x when nimvm: fn() else: - when defined(js): fn() + when defined(js) or defined(nimscript): fn() else: result = c_isnan(x) when defined(js): @@ -270,7 +270,6 @@ func classify*(x: float): FloatClass = ## Classifies a floating point value. ## ## Returns `x`'s class as specified by the `FloatClass enum<#FloatClass>`_. - ## Doesn't work with `--passc:-ffast-math`. runnableExamples: doAssert classify(0.3) == fcNormal doAssert classify(0.0) == fcZero @@ -279,6 +278,7 @@ func classify*(x: float): FloatClass = doAssert classify(5.0e-324) == fcSubnormal # JavaScript and most C compilers have no classify: + if isNan(x): return fcNan if x == 0.0: if 1.0 / x == Inf: return fcZero @@ -287,7 +287,6 @@ func classify*(x: float): FloatClass = if x * 0.5 == x: if x > 0.0: return fcInf else: return fcNegInf - if x != x: return fcNan if abs(x) < MinFloatNormal: return fcSubnormal return fcNormal From 01097fc1fc70d5c7ce38108d7773e5533fb3743b Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 19 Jan 2024 20:11:01 +0800 Subject: [PATCH 119/123] fix mime types data (#23226) generated via https://github.com/bung87/mimetypes_gen source data: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co --- lib/pure/mimetypes.nim | 2686 ++++++++++++----------------------- tests/stdlib/tmimetypes.nim | 3 + 2 files changed, 909 insertions(+), 1780 deletions(-) diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index e7dd2f8f2b7ae..e1ad94a5700cc 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -38,1869 +38,995 @@ type mimes: OrderedTable[string, string] const mimes* = { - "123": "application/vnd.lotus-1-2-3", - "1km": "application/vnd.1000minds.decision-model+xml", - "323": "text/h323", - "3dm": "text/vnd.in3d.3dml", - "3dmf": "x-world/x-3dmf", - "3dml": "text/vnd.in3d.3dml", - "3ds": "image/x-3ds", - "3g2": "video/3gpp2", - "3gp": "video/3gpp", - "3gpp": "audio/3gpp", - "3gpp2": "video/3gpp2", - "3mf": "application/vnd.ms-3mfdocument", - "669": "audio/x-mod", - "726": "audio/32kadpcm", - "7z": "application/x-7z-compressed", - "a": "text/plain", - "a2l": "application/a2l", - "aa3": "audio/atrac3", - "aab": "application/x-authorware-bin", - "aac": "audio/x-aac", - "aal": "audio/atrac-advanced-lossless", - "aam": "application/x-authorware-map", - "aas": "application/x-authorware-seg", - "abc": "text/vnd.abc", - "abw": "application/x-abiword", - "ac": "application/pkix-attr-cert", - "ac3": "audio/ac3", - "acc": "application/vnd.americandynamics.acc", - "ace": "application/x-ace-compressed", - "acn": "audio/asc", - "acu": "application/vnd.acucobol", - "acutc": "application/vnd.acucorp", - "acx": "application/internet-property-stream", - "adp": "audio/adpcm", - "aep": "application/vnd.audiograph", - "afl": "video/animaflex", - "afm": "application/x-font-type1", - "afp": "application/vnd.ibm.modcap", - "ahead": "application/vnd.ahead.space", - "ai": "application/postscript", - "aif": "audio/x-aiff", - "aifc": "audio/x-aiff", - "aiff": "audio/x-aiff", - "aim": "application/x-aim", - "aip": "text/x-audiosoft-intra", - "air": "application/vnd.adobe.air-application-installer-package+zip", - "ait": "application/vnd.dvb.ait", - "alc": "chemical/x-alchemy", - "ami": "application/vnd.amiga.ami", - "aml": "application/aml", - "amr": "audio/amr", - "ani": "application/x-navi-animation", - "anx": "application/x-annodex", - "aos": "application/x-nokia-9000-communicator-add-on-software", - "apinotes": "text/apinotes", - "apk": "application/vnd.android.package-archive", - "apkg": "application/vnd.anki", - "apng": "image/apng", - "appcache": "text/cache-manifest", - "appimage": "application/appimage", - "application": "application/x-ms-application", - "apr": "application/vnd.lotus-approach", - "aps": "application/mime", - "apxml": "application/auth-policy+xml", - "arc": "application/x-freearc", - "arj": "application/x-arj", - "art": "message/rfc822", - "asar": "binary/asar", - "asc": "text/plain", - "ascii": "text/vnd.ascii-art", - "asf": "application/vnd.ms-asf", - "asice": "application/vnd.etsi.asic-e+zip", - "asics": "application/vnd.etsi.asic-s+zip", - "asm": "text/x-asm", - "asn": "chemical/x-ncbi-asn1-spec", - "aso": "application/vnd.accpac.simply.aso", - "asp": "text/asp", - "asr": "video/x-ms-asf", - "asx": "video/x-ms-asf", - "at3": "audio/atrac3", - "atc": "application/vnd.acucorp", - "atf": "application/atf", - "atfx": "application/atfx", + "ez": "application/andrew-inset", + "aw": "application/applixware", "atom": "application/atom+xml", "atomcat": "application/atomcat+xml", - "atomdeleted": "application/atomdeleted+xml", - "atomsrv": "application/atomserv+xml", "atomsvc": "application/atomsvc+xml", - "atx": "application/vnd.antix.game-component", - "atxml": "application/atxml", - "au": "audio/basic", - "auc": "application/tamp-apex-update-confirm", - "avi": "video/x-msvideo", - "avs": "video/avs-video", - "aw": "application/applixware", - "awb": "audio/amr-wb", - "axa": "audio/x-annodex", - "axs": "application/olescript", - "axv": "video/x-annodex", - "azf": "application/vnd.airzip.filesecure.azf", - "azs": "application/vnd.airzip.filesecure.azs", - "azv": "image/vnd.airzip.accelerator.azv", - "azw": "application/vnd.amazon.ebook", - "azw3": "application/vnd.amazon.mobi8-ebook", - "b": "chemical/x-molconn-Z", - "bak": "application/x-trash", - "bar": "application/vnd.qualcomm.brew-app-res", - "bas": "text/plain", - "bash": "text/shell", - "bat": "application/x-msdos-program", - "bcpio": "application/x-bcpio", - "bdf": "application/x-font-bdf", - "bdm": "application/vnd.syncml.dm+wbxml", - "bdoc": "application/bdoc", - "bed": "application/vnd.realvnc.bed", - "bh2": "application/vnd.fujitsu.oasysprs", - "bib": "text/x-bibtex", - "bik": "video/vnd.radgamettools.bink", - "bin": "application/octet-stream", - "bk2": "video/vnd.radgamettools.bink", - "bkm": "application/vnd.nervana", - "blb": "application/x-blorb", - "blend": "binary/blender", - "blorb": "application/x-blorb", - "bm": "image/bmp", - "bmed": "multipart/vnd.bint.med-plus", - "bmi": "application/vnd.bmi", - "bmml": "application/vnd.balsamiq.bmml+xml", - "bmp": "image/bmp", - "bmpr": "application/vnd.balsamiq.bmpr", - "boo": "application/book", - "book": "application/book", - "box": "application/vnd.previewsystems.box", - "boz": "application/x-bzip2", - "bpd": "application/vnd.hbci", - "bpk": "application/octet-stream", - "brf": "text/plain", - "bsd": "chemical/x-crossfire", - "bsh": "application/x-bsh", - "bsp": "model/vnd.valve.source.compiled-map", - "btf": "image/prs.btif", - "btif": "image/prs.btif", - "bz": "application/x-bzip", - "bz2": "application/x-bzip2", - "c": "text/x-csrc", - "c++": "text/x-c++src", - "c11amc": "application/vnd.cluetrust.cartomobile-config", - "c11amz": "application/vnd.cluetrust.cartomobile-config-pkg", - "c3d": "chemical/x-chem3d", - "c3ex": "application/cccex", - "c4d": "application/vnd.clonk.c4group", - "c4f": "application/vnd.clonk.c4group", - "c4g": "application/vnd.clonk.c4group", - "c4p": "application/vnd.clonk.c4group", - "c4u": "application/vnd.clonk.c4group", - "cab": "application/vnd.ms-cab-compressed", - "cac": "chemical/x-cache", - "cache": "application/x-cache", - "caf": "audio/x-caf", - "cap": "application/vnd.tcpdump.pcap", - "car": "application/vnd.curl.car", - "cascii": "chemical/x-cactvs-binary", - "cat": "application/vnd.ms-pki.seccat", - "cb7": "application/x-cbr", - "cba": "application/x-cbr", - "cbin": "chemical/x-cactvs-binary", - "cbor": "application/cbor", - "cbr": "application/x-cbr", - "cbt": "application/x-cbr", - "cbz": "application/vnd.comicbook+zip", - "cc": "text/plain", - "ccad": "application/clariscad", - "ccc": "text/vnd.net2phone.commcenter.command", - "ccmp": "application/ccmp+xml", - "cco": "application/x-cocoa", - "cct": "application/x-director", "ccxml": "application/ccxml+xml", - "cda": "application/x-cdf", - "cdbcmsg": "application/vnd.contact.cmsg", - "cdf": "application/x-netcdf", - "cdfx": "application/cdfx+xml", - "cdkey": "application/vnd.mediastation.cdkey", "cdmia": "application/cdmi-capability", "cdmic": "application/cdmi-container", "cdmid": "application/cdmi-domain", "cdmio": "application/cdmi-object", "cdmiq": "application/cdmi-queue", - "cdr": "image/x-coreldraw", - "cdt": "image/x-coreldrawtemplate", - "cdx": "chemical/x-cdx", - "cdxml": "application/vnd.chemdraw+xml", - "cdy": "application/vnd.cinderella", - "cea": "application/cea", - "cef": "chemical/x-cxf", - "cellml": "application/cellml+xml", - "cer": "application/pkix-cert", - "cfg": "text/cfg", - "cfs": "application/x-cfs-compressed", - "cgm": "image/cgm", - "cha": "application/x-chat", - "chat": "application/x-chat", - "chm": "application/vnd.ms-htmlhelp", - "chrt": "application/vnd.kde.kchart", - "cif": "chemical/x-cif", - "cii": "application/vnd.anser-web-certificate-issue-initiation", - "cil": "application/vnd.ms-artgalry", - "cl": "application/simple-filter+xml", - "cla": "application/vnd.claymore", - "class": "application/java-vm", - "clkk": "application/vnd.crick.clicker.keyboard", - "clkp": "application/vnd.crick.clicker.palette", - "clkt": "application/vnd.crick.clicker.template", - "clkw": "application/vnd.crick.clicker.wordbank", - "clkx": "application/vnd.crick.clicker", - "clp": "application/x-msclip", - "cls": "text/x-tex", - "clue": "application/clue_info+xml", - "cmake": "text/cmake", - "cmc": "application/vnd.cosmocaller", - "cmdf": "chemical/x-cmdf", - "cml": "chemical/x-cml", - "cmp": "application/vnd.yellowriver-custom-menu", - "cmsc": "application/cms", - "cmx": "image/x-cmx", - "cnd": "text/jcr-cnd", - "cnf": "text/cnf", - "cod": "application/vnd.rim.cod", - "coffee": "application/vnd.coffeescript", - "com": "application/x-msdos-program", - "conf": "text/plain", - "copyright": "text/vnd.debian.copyright", - "cpa": "chemical/x-compass", - "cpio": "application/x-cpio", - "cpkg": "application/vnd.xmpie.cpkg", - "cpl": "application/cpl+xml", - "cpp": "text/x-c++src", - "cpt": "application/mac-compactpro", - "cr2": "image/x-canon-cr2", - "crd": "application/x-mscardfile", - "crl": "application/pkix-crl", - "crt": "application/x-x509-ca-cert", - "crtr": "application/vnd.multiad.creator", - "crw": "image/x-canon-crw", - "crx": "application/x-chrome-extension", - "cryptonote": "application/vnd.rig.cryptonote", - "cs": "text/c#", - "csf": "chemical/x-cache-csf", - "csh": "application/x-csh", - "csl": "application/vnd.citationstyles.style+xml", - "csm": "chemical/x-csml", - "csml": "chemical/x-csml", - "cson": "text/cson", - "csp": "application/vnd.commonspace", - "csrattrs": "application/csrattrs", - "css": "text/css", - "cst": "application/vnd.commonspace", - "csv": "text/csv", - "csvs": "text/csv-schema", - "ctab": "chemical/x-cactvs-binary", - "ctx": "chemical/x-ctx", "cu": "application/cu-seeme", - "cub": "chemical/x-gaussian-cube", - "cuc": "application/tamp-community-update-confirm", - "curl": "text/vnd.curl", - "cw": "application/prs.cww", - "cww": "application/prs.cww", - "cxf": "chemical/x-cxf", - "cxt": "application/x-director", - "cxx": "text/plain", - "d": "text/x-dsrc", - "dae": "model/vnd.collada+xml", - "daf": "application/vnd.mobius.daf", - "dart": "application/vnd.dart", - "dat": "application/x-ns-proxy-autoconfig", - "dataless": "application/vnd.fdsn.seed", "davmount": "application/davmount+xml", "dbk": "application/docbook+xml", - "dcd": "application/dcd", - "dcf": "application/vnd.oma.drm.content", - "dcm": "application/dicom", - "dcr": "application/x-director", - "dcurl": "text/vnd.curl.dcurl", - "dd": "application/vnd.oma.dd+xml", - "dd2": "application/vnd.oma.dd2+xml", - "ddd": "application/vnd.fujixerox.ddd", - "ddf": "application/vnd.syncml.dmddf+xml", - "deb": "application/vnd.debian.binary-package", - "deepv": "application/x-deepv", - "def": "text/plain", - "deploy": "application/octet-stream", - "der": "application/x-x509-ca-cert", - "dfac": "application/vnd.dreamfactory", - "dgc": "application/x-dgc-compressed", - "dib": "image/bmp", - "dic": "text/x-c", - "dif": "video/x-dv", - "diff": "text/x-diff", - "dii": "application/dii", - "dim": "application/vnd.fastcopy-disk-image", - "dir": "application/x-director", - "dis": "application/vnd.mobius.dis", - "disposition-notification": "message/disposition-notification", - "dist": "application/vnd.apple.installer+xml", - "distz": "application/vnd.apple.installer+xml", - "dit": "application/dit", - "djv": "image/vnd.djvu", - "djvu": "image/vnd.djvu", - "dl": "video/dl", - "dll": "application/x-msdos-program", - "dls": "audio/dls", - "dm": "application/vnd.oma.drm.message", - "dmg": "application/x-apple-diskimage", - "dmp": "application/vnd.tcpdump.pcap", - "dms": "text/vnd.dmclientscript", - "dna": "application/vnd.dna", - "doc": "application/msword", - "docjson": "application/vnd.document+json", - "docm": "application/vnd.ms-word.document.macroenabled.12", - "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "dor": "model/vnd.gdl", - "dot": "text/vnd.graphviz", - "dotm": "application/vnd.ms-word.template.macroenabled.12", - "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", - "dp": "application/vnd.osgi.dp", - "dpg": "application/vnd.dpgraph", - "dpgraph": "application/vnd.dpgraph", - "dpkg": "application/vnd.xmpie.dpkg", - "dr": "application/vnd.oma.drm.rights+xml", - "dra": "audio/vnd.dra", - "drc": "application/vnd.oma.drm.rights+wbxml", - "drle": "image/dicom-rle", - "drw": "application/drafting", - "dsc": "text/prs.lines.tag", - "dsm": "application/vnd.desmume.movie", "dssc": "application/dssc+der", - "dtb": "application/x-dtbook+xml", - "dtd": "application/xml-dtd", - "dts": "audio/vnd.dts", - "dtshd": "audio/vnd.dts.hd", - "dump": "application/octet-stream", - "dv": "video/x-dv", - "dvb": "video/vnd.dvb.file", - "dvc": "application/dvcs", - "dvi": "application/x-dvi", - "dwf": "model/vnd.dwf", - "dwg": "image/vnd.dwg", - "dx": "chemical/x-jcamp-dx", - "dxf": "image/vnd.dxf", - "dxp": "application/vnd.spotfire.dxp", - "dxr": "application/x-director", - "dzr": "application/vnd.dzr", - "ear": "binary/zip", - "ecelp4800": "audio/vnd.nuera.ecelp4800", - "ecelp7470": "audio/vnd.nuera.ecelp7470", - "ecelp9600": "audio/vnd.nuera.ecelp9600", - "ecig": "application/vnd.evolv.ecig.settings", - "ecigprofile": "application/vnd.evolv.ecig.profile", - "ecigtheme": "application/vnd.evolv.ecig.theme", + "xdssc": "application/dssc+xml", "ecma": "application/ecmascript", - "edm": "application/vnd.novadigm.edm", - "edx": "application/vnd.novadigm.edx", - "efi": "application/efi", - "efif": "application/vnd.picsel", - "ei6": "application/vnd.pg.osasli", - "ejs": "text/ejs", - "el": "text/plain", - "elc": "application/x-bytecode.elisp", - "emb": "chemical/x-embl-dl-nucleotide", - "embl": "chemical/x-embl-dl-nucleotide", - "emf": "image/emf", - "eml": "message/rfc822", - "emm": "application/vnd.ibm.electronic-media", "emma": "application/emma+xml", - "emotionml": "application/emotionml+xml", - "emz": "application/x-msmetafile", - "ent": "text/xml-external-parsed-entity", - "entity": "application/vnd.nervana", - "env": "application/x-envoy", - "enw": "audio/evrcnw", - "eol": "audio/vnd.digital-winds", - "eot": "application/vnd.ms-fontobject", - "ep": "application/vnd.bluetooth.ep.oob", - "eps": "application/postscript", - "eps2": "application/postscript", - "eps3": "application/postscript", - "epsf": "application/postscript", - "epsi": "application/postscript", "epub": "application/epub+zip", - "erb": "text/erb", - "erf": "image/x-epson-erf", - "es": "application/ecmascript", - "es3": "application/vnd.eszigno3+xml", - "esa": "application/vnd.osgi.subsystem", - "escn": "text/godot", - "esf": "application/vnd.epson.esf", - "espass": "application/vnd.espass-espass+zip", - "et3": "application/vnd.eszigno3+xml", - "etx": "text/x-setext", - "eva": "application/x-eva", - "evb": "audio/evrcb", - "evc": "audio/evrc", - "evw": "audio/evrcwb", - "evy": "application/x-envoy", - "exe": "application/x-msdos-program", "exi": "application/exi", - "exr": "image/aces", - "ext": "application/vnd.novadigm.ext", - "eyaml": "text/yaml", - "ez": "application/andrew-inset", - "ez2": "application/vnd.ezpix-album", - "ez3": "application/vnd.ezpix-package", - "f": "text/x-fortran", - "f4v": "video/x-f4v", - "f77": "text/x-fortran", - "f90": "text/plain", - "fb": "application/x-maker", - "fbdoc": "application/x-maker", - "fbs": "image/vnd.fastbidsheet", - "fbx": "model/filmbox", - "fcdt": "application/vnd.adobe.formscentral.fcdt", - "fch": "chemical/x-gaussian-checkpoint", - "fchk": "chemical/x-gaussian-checkpoint", - "fcs": "application/vnd.isac.fcs", - "fdf": "application/vnd.fdf", - "fdt": "application/fdt+xml", - "fe_launch": "application/vnd.denovo.fcselayout-link", - "feature": "text/gherkin", - "fg5": "application/vnd.fujitsu.oasysgp", - "fgd": "application/x-director", - "fh": "image/x-freehand", - "fh4": "image/x-freehand", - "fh5": "image/x-freehand", - "fh7": "image/x-freehand", - "fhc": "image/x-freehand", - "fif": "image/fif", - "fig": "application/x-xfig", - "finf": "application/fastinfoset", - "fish": "text/fish", - "fit": "image/fits", - "fits": "image/fits", - "fla": "application/vnd.dtg.local.flash", - "flac": "audio/x-flac", - "fli": "video/x-fli", - "flo": "application/vnd.micrografx.flo", - "flr": "x-world/x-vrml", - "flv": "video/x-flv", - "flw": "application/vnd.kde.kivio", - "flx": "text/vnd.fmi.flexstor", - "fly": "text/vnd.fly", - "fm": "application/vnd.framemaker", - "fmf": "video/x-atomic3d-feature", - "fnc": "application/vnd.frogans.fnc", - "fo": "application/vnd.software602.filler.form+xml", - "for": "text/x-fortran", - "fpx": "image/vnd.fpx", - "frame": "application/vnd.framemaker", - "frl": "application/freeloader", - "frm": "application/vnd.ufdl", - "fsc": "application/vnd.fsc.weblaunch", - "fst": "image/vnd.fst", - "ftc": "application/vnd.fluxtime.clip", - "fti": "application/vnd.anser-web-funds-transfer-initiation", - "fts": "image/fits", - "funk": "audio/make", - "fvt": "video/vnd.fvt", - "fxm": "video/x-javafx", - "fxp": "application/vnd.adobe.fxp", - "fxpl": "application/vnd.adobe.fxp", - "fzs": "application/vnd.fuzzysheet", - "g": "text/plain", - "g2w": "application/vnd.geoplan", - "g3": "image/g3fax", - "g3w": "application/vnd.geospace", - "gac": "application/vnd.groove-account", - "gal": "chemical/x-gaussian-log", - "gam": "application/x-tads", - "gamin": "chemical/x-gamess-input", - "gau": "chemical/x-gaussian-input", - "gbr": "application/rpki-ghostbusters", - "gca": "application/x-gca-compressed", - "gcd": "text/x-pcs-gcd", - "gcf": "application/x-graphing-calculator", - "gcg": "chemical/x-gcg8-sequence", - "gdl": "model/vnd.gdl", - "gdoc": "application/vnd.google-apps.document", - "gemspec": "text/ruby", - "gen": "chemical/x-genbank", - "geo": "application/vnd.dynageo", - "geojson": "application/geo+json", - "gex": "application/vnd.geometry-explorer", - "gf": "application/x-tex-gf", - "ggb": "application/vnd.geogebra.file", - "ggt": "application/vnd.geogebra.tool", - "ghf": "application/vnd.groove-help", - "gif": "image/gif", - "gim": "application/vnd.groove-identity-message", - "gjc": "chemical/x-gaussian-input", - "gjf": "chemical/x-gaussian-input", - "gl": "video/gl", - "glb": "model/gltf-binary", - "gltf": "model/gltf+json", + "pfr": "application/font-tdpfr", "gml": "application/gml+xml", - "gmx": "application/vnd.gmx", - "gnumeric": "application/x-gnumeric", - "go": "text/go", - "gotmpl": "text/gotmpl", - "gph": "application/vnd.flographit", - "gpt": "chemical/x-mopac-graph", "gpx": "application/gpx+xml", - "gqf": "application/vnd.grafeq", - "gqs": "application/vnd.grafeq", - "gradle": "text/groovy", - "gram": "application/srgs", - "gramps": "application/x-gramps-xml", - "gre": "application/vnd.geometry-explorer", - "groovy": "text/groovy", - "grv": "application/vnd.groove-injector", - "grxml": "application/srgs+xml", - "gsd": "audio/x-gsm", - "gsf": "application/x-font-ghostscript", - "gsheet": "application/vnd.google-apps.spreadsheet", - "gslides": "application/vnd.google-apps.presentation", - "gsm": "model/vnd.gdl", - "gsp": "application/x-gsp", - "gss": "application/x-gss", - "gtar": "application/x-gtar", - "gtm": "application/vnd.groove-tool-message", - "gtw": "model/vnd.gtw", - "gv": "text/vnd.graphviz", "gxf": "application/gxf", - "gxt": "application/vnd.geonext", - "gyb": "text/gyb", - "gyp": "text/gyp", - "gypi": "text/gyp", - "gz": "application/gzip", - "h": "text/x-chdr", - "h++": "text/x-c++hdr", - "h261": "video/h261", - "h263": "video/h263", - "h264": "video/h264", - "hal": "application/vnd.hal+xml", - "hbc": "application/vnd.hbci", - "hbci": "application/vnd.hbci", - "hbs": "text/x-handlebars-template", - "hdd": "application/x-virtualbox-hdd", - "hdf": "application/x-hdf", - "hdr": "image/vnd.radiance", - "hdt": "application/vnd.hdt", - "heic": "image/heic", - "heics": "image/heic-sequence", - "heif": "image/heif", - "heifs": "image/heif-sequence", - "help": "application/x-helpfile", - "hgl": "application/vnd.hp-hpgl", - "hh": "text/plain", - "hin": "chemical/x-hin", - "hjson": "application/hjson", - "hlb": "text/x-script", - "hlp": "application/winhlp", - "hpg": "application/vnd.hp-hpgl", - "hpgl": "application/vnd.hp-hpgl", - "hpi": "application/vnd.hp-hpid", - "hpid": "application/vnd.hp-hpid", - "hpp": "text/x-c++hdr", - "hps": "application/vnd.hp-hps", - "hpub": "application/prs.hpub+zip", - "hqx": "application/mac-binhex40", - "hs": "text/x-haskell", - "hta": "application/hta", - "htc": "text/x-component", - "htke": "application/vnd.kenameaapp", - "html": "text/html", - "htt": "text/webviewhtml", - "hvd": "application/vnd.yamaha.hv-dic", - "hvp": "application/vnd.yamaha.hv-voice", - "hvs": "application/vnd.yamaha.hv-script", - "hx": "text/haxe", - "hxml": "text/haxe", - "hxx": "text/plain", - "i2g": "application/vnd.intergeo", - "ic0": "application/vnd.commerce-battelle", - "ic1": "application/vnd.commerce-battelle", - "ic2": "application/vnd.commerce-battelle", - "ic3": "application/vnd.commerce-battelle", - "ic4": "application/vnd.commerce-battelle", - "ic5": "application/vnd.commerce-battelle", - "ic6": "application/vnd.commerce-battelle", - "ic7": "application/vnd.commerce-battelle", - "ic8": "application/vnd.commerce-battelle", - "ica": "application/vnd.commerce-battelle", - "icc": "application/vnd.iccprofile", - "icd": "application/vnd.commerce-battelle", - "ice": "x-conference/x-cooltalk", - "icf": "application/vnd.commerce-battelle", - "icm": "application/vnd.iccprofile", - "icns": "binary/icns", - "ico": "image/x-icon", - "ics": "text/calendar", - "icz": "text/calendar", - "idc": "text/plain", - "idl": "text/idl", - "ief": "image/ief", - "iefs": "image/ief", - "ifb": "text/calendar", - "ifm": "application/vnd.shana.informed.formdata", - "iges": "model/iges", - "igl": "application/vnd.igloader", - "igm": "application/vnd.insors.igm", - "ign": "application/vnd.coreos.ignition+json", - "ignition": "application/vnd.coreos.ignition+json", - "igs": "model/iges", - "igx": "application/vnd.micrografx.igx", - "iif": "application/vnd.shana.informed.interchange", - "iii": "application/x-iphone", - "ima": "application/x-ima", - "imap": "application/x-httpd-imap", - "imf": "application/vnd.imagemeter.folder+zip", - "img": "application/octet-stream", - "imgcal": "application/vnd.3lightssoftware.imagescal", - "imi": "application/vnd.imagemeter.image+zip", - "imp": "application/vnd.accpac.simply.imp", - "ims": "application/vnd.ms-ims", - "imscc": "application/vnd.ims.imsccv1p1", - "in": "text/plain", - "inc": "text/inc", - "inf": "application/inf", - "info": "application/x-info", - "ini": "text/ini", + "stk": "application/hyperstudio", "ink": "application/inkml+xml", "inkml": "application/inkml+xml", - "inp": "chemical/x-gamess-input", - "ins": "application/x-internet-signup", - "install": "application/x-install-instructions", - "iota": "application/vnd.astraea-software.iota", - "ip": "application/x-ip2", "ipfix": "application/ipfix", - "ipk": "application/vnd.shana.informed.package", - "irm": "application/vnd.ibm.rights-management", - "irp": "application/vnd.irepository.package+xml", - "ism": "model/vnd.gdl", - "iso": "application/x-iso9660-image", - "isp": "application/x-internet-signup", - "ist": "chemical/x-isostar", - "istr": "chemical/x-isostar", - "isu": "video/x-isvideo", - "it": "audio/it", - "itp": "application/vnd.shana.informed.formtemplate", - "its": "application/its+xml", - "iv": "application/x-inventor", - "ivp": "application/vnd.immervision-ivp", - "ivr": "i-world/i-vrml", - "ivu": "application/vnd.immervision-ivu", - "ivy": "application/x-livescreen", - "j2": "text/jinja", - "jad": "text/vnd.sun.j2me.app-descriptor", - "jade": "text/jade", - "jam": "application/vnd.jam", - "jar": "application/x-java-archive", - "jardiff": "application/x-java-archive-diff", - "java": "text/x-java-source", - "jcm": "application/x-java-commerce", - "jdx": "chemical/x-jcamp-dx", - "jenkinsfile": "text/groovy", - "jfif": "image/jpeg", - "jinja": "text/jinja", - "jinja2": "text/jinja", - "jisp": "application/vnd.jisp", - "jls": "image/jls", - "jlt": "application/vnd.hp-jlyt", - "jl": "text/julia", - "jmz": "application/x-jmol", - "jng": "image/x-jng", - "jnlp": "application/x-java-jnlp-file", - "joda": "application/vnd.joost.joda-archive", - "jp2": "image/jp2", - "jpe": "image/jpeg", - "jpeg": "image/jpeg", - "jpf": "image/jpx", - "jpg": "image/jpeg", - "jpg2": "image/jp2", - "jpgm": "image/jpm", - "jpgv": "video/jpeg", - "jpm": "image/jpm", - "jps": "image/x-jps", - "jpx": "image/jpx", - "jrd": "application/jrd+json", - "js": "application/javascript", + "jar": "application/java-archive", + "ser": "application/java-serialized-object", + "class": "application/java-vm", "json": "application/json", - "json-patch": "application/json-patch+json", - "json5": "application/json5", - "jsonld": "application/ld+json", "jsonml": "application/jsonml+json", - "jsx": "text/jsx", - "jtd": "text/vnd.esmertec.theme-descriptor", - "jut": "image/jutvision", - "kar": "audio/midi", - "karbon": "application/vnd.kde.karbon", - "kcm": "application/vnd.nervana", - "key": "application/pgp-keys", - "keynote": "application/vnd.apple.keynote", - "kfo": "application/vnd.kde.kformula", - "kia": "application/vnd.kidspiration", - "kil": "application/x-killustrator", - "kin": "chemical/x-kinemage", - "kml": "application/vnd.google-earth.kml+xml", - "kmz": "application/vnd.google-earth.kmz", - "kne": "application/vnd.kinar", - "knp": "application/vnd.kinar", - "kom": "application/vnd.hbci", - "kon": "application/vnd.kde.kontour", - "koz": "audio/vnd.audikoz", - "kpr": "application/vnd.kde.kpresenter", - "kpt": "application/vnd.kde.kpresenter", - "kpxx": "application/vnd.ds-keypoint", - "ksh": "application/x-ksh", - "ksp": "application/vnd.kde.kspread", - "kt": "text/kotlin", - "ktr": "application/vnd.kahootz", - "ktx": "image/ktx", - "ktz": "application/vnd.kahootz", - "kwd": "application/vnd.kde.kword", - "kwt": "application/vnd.kde.kword", - "l16": "audio/l16", - "la": "audio/nspaudio", - "lam": "audio/x-liveaudio", - "lasjson": "application/vnd.las.las+json", - "lasxml": "application/vnd.las.las+xml", - "latex": "application/x-latex", - "lbc": "audio/ilbc", - "lbd": "application/vnd.llamagraphics.life-balance.desktop", - "lbe": "application/vnd.llamagraphics.life-balance.exchange+xml", - "le": "application/vnd.bluetooth.le.oob", - "les": "application/vnd.hhe.lesson-player", - "less": "text/less", - "lgr": "application/lgr+xml", - "lha": "application/octet-stream", - "lhs": "text/x-literate-haskell", - "lhx": "application/octet-stream", - "lin": "application/bbolin", - "link66": "application/vnd.route66.link66+xml", - "list": "text/plain", - "list3820": "application/vnd.ibm.modcap", - "listafp": "application/vnd.ibm.modcap", - "lmp": "model/vnd.gdl", - "lnk": "application/x-ms-shortcut", - "log": "text/plain", - "lostsyncxml": "application/lostsync+xml", "lostxml": "application/lost+xml", - "lrf": "application/octet-stream", - "lrm": "application/vnd.ms-lrm", - "lsf": "video/x-la-asf", - "lsp": "text/x-script.lisp", - "lst": "text/plain", - "lsx": "video/x-la-asf", - "ltf": "application/vnd.frogans.ltf", - "ltx": "application/x-latex", - "lua": "text/x-lua", - "luac": "application/x-lua-bytecode", - "lvp": "audio/vnd.lucent.voice", - "lwp": "application/vnd.lotus-wordpro", - "lxf": "application/lxf", - "lyx": "application/x-lyx", - "lzh": "application/octet-stream", - "lzx": "application/x-lzx", - "m": "application/vnd.wolfram.mathematica.package", - "m13": "application/x-msmediaview", - "m14": "application/x-msmediaview", - "m15": "audio/x-mod", - "m1v": "video/mpeg", - "m21": "application/mp21", - "m2a": "audio/mpeg", - "m2v": "video/mpeg", - "m3a": "audio/mpeg", - "m3g": "application/m3g", - "m3u": "audio/x-mpegurl", - "m3u8": "application/vnd.apple.mpegurl", - "m4a": "audio/x-m4a", - "m4s": "video/iso.segment", - "m4u": "video/vnd.mpegurl", - "m4v": "video/x-m4v", - "ma": "application/mathematica", + "hqx": "application/mac-binhex40", + "cpt": "application/mac-compactpro", "mads": "application/mads+xml", - "mag": "application/vnd.ecowin.chart", - "mail": "message/rfc822", - "maker": "application/vnd.framemaker", - "man": "application/x-troff-man", - "manifest": "text/cache-manifest", - "map": "application/x-navimap", - "mar": "text/plain", - "markdown": "text/markdown", - "mathml": "application/mathml+xml", + "mrc": "application/marc", + "mrcx": "application/marcxml+xml", + "ma": "application/mathematica", + "nb": "application/mathematica", "mb": "application/mathematica", - "mbd": "application/mbedlet", - "mbk": "application/vnd.mobius.mbk", + "mathml": "application/mathml+xml", "mbox": "application/mbox", - "mc$": "application/x-magic-cap-package-1.0", - "mc1": "application/vnd.medcalcdata", - "mcd": "application/vnd.mcd", - "mcf": "image/vasa", - "mcif": "chemical/x-mmcif", - "mcm": "chemical/x-macmolecule", - "mcp": "application/netmc", - "mcurl": "text/vnd.curl.mcurl", - "md": "text/markdown", - "mdb": "application/x-msaccess", - "mdc": "application/vnd.marlin.drm.mdcf", - "mdi": "image/vnd.ms-modi", - "me": "application/x-troff-me", - "med": "audio/x-mod", - "mesh": "model/mesh", - "meta4": "application/metalink4+xml", + "mscml": "application/mediaservercontrol+xml", "metalink": "application/metalink+xml", + "meta4": "application/metalink4+xml", "mets": "application/mets+xml", - "mf4": "application/mf4", - "mfm": "application/vnd.mfmp", - "mft": "application/rpki-manifest", - "mgp": "application/vnd.osgeo.mapguide.package", - "mgz": "application/vnd.proteus.magazine", - "mht": "message/rfc822", - "mhtml": "message/rfc822", - "mib": "text/mib", - "mid": "audio/midi", - "midi": "audio/midi", - "mie": "application/x-mie", - "mif": "application/x-mif", - "mime": "message/rfc822", - "miz": "text/mizar", - "mj2": "video/mj2", - "mjf": "audio/x-vnd.audioexplosion.mjuicemediafile", - "mjp2": "video/mj2", - "mjpg": "video/x-motion-jpeg", - "mjs": "application/javascript", - "mk": "text/makefile", - "mk3d": "video/x-matroska-3d", - "mka": "audio/x-matroska", - "mkd": "text/x-markdown", - "mks": "video/x-matroska", - "mkv": "video/x-matroska", - "mlp": "application/vnd.dolby.mlp", - "mm": "application/x-freemind", - "mmd": "application/vnd.chipnuts.karaoke-mmd", - "mmdb": "application/vnd.maxmind.maxmind-db", - "mme": "application/base64", - "mmf": "application/vnd.smaf", - "mml": "text/mathml", - "mmod": "chemical/x-macromodel-input", - "mmr": "image/vnd.fujixerox.edmics-mmr", - "mms": "application/vnd.wap.mms-message", - "mng": "video/x-mng", - "mny": "application/x-msmoney", - "mobi": "application/x-mobipocket-ebook", - "moc": "text/x-moc", - "mod": "audio/x-mod", - "model-inter": "application/vnd.vd-study", "mods": "application/mods+xml", - "modulemap": "text/modulemap", - "mol": "chemical/x-mdl-molfile", - "mol2": "chemical/x-mol2", - "moml": "model/vnd.moml+xml", - "moo": "chemical/x-mopac-out", - "moov": "video/quicktime", - "mop": "chemical/x-mopac-input", - "mopcrt": "chemical/x-mopac-input", - "mov": "video/quicktime", - "movie": "video/x-sgi-movie", - "mp1": "audio/mpeg", - "mp2": "audio/mpeg", + "m21": "application/mp21", "mp21": "application/mp21", - "mp2a": "audio/mpeg", - "mp3": "audio/mp3", - "mp4": "video/mp4", - "mp4a": "audio/mp4", "mp4s": "application/mp4", - "mp4v": "video/mp4", - "mpa": "video/mpeg", - "mpc": "application/vnd.mophun.certificate", - "mpd": "application/dash+xml", - "mpdd": "application/dashdelta", - "mpe": "video/mpeg", - "mpeg": "video/mpeg", - "mpega": "audio/mpeg", - "mpf": "text/vnd.ms-mediapackage", - "mpg": "video/mpeg", - "mpg4": "video/mp4", - "mpga": "audio/mpeg", - "mpkg": "application/vnd.apple.installer+xml", - "mpm": "application/vnd.blueice.multipass", - "mpn": "application/vnd.mophun.application", - "mpp": "application/vnd.ms-project", - "mpt": "application/vnd.ms-project", - "mpv": "application/x-project", - "mpv2": "video/mpeg", - "mpx": "application/x-project", - "mpy": "application/vnd.ibm.minipay", - "mqy": "application/vnd.mobius.mqy", - "mrc": "application/marc", - "mrcx": "application/marcxml+xml", - "ms": "application/x-troff-ms", - "msa": "application/vnd.msa-disk-image", - "mscml": "application/mediaservercontrol+xml", - "msd": "application/vnd.fdsn.mseed", - "mseed": "application/vnd.fdsn.mseed", - "mseq": "application/vnd.mseq", - "msf": "application/vnd.epson.msf", - "msg": "application/vnd.ms-outlook", - "msh": "model/mesh", - "msi": "application/x-msi", - "msl": "application/vnd.mobius.msl", - "msm": "model/vnd.gdl", - "msty": "application/vnd.muvee.style", - "mtm": "audio/x-mod", - "mts": "model/vnd.mts", - "multitrack": "audio/vnd.presonus.multitrack", - "mus": "application/vnd.musician", - "musd": "application/mmt-usd+xml", - "musicxml": "application/vnd.recordare.musicxml+xml", - "mv": "video/x-sgi-movie", - "mvb": "application/x-msmediaview", - "mvt": "application/vnd.mapbox-vector-tile", - "mwc": "application/vnd.dpgraph", - "mwf": "application/vnd.mfer", + "doc": "application/msword", + "dot": "application/msword", "mxf": "application/mxf", - "mxi": "application/vnd.vd-study", - "mxl": "application/vnd.recordare.musicxml", - "mxmf": "audio/mobile-xmf", - "mxml": "application/xv+xml", - "mxs": "application/vnd.triscape.mxs", - "mxu": "video/vnd.mpegurl", - "my": "audio/make", - "mzz": "application/x-vnd.audioexplosion.mzz", - "n-gage": "application/vnd.nokia.n-gage.symbian.install", - "n3": "text/n3", - "nap": "image/naplps", - "naplps": "image/naplps", - "nb": "application/mathematica", - "nbp": "application/vnd.wolfram.player", - "nc": "application/x-netcdf", - "ncm": "application/vnd.nokia.configuration-message", - "ncx": "application/x-dtbncx+xml", - "ndc": "application/vnd.osa.netdeploy", - "ndjson": "application/json", - "ndl": "application/vnd.lotus-notes", - "nds": "application/vnd.nintendo.nitro.rom", - "nef": "image/x-nikon-nef", - "nfo": "text/x-nfo", - "ngdat": "application/vnd.nokia.n-gage.data", - "ngdoc": "text/ngdoc", - "nif": "image/x-niff", - "niff": "image/x-niff", - "nim": "text/nim", - "nimble": "text/nimble", - "nimf": "text/nim", - "nims": "text/nim", - "nitf": "application/vnd.nitf", - "nix": "application/x-mix-transfer", - "nlu": "application/vnd.neurolanguage.nlu", - "nml": "application/vnd.enliven", - "nnd": "application/vnd.noblenet-directory", - "nns": "application/vnd.noblenet-sealer", - "nnw": "application/vnd.noblenet-web", - "notebook": "application/vnd.smart.notebook", - "npx": "image/vnd.net-fpx", - "nq": "application/n-quads", - "ns2": "application/vnd.lotus-notes", - "ns3": "application/vnd.lotus-notes", - "ns4": "application/vnd.lotus-notes", - "nsc": "application/x-conference", - "nsf": "application/vnd.lotus-notes", - "nsg": "application/vnd.lotus-notes", - "nsh": "application/vnd.lotus-notes", - "nt": "application/n-triples", - "ntf": "application/vnd.lotus-notes", - "numbers": "application/vnd.apple.numbers", - "nvd": "application/x-navidoc", - "nwc": "application/x-nwc", - "nws": "message/rfc822", - "nzb": "application/x-nzb", - "o": "application/x-object", - "o4a": "application/vnd.oma.drm.dcf", - "o4v": "application/vnd.oma.drm.dcf", - "oa2": "application/vnd.fujitsu.oasys2", - "oa3": "application/vnd.fujitsu.oasys3", - "oas": "application/vnd.fujitsu.oasys", - "obd": "application/x-msbinder", - "obg": "application/vnd.openblox.game-binary", - "obgx": "application/vnd.openblox.game+xml", - "obj": "application/x-tgif", + "bin": "application/octet-stream", + "dms": "application/octet-stream", + "lrf": "application/octet-stream", + "mar": "application/octet-stream", + "so": "application/octet-stream", + "dist": "application/octet-stream", + "distz": "application/octet-stream", + "pkg": "application/octet-stream", + "bpk": "application/octet-stream", + "dump": "application/octet-stream", + "elc": "application/octet-stream", + "deploy": "application/octet-stream", "oda": "application/oda", - "odb": "application/vnd.oasis.opendocument.database", - "odc": "application/vnd.oasis.opendocument.chart", - "odd": "application/tei+xml", - "odf": "application/vnd.oasis.opendocument.formula", - "odft": "application/vnd.oasis.opendocument.formula-template", - "odg": "application/vnd.oasis.opendocument.graphics", - "odi": "application/vnd.oasis.opendocument.image", - "odm": "application/vnd.oasis.opendocument.text-master", - "odp": "application/vnd.oasis.opendocument.presentation", - "ods": "application/vnd.oasis.opendocument.spreadsheet", - "odt": "application/vnd.oasis.opendocument.text", - "odx": "application/odx", - "oeb": "application/vnd.openeye.oeb", - "oga": "audio/ogg", - "ogex": "model/vnd.opengex", - "ogg": "audio/ogg", - "ogv": "video/ogg", + "opf": "application/oebps-package+xml", "ogx": "application/ogg", - "old": "application/x-trash", - "omc": "application/x-omc", - "omcd": "application/x-omcdatamaker", - "omcr": "application/x-omcregerator", "omdoc": "application/omdoc+xml", - "omg": "audio/atrac3", - "onepkg": "application/onenote", - "onetmp": "application/onenote", "onetoc": "application/onenote", "onetoc2": "application/onenote", - "opf": "application/oebps-package+xml", - "opml": "text/x-opml", - "oprc": "application/vnd.palm", - "opus": "audio/ogg", - "or2": "application/vnd.lotus-organizer", - "or3": "application/vnd.lotus-organizer", - "orf": "image/x-olympus-orf", - "org": "text/x-org", - "orq": "application/ocsp-request", - "ors": "application/ocsp-response", - "osf": "application/vnd.yamaha.openscoreformat", - "osfpvg": "application/vnd.yamaha.openscoreformat.osfpvg+xml", - "osm": "application/vnd.openstreetmap.data+xml", - "otc": "application/vnd.oasis.opendocument.chart-template", - "otf": "font/otf", - "otg": "application/vnd.oasis.opendocument.graphics-template", - "oth": "application/vnd.oasis.opendocument.text-web", - "oti": "application/vnd.oasis.opendocument.image-template", - "otp": "application/vnd.oasis.opendocument.presentation-template", - "ots": "application/vnd.oasis.opendocument.spreadsheet-template", - "ott": "application/vnd.oasis.opendocument.text-template", - "ova": "application/x-virtualbox-ova", - "ovf": "application/x-virtualbox-ovf", - "owx": "application/owl+xml", - "oxlicg": "application/vnd.oxli.countgraph", + "onetmp": "application/onenote", + "onepkg": "application/onenote", "oxps": "application/oxps", - "oxt": "application/vnd.openofficeorg.extension", - "oza": "application/x-oz-application", - "p": "text/x-pascal", + "xer": "application/patch-ops-error+xml", + "pdf": "application/pdf", + "pgp": "application/pgp-encrypted", + "asc": "application/pgp-signature", + "sig": "application/pgp-signature", + "prf": "application/pics-rules", "p10": "application/pkcs10", - "p12": "application/pkcs12", - "p2p": "application/vnd.wfa.p2p", - "p7a": "application/x-pkcs7-signature", - "p7b": "application/x-pkcs7-certificates", - "p7c": "application/pkcs7-mime", "p7m": "application/pkcs7-mime", - "p7r": "application/x-pkcs7-certreqresp", + "p7c": "application/pkcs7-mime", "p7s": "application/pkcs7-signature", "p8": "application/pkcs8", - "pac": "application/x-ns-proxy-autoconfig", - "pack": "application/x-java-pack200", - "package": "application/vnd.autopackage", - "pages": "application/vnd.apple.pages", - "par": "text/plain-bas", - "part": "application/pro_eng", - "pas": "text/pascal", - "pat": "image/x-coreldrawpattern", - "patch": "text/x-diff", - "paw": "application/vnd.pawaafile", - "pbd": "application/vnd.powerbuilder6", - "pbm": "image/x-portable-bitmap", - "pcap": "application/vnd.tcpdump.pcap", - "pcf": "application/x-font-pcf", - "pcl": "application/vnd.hp-pcl", - "pclxl": "application/vnd.hp-pclxl", - "pct": "image/x-pict", - "pcurl": "application/vnd.curl.pcurl", - "pcx": "image/x-pcx", - "pdb": "application/vnd.palm", - "pde": "text/x-processing", - "pdf": "application/pdf", - "pdx": "application/pdx", - "pem": "text/pem", - "pfa": "application/x-font-type1", - "pfb": "application/x-font-type1", - "pfm": "application/x-font-type1", - "pfr": "application/font-tdpfr", - "pfunk": "audio/make", - "pfx": "application/pkcs12", - "pgb": "image/vnd.globalgraphics.pgb", - "pgm": "image/x-portable-graymap", - "pgn": "application/x-chess-pgn", - "pgp": "application/pgp-encrypted", - "php": "application/x-httpd-php", - "php3": "application/x-httpd-php3", - "php3p": "application/x-httpd-php3-preprocessed", - "php4": "application/x-httpd-php4", - "php5": "application/x-httpd-php5", - "phps": "application/x-httpd-php-source", - "pht": "application/x-httpd-php", - "phtml": "application/x-httpd-php", - "pic": "image/pict", - "pict": "image/pict", - "pil": "application/vnd.piaccess.application-license", - "pk": "application/x-tex-pk", - "pkd": "application/vnd.hbci", - "pkg": "application/vnd.apple.installer+xml", - "pki": "application/pkixcmp", + "ac": "application/pkix-attr-cert", + "cer": "application/pkix-cert", + "crl": "application/pkix-crl", "pkipath": "application/pkix-pkipath", - "pko": "application/ynd.ms-pkipko", - "pkpass": "application/vnd.apple.pkpass", - "pl": "application/x-perl", - "plantuml": "text/plantuml", - "plb": "application/vnd.3gpp.pic-bw-large", - "plc": "application/vnd.mobius.plc", - "plf": "application/vnd.pocketlearn", - "plj": "audio/vnd.everad.plj", - "plp": "application/vnd.panoply", + "pki": "application/pkixcmp", "pls": "application/pls+xml", - "plx": "application/x-pixclscript", - "ply": "model/stanford", - "pm": "text/plain", - "pm4": "application/x-pagemaker", - "pm5": "application/x-pagemaker", - "pma": "application/x-perfmon", - "pmc": "application/x-perfmon", - "pml": "application/vnd.ctc-posml", - "pmr": "application/x-perfmon", - "pmw": "application/x-perfmon", - "png": "image/png", - "pnm": "image/x-portable-anymap", - "po": "text/pofile", - "pod": "text/x-pod", - "portpkg": "application/vnd.macports.portpkg", - "pot": "application/vnd.ms-powerpoint", - "potm": "application/vnd.ms-powerpoint.template.macroenabled.12", - "potx": "application/vnd.openxmlformats-officedocument.presentationml.template", - "pov": "model/x-pov", - "pp": "text/puppet", - "ppa": "application/vnd.ms-powerpoint", - "ppam": "application/vnd.ms-powerpoint.addin.macroenabled.12", - "ppd": "application/vnd.cups-ppd", - "ppkg": "application/vnd.xmpie.ppkg", - "ppm": "image/x-portable-pixmap", - "pps": "application/vnd.ms-powerpoint", - "ppsm": "application/vnd.ms-powerpoint.slideshow.macroenabled.12", - "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", - "ppt": "application/vnd.ms-powerpoint", - "pptm": "application/vnd.ms-powerpoint.presentation.macroenabled.12", - "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "ppz": "application/mspowerpoint", - "pqa": "application/vnd.palm", - "prc": "application/vnd.palm", - "pre": "application/vnd.lotus-freelance", - "preminet": "application/vnd.preminet", - "prf": "application/pics-rules", - "proto": "text/proto", - "provn": "text/provenance-notation", - "provx": "application/provenance+xml", - "prt": "application/pro_eng", - "prz": "application/vnd.lotus-freelance", + "ai": "application/postscript", + "eps": "application/postscript", "ps": "application/postscript", - "psb": "application/vnd.3gpp.pic-bw-small", - "psd": "image/vnd.adobe.photoshop", - "pseg3820": "application/vnd.ibm.modcap", - "psf": "application/x-font-linux-psf", - "psid": "audio/prs.sid", + "cww": "application/prs.cww", "pskcxml": "application/pskc+xml", - "pti": "image/prs.pti", - "ptid": "application/vnd.pvi.ptid1", - "pub": "application/x-mspublisher", - "purs": "text/purescript", - "pvb": "application/vnd.3gpp.pic-bw-var", - "pvu": "paleovu/x-pv", - "pwn": "application/vnd.3m.post-it-notes", - "pwz": "application/vnd.ms-powerpoint", - "pxd": "text/cython", - "pxi": "text/cython", - "py": "text/x-script.phyton", - "pya": "audio/vnd.ms-playready.media.pya", - "pyc": "application/x-python-code", - "pyi": "text/pyi", - "pyo": "application/x-python-code", - "pyv": "video/vnd.ms-playready.media.pyv", - "pyx": "text/cython", - "qam": "application/vnd.epson.quickanime", - "qbo": "application/vnd.intu.qbo", - "qca": "application/vnd.ericsson.quickcall", - "qcall": "application/vnd.ericsson.quickcall", - "qcp": "audio/qcelp", - "qd3": "x-world/x-3dmf", - "qd3d": "x-world/x-3dmf", - "qfx": "application/vnd.intu.qfx", - "qgs": "application/x-qgis", - "qif": "image/x-quicktime", - "qps": "application/vnd.publishare-delta-tree", - "qt": "video/quicktime", - "qtc": "video/x-qtc", - "qti": "image/x-quicktime", - "qtif": "image/x-quicktime", - "qtl": "application/x-quicktimeplayer", - "quiz": "application/vnd.quobject-quoxdocument", - "quox": "application/vnd.quobject-quoxdocument", - "qvd": "application/vnd.theqvd", - "qwd": "application/vnd.quark.quarkxpress", - "qwt": "application/vnd.quark.quarkxpress", - "qxb": "application/vnd.quark.quarkxpress", - "qxd": "application/vnd.quark.quarkxpress", - "qxl": "application/vnd.quark.quarkxpress", - "qxt": "application/vnd.quark.quarkxpress", - "r": "text/r", - "ra": "audio/x-realaudio", - "ram": "audio/x-pn-realaudio", - "raml": "application/raml+yaml", - "rapd": "application/route-apd+xml", - "rar": "application/x-rar-compressed", - "ras": "image/x-cmu-raster", - "rast": "image/cmu-raster", - "rb": "application/x-ruby", - "rcprofile": "application/vnd.ipunplugged.rcprofile", - "rct": "application/prs.nprend", - "rd": "chemical/x-mdl-rdfile", - "rda": "text/r", - "rdata": "text/r", - "rds": "text/r", "rdf": "application/rdf+xml", - "rdf-crypt": "application/prs.rdf-xml-crypt", - "rdz": "application/vnd.data-vision.rdz", - "relo": "application/p2p-overlay+xml", - "rep": "application/vnd.businessobjects", - "request": "application/vnd.nervana", - "res": "application/x-dtbresource+xml", - "rexx": "text/x-script.rexx", - "rf": "image/vnd.rn-realflash", - "rfcxml": "application/rfc+xml", - "rgb": "image/x-rgb", - "rgbe": "image/vnd.radiance", - "rhtml": "application/x-httpd-eruby", "rif": "application/reginfo+xml", - "rip": "audio/vnd.rip", - "ris": "application/x-research-info-systems", + "rnc": "application/relax-ng-compact-syntax", "rl": "application/resource-lists+xml", - "rlc": "image/vnd.fujixerox.edmics-rlc", "rld": "application/resource-lists-diff+xml", - "rlib": "text/rust", - "rm": "application/vnd.rn-realmedia", - "rmi": "audio/mid", - "rmm": "audio/x-pn-realaudio", - "rmp": "audio/x-pn-realaudio-plugin", - "rms": "application/vnd.jcp.javame.midlet-rms", - "rmvb": "application/vnd.rn-realmedia-vbr", - "rnc": "application/relax-ng-compact-syntax", - "rnd": "application/prs.nprend", - "rng": "text/xml", - "rnx": "application/vnd.rn-realplayer", - "roa": "application/rpki-roa", - "roff": "text/troff", - "ros": "chemical/x-rosdal", - "rp": "image/vnd.rn-realpix", - "rp9": "application/vnd.cloanto.rp9", - "rpm": "application/x-redhat-package-manager", - "rpss": "application/vnd.nokia.radio-presets", - "rpst": "application/vnd.nokia.radio-preset", - "rq": "application/sparql-query", "rs": "application/rls-services+xml", + "gbr": "application/rpki-ghostbusters", + "mft": "application/rpki-manifest", + "roa": "application/rpki-roa", "rsd": "application/rsd+xml", - "rsheet": "application/urc-ressheet+xml", - "rsm": "model/vnd.gdl", "rss": "application/rss+xml", - "rst": "text/prs.fallenstein.rst", - "rt": "text/richtext", - "rtf": "text/rtf", - "rtx": "text/richtext", - "run": "application/x-makeself", - "rusd": "application/route-usd+xml", - "rv": "video/vnd.rn-realvideo", - "rxn": "chemical/x-mdl-rxnfile", - "s": "text/x-asm", - "s11": "video/vnd.sealed.mpeg1", - "s14": "video/vnd.sealed.mpeg4", - "s1a": "application/vnd.sealedmedia.softseal.pdf", - "s1e": "application/vnd.sealed.xls", - "s1g": "image/vnd.sealedmedia.softseal.gif", - "s1h": "application/vnd.sealedmedia.softseal.html", - "s1j": "image/vnd.sealedmedia.softseal.jpg", - "s1m": "audio/vnd.sealedmedia.softseal.mpeg", - "s1n": "image/vnd.sealed.png", - "s1p": "application/vnd.sealed.ppt", - "s1q": "video/vnd.sealedmedia.softseal.mov", - "s1w": "application/vnd.sealed.doc", - "s3df": "application/vnd.sealed.3df", - "s3m": "audio/s3m", - "sac": "application/tamp-sequence-adjust-confirm", - "saf": "application/vnd.yamaha.smaf-audio", - "sam": "application/vnd.lotus-wordpro", - "sandboxed": "text/html-sandboxed", - "sass": "text/x-sass", - "saveme": "application/octet-stream", - "sbk": "application/x-tbook", + "rtf": "application/rtf", "sbml": "application/sbml+xml", - "sc": "application/vnd.ibm.secure-container", - "scala": "text/x-scala", - "scd": "application/x-msschedule", - "sce": "application/vnd.etsi.asic-e+zip", - "scim": "application/scim+json", - "scld": "application/vnd.doremir.scorecloud-binary-document", - "scm": "application/vnd.lotus-screencam", "scq": "application/scvp-cv-request", - "scr": "application/x-silverlight", "scs": "application/scvp-cv-response", - "scsf": "application/vnd.sealed.csf", - "scss": "text/x-scss", - "sct": "text/scriptlet", - "scurl": "text/vnd.curl.scurl", - "sd": "chemical/x-mdl-sdfile", - "sd2": "audio/x-sd2", - "sda": "application/vnd.stardivision.draw", - "sdc": "application/vnd.stardivision.calc", - "sdd": "application/vnd.stardivision.impress", - "sdf": "application/vnd.kinar", - "sdkd": "application/vnd.solent.sdkm+xml", - "sdkm": "application/vnd.solent.sdkm+xml", - "sdml": "text/plain", - "sdo": "application/vnd.sealed.doc", - "sdoc": "application/vnd.sealed.doc", + "spq": "application/scvp-vp-request", + "spp": "application/scvp-vp-response", "sdp": "application/sdp", - "sdr": "application/sounder", - "sdw": "application/vnd.stardivision.writer", - "sea": "application/x-sea", - "see": "application/vnd.seemail", - "seed": "application/vnd.fdsn.seed", - "sem": "application/vnd.sealed.eml", - "sema": "application/vnd.sema", - "semd": "application/vnd.semd", - "semf": "application/vnd.semf", - "seml": "application/vnd.sealed.eml", - "ser": "application/java-serialized-object", - "set": "application/set", "setpay": "application/set-payment-initiation", "setreg": "application/set-registration-initiation", - "sfc": "application/vnd.nintendo.snes.rom", - "sfd": "application/vnd.font-fontforge-sfd", - "sfd-hdstx": "application/vnd.hydrostatix.sof-data", - "sfs": "application/vnd.spotfire.sfs", - "sfv": "text/x-sfv", - "sgf": "application/x-go-sgf", - "sgi": "image/sgi", - "sgif": "image/vnd.sealedmedia.softseal.gif", - "sgl": "application/vnd.stardivision.writer-global", - "sgm": "text/sgml", - "sgml": "text/sgml", - "sh": "application/x-sh", - "shar": "application/x-shar", - "shex": "text/shex", "shf": "application/shf+xml", - "shp": "application/x-qgis", - "shx": "application/x-qgis", - "si": "text/vnd.wap.si", - "sic": "application/vnd.wap.sic", - "sid": "image/x-mrsid-image", - "sieve": "application/sieve", - "sig": "application/pgp-signature", - "sik": "application/x-trash", - "sil": "audio/silk", - "silo": "model/mesh", - "sis": "application/vnd.symbian.install", - "sisx": "x-epoc/x-sisx-app", - "sit": "application/x-stuffit", - "sitx": "application/x-stuffitx", - "siv": "application/sieve", - "sjp": "image/vnd.sealedmedia.softseal.jpg", - "sjpg": "image/vnd.sealedmedia.softseal.jpg", - "skd": "application/vnd.koan", - "skm": "application/vnd.koan", - "skp": "application/vnd.koan", - "skt": "application/vnd.koan", - "sl": "text/vnd.wap.sl", - "sla": "application/vnd.scribus", - "slaz": "application/vnd.scribus", - "slc": "application/vnd.wap.slc", - "sldm": "application/vnd.ms-powerpoint.slide.macroenabled.12", - "sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", - "sls": "application/route-s-tsid+xml", - "slt": "application/vnd.epson.salt", - "sm": "application/vnd.stepmania.stepchart", - "smc": "application/vnd.nintendo.snes.rom", - "smf": "application/vnd.stardivision.math", - "smh": "application/vnd.sealed.mht", - "smht": "application/vnd.sealed.mht", "smi": "application/smil+xml", "smil": "application/smil+xml", - "smk": "video/vnd.radgamettools.smacker", - "sml": "application/smil+xml", - "smo": "video/vnd.sealedmedia.softseal.mov", - "smov": "video/vnd.sealedmedia.softseal.mov", - "smp": "audio/vnd.sealedmedia.softseal.mpeg", - "smp3": "audio/vnd.sealedmedia.softseal.mpeg", - "smpg": "video/vnd.sealed.mpeg1", - "sms": "application/vnd.3gpp2.sms", - "smv": "video/x-smv", - "smzip": "application/vnd.stepmania.package", - "snd": "audio/basic", - "snf": "application/x-font-snf", - "so": "application/octet-stream", - "soa": "text/dns", - "soc": "application/sgml-open-catalog", - "sol": "application/solids", - "spc": "text/x-speech", - "spd": "application/vnd.sealedmedia.softseal.pdf", - "spdf": "application/vnd.sealedmedia.softseal.pdf", - "spec": "text/spec", - "spf": "application/vnd.yamaha.smaf-phrase", - "spl": "application/x-futuresplash", - "spn": "image/vnd.sealed.png", - "spng": "image/vnd.sealed.png", - "spo": "text/vnd.in3d.spot", - "spot": "text/vnd.in3d.spot", - "spp": "application/scvp-vp-response", - "sppt": "application/vnd.sealed.ppt", - "spq": "application/scvp-vp-request", - "spr": "application/x-sprite", - "sprite": "application/x-sprite", - "spx": "audio/ogg", - "sql": "application/x-sql", - "sr": "application/vnd.sigrok.session", - "src": "application/x-wais-source", - "srt": "application/x-subrip", - "sru": "application/sru+xml", + "rq": "application/sparql-query", "srx": "application/sparql-results+xml", + "gram": "application/srgs", + "grxml": "application/srgs+xml", + "sru": "application/sru+xml", "ssdl": "application/ssdl+xml", - "sse": "application/vnd.kodak-descriptor", - "ssf": "application/vnd.epson.ssf", - "ssi": "text/x-server-parsed-html", - "ssm": "application/streamingmedia", "ssml": "application/ssml+xml", - "sst": "application/vnd.ms-pki.certstore", - "ssw": "video/vnd.sealed.swf", - "sswf": "video/vnd.sealed.swf", - "st": "application/vnd.sailingtracker.track", - "stc": "application/vnd.sun.xml.calc.template", - "std": "application/vnd.sun.xml.draw.template", - "step": "application/step", - "stf": "application/vnd.wt.stf", - "sti": "application/vnd.sun.xml.impress.template", - "stif": "application/vnd.sealed.tiff", - "stk": "application/hyperstudio", - "stl": "application/vnd.ms-pki.stl", - "stm": "audio/x-stm", - "stml": "application/vnd.sealedmedia.softseal.html", - "stp": "application/step", - "str": "application/vnd.pg.format", - "study-inter": "application/vnd.vd-study", - "stw": "application/vnd.sun.xml.writer.template", - "sty": "text/x-tex", - "styl": "text/stylus", - "sub": "text/vnd.dvb.subtitle", - "sus": "application/vnd.sus-calendar", - "susp": "application/vnd.sus-calendar", - "sv4cpio": "application/x-sv4cpio", - "sv4crc": "application/x-sv4crc", - "svc": "application/vnd.dvb.service", - "svd": "application/vnd.svd", - "svf": "image/x-dwg", - "svg": "image/svg+xml", - "svgz": "image/svg+xml", - "sw": "chemical/x-swissprot", - "swa": "application/x-director", - "swf": "application/x-shockwave-flash", - "swfl": "application/x-shockwave-flash", - "swi": "application/vnd.aristanetworks.swi", - "swift": "text/swift", - "swiftdeps": "text/swiftdeps", - "sxc": "application/vnd.sun.xml.calc", - "sxd": "application/vnd.sun.xml.draw", - "sxg": "application/vnd.sun.xml.writer.global", - "sxi": "application/vnd.sun.xml.impress", - "sxl": "application/vnd.sealed.xls", - "sxls": "application/vnd.sealed.xls", - "sxm": "application/vnd.sun.xml.math", - "sxw": "application/vnd.sun.xml.writer", - "t": "text/troff", - "t3": "application/x-t3vm-image", - "t38": "image/t38", - "tac": "text/twisted", - "tag": "text/prs.lines.tag", - "taglet": "application/vnd.mynfc", - "talk": "text/x-speech", - "tam": "application/vnd.onepager", - "tamp": "application/vnd.onepagertamp", - "tamx": "application/vnd.onepagertamx", - "tao": "application/vnd.tao.intent-module-archive", - "tap": "image/vnd.tencent.tap", - "tar": "application/x-tar", - "tat": "application/vnd.onepagertat", - "tatp": "application/vnd.onepagertatp", - "tatx": "application/vnd.onepagertatx", - "tau": "application/tamp-apex-update", - "taz": "application/x-gtar", - "tbk": "application/toolbook", - "tcap": "application/vnd.3gpp2.tcap", - "tcl": "application/x-tcl", - "tcsh": "text/x-script.tcsh", - "tcu": "application/tamp-community-update", - "td": "application/urc-targetdesc+xml", - "teacher": "application/vnd.smart.teacher", "tei": "application/tei+xml", "teicorpus": "application/tei+xml", - "ter": "application/tamp-error", - "tex": "application/x-tex", - "texi": "application/x-texinfo", - "texinfo": "application/x-texinfo", - "text": "text/plain", - "tf": "text/terraform", "tfi": "application/thraud+xml", - "tfm": "application/x-tex-tfm", - "tfx": "image/tiff-fx", - "tga": "image/x-tga", - "tgf": "chemical/x-mdl-tgf", - "tgz": "application/gzip", - "thmx": "application/vnd.ms-officetheme", - "thrift": "text/thrift", - "tif": "image/tiff", - "tiff": "image/tiff", - "tk": "text/x-tcl", - "tlclient": "application/vnd.cendio.thinlinc.clientconf", - "tm": "text/texmacs", - "tmo": "application/vnd.tmobile-livetv", - "tnef": "application/vnd.ms-tnef", - "tnf": "application/vnd.ms-tnef", - "toml": "text/toml", - "torrent": "application/x-bittorrent", - "tpl": "application/vnd.groove-tool-template", - "tpt": "application/vnd.trid.tpt", - "tr": "text/troff", - "tra": "application/vnd.trueapp", - "tree": "application/vnd.rainstor.data", - "trig": "application/trig", - "trm": "application/x-msterminal", - "ts": "video/mp2t", - "tsa": "application/tamp-sequence-adjust", - "tscn": "text/godot", "tsd": "application/timestamped-data", - "tsi": "audio/tsp-audio", - "tsp": "audio/tsplayer", - "tsq": "application/timestamp-query", - "tsr": "application/timestamp-reply", - "tst": "application/vnd.etsi.timestamp-token", - "tsv": "text/tab-separated-values", - "tsx": "text/tsx", - "ttc": "font/collection", - "ttf": "font/ttf", - "ttl": "text/turtle", - "ttml": "application/ttml+xml", - "tuc": "application/tamp-update-confirm", - "tur": "application/tamp-update", - "turbot": "image/florian", - "twd": "application/vnd.simtech-mindmapper", - "twds": "application/vnd.simtech-mindmapper", - "txd": "application/vnd.genomatix.tuxedo", - "txf": "application/vnd.mobius.txf", - "txt": "text/plain", - "u32": "application/x-authorware-bin", - "u8dsn": "message/global-delivery-status", - "u8hdr": "message/global-headers", - "u8mdn": "message/global-disposition-notification", - "u8msg": "message/global", - "udeb": "application/vnd.debian.binary-package", - "ufd": "application/vnd.ufdl", - "ufdl": "application/vnd.ufdl", - "uil": "text/x-uil", - "uis": "application/urc-uisocketdesc+xml", - "uls": "text/iuls", - "ult": "audio/x-mod", - "ulx": "application/x-glulx", - "umj": "application/vnd.umajin", - "uni": "audio/x-mod", - "unis": "text/uri-list", - "unityweb": "application/vnd.unity", - "unv": "application/i-deas", - "uo": "application/vnd.uoml+xml", - "uoml": "application/vnd.uoml+xml", - "upa": "application/vnd.hbci", - "uri": "text/uri-list", - "uric": "text/vnd.si.uricatalogue", - "urim": "application/vnd.uri-map", - "urimap": "application/vnd.uri-map", - "uris": "text/uri-list", - "urls": "text/uri-list", - "ustar": "application/x-ustar", - "utz": "application/vnd.uiq.theme", - "uu": "text/x-uuencode", - "uue": "text/x-uuencode", - "uva": "audio/vnd.dece.audio", - "uvd": "application/vnd.dece.data", - "uvf": "application/vnd.dece.data", - "uvg": "image/vnd.dece.graphic", - "uvh": "video/vnd.dece.hd", - "uvi": "image/vnd.dece.graphic", - "uvm": "video/vnd.dece.mobile", - "uvp": "video/vnd.dece.pd", - "uvs": "video/vnd.dece.sd", - "uvt": "application/vnd.dece.ttml+xml", - "uvu": "video/vnd.dece.mp4", - "uvv": "video/vnd.dece.video", - "uvva": "audio/vnd.dece.audio", - "uvvd": "application/vnd.dece.data", - "uvvf": "application/vnd.dece.data", - "uvvg": "image/vnd.dece.graphic", - "uvvh": "video/vnd.dece.hd", - "uvvi": "image/vnd.dece.graphic", - "uvvm": "video/vnd.dece.mobile", - "uvvp": "video/vnd.dece.pd", - "uvvs": "video/vnd.dece.sd", + "plb": "application/vnd.3gpp.pic-bw-large", + "psb": "application/vnd.3gpp.pic-bw-small", + "pvb": "application/vnd.3gpp.pic-bw-var", + "tcap": "application/vnd.3gpp2.tcap", + "pwn": "application/vnd.3m.post-it-notes", + "aso": "application/vnd.accpac.simply.aso", + "imp": "application/vnd.accpac.simply.imp", + "acu": "application/vnd.acucobol", + "atc": "application/vnd.acucorp", + "acutc": "application/vnd.acucorp", + "air": "application/vnd.adobe.air-application-installer-package+zip", + "fcdt": "application/vnd.adobe.formscentral.fcdt", + "fxp": "application/vnd.adobe.fxp", + "fxpl": "application/vnd.adobe.fxp", + "xdp": "application/vnd.adobe.xdp+xml", + "xfdf": "application/vnd.adobe.xfdf", + "ahead": "application/vnd.ahead.space", + "azf": "application/vnd.airzip.filesecure.azf", + "azs": "application/vnd.airzip.filesecure.azs", + "azw": "application/vnd.amazon.ebook", + "acc": "application/vnd.americandynamics.acc", + "ami": "application/vnd.amiga.ami", + "apk": "application/vnd.android.package-archive", + "cii": "application/vnd.anser-web-certificate-issue-initiation", + "fti": "application/vnd.anser-web-funds-transfer-initiation", + "atx": "application/vnd.antix.game-component", + "mpkg": "application/vnd.apple.installer+xml", + "m3u8": "application/vnd.apple.mpegurl", + "swi": "application/vnd.aristanetworks.swi", + "iota": "application/vnd.astraea-software.iota", + "aep": "application/vnd.audiograph", + "mpm": "application/vnd.blueice.multipass", + "bmi": "application/vnd.bmi", + "rep": "application/vnd.businessobjects", + "cdxml": "application/vnd.chemdraw+xml", + "mmd": "application/vnd.chipnuts.karaoke-mmd", + "cdy": "application/vnd.cinderella", + "cla": "application/vnd.claymore", + "rp9": "application/vnd.cloanto.rp9", + "c4g": "application/vnd.clonk.c4group", + "c4d": "application/vnd.clonk.c4group", + "c4f": "application/vnd.clonk.c4group", + "c4p": "application/vnd.clonk.c4group", + "c4u": "application/vnd.clonk.c4group", + "c11amc": "application/vnd.cluetrust.cartomobile-config", + "c11amz": "application/vnd.cluetrust.cartomobile-config-pkg", + "csp": "application/vnd.commonspace", + "cdbcmsg": "application/vnd.contact.cmsg", + "cmc": "application/vnd.cosmocaller", + "clkx": "application/vnd.crick.clicker", + "clkk": "application/vnd.crick.clicker.keyboard", + "clkp": "application/vnd.crick.clicker.palette", + "clkt": "application/vnd.crick.clicker.template", + "clkw": "application/vnd.crick.clicker.wordbank", + "wbs": "application/vnd.criticaltools.wbs+xml", + "pml": "application/vnd.ctc-posml", + "ppd": "application/vnd.cups-ppd", + "car": "application/vnd.curl.car", + "pcurl": "application/vnd.curl.pcurl", + "dart": "application/vnd.dart", + "rdz": "application/vnd.data-vision.rdz", + "uvf": "application/vnd.dece.data", + "uvvf": "application/vnd.dece.data", + "uvd": "application/vnd.dece.data", + "uvvd": "application/vnd.dece.data", + "uvt": "application/vnd.dece.ttml+xml", "uvvt": "application/vnd.dece.ttml+xml", - "uvvu": "video/vnd.dece.mp4", - "uvvv": "video/vnd.dece.video", - "uvvx": "application/vnd.dece.unspecified", - "uvvz": "application/vnd.dece.zip", "uvx": "application/vnd.dece.unspecified", + "uvvx": "application/vnd.dece.unspecified", "uvz": "application/vnd.dece.zip", - "val": "chemical/x-ncbi-asn1-binary", - "vbk": "audio/vnd.nortel.vbk", - "vbox": "application/x-virtualbox-vbox", - "vbox-extpack": "application/x-virtualbox-vbox-extpack", + "uvvz": "application/vnd.dece.zip", + "fe_launch": "application/vnd.denovo.fcselayout-link", + "dna": "application/vnd.dna", + "mlp": "application/vnd.dolby.mlp", + "dpg": "application/vnd.dpgraph", + "dfac": "application/vnd.dreamfactory", + "kpxx": "application/vnd.ds-keypoint", + "ait": "application/vnd.dvb.ait", + "svc": "application/vnd.dvb.service", + "geo": "application/vnd.dynageo", + "mag": "application/vnd.ecowin.chart", + "nml": "application/vnd.enliven", + "esf": "application/vnd.epson.esf", + "msf": "application/vnd.epson.msf", + "qam": "application/vnd.epson.quickanime", + "slt": "application/vnd.epson.salt", + "ssf": "application/vnd.epson.ssf", + "es3": "application/vnd.eszigno3+xml", + "et3": "application/vnd.eszigno3+xml", + "ez2": "application/vnd.ezpix-album", + "ez3": "application/vnd.ezpix-package", + "fdf": "application/vnd.fdf", + "mseed": "application/vnd.fdsn.mseed", + "seed": "application/vnd.fdsn.seed", + "dataless": "application/vnd.fdsn.seed", + "gph": "application/vnd.flographit", + "ftc": "application/vnd.fluxtime.clip", + "fm": "application/vnd.framemaker", + "frame": "application/vnd.framemaker", + "maker": "application/vnd.framemaker", + "book": "application/vnd.framemaker", + "fnc": "application/vnd.frogans.fnc", + "ltf": "application/vnd.frogans.ltf", + "fsc": "application/vnd.fsc.weblaunch", + "oas": "application/vnd.fujitsu.oasys", + "oa2": "application/vnd.fujitsu.oasys2", + "oa3": "application/vnd.fujitsu.oasys3", + "fg5": "application/vnd.fujitsu.oasysgp", + "bh2": "application/vnd.fujitsu.oasysprs", + "ddd": "application/vnd.fujixerox.ddd", + "xdw": "application/vnd.fujixerox.docuworks", + "xbd": "application/vnd.fujixerox.docuworks.binder", + "fzs": "application/vnd.fuzzysheet", + "txd": "application/vnd.genomatix.tuxedo", + "ggb": "application/vnd.geogebra.file", + "ggs": "application/vnd.geogebra.slides", + "ggt": "application/vnd.geogebra.tool", + "gex": "application/vnd.geometry-explorer", + "gre": "application/vnd.geometry-explorer", + "gxt": "application/vnd.geonext", + "g2w": "application/vnd.geoplan", + "g3w": "application/vnd.geospace", + "gmx": "application/vnd.gmx", + "kml": "application/vnd.google-earth.kml+xml", + "kmz": "application/vnd.google-earth.kmz", + "gqf": "application/vnd.grafeq", + "gqs": "application/vnd.grafeq", + "gac": "application/vnd.groove-account", + "ghf": "application/vnd.groove-help", + "gim": "application/vnd.groove-identity-message", + "grv": "application/vnd.groove-injector", + "gtm": "application/vnd.groove-tool-message", + "tpl": "application/vnd.groove-tool-template", + "vcg": "application/vnd.groove-vcard", + "hal": "application/vnd.hal+xml", + "zmm": "application/vnd.handheld-entertainment+xml", + "hbci": "application/vnd.hbci", + "les": "application/vnd.hhe.lesson-player", + "hpgl": "application/vnd.hp-hpgl", + "hpid": "application/vnd.hp-hpid", + "hps": "application/vnd.hp-hps", + "jlt": "application/vnd.hp-jlyt", + "pcl": "application/vnd.hp-pcl", + "pclxl": "application/vnd.hp-pclxl", + "sfd-hdstx": "application/vnd.hydrostatix.sof-data", + "mpy": "application/vnd.ibm.minipay", + "afp": "application/vnd.ibm.modcap", + "listafp": "application/vnd.ibm.modcap", + "list3820": "application/vnd.ibm.modcap", + "irm": "application/vnd.ibm.rights-management", + "sc": "application/vnd.ibm.secure-container", + "icc": "application/vnd.iccprofile", + "icm": "application/vnd.iccprofile", + "igl": "application/vnd.igloader", + "ivp": "application/vnd.immervision-ivp", + "ivu": "application/vnd.immervision-ivu", + "igm": "application/vnd.insors.igm", + "xpw": "application/vnd.intercon.formnet", + "xpx": "application/vnd.intercon.formnet", + "i2g": "application/vnd.intergeo", + "qbo": "application/vnd.intu.qbo", + "qfx": "application/vnd.intu.qfx", + "rcprofile": "application/vnd.ipunplugged.rcprofile", + "irp": "application/vnd.irepository.package+xml", + "xpr": "application/vnd.is-xpr", + "fcs": "application/vnd.isac.fcs", + "jam": "application/vnd.jam", + "rms": "application/vnd.jcp.javame.midlet-rms", + "jisp": "application/vnd.jisp", + "joda": "application/vnd.joost.joda-archive", + "ktz": "application/vnd.kahootz", + "ktr": "application/vnd.kahootz", + "karbon": "application/vnd.kde.karbon", + "chrt": "application/vnd.kde.kchart", + "kfo": "application/vnd.kde.kformula", + "flw": "application/vnd.kde.kivio", + "kon": "application/vnd.kde.kontour", + "kpr": "application/vnd.kde.kpresenter", + "kpt": "application/vnd.kde.kpresenter", + "ksp": "application/vnd.kde.kspread", + "kwd": "application/vnd.kde.kword", + "kwt": "application/vnd.kde.kword", + "htke": "application/vnd.kenameaapp", + "kia": "application/vnd.kidspiration", + "kne": "application/vnd.kinar", + "knp": "application/vnd.kinar", + "skp": "application/vnd.koan", + "skd": "application/vnd.koan", + "skt": "application/vnd.koan", + "skm": "application/vnd.koan", + "sse": "application/vnd.kodak-descriptor", + "lasxml": "application/vnd.las.las+xml", + "lbd": "application/vnd.llamagraphics.life-balance.desktop", + "lbe": "application/vnd.llamagraphics.life-balance.exchange+xml", + "123": "application/vnd.lotus-1-2-3", + "apr": "application/vnd.lotus-approach", + "pre": "application/vnd.lotus-freelance", + "nsf": "application/vnd.lotus-notes", + "org": "application/vnd.lotus-organizer", + "scm": "application/vnd.lotus-screencam", + "lwp": "application/vnd.lotus-wordpro", + "portpkg": "application/vnd.macports.portpkg", + "mcd": "application/vnd.mcd", + "mc1": "application/vnd.medcalcdata", + "cdkey": "application/vnd.mediastation.cdkey", + "mwf": "application/vnd.mfer", + "mfm": "application/vnd.mfmp", + "flo": "application/vnd.micrografx.flo", + "igx": "application/vnd.micrografx.igx", + "mif": "application/vnd.mif", + "daf": "application/vnd.mobius.daf", + "dis": "application/vnd.mobius.dis", + "mbk": "application/vnd.mobius.mbk", + "mqy": "application/vnd.mobius.mqy", + "msl": "application/vnd.mobius.msl", + "plc": "application/vnd.mobius.plc", + "txf": "application/vnd.mobius.txf", + "mpn": "application/vnd.mophun.application", + "mpc": "application/vnd.mophun.certificate", + "xul": "application/vnd.mozilla.xul+xml", + "cil": "application/vnd.ms-artgalry", + "cab": "application/vnd.ms-cab-compressed", + "xls": "application/vnd.ms-excel", + "xlm": "application/vnd.ms-excel", + "xla": "application/vnd.ms-excel", + "xlc": "application/vnd.ms-excel", + "xlt": "application/vnd.ms-excel", + "xlw": "application/vnd.ms-excel", + "xlam": "application/vnd.ms-excel.addin.macroenabled.12", + "xlsb": "application/vnd.ms-excel.sheet.binary.macroenabled.12", + "xlsm": "application/vnd.ms-excel.sheet.macroenabled.12", + "xltm": "application/vnd.ms-excel.template.macroenabled.12", + "eot": "application/vnd.ms-fontobject", + "chm": "application/vnd.ms-htmlhelp", + "ims": "application/vnd.ms-ims", + "lrm": "application/vnd.ms-lrm", + "thmx": "application/vnd.ms-officetheme", + "cat": "application/vnd.ms-pki.seccat", + "stl": "application/vnd.ms-pki.stl", + "ppt": "application/vnd.ms-powerpoint", + "pps": "application/vnd.ms-powerpoint", + "pot": "application/vnd.ms-powerpoint", + "ppam": "application/vnd.ms-powerpoint.addin.macroenabled.12", + "pptm": "application/vnd.ms-powerpoint.presentation.macroenabled.12", + "sldm": "application/vnd.ms-powerpoint.slide.macroenabled.12", + "ppsm": "application/vnd.ms-powerpoint.slideshow.macroenabled.12", + "potm": "application/vnd.ms-powerpoint.template.macroenabled.12", + "mpp": "application/vnd.ms-project", + "mpt": "application/vnd.ms-project", + "docm": "application/vnd.ms-word.document.macroenabled.12", + "dotm": "application/vnd.ms-word.template.macroenabled.12", + "wps": "application/vnd.ms-works", + "wks": "application/vnd.ms-works", + "wcm": "application/vnd.ms-works", + "wdb": "application/vnd.ms-works", + "wpl": "application/vnd.ms-wpl", + "xps": "application/vnd.ms-xpsdocument", + "mseq": "application/vnd.mseq", + "mus": "application/vnd.musician", + "msty": "application/vnd.muvee.style", + "taglet": "application/vnd.mynfc", + "nlu": "application/vnd.neurolanguage.nlu", + "ntf": "application/vnd.nitf", + "nitf": "application/vnd.nitf", + "nnd": "application/vnd.noblenet-directory", + "nns": "application/vnd.noblenet-sealer", + "nnw": "application/vnd.noblenet-web", + "ngdat": "application/vnd.nokia.n-gage.data", + "n-gage": "application/vnd.nokia.n-gage.symbian.install", + "rpst": "application/vnd.nokia.radio-preset", + "rpss": "application/vnd.nokia.radio-presets", + "edm": "application/vnd.novadigm.edm", + "edx": "application/vnd.novadigm.edx", + "ext": "application/vnd.novadigm.ext", + "odc": "application/vnd.oasis.opendocument.chart", + "otc": "application/vnd.oasis.opendocument.chart-template", + "odb": "application/vnd.oasis.opendocument.database", + "odf": "application/vnd.oasis.opendocument.formula", + "odft": "application/vnd.oasis.opendocument.formula-template", + "odg": "application/vnd.oasis.opendocument.graphics", + "otg": "application/vnd.oasis.opendocument.graphics-template", + "odi": "application/vnd.oasis.opendocument.image", + "oti": "application/vnd.oasis.opendocument.image-template", + "odp": "application/vnd.oasis.opendocument.presentation", + "otp": "application/vnd.oasis.opendocument.presentation-template", + "ods": "application/vnd.oasis.opendocument.spreadsheet", + "ots": "application/vnd.oasis.opendocument.spreadsheet-template", + "odt": "application/vnd.oasis.opendocument.text", + "odm": "application/vnd.oasis.opendocument.text-master", + "ott": "application/vnd.oasis.opendocument.text-template", + "oth": "application/vnd.oasis.opendocument.text-web", + "xo": "application/vnd.olpc-sugar", + "dd2": "application/vnd.oma.dd2+xml", + "oxt": "application/vnd.openofficeorg.extension", + "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", + "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + "potx": "application/vnd.openxmlformats-officedocument.presentationml.template", + "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + "mgp": "application/vnd.osgeo.mapguide.package", + "dp": "application/vnd.osgi.dp", + "esa": "application/vnd.osgi.subsystem", + "pdb": "application/vnd.palm", + "pqa": "application/vnd.palm", + "oprc": "application/vnd.palm", + "paw": "application/vnd.pawaafile", + "str": "application/vnd.pg.format", + "ei6": "application/vnd.pg.osasli", + "efif": "application/vnd.picsel", + "wg": "application/vnd.pmi.widget", + "plf": "application/vnd.pocketlearn", + "pbd": "application/vnd.powerbuilder6", + "box": "application/vnd.previewsystems.box", + "mgz": "application/vnd.proteus.magazine", + "qps": "application/vnd.publishare-delta-tree", + "ptid": "application/vnd.pvi.ptid1", + "qxd": "application/vnd.quark.quarkxpress", + "qxt": "application/vnd.quark.quarkxpress", + "qwd": "application/vnd.quark.quarkxpress", + "qwt": "application/vnd.quark.quarkxpress", + "qxl": "application/vnd.quark.quarkxpress", + "qxb": "application/vnd.quark.quarkxpress", + "bed": "application/vnd.realvnc.bed", + "mxl": "application/vnd.recordare.musicxml", + "musicxml": "application/vnd.recordare.musicxml+xml", + "cryptonote": "application/vnd.rig.cryptonote", + "cod": "application/vnd.rim.cod", + "rm": "application/vnd.rn-realmedia", + "rmvb": "application/vnd.rn-realmedia-vbr", + "link66": "application/vnd.route66.link66+xml", + "st": "application/vnd.sailingtracker.track", + "see": "application/vnd.seemail", + "sema": "application/vnd.sema", + "semd": "application/vnd.semd", + "semf": "application/vnd.semf", + "ifm": "application/vnd.shana.informed.formdata", + "itp": "application/vnd.shana.informed.formtemplate", + "iif": "application/vnd.shana.informed.interchange", + "ipk": "application/vnd.shana.informed.package", + "twd": "application/vnd.simtech-mindmapper", + "twds": "application/vnd.simtech-mindmapper", + "mmf": "application/vnd.smaf", + "teacher": "application/vnd.smart.teacher", + "sdkm": "application/vnd.solent.sdkm+xml", + "sdkd": "application/vnd.solent.sdkm+xml", + "dxp": "application/vnd.spotfire.dxp", + "sfs": "application/vnd.spotfire.sfs", + "sdc": "application/vnd.stardivision.calc", + "sda": "application/vnd.stardivision.draw", + "sdd": "application/vnd.stardivision.impress", + "smf": "application/vnd.stardivision.math", + "sdw": "application/vnd.stardivision.writer", + "vor": "application/vnd.stardivision.writer", + "sgl": "application/vnd.stardivision.writer-global", + "smzip": "application/vnd.stepmania.package", + "sm": "application/vnd.stepmania.stepchart", + "sxc": "application/vnd.sun.xml.calc", + "stc": "application/vnd.sun.xml.calc.template", + "sxd": "application/vnd.sun.xml.draw", + "std": "application/vnd.sun.xml.draw.template", + "sxi": "application/vnd.sun.xml.impress", + "sti": "application/vnd.sun.xml.impress.template", + "sxm": "application/vnd.sun.xml.math", + "sxw": "application/vnd.sun.xml.writer", + "sxg": "application/vnd.sun.xml.writer.global", + "stw": "application/vnd.sun.xml.writer.template", + "sus": "application/vnd.sus-calendar", + "susp": "application/vnd.sus-calendar", + "svd": "application/vnd.svd", + "sis": "application/vnd.symbian.install", + "sisx": "application/vnd.symbian.install", + "xsm": "application/vnd.syncml+xml", + "bdm": "application/vnd.syncml.dm+wbxml", + "xdm": "application/vnd.syncml.dm+xml", + "tao": "application/vnd.tao.intent-module-archive", + "pcap": "application/vnd.tcpdump.pcap", + "cap": "application/vnd.tcpdump.pcap", + "dmp": "application/vnd.tcpdump.pcap", + "tmo": "application/vnd.tmobile-livetv", + "tpt": "application/vnd.trid.tpt", + "mxs": "application/vnd.triscape.mxs", + "tra": "application/vnd.trueapp", + "ufd": "application/vnd.ufdl", + "ufdl": "application/vnd.ufdl", + "utz": "application/vnd.uiq.theme", + "umj": "application/vnd.umajin", + "unityweb": "application/vnd.unity", + "uoml": "application/vnd.uoml+xml", + "vcx": "application/vnd.vcx", + "vsd": "application/vnd.visio", + "vst": "application/vnd.visio", + "vss": "application/vnd.visio", + "vsw": "application/vnd.visio", + "vis": "application/vnd.visionary", + "vsf": "application/vnd.vsf", + "wbxml": "application/vnd.wap.wbxml", + "wmlc": "application/vnd.wap.wmlc", + "wmlsc": "application/vnd.wap.wmlscriptc", + "wtb": "application/vnd.webturbo", + "nbp": "application/vnd.wolfram.player", + "wpd": "application/vnd.wordperfect", + "wqd": "application/vnd.wqd", + "stf": "application/vnd.wt.stf", + "xar": "application/vnd.xara", + "xfdl": "application/vnd.xfdl", + "hvd": "application/vnd.yamaha.hv-dic", + "hvs": "application/vnd.yamaha.hv-script", + "hvp": "application/vnd.yamaha.hv-voice", + "osf": "application/vnd.yamaha.openscoreformat", + "osfpvg": "application/vnd.yamaha.openscoreformat.osfpvg+xml", + "saf": "application/vnd.yamaha.smaf-audio", + "spf": "application/vnd.yamaha.smaf-phrase", + "cmp": "application/vnd.yellowriver-custom-menu", + "zir": "application/vnd.zul", + "zirz": "application/vnd.zul", + "zaz": "application/vnd.zzazz.deck+xml", + "vxml": "application/voicexml+xml", + "wasm": "application/wasm", + "wgt": "application/widget", + "hlp": "application/winhlp", + "wsdl": "application/wsdl+xml", + "wspolicy": "application/wspolicy+xml", + "7z": "application/x-7z-compressed", + "abw": "application/x-abiword", + "ace": "application/x-ace-compressed", + "dmg": "application/x-apple-diskimage", + "aab": "application/x-authorware-bin", + "x32": "application/x-authorware-bin", + "u32": "application/x-authorware-bin", + "vox": "application/x-authorware-bin", + "aam": "application/x-authorware-map", + "aas": "application/x-authorware-seg", + "bcpio": "application/x-bcpio", + "torrent": "application/x-bittorrent", + "blb": "application/x-blorb", + "blorb": "application/x-blorb", + "bz": "application/x-bzip", + "bz2": "application/x-bzip2", + "boz": "application/x-bzip2", + "cbr": "application/x-cbr", + "cba": "application/x-cbr", + "cbt": "application/x-cbr", + "cbz": "application/x-cbr", + "cb7": "application/x-cbr", + "vcd": "application/x-cdlink", + "cfs": "application/x-cfs-compressed", + "chat": "application/x-chat", + "pgn": "application/x-chess-pgn", + "nsc": "application/x-conference", + "cpio": "application/x-cpio", + "csh": "application/x-csh", + "deb": "application/x-debian-package", + "udeb": "application/x-debian-package", + "dgc": "application/x-dgc-compressed", + "dir": "application/x-director", + "dcr": "application/x-director", + "dxr": "application/x-director", + "cst": "application/x-director", + "cct": "application/x-director", + "cxt": "application/x-director", + "w3d": "application/x-director", + "fgd": "application/x-director", + "swa": "application/x-director", + "wad": "application/x-doom", + "ncx": "application/x-dtbncx+xml", + "dtb": "application/x-dtbook+xml", + "res": "application/x-dtbresource+xml", + "dvi": "application/x-dvi", + "evy": "application/x-envoy", + "eva": "application/x-eva", + "bdf": "application/x-font-bdf", + "gsf": "application/x-font-ghostscript", + "psf": "application/x-font-linux-psf", + "pcf": "application/x-font-pcf", + "snf": "application/x-font-snf", + "pfa": "application/x-font-type1", + "pfb": "application/x-font-type1", + "pfm": "application/x-font-type1", + "afm": "application/x-font-type1", + "arc": "application/x-freearc", + "spl": "application/x-futuresplash", + "gca": "application/x-gca-compressed", + "ulx": "application/x-glulx", + "gnumeric": "application/x-gnumeric", + "gramps": "application/x-gramps-xml", + "gtar": "application/x-gtar", + "hdf": "application/x-hdf", + "install": "application/x-install-instructions", + "iso": "application/x-iso9660-image", + "jnlp": "application/x-java-jnlp-file", + "latex": "application/x-latex", + "lzh": "application/x-lzh-compressed", + "lha": "application/x-lzh-compressed", + "mie": "application/x-mie", + "prc": "application/x-mobipocket-ebook", + "mobi": "application/x-mobipocket-ebook", + "application": "application/x-ms-application", + "lnk": "application/x-ms-shortcut", + "wmd": "application/x-ms-wmd", + "wmz": "application/x-ms-wmz", + "xbap": "application/x-ms-xbap", + "mdb": "application/x-msaccess", + "obd": "application/x-msbinder", + "crd": "application/x-mscardfile", + "clp": "application/x-msclip", + "exe": "application/x-msdownload", + "dll": "application/x-msdownload", + "com": "application/x-msdownload", + "bat": "application/x-msdownload", + "msi": "application/x-msdownload", + "mvb": "application/x-msmediaview", + "m13": "application/x-msmediaview", + "m14": "application/x-msmediaview", + "wmf": "application/x-msmetafile", + "wmz": "application/x-msmetafile", + "emf": "application/x-msmetafile", + "emz": "application/x-msmetafile", + "mny": "application/x-msmoney", + "pub": "application/x-mspublisher", + "scd": "application/x-msschedule", + "trm": "application/x-msterminal", + "wri": "application/x-mswrite", + "nc": "application/x-netcdf", + "cdf": "application/x-netcdf", + "nzb": "application/x-nzb", + "p12": "application/x-pkcs12", + "pfx": "application/x-pkcs12", + "p7b": "application/x-pkcs7-certificates", + "spc": "application/x-pkcs7-certificates", + "p7r": "application/x-pkcs7-certreqresp", + "rar": "application/x-rar-compressed", + "ris": "application/x-research-info-systems", + "sh": "application/x-sh", + "shar": "application/x-shar", + "swf": "application/x-shockwave-flash", + "xap": "application/x-silverlight-app", + "sql": "application/x-sql", + "sit": "application/x-stuffit", + "sitx": "application/x-stuffitx", + "srt": "application/x-subrip", + "sv4cpio": "application/x-sv4cpio", + "sv4crc": "application/x-sv4crc", + "t3": "application/x-t3vm-image", + "gam": "application/x-tads", + "tar": "application/x-tar", + "tcl": "application/x-tcl", + "tex": "application/x-tex", + "tfm": "application/x-tex-tfm", + "texinfo": "application/x-texinfo", + "texi": "application/x-texinfo", + "obj": "application/x-tgif", + "ustar": "application/x-ustar", + "src": "application/x-wais-source", + "der": "application/x-x509-ca-cert", + "crt": "application/x-x509-ca-cert", + "fig": "application/x-xfig", + "xlf": "application/x-xliff+xml", + "xpi": "application/x-xpinstall", + "xz": "application/x-xz", + "z1": "application/x-zmachine", + "z2": "application/x-zmachine", + "z3": "application/x-zmachine", + "z4": "application/x-zmachine", + "z5": "application/x-zmachine", + "z6": "application/x-zmachine", + "z7": "application/x-zmachine", + "z8": "application/x-zmachine", + "xaml": "application/xaml+xml", + "xdf": "application/xcap-diff+xml", + "xenc": "application/xenc+xml", + "xhtml": "application/xhtml+xml", + "xht": "application/xhtml+xml", + "xml": "application/xml", + "xsl": "application/xml", + "dtd": "application/xml-dtd", + "xop": "application/xop+xml", + "xpl": "application/xproc+xml", + "xslt": "application/xslt+xml", + "xspf": "application/xspf+xml", + "mxml": "application/xv+xml", + "xhvml": "application/xv+xml", + "xvml": "application/xv+xml", + "xvm": "application/xv+xml", + "yang": "application/yang", + "yin": "application/yin+xml", + "zip": "application/zip", + "adp": "audio/adpcm", + "au": "audio/basic", + "snd": "audio/basic", + "mid": "audio/midi", + "midi": "audio/midi", + "kar": "audio/midi", + "rmi": "audio/midi", + "m4a": "audio/mp4", + "mp4a": "audio/mp4", + "mpga": "audio/mpeg", + "mp2": "audio/mpeg", + "mp2a": "audio/mpeg", + "mp3": "audio/mpeg", + "m2a": "audio/mpeg", + "m3a": "audio/mpeg", + "oga": "audio/ogg", + "ogg": "audio/ogg", + "spx": "audio/ogg", + "opus": "audio/ogg", + "s3m": "audio/s3m", + "sil": "audio/silk", + "uva": "audio/vnd.dece.audio", + "uvva": "audio/vnd.dece.audio", + "eol": "audio/vnd.digital-winds", + "dra": "audio/vnd.dra", + "dts": "audio/vnd.dts", + "dtshd": "audio/vnd.dts.hd", + "lvp": "audio/vnd.lucent.voice", + "pya": "audio/vnd.ms-playready.media.pya", + "ecelp4800": "audio/vnd.nuera.ecelp4800", + "ecelp7470": "audio/vnd.nuera.ecelp7470", + "ecelp9600": "audio/vnd.nuera.ecelp9600", + "rip": "audio/vnd.rip", + "weba": "audio/webm", + "aac": "audio/x-aac", + "aif": "audio/x-aiff", + "aiff": "audio/x-aiff", + "aifc": "audio/x-aiff", + "caf": "audio/x-caf", + "flac": "audio/x-flac", + "mka": "audio/x-matroska", + "m3u": "audio/x-mpegurl", + "wax": "audio/x-ms-wax", + "wma": "audio/x-ms-wma", + "ram": "audio/x-pn-realaudio", + "ra": "audio/x-pn-realaudio", + "rmp": "audio/x-pn-realaudio-plugin", + "wav": "audio/x-wav", + "xm": "audio/xm", + "cdx": "chemical/x-cdx", + "cif": "chemical/x-cif", + "cmdf": "chemical/x-cmdf", + "cml": "chemical/x-cml", + "csml": "chemical/x-csml", + "xyz": "chemical/x-xyz", + "ttc": "font/collection", + "otf": "font/otf", + "ttf": "font/ttf", + "woff": "font/woff", + "woff2": "font/woff2", + "bmp": "image/bmp", + "cgm": "image/cgm", + "g3": "image/g3fax", + "gif": "image/gif", + "ief": "image/ief", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "jpe": "image/jpeg", + "ktx": "image/ktx", + "png": "image/png", + "btif": "image/prs.btif", + "sgi": "image/sgi", + "svg": "image/svg+xml", + "svgz": "image/svg+xml", + "tiff": "image/tiff", + "tif": "image/tiff", + "psd": "image/vnd.adobe.photoshop", + "uvi": "image/vnd.dece.graphic", + "uvvi": "image/vnd.dece.graphic", + "uvg": "image/vnd.dece.graphic", + "uvvg": "image/vnd.dece.graphic", + "djvu": "image/vnd.djvu", + "djv": "image/vnd.djvu", + "sub": "image/vnd.dvb.subtitle", + "dwg": "image/vnd.dwg", + "dxf": "image/vnd.dxf", + "fbs": "image/vnd.fastbidsheet", + "fpx": "image/vnd.fpx", + "fst": "image/vnd.fst", + "mmr": "image/vnd.fujixerox.edmics-mmr", + "rlc": "image/vnd.fujixerox.edmics-rlc", + "mdi": "image/vnd.ms-modi", + "wdp": "image/vnd.ms-photo", + "npx": "image/vnd.net-fpx", + "wbmp": "image/vnd.wap.wbmp", + "xif": "image/vnd.xiff", + "webp": "image/webp", + "3ds": "image/x-3ds", + "ras": "image/x-cmu-raster", + "cmx": "image/x-cmx", + "fh": "image/x-freehand", + "fhc": "image/x-freehand", + "fh4": "image/x-freehand", + "fh5": "image/x-freehand", + "fh7": "image/x-freehand", + "ico": "image/x-icon", + "sid": "image/x-mrsid-image", + "pcx": "image/x-pcx", + "pic": "image/x-pict", + "pct": "image/x-pict", + "pnm": "image/x-portable-anymap", + "pbm": "image/x-portable-bitmap", + "pgm": "image/x-portable-graymap", + "ppm": "image/x-portable-pixmap", + "rgb": "image/x-rgb", + "tga": "image/x-tga", + "xbm": "image/x-xbitmap", + "xpm": "image/x-xpixmap", + "xwd": "image/x-xwindowdump", + "eml": "message/rfc822", + "mime": "message/rfc822", + "igs": "model/iges", + "iges": "model/iges", + "msh": "model/mesh", + "mesh": "model/mesh", + "silo": "model/mesh", + "dae": "model/vnd.collada+xml", + "dwf": "model/vnd.dwf", + "gdl": "model/vnd.gdl", + "gtw": "model/vnd.gtw", + "mts": "model/vnd.mts", + "vtu": "model/vnd.vtu", + "wrl": "model/vrml", + "vrml": "model/vrml", + "x3db": "model/x3d+binary", + "x3dbz": "model/x3d+binary", + "x3dv": "model/x3d+vrml", + "x3dvz": "model/x3d+vrml", + "x3d": "model/x3d+xml", + "x3dz": "model/x3d+xml", + "appcache": "text/cache-manifest", + "ics": "text/calendar", + "ifb": "text/calendar", + "css": "text/css", + "csv": "text/csv", + "html": "text/html", + "htm": "text/html", + "js": "text/javascript", + "mjs": "text/javascript", + "n3": "text/n3", + "txt": "text/plain", + "text": "text/plain", + "conf": "text/plain", + "def": "text/plain", + "list": "text/plain", + "log": "text/plain", + "in": "text/plain", + "dsc": "text/prs.lines.tag", + "rtx": "text/richtext", + "sgml": "text/sgml", + "sgm": "text/sgml", + "tsv": "text/tab-separated-values", + "t": "text/troff", + "tr": "text/troff", + "roff": "text/troff", + "man": "text/troff", + "me": "text/troff", + "ms": "text/troff", + "ttl": "text/turtle", + "uri": "text/uri-list", + "uris": "text/uri-list", + "urls": "text/uri-list", "vcard": "text/vcard", - "vcd": "application/x-cdlink", - "vcf": "text/x-vcard", - "vcg": "application/vnd.groove-vcard", + "curl": "text/vnd.curl", + "dcurl": "text/vnd.curl.dcurl", + "mcurl": "text/vnd.curl.mcurl", + "scurl": "text/vnd.curl.scurl", + "sub": "text/vnd.dvb.subtitle", + "fly": "text/vnd.fly", + "flx": "text/vnd.fmi.flexstor", + "gv": "text/vnd.graphviz", + "3dml": "text/vnd.in3d.3dml", + "spot": "text/vnd.in3d.spot", + "jad": "text/vnd.sun.j2me.app-descriptor", + "wml": "text/vnd.wap.wml", + "wmls": "text/vnd.wap.wmlscript", + "s": "text/x-asm", + "asm": "text/x-asm", + "c": "text/x-c", + "cc": "text/x-c", + "cxx": "text/x-c", + "cpp": "text/x-c", + "h": "text/x-c", + "hh": "text/x-c", + "dic": "text/x-c", + "f": "text/x-fortran", + "for": "text/x-fortran", + "f77": "text/x-fortran", + "f90": "text/x-fortran", + "java": "text/x-java-source", + "nfo": "text/x-nfo", + "opml": "text/x-opml", + "p": "text/x-pascal", + "pas": "text/x-pascal", + "etx": "text/x-setext", + "sfv": "text/x-sfv", + "uu": "text/x-uuencode", "vcs": "text/x-vcalendar", - "vcx": "application/vnd.vcx", - "vda": "application/vda", - "vdi": "application/x-virtualbox-vdi", - "vdo": "video/vdo", - "vdx": "text/vdx", - "vew": "application/vnd.lotus-approach", - "vfr": "application/vnd.tml", - "vhd": "application/x-virtualbox-vhd", - "viaframe": "application/vnd.tml", - "vim": "text/vim", - "vis": "application/vnd.visionary", + "vcf": "text/x-vcard", + "3gp": "video/3gpp", + "3g2": "video/3gpp2", + "h261": "video/h261", + "h263": "video/h263", + "h264": "video/h264", + "jpgv": "video/jpeg", + "jpm": "video/jpm", + "jpgm": "video/jpm", + "mj2": "video/mj2", + "mjp2": "video/mj2", + "mp4": "video/mp4", + "mp4v": "video/mp4", + "mpg4": "video/mp4", + "mpeg": "video/mpeg", + "mpg": "video/mpeg", + "mpe": "video/mpeg", + "m1v": "video/mpeg", + "m2v": "video/mpeg", + "ogv": "video/ogg", + "qt": "video/quicktime", + "mov": "video/quicktime", + "uvh": "video/vnd.dece.hd", + "uvvh": "video/vnd.dece.hd", + "uvm": "video/vnd.dece.mobile", + "uvvm": "video/vnd.dece.mobile", + "uvp": "video/vnd.dece.pd", + "uvvp": "video/vnd.dece.pd", + "uvs": "video/vnd.dece.sd", + "uvvs": "video/vnd.dece.sd", + "uvv": "video/vnd.dece.video", + "uvvv": "video/vnd.dece.video", + "dvb": "video/vnd.dvb.file", + "fvt": "video/vnd.fvt", + "mxu": "video/vnd.mpegurl", + "m4u": "video/vnd.mpegurl", + "pyv": "video/vnd.ms-playready.media.pyv", + "uvu": "video/vnd.uvvu.mp4", + "uvvu": "video/vnd.uvvu.mp4", "viv": "video/vnd.vivo", - "vivo": "video/vivo", - "vmd": "application/vocaltec-media-desc", - "vmdk": "application/x-virtualbox-vmdk", - "vmf": "application/vocaltec-media-file", - "vms": "chemical/x-vamas-iso14976", - "vmt": "application/vnd.valve.source.material", - "vob": "video/x-ms-vob", - "voc": "audio/voc", - "vor": "application/vnd.stardivision.writer", - "vos": "video/vosaic", - "vox": "audio/voxware", - "vpm": "multipart/voice-message", - "vqe": "audio/x-twinvq-plugin", - "vqf": "audio/x-twinvq", - "vql": "audio/x-twinvq-plugin", - "vrm": "x-world/x-vrml", - "vrml": "model/vrml", - "vrt": "x-world/x-vrt", - "vsc": "application/vnd.vidsoft.vidconference", - "vsd": "application/vnd.visio", - "vsf": "application/vnd.vsf", - "vss": "application/vnd.visio", - "vst": "application/vnd.visio", - "vsw": "application/vnd.visio", - "vtf": "image/vnd.valve.source.texture", - "vtt": "text/vtt", - "vtu": "model/vnd.vtu", - "vue": "text/vue", - "vwx": "application/vnd.vectorworks", - "vxml": "application/voicexml+xml", - "w3d": "application/x-director", - "w60": "application/wordperfect6.0", - "w61": "application/wordperfect6.1", - "w6w": "application/msword", - "wad": "application/x-doom", - "wadl": "application/vnd.sun.wadl+xml", - "war": "binary/zip", - "wasm": "application/wasm", - "wav": "audio/wave", - "wax": "audio/x-ms-wax", - "wb1": "application/x-qpro", - "wbmp": "image/vnd.wap.wbmp", - "wbs": "application/vnd.criticaltools.wbs+xml", - "wbxml": "application/vnd.wap.wbxml", - "wcm": "application/vnd.ms-works", - "wdb": "application/vnd.ms-works", - "wdp": "image/vnd.ms-photo", - "web": "application/vnd.xara", - "weba": "audio/webm", - "webapp": "application/x-web-app-manifest+json", "webm": "video/webm", - "webmanifest": "application/manifest+json", - "webp": "image/webp", - "wg": "application/vnd.pmi.widget", - "wgt": "application/widget", - "whl": "binary/wheel", - "wif": "application/watcherinfo+xml", - "win": "model/vnd.gdl", - "wiz": "application/msword", - "wk": "application/x-123", - "wk1": "application/vnd.lotus-1-2-3", - "wk3": "application/vnd.lotus-1-2-3", - "wk4": "application/vnd.lotus-1-2-3", - "wks": "application/vnd.ms-works", - "wkt": "text/wkt", - "wlnk": "application/link-format", + "f4v": "video/x-f4v", + "fli": "video/x-fli", + "flv": "video/x-flv", + "m4v": "video/x-m4v", + "mkv": "video/x-matroska", + "mk3d": "video/x-matroska", + "mks": "video/x-matroska", + "mng": "video/x-mng", + "asf": "video/x-ms-asf", + "asx": "video/x-ms-asf", + "vob": "video/x-ms-vob", "wm": "video/x-ms-wm", - "wma": "audio/x-ms-wma", - "wmc": "application/vnd.wmc", - "wmd": "application/x-ms-wmd", - "wmf": "image/wmf", - "wml": "text/vnd.wap.wml", - "wmlc": "application/vnd.wap.wmlc", - "wmls": "text/vnd.wap.wmlscript", - "wmlsc": "application/vnd.wap.wmlscriptc", "wmv": "video/x-ms-wmv", "wmx": "video/x-ms-wmx", - "wmz": "application/x-ms-wmz", - "woff": "font/woff", - "woff2": "font/woff2", - "word": "application/msword", - "wp": "application/wordperfect", - "wp5": "application/wordperfect", - "wp6": "application/wordperfect", - "wpd": "application/vnd.wordperfect", - "wpl": "application/vnd.ms-wpl", - "wps": "application/vnd.ms-works", - "wq1": "application/x-lotus", - "wqd": "application/vnd.wqd", - "wri": "application/x-mswrite", - "wrl": "model/vrml", - "wrz": "model/vrml", - "wsc": "message/vnd.wfa.wsc", - "wsdl": "application/wsdl+xml", - "wsgi": "text/wsgi", - "wspolicy": "application/wspolicy+xml", - "wsrc": "application/x-wais-source", - "wtb": "application/vnd.webturbo", - "wtk": "application/x-wintalk", - "wv": "application/vnd.wv.csp+wbxml", "wvx": "video/x-ms-wvx", - "wz": "application/x-wingz", - "x-png": "image/png", - "x32": "application/x-authorware-bin", - "x3d": "application/vnd.hzn-3d-crossword", - "x3db": "model/x3d+xml", - "x3dbz": "model/x3d+binary", - "x3dv": "model/x3d-vrml", - "x3dvz": "model/x3d-vrml", - "x3dz": "model/x3d+xml", - "x_b": "model/vnd.parasolid.transmit.binary", - "x_t": "model/vnd.parasolid.transmit.text", - "xaf": "x-world/x-vrml", - "xaml": "application/xaml+xml", - "xap": "application/x-silverlight-app", - "xar": "application/vnd.xara", - "xav": "application/xcap-att+xml", - "xbap": "application/x-ms-xbap", - "xbd": "application/vnd.fujixerox.docuworks.binder", - "xbm": "image/x-xbitmap", - "xca": "application/xcap-caps+xml", - "xcf": "application/x-xcf", - "xcs": "application/calendar+xml", - "xct": "application/vnd.fujixerox.docuworks.container", - "xdd": "application/bacnet-xdd+zip", - "xdf": "application/xcap-diff+xml", - "xdm": "application/vnd.syncml.dm+xml", - "xdp": "application/vnd.adobe.xdp+xml", - "xdr": "video/x-amt-demorun", - "xdssc": "application/dssc+xml", - "xdw": "application/vnd.fujixerox.docuworks", - "xel": "application/xcap-el+xml", - "xenc": "application/xenc+xml", - "xer": "application/patch-ops-error+xml", - "xfd": "application/vnd.xfdl", - "xfdf": "application/vnd.adobe.xfdf", - "xfdl": "application/vnd.xfdl", - "xgz": "xgl/drawing", - "xht": "application/xhtml+xml", - "xhtm": "application/xhtml+xml", - "xhtml": "application/xhtml+xml", - "xhvml": "application/xv+xml", - "xif": "image/vnd.xiff", - "xl": "application/excel", - "xla": "application/vnd.ms-excel", - "xlam": "application/vnd.ms-excel.addin.macroenabled.12", - "xlb": "application/vndms-excel", - "xlc": "application/vnd.ms-excel", - "xlf": "application/x-xliff+xml", - "xlim": "application/vnd.xmpie.xlim", - "xlm": "application/vnd.ms-excel", - "xls": "application/vnd.ms-excel", - "xlsb": "application/vnd.ms-excel.sheet.binary.macroenabled.12", - "xlsm": "application/vnd.ms-excel.sheet.macroenabled.12", - "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "xlt": "application/vnd.ms-excel", - "xltm": "application/vnd.ms-excel.template.macroenabled.12", - "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", - "xlw": "application/vnd.ms-excel", - "xm": "audio/xm", - "xml": "text/xml", - "xmls": "application/dskpp+xml", - "xmt_bin": "model/vnd.parasolid.transmit.binary", - "xmt_txt": "model/vnd.parasolid.transmit.text", - "xmz": "xgl/movie", - "xns": "application/xcap-ns+xml", - "xo": "application/vnd.olpc-sugar", - "xof": "x-world/x-vrml", - "xop": "application/xop+xml", - "xpdl": "application/xml", - "xpi": "application/x-xpinstall", - "xpix": "application/x-vnd.ls-xpix", - "xpl": "application/xproc+xml", - "xpm": "image/x-xpixmap", - "xpr": "application/vnd.is-xpr", - "xps": "application/vnd.ms-xpsdocument", - "xpw": "application/vnd.intercon.formnet", - "xpx": "application/vnd.intercon.formnet", - "xq": "text/xquery", - "xql": "text/xquery", - "xqm": "text/xquery", - "xqu": "text/xquery", - "xquery": "text/xquery", - "xqy": "text/xquery", - "xsd": "text/xml", - "xsf": "application/prs.xsf+xml", - "xsl": "application/xslt+xml", - "xslt": "application/xslt+xml", - "xsm": "application/vnd.syncml+xml", - "xspf": "application/xspf+xml", - "xsr": "video/x-amt-showrun", - "xtel": "chemical/x-xtel", - "xul": "application/vnd.mozilla.xul+xml", - "xvm": "application/xv+xml", - "xvml": "application/xv+xml", - "xwd": "image/x-xwindowdump", - "xyz": "chemical/x-xyz", - "xyze": "image/vnd.radiance", - "xz": "application/x-xz", - "yaml": "text/yaml", - "yang": "application/yang", - "yin": "application/yin+xml", - "yme": "application/vnd.yaoweme", - "yml": "text/yaml", - "ymp": "text/x-suse-ymp", - "z1": "application/x-zmachine", - "z2": "application/x-zmachine", - "z3": "application/x-zmachine", - "z4": "application/x-zmachine", - "z5": "application/x-zmachine", - "z6": "application/x-zmachine", - "z7": "application/x-zmachine", - "z8": "application/x-zmachine", - "zaz": "application/vnd.zzazz.deck+xml", - "zfc": "application/vnd.filmit.zfc", - "zfo": "application/vnd.software602.filler.form-xml-zip", - "zig": "text/zig", - "zip": "application/zip", - "zir": "application/vnd.zul", - "zirz": "application/vnd.zul", - "zmm": "application/vnd.handheld-entertainment+xml", - "zmt": "chemical/x-mopac-input", - "zone": "text/dns", - "zoo": "application/octet-stream", - "zsh": "text/x-script.zsh", - "~": "application/x-trash" + "avi": "video/x-msvideo", + "movie": "video/x-sgi-movie", + "smv": "video/x-smv", + "ice": "x-conference/x-cooltalk", } diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim index e332cea403f1b..372a8f3d86892 100644 --- a/tests/stdlib/tmimetypes.nim +++ b/tests/stdlib/tmimetypes.nim @@ -11,8 +11,11 @@ template main() = var m = newMimetypes() doAssert m.getMimetype("mp4") == "video/mp4" doAssert m.getExt("application/json") == "json" + doAssert m.getMimetype("json") == "application/json" m.register("foo", "baa") doAssert m.getMimetype("foo") == "baa" + doAssert m.getMimetype("txt") == "text/plain" + doAssert m.getExt("text/plain") == "txt" # see also `runnableExamples`. # xxx we should have a way to avoid duplicating code between runnableExamples and tests From af8b1d0cb9bfa2f3b91b95219f850d075fc745f1 Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Fri, 19 Jan 2024 12:12:31 +0000 Subject: [PATCH 120/123] Fixing overload resolution documentation (#23171) As requested. Let me know where adjustments are wanted. --- doc/manual.md | 86 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index 9ffd9b2cd9aa0..1de7f32b4afc1 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2619,13 +2619,20 @@ An expression `b` can be assigned to an expression `a` iff `a` is an Overload resolution =================== -In a call `p(args)` the routine `p` that matches best is selected. If -multiple routines match equally well, the ambiguity is reported during -semantic analysis. +In a call `p(args)` where `p` may refer to more than one +candidate, it is said to be a symbol choice. Overload resolution will attempt to +find the best candidate, thus transforming the symbol choice into a resolved symbol. +The routine `p` that matches best is selected following a series of trials explained below. +In order: Catagory matching, Hierarchical Order Comparison, and finally, Complexity Analysis. -Every arg in args needs to match. There are multiple different categories how an -argument can match. Let `f` be the formal parameter's type and `a` the type -of the argument. +If multiple candidates match equally well after all trials have been tested, the ambiguity +is reported during semantic analysis. + +First Trial: Catagory matching +-------------------------------- + +Every arg in `args` needs to match and there are multiple different categories of matches. +Let `f` be the formal parameter's type and `a` the type of the argument. 1. Exact match: `a` and `f` are of the same type. 2. Literal match: `a` is an integer literal of value `v` @@ -2635,9 +2642,7 @@ of the argument. range. 3. Generic match: `f` is a generic type and `a` matches, for instance `a` is `int` and `f` is a generic (constrained) parameter - type (like in `[T]` or `[T: int|char]`). Constraints given an alias (as in `T`) - shall be used to define `f`, when `f` is composed of `T`, following simple variable - substitution. + type (like in `[T]` or `[T: int|char]`). 4. Subrange or subtype match: `a` is a `range[T]` and `T` matches `f` exactly. Or: `a` is a subtype of `f`. 5. Integral conversion match: `a` is convertible to `f` and `f` and `a` @@ -2645,15 +2650,16 @@ of the argument. 6. Conversion match: `a` is convertible to `f`, possibly via a user defined `converter`. +Each operand may fall into one of the categories above; the operand's +highest priority category. The list above is in order or priority. +If a candidate has more priority matches than all other candidates, it is selected as the +resolved symbol. -There are two major methods of selecting the best matching candidate, namely -counting and disambiguation. Counting takes precedence to disambiguation. In counting, -each parameter is given a category and the number of parameters in each category is counted. For example, if a candidate with one exact match is compared to a candidate with multiple generic matches and zero exact matches, the candidate with an exact match will win. -In the following, `count(p, m)` counts the number of matches of the matching category `m` -for the routine `p`. +Below is a pseudocode interpretation of category matching, `count(p, m)` counts the number +of matches of the matching category `m` for the routine `p`. A routine `p` matches better than a routine `q` if the following algorithm returns true: @@ -2670,15 +2676,51 @@ algorithm returns true: return "ambiguous" ``` -When counting is ambiguous, disambiguation begins. Disambiguation also has two stages, first a -hierarchical type relation comparison, and if that is inconclusive, a complexity comparison. -Where counting relates the type of the operand to the formal parameter, disambiguation relates the -formal parameters with each other to find the most competitive choice. -Parameters are iterated by position and these parameter pairs are compared for their type -relation. The general goal of this comparison is to determine which parameter is least general. +Second Trial: Hierarchical Order Comparison +---------------------------------------------- + +The hierarchical order of a type is analogous to its relative specificity. Consider the type defined: + +```nim +type A[T] = object +``` + +Matching formals for this type include `T`, `object`, `A`, `A[...]` and `A[C]` where `C` is a concrete type, `A[...]` +is a generic typeclass composition and `T` is an unconstrained generic type variable. This list is in order of +specificity with respect to `A` as each subsequent category narrows the set of types that are members of their match set. + +In this trail, the formal parameters of candidates are compared in order (1st parameter, 2nd parameter, etc.) to search for +a candidate that has an unrivaled specificity. If such a formal parameter is found, the candidate it belongs to is chosen +as the resolved symbol. + +Third Trial: Complexity Analysis +---------------------------------- + +A slight clarification: While category matching digests all the formal parameters of a candidate at once (order doesn't matter), +specificity comparison and complexity analysis operate on each formal parameter at a time. The following +is the final trial to disambiguate a symbol choice when a pair of formal parameters have the same hierarchical order. + +The complexity of a type is essentially its number of modifiers and depth of shape. The definition with the *highest* +complexity wins. Consider the following types: + +```nim +type + A[T] = object + B[T, H] = object +``` + +Note: The below examples are not exhaustive. +We shall say that: -Some examples: +1. `A[T]` has a higher complexity than `A` +2. `var A[T]` has a higher complexity than `A[T]` +3. `A[A[T]]` has a higher complexity than `A[T]` +4. `B[T, H]` has a higher complexity than `A[T]` (`A` and `B` are not compatible here, but convoluted versions of this exist) +5. `B[ptr T, H]` has a higher complexity than `B[T, H]` + +Some Examples +--------------- ```nim proc takesInt(x: int) = echo "int" @@ -2749,7 +2791,7 @@ proc p[T: A](param: T) proc p[T: object](param: T) ``` -These signatures are not ambiguous for an instance of `A` even though the formal parameters match ("T" == "T"). +These signatures are not ambiguous for a concrete type of `A` even though the formal parameters match ("T" == "T"). Instead `T` is treated as a variable in that (`T` ?= `T`) depending on the bound type of `T` at the time of overload resolution. From 1855f67503e6c541f3d8c38c3ec28c0fbb02be1a Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 19 Jan 2024 23:04:30 +1000 Subject: [PATCH 121/123] Make `data-theme` default to "auto" in HTML (#23222) Makes docs default to using browser settings instead of light mode This should fix #16515 since it doesn't require the browser to run the JS to set the default Also means that dark mode can be used without JS if the browser is configured to default to dark mode --- config/nimdoc.cfg | 2 +- nimdoc/extlinks/project/expected/_._/util.html | 2 +- nimdoc/extlinks/project/expected/doc/manual.html | 2 +- nimdoc/extlinks/project/expected/main.html | 2 +- nimdoc/extlinks/project/expected/sub/submodule.html | 2 +- nimdoc/extlinks/project/expected/theindex.html | 2 +- nimdoc/rst2html/expected/rst_examples.html | 2 +- nimdoc/test_doctype/expected/test_doctype.html | 2 +- nimdoc/test_out_index_dot_html/expected/index.html | 2 +- nimdoc/test_out_index_dot_html/expected/theindex.html | 2 +- nimdoc/testproject/expected/subdir/subdir_b/utils.html | 2 +- nimdoc/testproject/expected/testproject.html | 2 +- nimdoc/testproject/expected/theindex.html | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 9535aa384fc22..5b902b362b597 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -226,7 +226,7 @@ doc.listing_end = "" doc.file = """ - + diff --git a/nimdoc/extlinks/project/expected/_._/util.html b/nimdoc/extlinks/project/expected/_._/util.html index 35f3332112893..2078d208ced8f 100644 --- a/nimdoc/extlinks/project/expected/_._/util.html +++ b/nimdoc/extlinks/project/expected/_._/util.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/extlinks/project/expected/doc/manual.html b/nimdoc/extlinks/project/expected/doc/manual.html index 7b964f4aceb0e..64a0f7b7e5e4f 100644 --- a/nimdoc/extlinks/project/expected/doc/manual.html +++ b/nimdoc/extlinks/project/expected/doc/manual.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/extlinks/project/expected/main.html b/nimdoc/extlinks/project/expected/main.html index f46d72115d905..d86bd1d358ba7 100644 --- a/nimdoc/extlinks/project/expected/main.html +++ b/nimdoc/extlinks/project/expected/main.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/extlinks/project/expected/sub/submodule.html b/nimdoc/extlinks/project/expected/sub/submodule.html index 60887ae37ad3b..786de5b860f19 100644 --- a/nimdoc/extlinks/project/expected/sub/submodule.html +++ b/nimdoc/extlinks/project/expected/sub/submodule.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/extlinks/project/expected/theindex.html b/nimdoc/extlinks/project/expected/theindex.html index 9d2f6723cb891..86af18407c004 100644 --- a/nimdoc/extlinks/project/expected/theindex.html +++ b/nimdoc/extlinks/project/expected/theindex.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index af46771f37e67..6bfc4bc7930cd 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/test_doctype/expected/test_doctype.html b/nimdoc/test_doctype/expected/test_doctype.html index 694ed9b00e4a5..149c88a18a22e 100644 --- a/nimdoc/test_doctype/expected/test_doctype.html +++ b/nimdoc/test_doctype/expected/test_doctype.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 40df1943a84cb..80f09c5adf294 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html index ea3486d4b697a..dcda2574c3449 100644 --- a/nimdoc/test_out_index_dot_html/expected/theindex.html +++ b/nimdoc/test_out_index_dot_html/expected/theindex.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 5969e48bba066..4ddf458f204c9 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index dfd10390a5146..6a7870c6a8804 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -1,7 +1,7 @@ - + diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 70916f7e0c624..6b811f5e27d03 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -1,7 +1,7 @@ - + From 720021908db1f6622c1ebcdad60dff5c2740a80b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 20 Jan 2024 03:37:16 +0800 Subject: [PATCH 122/123] fixes #23233; Regression when using generic type with Table/OrderedTable (#23235) fixes #23233 --- compiler/types.nim | 2 +- tests/generics/tgeneric0.nim | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 8c447ddbfbae2..3726378273d97 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1234,7 +1234,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = let lhs = x.skipGenericAlias rhs = y.skipGenericAlias - if rhs.kind != tyGenericInst or lhs.base != rhs.base: + if rhs.kind != tyGenericInst or lhs.base != rhs.base or rhs.kidsLen != lhs.kidsLen: return false for ff, aa in underspecifiedPairs(rhs, lhs, 1, -1): if not sameTypeAux(ff, aa, c): return false diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index b5e1c4bb4e6c7..e0b61a58d7a98 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -9,7 +9,7 @@ float32 """ -import tables +import std/tables block tgeneric0: @@ -166,3 +166,23 @@ type # bug #8295 var x = AtomicContainer[int]() doAssert (ptr Block[int])(x.b) == nil + + +# bug #23233 +type + JsonObjectType*[T: string or uint64] = Table[string, JsonValueRef[T]] + + JsonValueRef*[T: string or uint64] = object + objVal*: JsonObjectType[T] + +proc scanValue[K](val: var K) = + var map: JsonObjectType[K.T] + var newVal: K + map["one"] = newVal + +block: + var a: JsonValueRef[uint64] + scanValue(a) + + var b: JsonValueRef[string] + scanValue(b) From 83f2708909e0c59b84f61c2721907ff896285dce Mon Sep 17 00:00:00 2001 From: Angel Ezquerra Date: Sat, 20 Jan 2024 06:39:49 +0100 Subject: [PATCH 123/123] Speed up complex.pow when the exponent is 2.0 or 0.5 (#23237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR speeds up the calculation of the power of a complex number when the exponent is 2.0 or 0.5 (i.e the square and the square root of a complex number). These are probably two of (if not) the most common exponents. The speed up that is achieved according to my measurements (using the timeit library) when the exponent is set to 2.0 or 0.5 is > x7, while there is no measurable difference when using other exponents. For the record, this is the function I used to mesure the performance: ```nim import std/complex import timeit proc calculcatePows(v: seq[Complex], factor: Complex): seq[Complex] {.noinit, discardable.} = result = newSeq[Complex](v.len) for n in 0 ..< v.len: result[n] = pow(v[n], factor) let v: seq[Complex64] = collect: for n in 0 ..< 1000: complex(float(n)) echo timeGo(calculcatePows(v, complex(1.5))) echo timeGo(calculcatePows(v, complex(0.5))) echo timeGo(calculcatePows(v, complex(2.0))) ``` Which with the original code got: > [177μs 857.03ns] ± [1μs 234.85ns] per loop (mean ± std. dev. of 7 runs, 1000 loops each) > [128μs 217.92ns] ± [1μs 630.93ns] per loop (mean ± std. dev. of 7 runs, 1000 loops each) > [136μs 220.16ns] ± [3μs 475.56ns] per loop (mean ± std. dev. of 7 runs, 1000 loops each) While with the improved code got: > [176μs 884.30ns] ± [1μs 307.30ns] per loop (mean ± std. dev. of 7 runs, 1000 loops each) > [23μs 160.79ns] ± [340.18ns] per loop (mean ± std. dev. of 7 runs, 10000 loops each) > [19μs 93.29ns] ± [1μs 128.92ns] per loop (mean ± std. dev. of 7 runs, 10000 loops each) That is, the new optimized path is 5.6 (23 vs 128 us per loop) to 7.16 times faster (19 vs 136 us per loop), while the non-optimized path takes the same time as the original code. --- lib/pure/complex.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 2ea29a4f98cd0..dc899a2f76230 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -81,7 +81,7 @@ func abs2*[T](z: Complex[T]): T = ## that is the squared distance from (0, 0) to `z`. ## This is more efficient than `abs(z) ^ 2`. result = z.re * z.re + z.im * z.im - + func sgn*[T](z: Complex[T]): Complex[T] = ## Returns the phase of `z` as a unit complex number, ## or 0 if `z` is 0. @@ -253,6 +253,10 @@ func pow*[T](x, y: Complex[T]): Complex[T] = result = x elif y.re == -1.0 and y.im == 0.0: result = T(1.0) / x + elif y.re == 2.0 and y.im == 0.0: + result = x * x + elif y.re == 0.5 and y.im == 0.0: + result = sqrt(x) else: let rho = abs(x)