diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-07-18 18:16:32 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-07-18 18:16:32 +0200 |
commit | fbb0642e278efd1b9ac4175228befc58655c3849 (patch) | |
tree | ae4d5349c81e33bd83cfe8c3ea94bc0c5e684100 | |
parent | 9852cf804b09710837c849bdfda2be499e702a05 (diff) | |
parent | 6d8913ee1422143baebd438f7526208193c0bd5e (diff) | |
download | Nim-fbb0642e278efd1b9ac4175228befc58655c3849.tar.gz |
Merge branch 'devel' into araq-detect-unused-imports
105 files changed, 1274 insertions, 791 deletions
diff --git a/changelog_v020.md b/changelog_v020.md index 346ccda89..0f4582ae7 100644 --- a/changelog_v020.md +++ b/changelog_v020.md @@ -1,39 +1,20 @@ -# v0.20.2 - XXXX-XX-XX +# v0.20.4 - xxxx-xx-xx ## Changes affecting backwards compatibility -- All `strutils.rfind` procs now take `start` and `last` like `strutils.find` - with the same data slice/index meaning. This is backwards compatible for - calls *not* changing the `rfind` `start` parameter from its default. (#11487) - - In the unlikely case that you were using `rfind X, start=N`, or `rfind X, N`, - then you need to change that to `rfind X, last=N` or `rfind X, 0, N`. (This - should minimize gotchas porting code from other languages like Python or C++.) - -- On Windows stderr/stdout/stdin are not opened as binary files anymore. Use the switch - `-d:nimBinaryStdFiles` for a transition period. ### Breaking changes in the standard library -- Mac OS X / BSD: TSa_Family is now the ``uint8`` type, so type - conversions like ``x.sin_family = uint16 toInt(nativesockets.AF_INET)`` - need to be changed into ``x.sin_family = TSa_Family toInt(nativesockets.AF_INET)``. - ### Breaking changes in the compiler ## Library additions -- `toOpenArray` is now available for the JS target. ## Library changes -- Fix async IO operations stalling even after socket is closed. (#11232) - -- More informative error message for `streams.openFileStream`. (#11438) - ## Language additions @@ -46,10 +27,5 @@ ### Compiler changes -- Better error message for IndexError for empty containers. (#11476) - -- Fix regression in semfold for old right shift. (#11477) - -- Fix for passing tuples as static params to macros. (#11423) ## Bugfixes diff --git a/changelogs/changelog_0_20_2.md b/changelogs/changelog_0_20_2.md new file mode 100644 index 000000000..4f09ae3c5 --- /dev/null +++ b/changelogs/changelog_0_20_2.md @@ -0,0 +1,55 @@ +# v0.20.2 - 2019-07-17 + + +## Changes affecting backwards compatibility + +- All `strutils.rfind` procs now take `start` and `last` like `strutils.find` + with the same data slice/index meaning. This is backwards compatible for + calls *not* changing the `rfind` `start` parameter from its default. (#11487) + + In the unlikely case that you were using `rfind X, start=N`, or `rfind X, N`, + then you need to change that to `rfind X, last=N` or `rfind X, 0, N`. (This + should minimize gotchas porting code from other languages like Python or C++.) + +- On Windows stderr/stdout/stdin are not opened as binary files anymore. Use the switch + `-d:nimBinaryStdFiles` for a transition period. + +### Breaking changes in the standard library + +- Mac OS X / BSD: TSa_Family is now the ``uint8`` type, so type + conversions like ``x.sin_family = uint16 toInt(nativesockets.AF_INET)`` + need to be changed into ``x.sin_family = TSa_Family toInt(nativesockets.AF_INET)``. + + +### Breaking changes in the compiler + + +## Library additions + +- `toOpenArray` is now available for the JS target. + +## Library changes + +- Fix async IO operations stalling even after socket is closed. (#11232) + +- More informative error message for `streams.openFileStream`. (#11438) + + +## Language additions + + +## Language changes + + +### Tool changes + + +### Compiler changes + +- Better error message for IndexError for empty containers. (#11476) + +- Fix regression in semfold for old right shift. (#11477) + +- Fix for passing tuples as static params to macros. (#11423) + +## Bugfixes diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md index 7ca4a1b9a..8b8d5eb91 100644 --- a/changelogs/changelog_X_XX_X.md +++ b/changelogs/changelog_X_XX_X.md @@ -1,27 +1,33 @@ -## v0.XX.0 - XX/XX/2018 +# vx.xx.x - yyyy-mm-dd -### Changes affecting backwards compatibility -- Example item: ``Foo`` changed to ``Bar``. +## Changes affecting backwards compatibility -#### Breaking changes in the standard library +- Example item: `Foo` changed to `Bar`. -#### Breaking changes in the compiler +### Breaking changes in the standard library -### Library additions -### Library changes +### Breaking changes in the compiler -### Language additions +## Library additions -### Language changes +## Library changes + + +## Language additions + + +## Language changes ### Tool changes + ### Compiler changes -### Bugfixes + +## Bugfixes diff --git a/compiler/ast.nim b/compiler/ast.nim index c8ce0dccb..8d52f12ff 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,8 +10,7 @@ # abstract syntax tree + symbol table import - lineinfos, hashes, nversion, options, strutils, std / sha1, ropes, idents, - intsets, idgen + lineinfos, hashes, options, ropes, idents, idgen type TCallingConvention* = enum diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index a0aa1b05d..cdb43f20f 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -11,8 +11,8 @@ ## is needed for incremental compilation. import - ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils, - intsets, platform, llstream, tables, sighashes, modulegraphs, pathutils + ast, ropes, options, strutils, nimlexbase, cgendata, rodutils, + intsets, llstream, tables, modulegraphs, pathutils # Careful! Section marks need to contain a tabulator so that they cannot # be part of C string literals. diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 455012e60..3c7b0510e 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,7 +10,7 @@ # This module declares some helpers for the C code generator. import - ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg, + ast, hashes, strutils, msgs, wordrecg, platform, trees, options proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 4f136d9e3..d2ddd4a39 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -11,9 +11,9 @@ import ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, - nversion, nimsets, msgs, std / sha1, bitsets, idents, types, + nversion, nimsets, msgs, bitsets, idents, types, ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, - condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, + condsyms, rodutils, renderer, cgendata, ccgmerge, aliases, lowerings, tables, sets, ndi, lineinfos, pathutils, transf, enumtostr when not defined(leanCompiler): diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 76c64782c..77445639e 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -10,7 +10,7 @@ ## This module contains the data structures for the C code generation phase. import - ast, astalgo, ropes, passes, options, intsets, platform, sighashes, + ast, ropes, passes, options, intsets, tables, ndi, lineinfos, pathutils, modulegraphs type diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index ab406bc4b..d83ca3c55 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -10,7 +10,7 @@ ## This module implements code generation for multi methods. import - intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, + intsets, options, ast, msgs, idents, renderer, types, magicsys, sempass2, strutils, modulegraphs, lineinfos proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index d1f2a6cd6..22595b772 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -131,8 +131,8 @@ # break :stateLoop import - intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents, - renderer, types, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos + ast, msgs, idents, + renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos type Ctx = object diff --git a/compiler/commands.nim b/compiler/commands.nim index ff76fff71..ed0320a7c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -27,7 +27,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, - wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, lineinfos, + wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos, pathutils, strtabs # but some have deps to imported modules. Yay. diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ed95c8183..ce295c8b9 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -10,7 +10,7 @@ # This module handles the conditional symbols. import - strtabs, platform, strutils, idents + strtabs from options import Feature from lineinfos import HintsToStr, WarningsToStr diff --git a/compiler/depends.nim b/compiler/depends.nim index 300ab3b54..603f67e77 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -10,8 +10,7 @@ # This module implements a dependency file generator. import - os, options, ast, astalgo, msgs, ropes, idents, passes, modulepaths, - pathutils + options, ast, ropes, idents, passes, modulepaths, pathutils from modulegraphs import ModuleGraph, PPassContext diff --git a/compiler/dfa.nim b/compiler/dfa.nim index f97d8f298..7315e74bc 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -29,7 +29,7 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer +import ast, types, intsets, lineinfos, renderer from patterns import sameTrees diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a98360c07..2e03c0d4d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -16,7 +16,7 @@ import wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, packages/docutils/rst, packages/docutils/rstgen, packages/docutils/highlite, json, xmltree, cgi, trees, types, - typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets, + typesrenderer, astalgo, modulepaths, lineinfos, intsets, pathutils, trees const diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 048860423..e19b3a989 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -11,8 +11,7 @@ # semantic checking. import - os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos, - pathutils + options, ast, msgs, idents, passes, docgen, lineinfos, pathutils from modulegraphs import ModuleGraph, PPassContext diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 8acb85907..d3d3e5f77 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -10,8 +10,7 @@ ## Template evaluation engine. Now hygienic. import - strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer, - lineinfos + strutils, options, ast, astalgo, msgs, renderer, lineinfos type TemplCtx = object diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 4ecad6d58..011252fe4 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -949,6 +949,8 @@ proc callCCompiler*(conf: ConfigRef) = #from json import escapeJson import json, std / sha1 +template hashNimExe(): string = $secureHashFile(os.getAppFilename()) + proc writeJsonBuildInstructions*(conf: ConfigRef) = template lit(x: untyped) = f.write x template str(x: untyped) = @@ -1028,7 +1030,9 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = str conf.commandLine lit ",\L\"nimfiles\":[\L" nimfiles(conf, f) - lit "]\L" + lit "],\L\"nimexe\": \L" + str hashNimExe() + lit "\L" lit "\L}\L" close(f) @@ -1045,6 +1049,8 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol let oldCmdLine = data["cmdline"].getStr if conf.commandLine != oldCmdLine: return true + if hashNimExe() != data["nimexe"].getStr: + return true let nimfilesPairs = data["nimfiles"] doAssert nimfilesPairs.kind == JArray for p in nimfilesPairs: diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index b884b1ec3..490c184cf 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -10,8 +10,8 @@ # This module implements Nim's standard template filter. import - llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, - renderer, filters, lineinfos, pathutils + llstream, strutils, ast, msgs, options, + filters, lineinfos, pathutils type TParseState = enum diff --git a/compiler/filters.nim b/compiler/filters.nim index c04d61320..a2f7b6bbb 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -10,7 +10,7 @@ # This module implements Nim's simple filters and helpers for filters. import - llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, + llstream, idents, strutils, ast, msgs, options, renderer, pathutils proc invalidPragma(conf: ConfigRef; n: PNode) = diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index d61dcdac3..c9f82b505 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -9,7 +9,7 @@ ## Module that implements ``gorge`` for the compiler. -import msgs, std / sha1, os, osproc, streams, strutils, options, +import msgs, std / sha1, os, osproc, streams, options, lineinfos, pathutils proc readOutput(p: Process): (string, int) = diff --git a/compiler/idents.nim b/compiler/idents.nim index f82ff5db5..3153745d5 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -12,7 +12,7 @@ # id. This module is essential for the compiler's performance. import - hashes, strutils, wordrecg + hashes, wordrecg type TIdObj* = object of RootObj diff --git a/compiler/idgen.nim b/compiler/idgen.nim index 239df0c57..7d49e33e3 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -9,7 +9,7 @@ ## This module contains a simple persistent id generator. -import idents, strutils, os, options, pathutils +import idents, strutils, options, pathutils var gFrontEndId*: int diff --git a/compiler/importer.nim b/compiler/importer.nim index cab5485aa..426b79981 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -10,8 +10,8 @@ ## This module implements the symbol importing mechanism. import - intsets, strutils, os, ast, astalgo, msgs, options, idents, lookups, - semdata, passes, renderer, modulepaths, sigmatch, lineinfos + intsets, ast, astalgo, msgs, options, idents, lookups, + semdata, modulepaths, sigmatch, lineinfos proc readExceptSet*(c: PContext, n: PNode): IntSet = assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} diff --git a/compiler/incremental.nim b/compiler/incremental.nim index f66a75efd..29528bbd3 100644 --- a/compiler/incremental.nim +++ b/compiler/incremental.nim @@ -12,10 +12,10 @@ const nimIncremental* = defined(nimIncremental) -import options, lineinfos, pathutils +import options, lineinfos when nimIncremental: - import ast, msgs, intsets, btrees, db_sqlite, std / sha1 + import ast, msgs, intsets, btrees, db_sqlite, std / sha1, pathutils from strutils import parseInt type diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index a8a2cf97f..6f1da37fb 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -134,7 +134,7 @@ to do it. ]# import - intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, + intsets, ast, msgs, renderer, magicsys, types, idents, strutils, options, dfa, lowerings, tables, modulegraphs, msgs, lineinfos, parampatterns, sighashes diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0c04b339c..788e3e75b 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -29,11 +29,11 @@ implements the required case distinction. import - ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, - nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables, - times, ropes, math, passes, ccgutils, wordrecg, renderer, + ast, strutils, trees, magicsys, options, + nversion, msgs, idents, types, tables, + ropes, math, passes, ccgutils, wordrecg, renderer, intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - pathutils, transf + transf from modulegraphs import ModuleGraph, PPassContext diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6d87444ec..679391224 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -10,7 +10,7 @@ # This file implements lambda lifting for the transformator. import - intsets, strutils, options, ast, astalgo, trees, treetab, msgs, + intsets, strutils, options, ast, astalgo, msgs, idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos, transf, liftdestructors diff --git a/compiler/layouter.nim b/compiler/layouter.nim index bff7d8a1b..367d2aead 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -32,7 +32,7 @@ type ltTab, ltOptionalNewline, ## optional newline introduced by nimpretty ltComment, ltLit, ltKeyword, ltExportMarker, ltIdent, - ltOther, ltOpr, + ltOther, ltOpr, ltSomeParLe, ltSomeParRi, ltBeginSection, ltEndSection Emitter* = object @@ -142,7 +142,7 @@ proc optionalIsGood(em: var Emitter; pos, currentLen: int): bool = result = true elif em.tokens[p+1].len < ourIndent: result = isLongEnough(lineLen, pos, p) - elif em.kinds[pos+1] == ltOther: # note: pos+1, not p+1 + elif em.kinds[pos+1] in {ltOther, ltSomeParLe, ltSomeParRi}: # note: pos+1, not p+1 result = false else: result = isLongEnough(lineLen, pos, p) @@ -153,13 +153,28 @@ proc lenOfNextTokens(em: Emitter; pos: int): int = if em.kinds[pos+i] in {ltCrucialNewline, ltSplittingNewline, ltOptionalNewline}: break inc result, em.tokens[pos+i].len +proc guidingInd(em: Emitter; pos: int): int = + var i = pos - 1 + while i >= 0 and em.kinds[i] != ltSomeParLe: + dec i + while i+1 <= em.kinds.high and em.kinds[i] != ltSomeParRi: + if em.kinds[i] == ltSplittingNewline and em.kinds[i+1] == ltSpaces: + return em.tokens[i+1].len + inc i + result = -1 + proc closeEmitter*(em: var Emitter) = + template defaultCase() = + content.add em.tokens[i] + inc lineLen, em.tokens[i].len + let outFile = em.config.absOutFile var content = newStringOfCap(16_000) var maxLhs = 0 var lineLen = 0 var lineBegin = 0 + var openPars = 0 var i = 0 while i <= em.tokens.high: when defined(debug): @@ -201,8 +216,13 @@ proc closeEmitter*(em: var Emitter) = let spaces = em.tokens[i-1].len content.setLen(content.len - spaces) content.add "\L" - content.add em.tokens[i] - lineLen = em.tokens[i].len + let guide = if openPars > 0: guidingInd(em, i) else: -1 + if guide >= 0: + content.add repeat(' ', guide) + lineLen = guide + else: + content.add em.tokens[i] + lineLen = em.tokens[i].len lineBegin = i+1 if i+1 < em.kinds.len and em.kinds[i+1] == ltSpaces: # inhibit extra spaces at the start of a new line @@ -215,9 +235,15 @@ proc closeEmitter*(em: var Emitter) = else: inc lineLen, em.tokens[i].len content.add em.tokens[i] + of ltSomeParLe: + inc openPars + defaultCase() + of ltSomeParRi: + doAssert openPars > 0 + dec openPars + defaultCase() else: - content.add em.tokens[i] - inc lineLen, em.tokens[i].len + defaultCase() inc i if fileExists(outFile) and readFile(outFile.string) == content: @@ -292,7 +318,7 @@ const tkCurlyLe} closedPars = {tkParRi, tkParDotRi, tkBracketRi, tkCurlyDotRi, - tkCurlyRi} + tkCurlyRi, tkBracketDotRi} splitters = openPars + {tkComma, tkSemiColon} # do not add 'tkColon' here! oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, @@ -416,7 +442,8 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = var newlineKind = ltCrucialNewline if em.keepIndents > 0: em.indentLevel = tok.indent - elif (em.lastTok in (splitters + oprSet) and tok.tokType notin closedPars): + elif (em.lastTok in (splitters + oprSet) and + tok.tokType notin (closedPars - {tkBracketDotRi})): # aka: we are in an expression context: let alignment = max(tok.indent - em.indentStack[^1], 0) em.indentLevel = alignment + em.indentStack.high * em.indWidth @@ -471,18 +498,14 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wr(em, TokTypeToStr[tok.tokType], ltOther) rememberSplit(splitComma) wrSpace em - of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe, - tkCurlyLe, tkCurlyDotLe, tkBracketLeColon: + of openPars: if tok.strongSpaceA > 0 and not em.endsInWhite and not em.wasExportMarker: wrSpace em - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, TokTypeToStr[tok.tokType], ltSomeParLe) rememberSplit(splitParLe) - of tkParRi, - tkBracketRi, tkCurlyRi, - tkBracketDotRi, - tkCurlyDotRi, - tkParDotRi, - tkColonColon: + of closedPars: + wr(em, TokTypeToStr[tok.tokType], ltSomeParRi) + of tkColonColon: wr(em, TokTypeToStr[tok.tokType], ltOther) of tkDot: lastTokWasTerse = true diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 97c2636ac..5619350ef 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -13,7 +13,7 @@ # Todo: # - use openArray instead of array to avoid over-specializations -import modulegraphs, lineinfos, idents, ast, astalgo, renderer, semdata, +import modulegraphs, lineinfos, idents, ast, renderer, semdata, sighashes, lowerings, options, types, msgs, magicsys, tables type diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index ae789cd88..eed0560ab 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -10,7 +10,7 @@ ## This module implements the '.liftLocals' pragma. import - intsets, strutils, options, ast, astalgo, msgs, + strutils, options, ast, msgs, idents, renderer, types, lowerings, lineinfos from pragmas import getPragmaVal diff --git a/compiler/linter.nim b/compiler/linter.nim index abefe9bec..d3c461b66 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -9,11 +9,9 @@ ## This module implements the style checker. -import - strutils, os, intsets, strtabs +import strutils -import options, ast, astalgo, msgs, semdata, ropes, idents, - lineinfos, pathutils, wordrecg +import options, ast, msgs, idents, lineinfos, wordrecg const Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'} diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 69a6905af..ab4e1645c 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -10,7 +10,7 @@ ## Low-level streams for high performance. import - strutils, pathutils + pathutils # support '-d:useGnuReadline' for backwards compatibility: when not defined(windows) and (defined(useGnuReadline) or defined(useLinenoise)): @@ -97,7 +97,7 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} = proc countTriples(s: string): int = var i = 0 - while i < s.len: + while i+2 < s.len: if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"': inc result inc i, 2 diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 7c37817fd..4de1fc371 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,7 +11,7 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, wordrecg, idgen, nimfix/prettybase, lineinfos, strutils + renderer, nimfix/prettybase, lineinfos, strutils proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 0030f1a49..727b88760 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -14,7 +14,6 @@ const import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs, lineinfos -from trees import getMagic proc newDeref*(n: PNode): PNode {.inline.} = result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0]) diff --git a/compiler/macrocacheimpl.nim b/compiler/macrocacheimpl.nim index d23040763..365497e31 100644 --- a/compiler/macrocacheimpl.nim +++ b/compiler/macrocacheimpl.nim @@ -9,7 +9,7 @@ ## This module implements helpers for the macro cache. -import lineinfos, ast, modulegraphs, vmdef, magicsys +import lineinfos, ast, modulegraphs, vmdef proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) = var recorded = newNodeI(nkCommentStmt, info) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index aeeb489c0..38240061f 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -10,7 +10,7 @@ # Built-in types and compilerprocs are registered here. import - ast, astalgo, hashes, msgs, platform, nversion, times, idents, + ast, astalgo, msgs, platform, idents, modulegraphs, lineinfos export createMagic diff --git a/compiler/main.nim b/compiler/main.nim index 460fd90c7..ce80af36d 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -13,12 +13,12 @@ when not defined(nimcore): {.error: "nimcore MUST be defined for Nim's core tooling".} import - llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs, - os, condsyms, times, - wordrecg, sem, semdata, idents, passes, extccomp, + llstream, strutils, ast, lexer, syntaxes, options, msgs, + condsyms, times, + sem, idents, passes, extccomp, cgen, json, nversion, - platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - parser, modules, ccgutils, sigmatch, ropes, + platform, nimconf, passaux, depends, vm, idgen, + parser, modules, modulegraphs, tables, rod, lineinfos, pathutils when not defined(leanCompiler): diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 6130c3032..eedb22084 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -8,7 +8,7 @@ # import ast, renderer, strutils, msgs, options, idents, os, lineinfos, - pathutils, nimblecmd + pathutils when false: const diff --git a/compiler/modules.nim b/compiler/modules.nim index 3dbc1b2c1..40d9a904c 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -10,8 +10,8 @@ ## Implements the module handling, including the caching of modules. import - ast, astalgo, magicsys, std / sha1, msgs, cgendata, sigmatch, options, - idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod, + ast, astalgo, magicsys, msgs, options, + idents, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod, lineinfos, pathutils, tables proc resetSystemArtifacts*(g: ModuleGraph) = diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 03b6213fa..1264133a9 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -8,7 +8,7 @@ # import - options, strutils, os, tables, ropes, platform, terminal, macros, + options, strutils, os, tables, ropes, terminal, macros, lineinfos, pathutils proc toCChar*(c: char; result: var string) = diff --git a/compiler/nim.nim b/compiler/nim.nim index 5fcf043b5..ec7e8b8dc 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -19,9 +19,9 @@ when defined(i386) and defined(windows) and defined(vcc): {.link: "../icons/nim-i386-windows-vcc.res".} import - commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, - extccomp, strutils, os, osproc, platform, main, parseopt, - scriptconfig, idents, modulegraphs, lineinfos, cmdlinehelper, + commands, options, msgs, + extccomp, strutils, os, main, parseopt, + idents, lineinfos, cmdlinehelper, pathutils include nodejs diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index f518b3abf..a470179bd 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -10,7 +10,7 @@ # This module handles the reading of the config file. import - llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, + llstream, commands, os, strutils, msgs, lexer, options, idents, wordrecg, strtabs, lineinfos, pathutils # ---------------- configuration file parser ----------------------------- diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index c3e16e5ba..fbc2e3bd1 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -8,9 +8,7 @@ # import strutils except Letters -import lexbase, streams import ".." / [ast, msgs, lineinfos, idents, options, linter] -from os import splitFile proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) = let line = sourceLine(conf, info) diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index c2436dff0..f4ef0cc39 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -10,8 +10,7 @@ # this unit handles Nim sets; it implements symbolic sets import - ast, astalgo, trees, nversion, lineinfos, platform, bitsets, types, renderer, - options + ast, astalgo, lineinfos, bitsets, types, options proc inSet*(s: PNode, elem: PNode): bool = assert s.kind == nkCurly diff --git a/compiler/options.nim b/compiler/options.nim index 985955d98..6303224a2 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -8,7 +8,7 @@ # import - os, strutils, strtabs, osproc, sets, lineinfos, platform, + os, strutils, strtabs, sets, lineinfos, platform, prefixmatches, pathutils from terminal import isatty diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index b4409fcec..1bd703fe8 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -10,7 +10,7 @@ ## This module implements the pattern matching features for term rewriting ## macro support. -import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees, +import strutils, ast, types, msgs, idents, renderer, wordrecg, trees, options # we precompile the pattern here for efficiency into some internal diff --git a/compiler/parser.nim b/compiler/parser.nim index 12036f20b..101e66ba4 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -27,7 +27,7 @@ when isMainModule: outp.close import - llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos, + llstream, lexer, idents, strutils, ast, msgs, options, lineinfos, pathutils when defined(nimpretty): @@ -1203,6 +1203,13 @@ proc parseFor(p: var TParser): PNode = colcom(p, result) addSon(result, parseStmt(p)) +template nimprettyDontTouch(body) = + when defined(nimpretty): + inc p.em.keepIndents + body + when defined(nimpretty): + dec p.em.keepIndents + proc parseExpr(p: var TParser): PNode = #| expr = (blockExpr #| | ifExpr @@ -1212,12 +1219,26 @@ proc parseExpr(p: var TParser): PNode = #| | tryExpr) #| / simpleExpr case p.tok.tokType: - of tkBlock: result = parseBlock(p) - of tkIf: result = parseIfExpr(p, nkIfExpr) - of tkFor: result = parseFor(p) - of tkWhen: result = parseIfExpr(p, nkWhenExpr) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p, isExpr=true) + of tkBlock: + nimprettyDontTouch: + result = parseBlock(p) + of tkIf: + nimprettyDontTouch: + result = parseIfExpr(p, nkIfExpr) + of tkFor: + nimprettyDontTouch: + result = parseFor(p) + of tkWhen: + nimprettyDontTouch: + result = parseIfExpr(p, nkWhenExpr) + of tkCase: + # Currently we think nimpretty is good enough with case expressions, + # so it is allowed to touch them: + #nimprettyDontTouch: + result = parseCase(p) + of tkTry: + nimprettyDontTouch: + result = parseTry(p, isExpr=true) else: result = simpleExpr(p) proc parseEnum(p: var TParser): PNode diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 17c4c506a..2ac89c24e 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -10,7 +10,7 @@ ## implements some little helper passes import - strutils, ast, astalgo, passes, idents, msgs, options, idgen, lineinfos + ast, passes, idents, msgs, options, idgen, lineinfos from modulegraphs import ModuleGraph, PPassContext diff --git a/compiler/passes.nim b/compiler/passes.nim index 72140d9de..7effcfeb5 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -11,9 +11,9 @@ ## `TPass` interface. import - strutils, options, ast, astalgo, llstream, msgs, platform, os, - condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, - nimsets, syntaxes, times, idgen, modulegraphs, reorder, rod, + options, ast, llstream, msgs, + idents, + syntaxes, idgen, modulegraphs, reorder, rod, lineinfos, pathutils type diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index cd6fb2a53..b73942a21 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -10,7 +10,7 @@ ## Path handling utilities for Nim. Strictly typed code in order ## to avoid the never ending time sink in getting path handling right. -import os, strutils, pathnorm +import os, pathnorm type AbsoluteFile* = distinct string diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 5ec18f67b..623a04406 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -11,8 +11,7 @@ ## macro support. import - ast, astalgo, types, semdata, sigmatch, msgs, idents, aliases, parampatterns, - trees + ast, types, semdata, sigmatch, idents, aliases, parampatterns, trees type TPatternContext = object diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index 440d2e081..e4b3a5029 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -9,9 +9,7 @@ ## Plugin to transform an inline iterator into a data structure. -import ".." / [ast, astalgo, - magicsys, lookups, semdata, - lambdalifting, msgs] +import ".." / [ast, lookups, semdata, lambdalifting, msgs] proc iterToProcImpl*(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) diff --git a/compiler/plugins/locals.nim b/compiler/plugins/locals.nim index eb3324b36..08d836f7d 100644 --- a/compiler/plugins/locals.nim +++ b/compiler/plugins/locals.nim @@ -9,7 +9,7 @@ ## The builtin 'system.locals' implemented as a plugin. -import ".." / [pluginsupport, ast, astalgo, +import ".." / [ast, astalgo, magicsys, lookups, semdata, lowerings] proc semLocals*(c: PContext, n: PNode): PNode = diff --git a/compiler/reorder.nim b/compiler/reorder.nim index e341885ee..960929811 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -1,7 +1,7 @@ import - intsets, ast, idents, algorithm, renderer, parser, os, strutils, - sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables, + intsets, ast, idents, algorithm, renderer, os, strutils, + msgs, modulegraphs, syntaxes, options, modulepaths, lineinfos type diff --git a/compiler/rod.nim b/compiler/rod.nim index bbd2f0c6c..e3e568a0e 100644 --- a/compiler/rod.nim +++ b/compiler/rod.nim @@ -9,7 +9,7 @@ ## This module implements the canonalization for the various caching mechanisms. -import ast, idgen, lineinfos, msgs, incremental, modulegraphs, pathutils +import ast, idgen, lineinfos, incremental, modulegraphs, pathutils when not nimIncremental: template setupModuleCache*(g: ModuleGraph) = discard diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 6c3d0a122..9878cf597 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -11,9 +11,10 @@ ## language. import - ast, modules, idents, passes, passaux, condsyms, - options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs, - os, times, osproc, wordrecg, strtabs, modulegraphs, lineinfos, pathutils + ast, modules, idents, passes, condsyms, + options, sem, llstream, vm, vmdef, commands, msgs, + os, times, osproc, wordrecg, strtabs, modulegraphs, + lineinfos, pathutils # we support 'cmpIgnoreStyle' natively for efficiency: from strutils import cmpIgnoreStyle, contains diff --git a/compiler/sem.nim b/compiler/sem.nim index 39ffeeb4d..e33170553 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -10,13 +10,13 @@ # This module implements the semantic checking pass. import - ast, strutils, hashes, options, lexer, astalgo, trees, treetab, - wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, - magicsys, parser, nversion, nimsets, semfold, modulepaths, importer, + ast, strutils, options, astalgo, trees, + wordrecg, ropes, msgs, idents, renderer, types, platform, math, + magicsys, nversion, nimsets, semfold, modulepaths, importer, procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, pluginsupport, plugins/active, rod, lineinfos, strtabs, int128 + lowerings, plugins/active, rod, lineinfos, strtabs, int128 from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 23ac4f65b..d2f878831 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -107,7 +107,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, elif errorsEnabled or z.diagnosticsEnabled: errors.add(CandidateError( sym: sym, - unmatchedVarParam: int z.mutabilityProblem, firstMismatch: z.firstMismatch, diagnostics: z.diagnostics)) else: @@ -173,14 +172,14 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): var filterOnlyFirst = false if optShowAllMismatches notin c.config.globalOptions: for err in errors: - if err.firstMismatch > 1: + if err.firstMismatch.arg > 1: filterOnlyFirst = true break var candidates = "" var skipped = 0 for err in errors: - if filterOnlyFirst and err.firstMismatch == 1: + if filterOnlyFirst and err.firstMismatch.arg == 1: inc skipped continue if err.sym.kind in routineKinds and err.sym.ast != nil: @@ -189,34 +188,35 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): else: add(candidates, getProcHeader(c.config, err.sym, prefer)) add(candidates, "\n") - if err.firstMismatch != 0 and n.len > 1: - let cond = n.len > 2 - if cond: - candidates.add(" first type mismatch at position: " & $abs(err.firstMismatch)) - if err.firstMismatch >= 0: candidates.add("\n required type: ") - else: candidates.add("\n unknown named parameter: " & $n[-err.firstMismatch][0]) - var wanted, got: PType = nil - if err.firstMismatch < 0: - discard - elif err.firstMismatch < err.sym.typ.len: - wanted = err.sym.typ.sons[err.firstMismatch] - if cond: candidates.add typeToString(wanted) - else: - if cond: candidates.add "none" - if err.firstMismatch > 0 and err.firstMismatch < n.len: - if cond: - candidates.add "\n but expression '" - candidates.add renderTree(n[err.firstMismatch]) + let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil + let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: "" + if n.len > 1: + candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg) + # candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging + case err.firstMismatch.kind + of kUnknownNamedParam: candidates.add("\n unknown named parameter: " & $nArg[0]) + of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0]) + of kExtraArg: candidates.add("\n extra argument given") + of kMissingParam: candidates.add("\n missing parameter: " & nameParam) + of kTypeMismatch, kVarNeeded: + doAssert nArg != nil + var wanted = err.firstMismatch.formal.typ + doAssert err.firstMismatch.formal != nil + candidates.add("\n required type for " & nameParam & ": ") + candidates.add typeToString(wanted) + candidates.add "\n but expression '" + if err.firstMismatch.kind == kVarNeeded: + candidates.add renderNotLValue(nArg) + candidates.add "' is immutable, not 'var'" + else: + candidates.add renderTree(nArg) candidates.add "' is of type: " - got = n[err.firstMismatch].typ - if cond: candidates.add typeToString(got) - if wanted != nil and got != nil: - effectProblem(wanted, got, candidates) - if cond: candidates.add "\n" - if err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len: - candidates.add(" for a 'var' type a variable needs to be passed, but '" & - renderNotLValue(n[err.unmatchedVarParam]) & - "' is immutable\n") + var got = nArg.typ + candidates.add typeToString(got) + doAssert wanted != nil + if got != nil: effectProblem(wanted, got, candidates) + of kUnknown: internalAssert(c.config, false) + candidates.add "\n" for diag in err.diagnostics: candidates.add(diag & "\n") if skipped > 0: @@ -260,7 +260,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) = while symx != nil: if symx.kind in routineKinds: errors.add(CandidateError(sym: symx, - unmatchedVarParam: 0, firstMismatch: 0, + firstMismatch: MismatchInfo(), diagnostics: @[], enabled: false)) symx = nextOverloadIter(o, c, headSymbol) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index a64f88962..76eb468ed 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -10,11 +10,8 @@ ## This module contains the data structures for the semantic checking phase. import - strutils, intsets, options, lexer, ast, astalgo, trees, treetab, - wordrecg, - ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, - magicsys, nversion, nimsets, parser, times, passes, vmdef, - modulegraphs, lineinfos + intsets, options, ast, astalgo, msgs, idents, renderer, + magicsys, passes, vmdef, modulegraphs, lineinfos type TOptionEntry* = object # entries to put on a stack for pragma parsing diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 733df2c40..929283bef 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1414,6 +1414,9 @@ proc semDeref(c: PContext, n: PNode): PNode = var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned}) case t.kind of tyRef, tyPtr: n.typ = t.lastSon + of tyTypeDesc: + # typeof(x[]) is still a typedesc: + n.typ = makeTypeDesc(c, t.lastSon.lastSon) else: result = nil #GlobalError(n.sons[0].info, errCircumNeedsPointer) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 2f07940c8..c7efa1a87 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -11,8 +11,8 @@ # and evaluation phase import - strutils, options, ast, astalgo, trees, treetab, nimsets, - nversion, platform, math, msgs, os, condsyms, idents, renderer, types, + strutils, options, ast, trees, nimsets, + platform, math, msgs, idents, renderer, types, commands, magicsys, modulegraphs, strtabs, lineinfos proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode = diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index faf3e3868..af740e518 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -10,7 +10,7 @@ ## Implements type sanity checking for ASTs resulting from macros. Lots of ## room for improvement here. -import ast, astalgo, msgs, types, options +import ast, msgs, types, options proc ithField(n: PNode, field: var int): PSym = result = nil diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 0e1c9cb07..8252a7857 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, lowerings, sigmatch, tables + modulegraphs when not defined(leanCompiler): import writetracking diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index c69797391..a9d911e27 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -11,9 +11,7 @@ import ast, tables, ropes, md5, modulegraphs from hashes import Hash -from astalgo import debug import types -from strutils import startsWith, contains proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 103608afc..828d25fe8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -12,19 +12,29 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, + magicsys, idents, lexer, options, parampatterns, strutils, trees, linter, lineinfos, lowerings, modulegraphs when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler): import docgen type + MismatchKind* = enum + kUnknown, kAlreadyGiven, kUnknownNamedParam, kTypeMismatch, kVarNeeded, + kMissingParam, kExtraArg + + MismatchInfo* = object + kind*: MismatchKind # reason for mismatch + arg*: int # position of provided arguments that mismatches + formal*: PSym # parameter that mismatches against provided argument + # its position can differ from `arg` because of varargs + TCandidateState* = enum csEmpty, csMatch, csNoMatch CandidateError* = object sym*: PSym - unmatchedVarParam*, firstMismatch*: int + firstMismatch*: MismatchInfo diagnostics*: seq[string] enabled*: bool @@ -56,7 +66,6 @@ type # a distrinct type typedescMatched*: bool isNoCall*: bool # misused for generic type instantiations C[T] - mutabilityProblem*: uint8 # tyVar mismatch inferredTypes: seq[PType] # inferred types during the current signature # matching. they will be reset if the matching # is not successful. may replace the bindings @@ -70,8 +79,7 @@ type # triggered with an idetools command in the # future. inheritancePenalty: int # to prefer closest father object type - firstMismatch*: int # position of the first type mismatch for - # better error messages + firstMismatch*: MismatchInfo # mismatch info for better error messages diagnosticsEnabled*: bool TTypeRelFlag* = enum @@ -112,6 +120,7 @@ proc initCandidateAux(ctx: PContext, c.intConvMatches = 0 c.genericMatches = 0 c.state = csEmpty + c.firstMismatch = MismatchInfo() c.callee = callee c.call = nil c.baseTypeMatch = false @@ -2280,42 +2289,47 @@ template isVarargsUntyped(x): untyped = proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var IntSet) = + var + a = 1 # iterates over the actual given arguments + f = if m.callee.kind != tyGenericBody: 1 + else: 0 # iterates over formal parameters + arg: PNode # current prepared argument + formal: PSym # current routine parameter + + template noMatch() = + m.state = csNoMatch + m.firstMismatch.arg = a + m.firstMismatch.formal = formal + template checkConstraint(n: untyped) {.dirty.} = if not formal.constraint.isNil: if matchNodeKinds(formal.constraint, n): # better match over other routines with no such restriction: inc(m.genericMatches, 100) else: - m.state = csNoMatch + noMatch() return if formal.typ.kind == tyVar: let argConverter = if arg.kind == nkHiddenDeref: arg[0] else: arg if argConverter.kind == nkHiddenCallConv: if argConverter.typ.kind != tyVar: - m.state = csNoMatch - m.mutabilityProblem = uint8(f-1) + m.firstMismatch.kind = kVarNeeded + noMatch() return elif not n.isLValue: - m.state = csNoMatch - m.mutabilityProblem = uint8(f-1) + m.firstMismatch.kind = kVarNeeded + noMatch() return - var - # iterates over formal parameters - f = if m.callee.kind != tyGenericBody: 1 - else: 0 - # iterates over the actual given arguments - a = 1 - arg: PNode # current prepared argument - m.state = csMatch # until proven otherwise + m.firstMismatch = MismatchInfo() m.call = newNodeI(n.kind, n.info) m.call.typ = base(m.callee) # may be nil var formalLen = m.callee.n.len addSon(m.call, copyTree(n.sons[0])) var container: PNode = nil # constructed container - var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil + formal = if formalLen > 1: m.callee.n.sons[1].sym else: nil while a < n.len: if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: @@ -2336,26 +2350,26 @@ proc matchesAux(c: PContext, n, nOrig: PNode, addSon(container, n.sons[a]) elif n.sons[a].kind == nkExprEqExpr: # named param + m.firstMismatch.kind = kUnknownNamedParam # check if m.callee has such a param: prepareNamedParam(n.sons[a], c) if n.sons[a].sons[0].kind != nkIdent: localError(c.config, n.sons[a].info, "named parameter has to be an identifier") - m.state = csNoMatch - m.firstMismatch = -a + noMatch() return formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) if formal == nil: # no error message! - m.state = csNoMatch - m.firstMismatch = -a + noMatch() return if containsOrIncl(marker, formal.position): + m.firstMismatch.kind = kAlreadyGiven # already in namedParams, so no match # we used to produce 'errCannotBindXTwice' here but see # bug #3836 of why that is not sound (other overload with # different parameter names could match later on): when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) - m.state = csNoMatch + noMatch() return m.baseTypeMatch = false m.typedescMatched = false @@ -2363,9 +2377,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, n.sons[a].typ = n.sons[a].sons[1].typ arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a].sons[1], n.sons[a].sons[1]) + m.firstMismatch.kind = kTypeMismatch if arg == nil: - m.state = csNoMatch - m.firstMismatch = a + noMatch() return checkConstraint(n.sons[a].sons[1]) if m.baseTypeMatch: @@ -2392,6 +2406,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, else: addSon(m.call, copyTree(n.sons[a])) elif formal != nil and formal.typ.kind == tyVarargs: + m.firstMismatch.kind = kTypeMismatch # beware of the side-effects in 'prepareOperand'! So only do it for # varargs matching. See tests/metatype/tstatic_overloading. m.baseTypeMatch = false @@ -2405,20 +2420,24 @@ proc matchesAux(c: PContext, n, nOrig: PNode, incrIndexType(container.typ) checkConstraint(n.sons[a]) else: - m.state = csNoMatch + noMatch() return else: - m.state = csNoMatch + m.firstMismatch.kind = kExtraArg + noMatch() return else: if m.callee.n.sons[f].kind != nkSym: internalError(c.config, n.sons[a].info, "matches") + noMatch() return formal = m.callee.n.sons[f].sym + m.firstMismatch.kind = kTypeMismatch if containsOrIncl(marker, formal.position) and container.isNil: + m.firstMismatch.kind = kAlreadyGiven # already in namedParams: (see above remark) when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) - m.state = csNoMatch + noMatch() return if formal.typ.isVarargsUntyped: @@ -2435,8 +2454,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a], nOrig.sons[a]) if arg == nil: - m.state = csNoMatch - m.firstMismatch = f + noMatch() return if m.baseTypeMatch: assert formal.typ.kind == tyVarargs @@ -2465,10 +2483,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # this assertion can be off localError(c.config, n.sons[a].info, "cannot convert $1 to $2" % [ typeToString(n.sons[a].typ), typeToString(formal.typ) ]) - m.state = csNoMatch + noMatch() return checkConstraint(n.sons[a]) inc(a) + # for some edge cases (see tdont_return_unowned_from_owned test case) + m.firstMismatch.arg = a + m.firstMismatch.formal = formal proc semFinishOperands*(c: PContext, n: PNode) = # this needs to be called to ensure that after overloading resolution every @@ -2510,7 +2531,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = else: # no default value m.state = csNoMatch - m.firstMismatch = f + m.firstMismatch.kind = kMissingParam + m.firstMismatch.formal = formal break else: if formal.ast.kind == nkEmpty: diff --git a/compiler/spawn.nim b/compiler/spawn.nim index b8477567b..733ce7732 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -1,428 +1,428 @@ -# -# -# The Nim Compiler -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements threadpool's ``spawn``. - -import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs, - lineinfos, lowerings -from trees import getMagic - -proc callProc(a: PNode): PNode = - result = newNodeI(nkCall, a.info) - result.add a - result.typ = a.typ.sons[0] - -# we have 4 cases to consider: -# - a void proc --> nothing to do -# - a proc returning GC'ed memory --> requires a flowVar -# - a proc returning non GC'ed memory --> pass as hidden 'var' parameter -# - not in a parallel environment --> requires a flowVar for memory safety -type - TSpawnResult* = enum - srVoid, srFlowVar, srByVar - TFlowVarKind = enum - fvInvalid # invalid type T for 'FlowVar[T]' - fvGC # FlowVar of a GC'ed type - fvBlob # FlowVar of a blob type - -proc spawnResult*(t: PType; inParallel: bool): TSpawnResult = - if t.isEmptyType: srVoid - elif inParallel and not containsGarbageCollectedRef(t): srByVar - else: srFlowVar - -proc flowVarKind(t: PType): TFlowVarKind = - if t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC - elif containsGarbageCollectedRef(t): fvInvalid - else: fvBlob - -proc typeNeedsNoDeepCopy(t: PType): bool = - var t = t.skipTypes(abstractInst) - # for the tconvexhull example (and others) we're a bit lax here and pretend - # seqs and strings are *by value* only and 'shallow' doesn't exist! - if t.kind == tyString: return true - # 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 - result = not containsGarbageCollectedRef(t) - -proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; - v: PNode; useShallowCopy=false): PSym = - result = newSym(skTemp, getIdent(g.cache, genPrefix), owner, varSection.info, - owner.options) - result.typ = typ - incl(result.flags, sfFromGeneric) - - var vpart = newNodeI(nkIdentDefs, varSection.info, 3) - vpart.sons[0] = newSymNode(result) - vpart.sons[1] = newNodeI(nkEmpty, varSection.info) - vpart.sons[2] = if varInit.isNil: v else: vpart[1] - varSection.add vpart - if varInit != nil: - if useShallowCopy and typeNeedsNoDeepCopy(typ): - varInit.add newFastAsgnStmt(newSymNode(result), v) - else: - let deepCopyCall = newNodeI(nkCall, varInit.info, 3) - deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy)) - deepCopyCall.sons[1] = newSymNode(result) - deepCopyCall.sons[2] = v - varInit.add deepCopyCall - -discard """ -We generate roughly this: - -proc f_wrapper(thread, args) = - barrierEnter(args.barrier) # for parallel statement - var a = args.a # thread transfer; deepCopy or shallowCopy or no copy - # depending on whether we're in a 'parallel' statement - var b = args.b - var fv = args.fv - - fv.owner = thread # optional - nimArgsPassingDone() # signal parent that the work is done - # - args.fv.blob = f(a, b, ...) - nimFlowVarSignal(args.fv) - - # - or - - f(a, b, ...) - barrierLeave(args.barrier) # for parallel statement - -stmtList: - var scratchObj - scratchObj.a = a - scratchObj.b = b - - nimSpawn(f_wrapper, addr scratchObj) - scratchObj.fv # optional - -""" - -proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; - varSection, varInit, call, barrier, fv: PNode; - spawnKind: TSpawnResult): PSym = - var body = newNodeI(nkStmtList, f.info) - body.flags.incl nfTransf # do not transform further - - var threadLocalBarrier: PSym - if barrier != nil: - var varSection2 = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner, - barrier.typ, barrier) - body.add varSection2 - body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.info, - threadLocalBarrier.newSymNode) - var threadLocalProm: PSym - if spawnKind == srByVar: - threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) - elif fv != nil: - internalAssert g.config, fv.typ.kind == tyGenericInst - threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) - body.add varSection - body.add varInit - if fv != nil and spawnKind != srByVar: - # generate: - # fv.owner = threadParam - body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, - "owner", fv.info, g.cache), threadParam.newSymNode) - - body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.info, - threadParam.newSymNode) - if spawnKind == srByVar: - body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) - elif fv != nil: - let fk = fv.typ.sons[1].flowVarKind - if fk == fvInvalid: - localError(g.config, f.info, "cannot create a flowVar of type: " & - typeToString(fv.typ.sons[1])) - body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, - if fk == fvGC: "data" else: "blob", fv.info, g.cache), call) - if fk == fvGC: - let incRefCall = newNodeI(nkCall, fv.info, 2) - incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref)) - incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode, - "data", fv.info, g.cache) - body.add incRefCall - if barrier == nil: - # by now 'fv' is shared and thus might have beeen overwritten! we need - # to use the thread-local view instead: - body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.info, - threadLocalProm.newSymNode) - else: - body.add call - if barrier != nil: - body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.info, - threadLocalBarrier.newSymNode) - - var params = newNodeI(nkFormalParams, f.info) - params.add newNodeI(nkEmpty, f.info) - params.add threadParam.newSymNode - params.add argsParam.newSymNode - - var t = newType(tyProc, threadParam.owner) - t.rawAddSon nil - t.rawAddSon threadParam.typ - t.rawAddSon argsParam.typ - t.n = newNodeI(nkFormalParams, f.info) - t.n.add newNodeI(nkEffectList, f.info) - t.n.add threadParam.newSymNode - t.n.add argsParam.newSymNode - - let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper" - result = newSym(skProc, getIdent(g.cache, name), argsParam.owner, f.info, - argsParam.options) - let emptyNode = newNodeI(nkEmpty, f.info) - result.ast = newProcNode(nkProcDef, f.info, body = body, - params = params, name = newSymNode(result), pattern = emptyNode, - genericParams = emptyNode, pragmas = emptyNode, - exceptions = emptyNode) - result.typ = t - -proc createCastExpr(argsParam: PSym; objType: PType): PNode = - result = newNodeI(nkCast, argsParam.info) - result.add newNodeI(nkEmpty, argsParam.info) - result.add newSymNode(argsParam) - result.typ = newType(tyPtr, objType.owner) - result.typ.rawAddSon(objType) - -proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym, - castExpr, call, - varSection, varInit, result: PNode) = - let formals = n[0].typ.n - let tmpName = getIdent(g.cache, genPrefix) - for i in 1 ..< n.len: - # we pick n's type here, which hopefully is 'tyArray' and not - # 'tyOpenArray': - var argType = n[i].typ.skipTypes(abstractInst) - if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}: - localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") - #elif containsTyRef(argType): - # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") - - let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) - field.typ = argType - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) - - let temp = addLocalVar(g, varSection, varInit, objType.owner, argType, - indirectAccess(castExpr, field, n.info)) - call.add(newSymNode(temp)) - -proc getRoot*(n: PNode): PSym = - ## ``getRoot`` takes a *path* ``n``. A path is an lvalue expression - ## like ``obj.x[i].y``. The *root* of a path is the symbol that can be - ## determined as the owner; ``obj`` in the example. - case n.kind - of nkSym: - if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar}: - result = n.sym - of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr, - nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: - result = getRoot(n.sons[0]) - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - result = getRoot(n.sons[1]) - of nkCallKinds: - if getMagic(n) == mSlice: result = getRoot(n.sons[1]) - else: discard - -proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym; - castExpr, call, - varSection, varInit, result: PNode) = - let formals = n[0].typ.n - let tmpName = getIdent(g.cache, genPrefix) - # we need to copy the foreign scratch object fields into local variables - # for correctness: These are called 'threadLocal' here. - for i in 1 ..< n.len: - let n = n[i] - let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ, - abstractInst) - #if containsTyRef(argType): - # localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure") - - let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) - - if argType.kind in {tyVarargs, tyOpenArray}: - # important special case: we always create a zero-copy slice: - let slice = newNodeI(nkCall, n.info, 4) - slice.typ = n.typ - slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice)) - slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type - var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options) - fieldB.typ = getSysType(g, n.info, tyInt) - objType.addField(fieldB, g.cache) - - if getMagic(n) == mSlice: - let a = genAddrOf(n[1]) - field.typ = a.typ - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - - var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options) - fieldA.typ = getSysType(g, n.info, tyInt) - objType.addField(fieldA, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) - result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) - - let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ, - indirectAccess(castExpr, fieldA, n.info), - useShallowCopy=true) - slice.sons[2] = threadLocal.newSymNode - else: - let a = genAddrOf(n) - field.typ = a.typ - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n)) - - slice.sons[2] = newIntLit(g, n.info, 0) - # the array itself does not need to go through a thread local variable: - slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info)) - - let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ, - indirectAccess(castExpr, fieldB, n.info), - useShallowCopy=true) - slice.sons[3] = threadLocal.newSymNode - call.add slice - elif (let size = computeSize(g.config, argType); size < 0 or size > 16) and - n.getRoot != nil: - # it is more efficient to pass a pointer instead: - let a = genAddrOf(n) - field.typ = a.typ - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ, - indirectAccess(castExpr, field, n.info), - useShallowCopy=true) - call.add(genDeref(threadLocal.newSymNode)) - else: - # boring case - field.typ = argType - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) - let threadLocal = addLocalVar(g, varSection, varInit, - objType.owner, field.typ, - indirectAccess(castExpr, field, n.info), - useShallowCopy=true) - call.add(threadLocal.newSymNode) - -proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType; - barrier, dest: PNode = nil): PNode = - # if 'barrier' != nil, then it is in a 'parallel' section and we - # generate quite different code - let n = spawnExpr[^2] - let spawnKind = spawnResult(retType, barrier!=nil) - case spawnKind - of srVoid: - internalAssert g.config, dest == nil - result = newNodeI(nkStmtList, n.info) - of srFlowVar: - internalAssert g.config, dest == nil - result = newNodeIT(nkStmtListExpr, n.info, retType) - of srByVar: - if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded") - result = newNodeI(nkStmtList, n.info) - - if n.kind notin nkCallKinds: - localError(g.config, n.info, "'spawn' takes a call expression") - return - if optThreadAnalysis in g.config.globalOptions: - if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: - localError(g.config, n.info, "'spawn' takes a GC safe call expression") - var - threadParam = newSym(skParam, getIdent(g.cache, "thread"), owner, n.info, g.config.options) - argsParam = newSym(skParam, getIdent(g.cache, "args"), owner, n.info, g.config.options) - block: - let ptrType = getSysType(g, n.info, tyPointer) - threadParam.typ = ptrType - argsParam.typ = ptrType - argsParam.position = 1 - - var objType = createObj(g, owner, n.info) - incl(objType.flags, tfFinal) - let castExpr = createCastExpr(argsParam, objType) - - var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), owner, n.info, g.config.options) - block: - scratchObj.typ = objType - incl(scratchObj.flags, sfFromGeneric) - var varSectionB = newNodeI(nkVarSection, n.info) - varSectionB.addVar(scratchObj.newSymNode) - result.add varSectionB - - var call = newNodeIT(nkCall, n.info, n.typ) - var fn = n.sons[0] - # templates and macros are in fact valid here due to the nature of - # the transformation: - if fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure): - localError(g.config, n.info, "closure in spawn environment is not allowed") - if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro, - skFunc, skMethod, skConverter}): - # for indirect calls we pass the function pointer in the scratchObj - var argType = n[0].typ.skipTypes(abstractInst) - var field = newSym(skField, getIdent(g.cache, "fn"), owner, n.info, g.config.options) - field.typ = argType - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) - fn = indirectAccess(castExpr, field, n.info) - elif fn.kind == nkSym and fn.sym.kind == skIterator: - localError(g.config, n.info, "iterator in spawn environment is not allowed") - elif fn.typ.callConv == ccClosure: - localError(g.config, n.info, "closure in spawn environment is not allowed") - - call.add(fn) - var varSection = newNodeI(nkVarSection, n.info) - var varInit = newNodeI(nkStmtList, n.info) - if barrier.isNil: - setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call, - varSection, varInit, result) - else: - setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call, - varSection, varInit, result) - - var barrierAsExpr: PNode = nil - if barrier != nil: - let typ = newType(tyPtr, owner) - typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) - var field = newSym(skField, getIdent(g.cache, "barrier"), owner, n.info, g.config.options) - field.typ = typ - objType.addField(field, g.cache) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) - barrierAsExpr = indirectAccess(castExpr, field, n.info) - - var fvField, fvAsExpr: PNode = nil - if spawnKind == srFlowVar: - var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options) - field.typ = retType - objType.addField(field, g.cache) - fvField = newDotExpr(scratchObj, field) - fvAsExpr = indirectAccess(castExpr, field, n.info) - # create flowVar: - result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1])) - if barrier == nil: - result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, - fvField) - - elif spawnKind == srByVar: - var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options) - field.typ = newType(tyPtr, objType.owner) - field.typ.rawAddSon(retType) - objType.addField(field, g.cache) - fvAsExpr = indirectAccess(castExpr, field, n.info) - result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) - - let wrapper = createWrapperProc(g, fn, threadParam, argsParam, - varSection, varInit, call, - barrierAsExpr, fvAsExpr, spawnKind) - result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.info, - wrapper.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr) - - if spawnKind == srFlowVar: result.add fvField - +# +# +# The Nim Compiler +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements threadpool's ``spawn``. + +import ast, types, idents, magicsys, msgs, options, modulegraphs, + lowerings +from trees import getMagic + +proc callProc(a: PNode): PNode = + result = newNodeI(nkCall, a.info) + result.add a + result.typ = a.typ.sons[0] + +# we have 4 cases to consider: +# - a void proc --> nothing to do +# - a proc returning GC'ed memory --> requires a flowVar +# - a proc returning non GC'ed memory --> pass as hidden 'var' parameter +# - not in a parallel environment --> requires a flowVar for memory safety +type + TSpawnResult* = enum + srVoid, srFlowVar, srByVar + TFlowVarKind = enum + fvInvalid # invalid type T for 'FlowVar[T]' + fvGC # FlowVar of a GC'ed type + fvBlob # FlowVar of a blob type + +proc spawnResult*(t: PType; inParallel: bool): TSpawnResult = + if t.isEmptyType: srVoid + elif inParallel and not containsGarbageCollectedRef(t): srByVar + else: srFlowVar + +proc flowVarKind(t: PType): TFlowVarKind = + if t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC + elif containsGarbageCollectedRef(t): fvInvalid + else: fvBlob + +proc typeNeedsNoDeepCopy(t: PType): bool = + var t = t.skipTypes(abstractInst) + # for the tconvexhull example (and others) we're a bit lax here and pretend + # seqs and strings are *by value* only and 'shallow' doesn't exist! + if t.kind == tyString: return true + # 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 + result = not containsGarbageCollectedRef(t) + +proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; + v: PNode; useShallowCopy=false): PSym = + result = newSym(skTemp, getIdent(g.cache, genPrefix), owner, varSection.info, + owner.options) + result.typ = typ + incl(result.flags, sfFromGeneric) + + var vpart = newNodeI(nkIdentDefs, varSection.info, 3) + vpart.sons[0] = newSymNode(result) + vpart.sons[1] = newNodeI(nkEmpty, varSection.info) + vpart.sons[2] = if varInit.isNil: v else: vpart[1] + varSection.add vpart + if varInit != nil: + if useShallowCopy and typeNeedsNoDeepCopy(typ): + varInit.add newFastAsgnStmt(newSymNode(result), v) + else: + let deepCopyCall = newNodeI(nkCall, varInit.info, 3) + deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy)) + deepCopyCall.sons[1] = newSymNode(result) + deepCopyCall.sons[2] = v + varInit.add deepCopyCall + +discard """ +We generate roughly this: + +proc f_wrapper(thread, args) = + barrierEnter(args.barrier) # for parallel statement + var a = args.a # thread transfer; deepCopy or shallowCopy or no copy + # depending on whether we're in a 'parallel' statement + var b = args.b + var fv = args.fv + + fv.owner = thread # optional + nimArgsPassingDone() # signal parent that the work is done + # + args.fv.blob = f(a, b, ...) + nimFlowVarSignal(args.fv) + + # - or - + f(a, b, ...) + barrierLeave(args.barrier) # for parallel statement + +stmtList: + var scratchObj + scratchObj.a = a + scratchObj.b = b + + nimSpawn(f_wrapper, addr scratchObj) + scratchObj.fv # optional + +""" + +proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; + varSection, varInit, call, barrier, fv: PNode; + spawnKind: TSpawnResult): PSym = + var body = newNodeI(nkStmtList, f.info) + body.flags.incl nfTransf # do not transform further + + var threadLocalBarrier: PSym + if barrier != nil: + var varSection2 = newNodeI(nkVarSection, barrier.info) + threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner, + barrier.typ, barrier) + body.add varSection2 + body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.info, + threadLocalBarrier.newSymNode) + var threadLocalProm: PSym + if spawnKind == srByVar: + threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) + elif fv != nil: + internalAssert g.config, fv.typ.kind == tyGenericInst + threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) + body.add varSection + body.add varInit + if fv != nil and spawnKind != srByVar: + # generate: + # fv.owner = threadParam + body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, + "owner", fv.info, g.cache), threadParam.newSymNode) + + body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.info, + threadParam.newSymNode) + if spawnKind == srByVar: + body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) + elif fv != nil: + let fk = fv.typ.sons[1].flowVarKind + if fk == fvInvalid: + localError(g.config, f.info, "cannot create a flowVar of type: " & + typeToString(fv.typ.sons[1])) + body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, + if fk == fvGC: "data" else: "blob", fv.info, g.cache), call) + if fk == fvGC: + let incRefCall = newNodeI(nkCall, fv.info, 2) + incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref)) + incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode, + "data", fv.info, g.cache) + body.add incRefCall + if barrier == nil: + # by now 'fv' is shared and thus might have beeen overwritten! we need + # to use the thread-local view instead: + body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.info, + threadLocalProm.newSymNode) + else: + body.add call + if barrier != nil: + body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.info, + threadLocalBarrier.newSymNode) + + var params = newNodeI(nkFormalParams, f.info) + params.add newNodeI(nkEmpty, f.info) + params.add threadParam.newSymNode + params.add argsParam.newSymNode + + var t = newType(tyProc, threadParam.owner) + t.rawAddSon nil + t.rawAddSon threadParam.typ + t.rawAddSon argsParam.typ + t.n = newNodeI(nkFormalParams, f.info) + t.n.add newNodeI(nkEffectList, f.info) + t.n.add threadParam.newSymNode + t.n.add argsParam.newSymNode + + let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper" + result = newSym(skProc, getIdent(g.cache, name), argsParam.owner, f.info, + argsParam.options) + let emptyNode = newNodeI(nkEmpty, f.info) + result.ast = newProcNode(nkProcDef, f.info, body = body, + params = params, name = newSymNode(result), pattern = emptyNode, + genericParams = emptyNode, pragmas = emptyNode, + exceptions = emptyNode) + result.typ = t + +proc createCastExpr(argsParam: PSym; objType: PType): PNode = + result = newNodeI(nkCast, argsParam.info) + result.add newNodeI(nkEmpty, argsParam.info) + result.add newSymNode(argsParam) + result.typ = newType(tyPtr, objType.owner) + result.typ.rawAddSon(objType) + +proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym, + castExpr, call, + varSection, varInit, result: PNode) = + let formals = n[0].typ.n + let tmpName = getIdent(g.cache, genPrefix) + for i in 1 ..< n.len: + # we pick n's type here, which hopefully is 'tyArray' and not + # 'tyOpenArray': + var argType = n[i].typ.skipTypes(abstractInst) + if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}: + localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") + #elif containsTyRef(argType): + # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") + + let fieldname = if i < formals.len: formals[i].sym.name else: tmpName + var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) + field.typ = argType + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) + + let temp = addLocalVar(g, varSection, varInit, objType.owner, argType, + indirectAccess(castExpr, field, n.info)) + call.add(newSymNode(temp)) + +proc getRoot*(n: PNode): PSym = + ## ``getRoot`` takes a *path* ``n``. A path is an lvalue expression + ## like ``obj.x[i].y``. The *root* of a path is the symbol that can be + ## determined as the owner; ``obj`` in the example. + case n.kind + of nkSym: + if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar}: + result = n.sym + of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr, + nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: + result = getRoot(n.sons[0]) + of nkHiddenStdConv, nkHiddenSubConv, nkConv: + result = getRoot(n.sons[1]) + of nkCallKinds: + if getMagic(n) == mSlice: result = getRoot(n.sons[1]) + else: discard + +proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym; + castExpr, call, + varSection, varInit, result: PNode) = + let formals = n[0].typ.n + let tmpName = getIdent(g.cache, genPrefix) + # we need to copy the foreign scratch object fields into local variables + # for correctness: These are called 'threadLocal' here. + for i in 1 ..< n.len: + let n = n[i] + let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ, + abstractInst) + #if containsTyRef(argType): + # localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure") + + let fieldname = if i < formals.len: formals[i].sym.name else: tmpName + var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) + + if argType.kind in {tyVarargs, tyOpenArray}: + # important special case: we always create a zero-copy slice: + let slice = newNodeI(nkCall, n.info, 4) + slice.typ = n.typ + slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice)) + slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type + var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options) + fieldB.typ = getSysType(g, n.info, tyInt) + objType.addField(fieldB, g.cache) + + if getMagic(n) == mSlice: + let a = genAddrOf(n[1]) + field.typ = a.typ + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) + + var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options) + fieldA.typ = getSysType(g, n.info, tyInt) + objType.addField(fieldA, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) + result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) + + let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ, + indirectAccess(castExpr, fieldA, n.info), + useShallowCopy=true) + slice.sons[2] = threadLocal.newSymNode + else: + let a = genAddrOf(n) + field.typ = a.typ + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) + result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n)) + + slice.sons[2] = newIntLit(g, n.info, 0) + # the array itself does not need to go through a thread local variable: + slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info)) + + let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ, + indirectAccess(castExpr, fieldB, n.info), + useShallowCopy=true) + slice.sons[3] = threadLocal.newSymNode + call.add slice + elif (let size = computeSize(g.config, argType); size < 0 or size > 16) and + n.getRoot != nil: + # it is more efficient to pass a pointer instead: + let a = genAddrOf(n) + field.typ = a.typ + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) + let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ, + indirectAccess(castExpr, field, n.info), + useShallowCopy=true) + call.add(genDeref(threadLocal.newSymNode)) + else: + # boring case + field.typ = argType + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) + let threadLocal = addLocalVar(g, varSection, varInit, + objType.owner, field.typ, + indirectAccess(castExpr, field, n.info), + useShallowCopy=true) + call.add(threadLocal.newSymNode) + +proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType; + barrier, dest: PNode = nil): PNode = + # if 'barrier' != nil, then it is in a 'parallel' section and we + # generate quite different code + let n = spawnExpr[^2] + let spawnKind = spawnResult(retType, barrier!=nil) + case spawnKind + of srVoid: + internalAssert g.config, dest == nil + result = newNodeI(nkStmtList, n.info) + of srFlowVar: + internalAssert g.config, dest == nil + result = newNodeIT(nkStmtListExpr, n.info, retType) + of srByVar: + if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded") + result = newNodeI(nkStmtList, n.info) + + if n.kind notin nkCallKinds: + localError(g.config, n.info, "'spawn' takes a call expression") + return + if optThreadAnalysis in g.config.globalOptions: + if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: + localError(g.config, n.info, "'spawn' takes a GC safe call expression") + var + threadParam = newSym(skParam, getIdent(g.cache, "thread"), owner, n.info, g.config.options) + argsParam = newSym(skParam, getIdent(g.cache, "args"), owner, n.info, g.config.options) + block: + let ptrType = getSysType(g, n.info, tyPointer) + threadParam.typ = ptrType + argsParam.typ = ptrType + argsParam.position = 1 + + var objType = createObj(g, owner, n.info) + incl(objType.flags, tfFinal) + let castExpr = createCastExpr(argsParam, objType) + + var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), owner, n.info, g.config.options) + block: + scratchObj.typ = objType + incl(scratchObj.flags, sfFromGeneric) + var varSectionB = newNodeI(nkVarSection, n.info) + varSectionB.addVar(scratchObj.newSymNode) + result.add varSectionB + + var call = newNodeIT(nkCall, n.info, n.typ) + var fn = n.sons[0] + # templates and macros are in fact valid here due to the nature of + # the transformation: + if fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure): + localError(g.config, n.info, "closure in spawn environment is not allowed") + if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro, + skFunc, skMethod, skConverter}): + # for indirect calls we pass the function pointer in the scratchObj + var argType = n[0].typ.skipTypes(abstractInst) + var field = newSym(skField, getIdent(g.cache, "fn"), owner, n.info, g.config.options) + field.typ = argType + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) + fn = indirectAccess(castExpr, field, n.info) + elif fn.kind == nkSym and fn.sym.kind == skIterator: + localError(g.config, n.info, "iterator in spawn environment is not allowed") + elif fn.typ.callConv == ccClosure: + localError(g.config, n.info, "closure in spawn environment is not allowed") + + call.add(fn) + var varSection = newNodeI(nkVarSection, n.info) + var varInit = newNodeI(nkStmtList, n.info) + if barrier.isNil: + setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call, + varSection, varInit, result) + else: + setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call, + varSection, varInit, result) + + var barrierAsExpr: PNode = nil + if barrier != nil: + let typ = newType(tyPtr, owner) + typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) + var field = newSym(skField, getIdent(g.cache, "barrier"), owner, n.info, g.config.options) + field.typ = typ + objType.addField(field, g.cache) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) + barrierAsExpr = indirectAccess(castExpr, field, n.info) + + var fvField, fvAsExpr: PNode = nil + if spawnKind == srFlowVar: + var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options) + field.typ = retType + objType.addField(field, g.cache) + fvField = newDotExpr(scratchObj, field) + fvAsExpr = indirectAccess(castExpr, field, n.info) + # create flowVar: + result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1])) + if barrier == nil: + result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, + fvField) + + elif spawnKind == srByVar: + var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options) + field.typ = newType(tyPtr, objType.owner) + field.typ.rawAddSon(retType) + objType.addField(field, g.cache) + fvAsExpr = indirectAccess(castExpr, field, n.info) + result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) + + let wrapper = createWrapperProc(g, fn, threadParam, argsParam, + varSection, varInit, call, + barrierAsExpr, fvAsExpr, spawnKind) + result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.info, + wrapper.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr) + + if spawnKind == srFlowVar: result.add fvField + diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 1fd12d750..59e3a7242 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -32,11 +32,11 @@ # included from sigmatch.nim -import algorithm, prefixmatches, lineinfos, pathutils, parseutils, linter +import algorithm, prefixmatches, lineinfos, parseutils, linter from wordrecg import wDeprecated, wError, wAddr, wYield, specialWords when defined(nimsuggest): - import passes, tables # importer + import passes, tables, pathutils # importer const sep = '\t' diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 3e4f65c0b..3b67b3263 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -10,7 +10,7 @@ ## Implements the dispatcher for the different parsers. import - strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, + strutils, llstream, ast, idents, lexer, options, msgs, parser, filters, filter_tmpl, renderer, lineinfos, pathutils type diff --git a/compiler/transf.nim b/compiler/transf.nim index 4dd348742..60a7ce224 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -19,9 +19,9 @@ # * transforms 'defer' into a 'try finally' statement import - intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups, + options, ast, astalgo, trees, msgs, idents, renderer, types, passes, semfold, magicsys, cgmeth, - sempass2, lowerings, injectdestructors, liftlocals, + lowerings, injectdestructors, liftlocals, modulegraphs, lineinfos proc transformBody*(g: ModuleGraph, prc: PSym, cache = true; diff --git a/compiler/trees.nim b/compiler/trees.nim index c878eb1bf..87ab7c00e 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -10,7 +10,7 @@ # tree helper routines import - ast, astalgo, lexer, msgs, strutils, wordrecg, idents + ast, wordrecg, idents proc cyclicTreeAux(n: PNode, visited: var seq[PNode]): bool = if n == nil: return diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 0c4fe01e1..7084349e5 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import renderer, strutils, ast, msgs, types, astalgo +import renderer, strutils, ast, types const defaultParamSeparator* = "," diff --git a/compiler/vm.nim b/compiler/vm.nim index bb8c6bbf2..34caec83f 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -13,7 +13,7 @@ import ast except getstr import - strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, + strutils, msgs, vmdef, vmgen, nimsets, types, passes, parser, vmdeps, idents, trees, renderer, options, transf, parseutils, vmmarshal, gorgeimpl, lineinfos, tables, btrees, macrocacheimpl, modulegraphs, sighashes diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 723863ca7..425f728e7 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,8 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets, options, modulegraphs, lineinfos, - tables, btrees +import ast, passes, idents, intsets, options, modulegraphs, lineinfos const byteExcess* = 128 # we use excess-K for immediates diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 5130f30c9..1b2538c79 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import ast, types, msgs, os, streams, options, idents, lineinfos +import ast, types, msgs, os, options, idents, lineinfos proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string = try: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 37706f1ea..a27cd62c6 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -28,10 +28,8 @@ # this copy depends on the involved types. import - strutils, ast, astalgo, types, msgs, renderer, vmdef, - trees, intsets, magicsys, options, lowerings, lineinfos, transf -import platform -from os import splitFile + strutils, ast, types, msgs, renderer, vmdef, + intsets, magicsys, options, lowerings, lineinfos, transf const debugEchoCode* = defined(nimVMDebug) diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index 04d3b7a16..b310701ca 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -15,8 +15,7 @@ ## * Computing an aliasing relation based on the assignments. This relation ## is then used to compute the 'writes' and 'escapes' effects. -import intsets, idents, ast, astalgo, trees, renderer, msgs, types, options, - lineinfos +import intsets, idents, ast, trees, msgs, types, options, lineinfos const debug = false diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 0892ad434..fa8a682ad 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1420,7 +1420,7 @@ proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = if n.kind == nnkIntLit: n.intVal != 0 else: n == bindSym"true" # hacky solution for now -macro expandMacros*(body: typed): typed = +macro expandMacros*(body: typed): untyped = ## Expands one level of macro - useful for debugging. ## Can be used to inspect what happens when a macro call is expanded, ## without altering its result. diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index f0f498b9f..f1f27cc42 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -169,7 +169,7 @@ include "system/inclrtl" import os, tables, strutils, times, heapqueue, lists, options, asyncstreams -import options, math +import options, math, std/monotimes import asyncfutures except callSoon import nativesockets, net, deques @@ -184,7 +184,7 @@ export asyncstreams type PDispatcherBase = ref object of RootRef - timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]] + timers*: HeapQueue[tuple[finishAt: MonoTime, fut: Future[void]]] callbacks*: Deque[proc () {.gcsafe.}] proc processTimers( @@ -192,7 +192,7 @@ proc processTimers( ): Option[int] {.inline.} = # Pop the timers in the order in which they will expire (smaller `finishAt`). var count = p.timers.len - let t = epochTime() + let t = getMonoTime() while count > 0 and t >= p.timers[0].finishAt: p.timers.pop().fut.complete() dec count @@ -201,8 +201,8 @@ proc processTimers( # Return the number of miliseconds in which the next timer will expire. if p.timers.len == 0: return - let milisecs = (p.timers[0].finishAt - epochTime()) * 1000 - return some(ceil(milisecs).int) + let millisecs = (p.timers[0].finishAt - getMonoTime()).inMilliseconds + return some(millisecs.int + 1) proc processPendingCallbacks(p: PDispatcherBase; didSomeWork: var bool) = while p.callbacks.len > 0: @@ -1778,7 +1778,11 @@ proc sleepAsync*(ms: int | float): owned(Future[void]) = ## ``ms`` milliseconds. var retFuture = newFuture[void]("sleepAsync") let p = getGlobalDispatcher() - p.timers.push((epochTime() + (ms / 1000), retFuture)) + when ms is int: + p.timers.push((getMonoTime() + initDuration(milliseconds = ms), retFuture)) + elif ms is float: + let ns = (ms * 1_000_000).int64 + p.timers.push((getMonoTime() + initDuration(nanoseconds = ns), retFuture)) return retFuture proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) = diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 91b6b55e8..8b7703804 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -20,7 +20,7 @@ import - hashes, math + hashes type BitScalar = uint diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 4f681f980..6fc5eb95b 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -11,10 +11,8 @@ include "system/inclrtl" -import strutils, os - when not defined(windows): - import posix + import strutils, posix, os when defined(linux): import linux diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 8104470e3..48e192a59 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -44,10 +44,6 @@ ## * `std/sha1 module <sha1.html>`_ for a sha1 encoder and decoder ## * `tables module <tables.html>`_ for hash tables - -import - strutils - type Hash* = int ## A hash value. Hash tables using these values should ## always have a size of a power of two and can use the ``and`` diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index cef0d9607..9ae9819c3 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -176,7 +176,7 @@ ## import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, - math, random, httpcore, times, tables, streams + math, random, httpcore, times, tables, streams, std/monotimes import asyncnet, asyncdispatch, asyncfile import nativesockets @@ -610,7 +610,7 @@ type contentTotal: BiggestInt contentProgress: BiggestInt oneSecondProgress: BiggestInt - lastProgressReport: float + lastProgressReport: MonoTime when SocketType is AsyncSocket: bodyStream: FutureStream[string] parseBodyFut: Future[void] @@ -706,13 +706,13 @@ proc reportProgress(client: HttpClient | AsyncHttpClient, progress: BiggestInt) {.multisync.} = client.contentProgress += progress client.oneSecondProgress += progress - if epochTime() - client.lastProgressReport >= 1.0: + if (getMonoTime() - client.lastProgressReport).inSeconds > 1: if not client.onProgressChanged.isNil: await client.onProgressChanged(client.contentTotal, client.contentProgress, client.oneSecondProgress) client.oneSecondProgress = 0 - client.lastProgressReport = epochTime() + client.lastProgressReport = getMonoTime() proc recvFull(client: HttpClient | AsyncHttpClient, size: int, timeout: int, keep: bool): Future[int] {.multisync.} = @@ -784,7 +784,7 @@ proc parseBody(client: HttpClient | AsyncHttpClient, client.contentTotal = 0 client.contentProgress = 0 client.oneSecondProgress = 0 - client.lastProgressReport = 0 + client.lastProgressReport = MonoTime() when client is AsyncHttpClient: assert(not client.bodyStream.finished) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index fa2ddb6f2..1ef08f547 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -142,8 +142,8 @@ runnableExamples: doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" import - hashes, tables, strutils, lexbase, streams, unicode, macros, parsejson, - typetraits, options + hashes, tables, strutils, lexbase, streams, macros, parsejson, + options export tables.`$` diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 8ae40a799..6e2f5d049 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -65,7 +65,8 @@ ## echo("Client connected from: ", address) {.deadCodeElim: on.} # dce option deprecated -import nativesockets, os, strutils, parseutils, times, sets, options +import nativesockets, os, strutils, parseutils, times, sets, options, + std/monotimes export Port, `$`, `==` export Domain, SockType, Protocol @@ -1077,7 +1078,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect] # Save the error in case it gets reset. socket.lastError = osLastError() -proc waitFor(socket: Socket, waited: var float, timeout, size: int, +proc waitFor(socket: Socket, waited: var Duration, timeout, size: int, funcName: string): int {.tags: [TimeEffect].} = ## determines the amount of characters that can be read. Result will never ## be larger than ``size``. For unbuffered sockets this will be ``1``. @@ -1092,7 +1093,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int, result = socket.bufLen - socket.currPos result = min(result, size) else: - if timeout - int(waited * 1000.0) < 1: + if timeout - waited.inMilliseconds < 1: raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") when defineSsl: @@ -1104,17 +1105,17 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int, if sslPending != 0: return min(sslPending, size) - var startTime = epochTime() - let selRet = select(socket, timeout - int(waited * 1000.0)) + var startTime = getMonoTime() + let selRet = select(socket, (timeout - waited.inMilliseconds).int) if selRet < 0: raiseOSError(osLastError()) if selRet != 1: raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") - waited += (epochTime() - startTime) + waited += (getMonoTIme() - startTime) proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. tags: [ReadIOEffect, TimeEffect].} = ## overload with a ``timeout`` parameter in milliseconds. - var waited = 0.0 # number of seconds already waited + var waited: Duration # duration already waited var read = 0 while read < size: @@ -1223,7 +1224,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, if flags.isDisconnectionError(lastError): setLen(line.string, 0); return socket.socketError(n, lastError = lastError) - var waited = 0.0 + var waited: Duration setLen(line.string, 0) while true: @@ -1307,7 +1308,7 @@ proc skip*(socket: Socket, size: int, timeout = -1) = ## bytes takes longer than specified a TimeoutError exception will be raised. ## ## Returns the number of skipped bytes. - var waited = 0.0 + var waited: Duration var dummy = alloc(size) var bytesSkipped = 0 while bytesSkipped != size: diff --git a/lib/pure/os.nim b/lib/pure/os.nim index ee40a24c7..9ee6a4d4f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1849,7 +1849,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", break # getFullPathName doesn't do case corrections, so we have to use this convoluted # way of retrieving the true filename - for x in walkFiles(result.string): + for x in walkFiles(result): result = x if not existsFile(result) and not existsDir(result): raise newException(OSError, "file '" & result & "' does not exist") diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index eb65b6f57..0d386bf18 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -19,7 +19,7 @@ import macros import strformat from strutils import toLowerAscii, `%` -import colors, tables +import colors when defined(windows): import winlean diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index bbd378740..35c364221 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1281,7 +1281,7 @@ when isMainModule: compared = (someString == $someRunes) doAssert compared == true - proc test_replacements(word: string): string = + proc testReplacements(word: string): string = case word of "two": return "2" @@ -1294,8 +1294,8 @@ when isMainModule: else: return "12345" - doAssert translate("two not alpha foo βeta", test_replacements) == "2 12345 αlpha BAR beta" - doAssert translate(" two not foo βeta ", test_replacements) == " 2 12345 BAR beta " + doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta" + doAssert translate(" two not foo βeta ", testReplacements) == " 2 12345 BAR beta " doAssert title("foo bar") == "Foo Bar" doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma" diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index a6104428d..4cbd2f734 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -190,7 +190,7 @@ proc defaultConsoleFormatter*(): <//>ConsoleOutputFormatter = var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string var colorOutput = isatty(stdout) if existsEnv("NIMTEST_COLOR"): - let colorEnv = getenv("NIMTEST_COLOR") + let colorEnv = getEnv("NIMTEST_COLOR") if colorEnv == "never": colorOutput = false elif colorEnv == "always": @@ -349,7 +349,7 @@ proc glob(matcher, filter: string): bool = let beforeAndAfter = filter.split('*', maxsplit=1) if beforeAndAfter.len == 1: # "foo*" - return matcher.startswith(beforeAndAfter[0]) + return matcher.startsWith(beforeAndAfter[0]) if matcher.len < filter.len - 1: return false # "12345" should not match "123*345" @@ -366,8 +366,8 @@ proc matchFilter(suiteName, testName, filter: string): bool = if suiteAndTestFilters.len == 1: # no suite specified - let test_f = suiteAndTestFilters[0] - return glob(testName, test_f) + let testFilter = suiteAndTestFilters[0] + return glob(testName, testFilter) return glob(suiteName, suiteAndTestFilters[0]) and glob(testName, suiteAndTestFilters[1]) @@ -627,7 +627,7 @@ macro check*(conditions: untyped): untyped = # Ident !"v" # IntLit 2 result.check[i] = exp[i][1] - if exp[i].typekind notin {ntyTypeDesc}: + if exp[i].typeKind notin {ntyTypeDesc}: let arg = newIdentNode(":p" & $counter) result.assigns.add getAst(asgn(arg, paramAst)) result.printOuts.add getAst(print(argStr, arg)) @@ -640,7 +640,7 @@ macro check*(conditions: untyped): untyped = of nnkCallKinds: let (assigns, check, printOuts) = inspectArgs(checked) - let lineinfo = newStrLitNode(checked.lineinfo) + let lineinfo = newStrLitNode(checked.lineInfo) let callLit = checked.toStrLit result = quote do: block: @@ -657,7 +657,7 @@ macro check*(conditions: untyped): untyped = result.add(newCall(!"check", node)) else: - let lineinfo = newStrLitNode(checked.lineinfo) + let lineinfo = newStrLitNode(checked.lineInfo) let callLit = checked.toStrLit result = quote do: @@ -712,7 +712,7 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = for i in countup(1, exp.len - 2): errorTypes.add(exp[i]) - result = getAst(expectBody(errorTypes, exp.lineinfo, body)) + result = getAst(expectBody(errorTypes, exp.lineInfo, body)) proc disableParamFiltering* = ## disables filtering tests with the command line params diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index e0b27c231..aa6784c82 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -25,7 +25,7 @@ const Usage: nimpretty [options] file.nim Options: - --output:file set the output file (default: overwrite the input file) + --out:file set the output file (default: overwrite the input file) --indent:N[=0] set the number of spaces that is used for indentation --indent:0 means autodetection (default behaviour) --maxLineLen:N set the desired maximum line length (default: 80) @@ -79,7 +79,7 @@ proc main = of "help", "h": writeHelp() of "version", "v": writeVersion() of "backup": backup = parseBool(val) - of "output", "o": outfile = val + of "output", "o", "out": outfile = val of "indent": opt.indWidth = parseInt(val) of "maxlinelen": opt.maxLineLen = parseInt(val) else: writeHelp() diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index 7dde99ca5..91ab530e4 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -761,3 +761,64 @@ var rows2 = await pool.rows(sql""" "BBBB" ] ) + + +# bug #11699 + +const keywords = @[ + "foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar", + "zzz", "ggg", "ddd", +] + +let keywords1 = @[ + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", "bar5", "foo6", "bar6", "foo7", + "zzz", "ggg", "ddd", +] + +let keywords2 = @[ + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", "bar5", "foo6", "bar6", "foo7", + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", "bar5", "foo6", "bar6", "foo7", + "zzz", "ggg", "ddd", +] + +if true: + let keywords3 = @[ + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", "bar5", "foo6", "bar6", "foo7", + "zzz", "ggg", "ddd", + ] + +const b = true +let fooB = + if true: + if b: 7 else: 8 + else: ord(b) + +let foo = if cond: + if b: T else: F + else: b + +let a = + [[aaadsfas, bbb], + [ccc, ddd]] + +let b = [ + [aaa, bbb], + [ccc, ddd] +] + +# bug #11616 +proc newRecordGen(ctx: Context; typ: TypRef): PNode = + result = nkTypeDef.t( + newId(typ.optSym.name, true, pragmas = [id(if typ.isUnion: "cUnion" + else: "cStruct")]), + empty(), + nkObjectTy.t( + empty(), + empty(), + nkRecList.t( + typ.recFields.map(newRecFieldGen)))) + +proc f = + # doesn't break the code, but leaving indentation as is would be nice. + let x = if true: callingProcWhatever() + else: callingADifferentProc() diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim index 79f0ad05a..247ece887 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -769,3 +769,69 @@ var rows2 = await pool.rows(sql""" "BBBB" ] ) + + +# bug #11699 + +const keywords = @[ + "foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar", "foo", "bar", "foo", + "bar", "foo", "bar", + "zzz", "ggg", "ddd", +] + +let keywords1 = @[ + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", + "bar5", "foo6", "bar6", "foo7", + "zzz", "ggg", "ddd", +] + +let keywords2 = @[ + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", + "bar5", "foo6", "bar6", "foo7", + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", + "bar5", "foo6", "bar6", "foo7", + "zzz", "ggg", "ddd", +] + +if true: + let keywords3 = @[ + "foo1", "bar1", "foo2", "bar2", "foo3", "bar3", "foo4", "bar4", "foo5", + "bar5", "foo6", "bar6", "foo7", + "zzz", "ggg", "ddd", + ] + +const b = true +let fooB = + if true: + if b: 7 else: 8 + else: ord(b) + +let foo = if cond: + if b: T else: F + else: b + +let a = + [[aaadsfas, bbb], + [ccc, ddd]] + +let b = [ + [aaa, bbb], + [ccc, ddd] +] + +# bug #11616 +proc newRecordGen(ctx: Context; typ: TypRef): PNode = + result = nkTypeDef.t( + newId(typ.optSym.name, true, pragmas = [id(if typ.isUnion: "cUnion" + else: "cStruct")]), + empty(), + nkObjectTy.t( + empty(), + empty(), + nkRecList.t( + typ.recFields.map(newRecFieldGen)))) + +proc f = + # doesn't break the code, but leaving indentation as is would be nice. + let x = if true: callingProcWhatever() + else: callingADifferentProc() diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index a1ad96f2b..6bf52f3aa 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -1,49 +1,63 @@ discard """ errormsg: "type mismatch: got <Bar[system.int]>" -disabled: "true" +disabled: "32bit" nimout: ''' -t3330.nim(63, 4) Error: type mismatch: got <Bar[system.int]> +t3330.nim(78, 4) Error: type mismatch: got <Bar[system.int]> but expected one of: proc test(foo: Foo[int]) -t3330.nim(48, 8) Hint: Non-matching candidates for add(k, string, T) + first type mismatch at position: 1 + required type for foo: Foo[int] + but expression 'bar' is of type: Bar[system.int] +t3330.nim(63, 8) Hint: Non-matching candidates for add(k, string, T) proc add[T](x: var seq[T]; y: openArray[T]) first type mismatch at position: 1 - required type: var seq[T] + required type for x: var seq[T] but expression 'k' is of type: Alias proc add(result: var string; x: float) first type mismatch at position: 1 - required type: var string + required type for result: var string but expression 'k' is of type: Alias proc add(x: var string; y: string) first type mismatch at position: 1 - required type: var string + required type for x: var string but expression 'k' is of type: Alias proc add(x: var string; y: cstring) first type mismatch at position: 1 - required type: var string + required type for x: var string but expression 'k' is of type: Alias proc add[T](x: var seq[T]; y: T) first type mismatch at position: 1 - required type: var seq[T] + required type for x: var seq[T] but expression 'k' is of type: Alias proc add(result: var string; x: int64) first type mismatch at position: 1 - required type: var string + required type for result: var string but expression 'k' is of type: Alias proc add(x: var string; y: char) first type mismatch at position: 1 - required type: var string + required type for x: var string but expression 'k' is of type: Alias -t3330.nim(48, 8) template/generic instantiation of `add` from here -t3330.nim(55, 6) Foo: 'bar.value' cannot be assigned to -t3330.nim(48, 8) template/generic instantiation of `add` from here -t3330.nim(56, 6) Foo: 'bar.x' cannot be assigned to +t3330.nim(63, 8) template/generic instantiation of `add` from here +t3330.nim(70, 6) Foo: 'bar.value' cannot be assigned to +t3330.nim(63, 8) template/generic instantiation of `add` from here +t3330.nim(71, 6) Foo: 'bar.x' cannot be assigned to expression: test(bar)''' """ +# Note: currently disabled on 32bit because the candidates are presented in +# different order on travis with `NIM_COMPILE_TO_CPP=false CPU=i386`; +# a possible fix would be to sort the candidates by proc signature or +# declaration location + + + + + + +## line 60 type Foo[T] = concept k add(k, string, T) diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim index 4ec848732..f3d70320f 100644 --- a/tests/concepts/texplain.nim +++ b/tests/concepts/texplain.nim @@ -2,69 +2,101 @@ discard """ cmd: "nim c --verbosity:0 --colors:off $file" nimout: ''' Hint: texplain [Processing] -texplain.nim(118, 10) Hint: Non-matching candidates for e(y) +texplain.nim(158, 10) Hint: Non-matching candidates for e(y) proc e(i: int): int + first type mismatch at position: 1 + required type for i: int + but expression 'y' is of type: MatchingType -texplain.nim(121, 7) Hint: Non-matching candidates for e(10) +texplain.nim(161, 7) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int -texplain.nim(84, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(84, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(84, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(84, 5) ExplainedConcept: concept predicate failed -texplain.nim(85, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(85, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(85, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(84, 5) ExplainedConcept: concept predicate failed - -texplain.nim(124, 10) Hint: Non-matching candidates for e(10) + first type mismatch at position: 1 + required type for o: ExplainedConcept + but expression '10' is of type: int literal(10) +texplain.nim(124, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(124, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(124, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(125, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(125, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(125, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed + +texplain.nim(164, 10) Hint: Non-matching candidates for e(10) proc e(o: ExplainedConcept): int -texplain.nim(84, 6) ExplainedConcept: undeclared field: 'foo' -texplain.nim(84, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(84, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(84, 5) ExplainedConcept: concept predicate failed -texplain.nim(85, 6) ExplainedConcept: undeclared field: 'bar' -texplain.nim(85, 6) ExplainedConcept: undeclared field: '.' -texplain.nim(85, 6) ExplainedConcept: expression '.' cannot be called -texplain.nim(84, 5) ExplainedConcept: concept predicate failed - -texplain.nim(128, 20) Error: type mismatch: got <NonMatchingType> + first type mismatch at position: 1 + required type for o: ExplainedConcept + but expression '10' is of type: int literal(10) +texplain.nim(124, 6) ExplainedConcept: undeclared field: 'foo' +texplain.nim(124, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(124, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed +texplain.nim(125, 6) ExplainedConcept: undeclared field: 'bar' +texplain.nim(125, 6) ExplainedConcept: undeclared field: '.' +texplain.nim(125, 6) ExplainedConcept: expression '.' cannot be called +texplain.nim(124, 5) ExplainedConcept: concept predicate failed + +texplain.nim(168, 20) Error: type mismatch: got <NonMatchingType> but expected one of: proc e(o: ExplainedConcept): int -texplain.nim(128, 9) template/generic instantiation of `assert` from here -texplain.nim(84, 5) ExplainedConcept: concept predicate failed + first type mismatch at position: 1 + required type for o: ExplainedConcept + but expression 'n' is of type: NonMatchingType +texplain.nim(168, 9) template/generic instantiation of `assert` from here +texplain.nim(124, 5) ExplainedConcept: concept predicate failed proc e(i: int): int + first type mismatch at position: 1 + required type for i: int + but expression 'n' is of type: NonMatchingType expression: e(n) -texplain.nim(129, 20) Error: type mismatch: got <NonMatchingType> +texplain.nim(169, 20) Error: type mismatch: got <NonMatchingType> but expected one of: proc r(o: RegularConcept): int -texplain.nim(129, 9) template/generic instantiation of `assert` from here -texplain.nim(88, 5) RegularConcept: concept predicate failed + first type mismatch at position: 1 + required type for o: RegularConcept + but expression 'n' is of type: NonMatchingType +texplain.nim(169, 9) template/generic instantiation of `assert` from here +texplain.nim(128, 5) RegularConcept: concept predicate failed proc r[T](a: SomeNumber; b: T; c: auto) + first type mismatch at position: 1 + required type for a: SomeNumber + but expression 'n' is of type: NonMatchingType proc r(i: string): int + first type mismatch at position: 1 + required type for i: string + but expression 'n' is of type: NonMatchingType expression: r(n) -texplain.nim(130, 20) Hint: Non-matching candidates for r(y) +texplain.nim(170, 20) Hint: Non-matching candidates for r(y) proc r[T](a: SomeNumber; b: T; c: auto) + first type mismatch at position: 1 + required type for a: SomeNumber + but expression 'y' is of type: MatchingType proc r(i: string): int + first type mismatch at position: 1 + required type for i: string + but expression 'y' is of type: MatchingType -texplain.nim(138, 2) Error: type mismatch: got <MatchingType> +texplain.nim(178, 2) Error: type mismatch: got <MatchingType> but expected one of: proc f(o: NestedConcept) -texplain.nim(88, 6) RegularConcept: undeclared field: 'foo' -texplain.nim(88, 6) RegularConcept: undeclared field: '.' -texplain.nim(88, 6) RegularConcept: expression '.' cannot be called -texplain.nim(88, 5) RegularConcept: concept predicate failed -texplain.nim(89, 6) RegularConcept: undeclared field: 'bar' -texplain.nim(89, 6) RegularConcept: undeclared field: '.' -texplain.nim(89, 6) RegularConcept: expression '.' cannot be called -texplain.nim(88, 5) RegularConcept: concept predicate failed -texplain.nim(92, 5) NestedConcept: concept predicate failed - -expression: f(y) -''' + first type mismatch at position: 1 + required type for o: NestedConcept + but expression 'y' is of type: MatchingType +texplain.nim(128, 6) RegularConcept: undeclared field: 'foo' +texplain.nim(128, 6) RegularConcept: undeclared field: '.' +texplain.nim(128, 6) RegularConcept: expression '.' cannot be called +texplain.nim(128, 5) RegularConcept: concept predicate failed +texplain.nim(129, 6) RegularConcept: undeclared field: 'bar' +texplain.nim(129, 6) RegularConcept: undeclared field: '.' +texplain.nim(129, 6) RegularConcept: expression '.' cannot be called +texplain.nim(128, 5) RegularConcept: concept predicate failed +texplain.nim(132, 5) NestedConcept: concept predicate failed + +expression: f(y)''' errormsg: "type mismatch: got <MatchingType>" - line: 138 + line: 178 disabled: 32bit """ @@ -77,7 +109,15 @@ expression: f(y) -# line 80 HERE + + + + + + + + +# line 120 HERE type ExplainedConcept {.explain.} = concept o diff --git a/tests/destructor/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim index 5794dec1d..a726960c6 100644 --- a/tests/destructor/tdont_return_unowned_from_owned.nim +++ b/tests/destructor/tdont_return_unowned_from_owned.nim @@ -1,21 +1,33 @@ discard """ cmd: "nim check --newruntime --hints:off $file" - nimout: '''tdont_return_unowned_from_owned.nim(24, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(27, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(30, 6) Error: type mismatch: got <Obj> + nimout: '''tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(39, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(42, 6) Error: type mismatch: got <Obj> but expected one of: proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) + first type mismatch at position: 2 + missing parameter: finalizer 2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them expression: new(result) -tdont_return_unowned_from_owned.nim(30, 6) Error: illformed AST: -tdont_return_unowned_from_owned.nim(38, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(39, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type +tdont_return_unowned_from_owned.nim(42, 6) Error: illformed AST: +tdont_return_unowned_from_owned.nim(50, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(51, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(55, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type ''' errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type" - line: 43 + line: 55 """ + + + + + + + + + +## line 30 # bug #11073 type Obj = ref object diff --git a/tests/errmsgs/t8434.nim b/tests/errmsgs/t8434.nim index b37468111..ada38e9c0 100644 --- a/tests/errmsgs/t8434.nim +++ b/tests/errmsgs/t8434.nim @@ -4,7 +4,7 @@ discard """ proc fun0[T1: int | float | object | array | seq](a1: T1; a2: int) first type mismatch at position: 1 - required type: T1: int or float or object or array or seq[T] + required type for a1: T1: int or float or object or array or seq[T] but expression 'byte(1)' is of type: byte expression: fun0(byte(1), 0) diff --git a/tests/errmsgs/tdetailed_position.nim b/tests/errmsgs/tdetailed_position.nim index ce5b18bbd..ecece7972 100644 --- a/tests/errmsgs/tdetailed_position.nim +++ b/tests/errmsgs/tdetailed_position.nim @@ -6,7 +6,7 @@ nimout: ''' but expected one of: proc main(a, b, c: string) first type mismatch at position: 1 - required type: string + required type for a: string but expression '1' is of type: int literal(1) expression: main(1, 2, 3) diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim index 0ae60f200..e6a62204e 100644 --- a/tests/errmsgs/tgcsafety.nim +++ b/tests/errmsgs/tgcsafety.nim @@ -8,7 +8,7 @@ proc serve(server: AsyncHttpServer; port: Port; callback: proc (request: Request): Future[void] {.closure, gcsafe.}; address = ""): owned(Future[void]) first type mismatch at position: 3 - required type: proc (request: Request): Future[system.void]{.closure, gcsafe.} + required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.} but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: <unknown>.} This expression is not GC-safe. Annotate the proc with {.gcsafe.} to get extended error information. diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim new file mode 100644 index 000000000..42a98a891 --- /dev/null +++ b/tests/errmsgs/tsigmatch.nim @@ -0,0 +1,172 @@ +discard """ + cmd: "nim check --showAllMismatches:on --hints:off $file" + nimout: ''' +tsigmatch.nim(111, 4) Error: type mismatch: got <A, string> +but expected one of: +proc f(b: B) + first type mismatch at position: 1 + required type for b: B + but expression 'A()' is of type: A +proc f(a: A) + first type mismatch at position: 2 + extra argument given + +expression: f(A(), "extra") +tsigmatch.nim(125, 6) Error: type mismatch: got <tuple of (string, proc (){.gcsafe, locks: 0.})> +but expected one of: +proc foo(x: (string, proc ())) + first type mismatch at position: 1 + required type for x: tuple of (string, proc (){.closure.}) + but expression '("foobar", proc () = echo(["Hello!"]))' is of type: tuple of (string, proc (){.gcsafe, locks: 0.}) + +expression: foo(("foobar", proc () = echo(["Hello!"]))) +tsigmatch.nim(132, 11) Error: type mismatch: got <proc (s: string): string{.noSideEffect, gcsafe, locks: 0.}> +but expected one of: +proc foo[T, S](op: proc (x: T): S {.cdecl.}): auto + first type mismatch at position: 1 + required type for op: proc (x: T): S{.cdecl.} + but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe, locks: 0.} +proc foo[T, S](op: proc (x: T): S {.safecall.}): auto + first type mismatch at position: 1 + required type for op: proc (x: T): S{.safecall.} + but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe, locks: 0.} + +expression: foo(fun) +tsigmatch.nim(143, 13) Error: type mismatch: got <array[0..0, proc (x: int){.gcsafe, locks: 0.}]> +but expected one of: +proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe, locks: 0.}]) + first type mismatch at position: 1 + required type for fs: openarray[proc (x: int){.closure, gcsafe, locks: 0.}] + but expression '[proc (x: int) {.gcsafe, locks: 0.} = echo [x]]' is of type: array[0..0, proc (x: int){.gcsafe, locks: 0.}] + +expression: takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo [x]]) +tsigmatch.nim(149, 4) Error: type mismatch: got <int literal(10), a0: int literal(5), string> +but expected one of: +proc f(a0: uint8; b: string) + first type mismatch at position: 2 + named param already provided: a0 + +expression: f(10, a0 = 5, "") +tsigmatch.nim(156, 4) Error: type mismatch: got <string, string, string, string, string, float64, string> +but expected one of: +proc f(a1: int) + first type mismatch at position: 1 + required type for a1: int + but expression '"asdf"' is of type: string +proc f(a1: string; a2: varargs[string]; a3: float; a4: var string) + first type mismatch at position: 7 + required type for a4: var string + but expression '"bad"' is immutable, not 'var' + +expression: f("asdf", "1", "2", "3", "4", 2.3, "bad") +tsigmatch.nim(164, 4) Error: type mismatch: got <string, a0: int literal(12)> +but expected one of: +proc f(x: string; a0: var int) + first type mismatch at position: 2 + required type for a0: var int + but expression 'a0 = 12' is immutable, not 'var' +proc f(x: string; a0: string) + first type mismatch at position: 2 + required type for a0: string + but expression 'a0 = 12' is of type: int literal(12) + +expression: f(foo, a0 = 12) +tsigmatch.nim(171, 7) Error: type mismatch: got <Mystring, string> +but expected one of: +proc fun1(a1: MyInt; a2: Mystring) + first type mismatch at position: 1 + required type for a1: MyInt + but expression 'default(Mystring)' is of type: Mystring +proc fun1(a1: float; a2: Mystring) + first type mismatch at position: 1 + required type for a1: float + but expression 'default(Mystring)' is of type: Mystring + +expression: fun1(default(Mystring), "asdf") +''' + errormsg: "type mismatch" +""" + + + + + + + + + + + +## line 100 +block: + # bug #11061 Type mismatch error "first type mismatch at" points to wrong argument/position + # Note: the error msg now gives correct position for mismatched argument + type + A = object of RootObj + B = object of A + + proc f(b: B) = discard + proc f(a: A) = discard + + f(A(), "extra") +#[ +this one is similar but error msg was even more misleading, since the user +would think float != float64 where in fact the issue is another param: +first type mismatch at position: 1; required type: float; but expression 'x = 1.2' is of type: float64 + proc f(x: string, a0 = 0, a1 = 0, a2 = 0) = discard + proc f(x: float, a0 = 0, a1 = 0, a2 = 0) = discard + f(x = float(1.2), a0 = 0, a0 = 0) +]# + +block: + # bug #7808 Passing tuple with proc leads to confusing errors + # Note: the error message now shows `closure` which helps debugging the issue + proc foo(x: (string, proc ())) = x[1]() + foo(("foobar", proc () = echo("Hello!"))) + +block: + # bug #8305 type mismatch error drops crucial pragma info when there's only 1 argument + proc fun(s: string): string {. .} = discard + proc foo[T, S](op: proc (x: T): S {. cdecl .}): auto = 1 + proc foo[T, S](op: proc (x: T): S {. safecall .}): auto = 1 + echo foo(fun) + +block: + # bug #10285 Function signature don't match when inside seq/array/openarray + # Note: the error message now shows `closure` which helps debugging the issue + # out why it doesn't match + proc takesFunc(f: proc (x: int) {.gcsafe, locks: 0.}) = + echo "takes single Func" + proc takesFuncs(fs: openarray[proc (x: int) {.gcsafe, locks: 0.}]) = + echo "takes multiple Func" + takesFunc(proc (x: int) {.gcsafe, locks: 0.} = echo x) # works + takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo x]) # fails + +block: + # bug https://github.com/nim-lang/Nim/issues/11061#issuecomment-508970465 + # better fix for removal of `errCannotBindXTwice` due to #3836 + proc f(a0: uint8, b: string) = discard + f(10, a0 = 5, "") + +block: + # bug: https://github.com/nim-lang/Nim/issues/11061#issuecomment-508969796 + # sigmatch gets confused with param/arg position after varargs + proc f(a1: int) = discard + proc f(a1: string, a2: varargs[string], a3: float, a4: var string) = discard + f("asdf", "1", "2", "3", "4", 2.3, "bad") + +block: + # bug: https://github.com/nim-lang/Nim/issues/11061#issuecomment-508970046 + # err msg incorrectly said something is immutable + proc f(x: string, a0: var int) = discard + proc f(x: string, a0: string) = discard + var foo = "" + f(foo, a0 = 12) + +block: + type Mystring = string + type MyInt = int + proc fun1(a1: MyInt, a2: Mystring) = discard + proc fun1(a1: float, a2: Mystring) = discard + fun1(Mystring.default, "asdf") + diff --git a/tests/errmsgs/tunknown_named_parameter.nim b/tests/errmsgs/tunknown_named_parameter.nim index 3051787ea..e9be23068 100644 --- a/tests/errmsgs/tunknown_named_parameter.nim +++ b/tests/errmsgs/tunknown_named_parameter.nim @@ -4,14 +4,14 @@ errormsg: "type mismatch: got <string, set[char], maxsplits: int literal(1)>" nimout: ''' proc rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] first type mismatch at position: 2 - required type: char + required type for sep: char but expression '{':'}' is of type: set[char] proc rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[string] first type mismatch at position: 3 unknown named parameter: maxsplits proc rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] first type mismatch at position: 2 - required type: string + required type for sep: string but expression '{':'}' is of type: set[char] expression: rsplit("abc:def", {':'}, maxsplits = 1) diff --git a/tests/errmsgs/twrong_at_operator.nim b/tests/errmsgs/twrong_at_operator.nim index 5413515cb..7ce077003 100644 --- a/tests/errmsgs/twrong_at_operator.nim +++ b/tests/errmsgs/twrong_at_operator.nim @@ -1,11 +1,17 @@ discard """ errormsg: "type mismatch: got <array[0..0, type int]>" -line: 16 +line: 22 nimout: ''' -twrong_at_operator.nim(16, 30) Error: type mismatch: got <array[0..0, type int]> +twrong_at_operator.nim(22, 30) Error: type mismatch: got <array[0..0, type int]> but expected one of: proc `@`[T](a: openArray[T]): seq[T] + first type mismatch at position: 1 + required type for a: openarray[T] + but expression '[int]' is of type: array[0..0, type int] proc `@`[IDX, T](a: array[IDX, T]): seq[T] + first type mismatch at position: 1 + required type for a: array[IDX, T] + but expression '[int]' is of type: array[0..0, type int] expression: @[int] ''' diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim index bd973eed1..a90690591 100644 --- a/tests/metatype/ttypedesc3.nim +++ b/tests/metatype/ttypedesc3.nim @@ -5,6 +5,7 @@ proc Child method Base yield Base yield Child +12 ''' """ @@ -27,3 +28,16 @@ when false: for s in Base.it: echo s for s in Child.it: echo s #<- bug #2662 + + +# bug #11747 + +type + MyType = object + a: int32 + b: int32 + c: int32 + + MyRefType = ref MyType + +echo sizeof(MyRefType[]) diff --git a/tests/typerel/t7600_1.nim b/tests/typerel/t7600_1.nim index e3a5fefa2..e9d01bd0d 100644 --- a/tests/typerel/t7600_1.nim +++ b/tests/typerel/t7600_1.nim @@ -1,8 +1,11 @@ discard """ errormsg: "type mismatch: got <Thin[system.int]>" -nimout: '''t7600_1.nim(18, 6) Error: type mismatch: got <Thin[system.int]> +nimout: '''t7600_1.nim(21, 6) Error: type mismatch: got <Thin[system.int]> but expected one of: proc test[T](x: Paper[T]) + first type mismatch at position: 1 + required type for x: Paper[test.T] + but expression 'tn' is of type: Thin[system.int] expression: test tn''' """ diff --git a/tests/typerel/t7600_2.nim b/tests/typerel/t7600_2.nim index 7badb69cf..371707f4c 100644 --- a/tests/typerel/t7600_2.nim +++ b/tests/typerel/t7600_2.nim @@ -1,8 +1,11 @@ discard """ errormsg: "type mismatch: got <Thin>" -nimout: '''t7600_2.nim(17, 6) Error: type mismatch: got <Thin> +nimout: '''t7600_2.nim(20, 6) Error: type mismatch: got <Thin> but expected one of: proc test(x: Paper) + first type mismatch at position: 1 + required type for x: Paper + but expression 'tn' is of type: Thin expression: test tn''' """ diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index 43cc04f30..398191658 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -1,10 +1,12 @@ discard """ errmsg: "type mismatch: got <int>" - line: 15 + line: 17 nimout: '''type mismatch: got <int> but expected one of: proc inc[T: Ordinal | uint | uint64](x: var T; y = 1) - for a 'var' type a variable needs to be passed, but 'i' is immutable + first type mismatch at position: 1 + required type for x: var T: Ordinal or uint or uint64 + but expression 'i' is immutable, not 'var' expression: inc i ''' |