From a651809411b9b7f2d909f3ccfeeca844210a14de Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 18 Jul 2018 14:54:44 +0200 Subject: [PATCH 01/57] Fixes #8343, Fixes #8344 (#8347) --- compiler/renderer.nim | 8 +++----- tests/macros/tmacrostmt.nim | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 83cf288ffe..ae5b05b182 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -627,11 +627,12 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) = gcoms(g) if doIndent: dedent(g) else: - if rfLongMode in c.flags: indentNL(g) + indentNL(g) gsub(g, n) gcoms(g) + dedent(g) optNL(g) - if rfLongMode in c.flags: dedent(g) + proc gif(g: var TSrcGen, n: PNode) = var c: TContext @@ -785,10 +786,7 @@ proc gblock(g: var TSrcGen, n: PNode) = if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) - # XXX I don't get why this is needed here! gstmts should already handle this! - indentNL(g) gstmts(g, n.sons[1], c) - dedent(g) proc gstaticStmt(g: var TSrcGen, n: PNode) = var c: TContext diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim index a6e1e66dd9..abb4cc0505 100644 --- a/tests/macros/tmacrostmt.nim +++ b/tests/macros/tmacrostmt.nim @@ -43,4 +43,19 @@ macro repr_and_parse(fn: typed): typed = echo fn_impl.repr result = parseStmt(fn_impl.repr) -repr_and_parse(f) \ No newline at end of file +repr_and_parse(f) + + +#------------------------------------ +# bugs #8343 and #8344 +proc one_if_proc(x, y : int): int = + if x < y: result = x + else: result = y + +proc test_block(x, y : int): int = + block label: + result = x + result = y + +repr_and_parse(one_if_proc) +repr_and_parse(test_block) From 143834ba4e2596f30272e537faac526ce58e1796 Mon Sep 17 00:00:00 2001 From: skilchen Date: Thu, 19 Jul 2018 01:05:07 +0200 Subject: [PATCH 02/57] keep the imports in runnableExamples visible in generated html doc (#8354) --- compiler/semexprs.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3a72d1f5ab..d7a0d7b8b8 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2031,9 +2031,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = c.runnableExamples = newTree(nkStmtList, newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp)))) let imports = newTree(nkStmtList) - extractImports(n.lastSon, imports) + var saved_lastSon = copyTree n.lastSon + extractImports(saved_lastSon, imports) for imp in imports: c.runnableExamples.add imp - c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree n.lastSon) + c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree saved_lastSon) result = setMs(n, s) else: result = c.graph.emptyNode From f92d61b1f4e193bd17e1f76722d26f1f0605ad17 Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 19 Jul 2018 22:38:40 +0700 Subject: [PATCH 03/57] fixes #8037, json.to support object with distinct types (#8086) * add distinct types to json 'to' macro * fix json 'to' macro and add more test --- lib/pure/json.nim | 35 ++++++++++-- tests/stdlib/tjsonmacro.nim | 105 ++++++++++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 8 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 67f92dffee..b9279b18c9 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1004,6 +1004,13 @@ proc processElseBranch(recCaseNode, elseBranch, jsonNode, kindType, exprColonExpr.add(ifStmt) proc createConstructor(typeSym, jsonNode: NimNode): NimNode {.compileTime.} + +proc detectDistinctType(typeSym: NimNode): NimNode = + let + typeImpl = getTypeImpl(typeSym) + typeInst = getTypeInst(typeSym) + result = if typeImpl.typeKind == ntyDistinct: typeImpl else: typeInst + proc processObjField(field, jsonNode: NimNode): seq[NimNode] = ## Process a field from a ``RecList``. ## @@ -1022,8 +1029,8 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] = # Add the field value. # -> jsonNode["`field`"] let indexedJsonNode = createJsonIndexer(jsonNode, $field) - exprColonExpr.add(createConstructor(getTypeInst(field), indexedJsonNode)) - + let typeNode = detectDistinctType(field) + exprColonExpr.add(createConstructor(typeNode, indexedJsonNode)) of nnkRecCase: # A "case" field that introduces a variant. let exprColonExpr = newNimNode(nnkExprColonExpr) @@ -1248,7 +1255,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = let seqT = typeSym[1] let forLoopI = genSym(nskForVar, "i") let indexerNode = createJsonIndexer(jsonNode, forLoopI) - let constructorNode = createConstructor(seqT, indexerNode) + let constructorNode = createConstructor(detectDistinctType(seqT), indexerNode) # Create a statement expression containing a for loop. result = quote do: @@ -1284,7 +1291,10 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = # Handle all other types. let obj = getType(typeSym) - if obj.kind == nnkBracketExpr: + let typeNode = getTypeImpl(typeSym) + if typeNode.typeKind == ntyDistinct: + result = createConstructor(typeNode, jsonNode) + elif obj.kind == nnkBracketExpr: # When `Sym "Foo"` turns out to be a `ref object`. result = createConstructor(obj, jsonNode) else: @@ -1295,6 +1305,21 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = # TODO: The fact that `jsonNode` here works to give a good line number # is weird. Specifying typeSym should work but doesn't. error("Use a named tuple instead of: " & $toStrLit(typeSym), jsonNode) + of nnkDistinctTy: + var baseType = typeSym + # solve nested distinct types + while baseType.typeKind == ntyDistinct: + let impl = getTypeImpl(baseType[0]) + if impl.typeKind != ntyDistinct: + baseType = baseType[0] + break + baseType = impl + let ret = createConstructor(baseType, jsonNode) + let typeInst = getTypeInst(typeSym) + result = quote do: + ( + `typeInst`(`ret`) + ) else: doAssert false, "Unable to create constructor for: " & $typeSym.kind @@ -1418,7 +1443,7 @@ macro to*(node: JsonNode, T: typedesc): untyped = ## doAssert data.person.age == 21 ## doAssert data.list == @[1, 2, 3, 4] - let typeNode = getTypeInst(T) + let typeNode = getTypeImpl(T) expectKind(typeNode, nnkBracketExpr) doAssert(($typeNode[0]).normalize == "typedesc") diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index f13d2e5cb4..c0b4d5f787 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -337,7 +337,7 @@ when isMainModule: n2: Option[int] n3: Option[string] n4: Option[bool] - + var j0 = parseJson("""{"n1": 1, "n2": null, "n3": null, "n4": null}""") let j0Deser = j0.to(Obj) doAssert j0Deser.n1 == 1 @@ -411,10 +411,109 @@ when isMainModule: doAssert dataDeser.a == 1 doAssert dataDeser.f == 6 doAssert dataDeser.i == 9.9'f32 - + # deserialize directly into a table block: let s = """{"a": 1, "b": 2}""" let t = parseJson(s).to(Table[string, int]) doAssert t["a"] == 1 - doAssert t["b"] == 2 \ No newline at end of file + doAssert t["b"] == 2 + + block: + # bug #8037 + type + Apple = distinct string + String = distinct Apple + Email = distinct string + MyList = distinct seq[int] + MyYear = distinct Option[int] + MyTable = distinct Table[string, int] + MyArr = distinct array[3, float] + MyRef = ref object + name: string + MyObj = object + color: int + MyDistRef = distinct MyRef + MyDistObj = distinct MyObj + Toot = object + name*: String + email*: Email + list: MyList + year: MyYear + dict: MyTable + arr: MyArr + person: MyDistRef + distfruit: MyDistObj + dog: MyRef + fruit: MyObj + emails: seq[String] + + var tJson = parseJson(""" + { + "name":"Bongo", + "email":"bongo@bingo.com", + "list": [11,7,15], + "year": 1975, + "dict": {"a": 1, "b": 2}, + "arr": [1.0, 2.0, 7.0], + "person": {"name": "boney"}, + "dog": {"name": "honey"}, + "fruit": {"color": 10}, + "distfruit": {"color": 11}, + "emails": ["abc", "123"] + } + """) + + var t = to(tJson, Toot) + doAssert string(t.name) == "Bongo" + doAssert string(t.email) == "bongo@bingo.com" + doAssert seq[int](t.list) == @[11,7,15] + doAssert Option[int](t.year).get() == 1975 + doAssert Table[string,int](t.dict)["a"] == 1 + doAssert Table[string,int](t.dict)["b"] == 2 + doAssert array[3, float](t.arr) == [1.0,2.0,7.0] + doAssert MyRef(t.person).name == "boney" + doAssert MyObj(t.distFruit).color == 11 + doAssert t.dog.name == "honey" + doAssert t.fruit.color == 10 + doAssert seq[string](t.emails) == @["abc", "123"] + + block test_table: + var y = parseJson("""{"a": 1, "b": 2, "c": 3}""") + var u = y.to(MyTable) + var v = y.to(Table[string, int]) + doAssert Table[string, int](u)["a"] == 1 + doAssert Table[string, int](u)["b"] == 2 + doAssert Table[string, int](u)["c"] == 3 + doAssert v["a"] == 1 + + block primitive_string: + const kApple = "apple" + var u = newJString(kApple) + var v = u.to(Email) + var w = u.to(Apple) + var x = u.to(String) + doAssert string(v) == kApple + doAssert string(w) == kApple + doAssert string(x) == kApple + + block test_option: + var u = newJInt(1137) + var v = u.to(MyYear) + var w = u.to(Option[int]) + doAssert Option[int](v).get() == 1137 + doAssert w.get() == 1137 + + block test_object: + var u = parseJson("""{"color": 987}""") + var v = u.to(MyObj) + var w = u.to(MyDistObj) + doAssert v.color == 987 + doAssert MyObj(w).color == 987 + + block test_ref_object: + var u = parseJson("""{"name": "smith"}""") + var v = u.to(MyRef) + var w = u.to(MyDistRef) + doAssert v.name == "smith" + doAssert MyRef(w).name == "smith" From 060871e64ac9d665430d4d9ae912bf7a379ee976 Mon Sep 17 00:00:00 2001 From: Ray Imber Date: Fri, 20 Jul 2018 02:58:42 -0700 Subject: [PATCH 04/57] Better doc search (#8260) * Modified the doc generation to produce a custom data attribute to allow for better search functionality * Implemented fuzzy matching for the Nim Doc search instead of the simple regex match. * Fix to the WordBoundry state transition from code review with @Varriount. Also removed silly testing template that is no longer used. * Update fuzzysearch.nim * Update fuzzysearch.nim * Update fuzzysearch.nim * Update dochack.nim * Update dochack.nim --- lib/packages/docutils/rstgen.nim | 12 ++- tools/dochack/dochack.nim | 36 ++++---- tools/dochack/fuzzysearch.nim | 139 +++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 20 deletions(-) create mode 100644 tools/dochack/fuzzysearch.nim diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index ef456f0938..43a429a17b 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -449,10 +449,11 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string = desc = if not symbols[j].linkDesc.isNil: symbols[j].linkDesc else: "" if desc.len > 0: result.addf("""
  • $2
  • + title="$3" data-doc-search-tag="$2" href="$1">$2 """, [url, text, desc]) else: - result.addf("""
  • $2
  • + result.addf("""
  • $2
  • """, [url, text]) inc j result.add("\n") @@ -493,6 +494,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = # Build a list of levels and extracted titles to make processing easier. var titleRef: string + titleTag: string levels: seq[tuple[level: int, text: string]] L = 0 level = 1 @@ -519,10 +521,12 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = let link = entries[L].link if link.isDocumentationTitle: titleRef = link + titleTag = levels[L].text else: result.add(level.indentToLevel(levels[L].level)) - result.add("
  • " & - levels[L].text & "
  • \n") + result.addf("""
  • + $3
  • + """, [titleTag & " : " & levels[L].text, link, levels[L].text]) inc L result.add(level.indentToLevel(1) & "\n") assert(not titleRef.isNil, diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 79a0e74827..8cc27b6eb6 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -1,6 +1,5 @@ - - import karax +import fuzzysearch proc findNodeWith(x: Element; tag, content: cstring): Element = if x.nodeName == tag and x.textContent == content: @@ -88,11 +87,11 @@ proc toHtml(x: TocEntry; isRoot=false): Element = if ul.len != 0: result.add ul if result.len == 0: result = nil -proc containsWord(a, b: cstring): bool {.asmNoStackFrame.} = - {.emit: """ - var escaped = `b`.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - return new RegExp("\\b" + escaped + "\\b").test(`a`); - """.} +#proc containsWord(a, b: cstring): bool {.asmNoStackFrame.} = + #{.emit: """ + #var escaped = `b`.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + #return new RegExp("\\b" + escaped + "\\b").test(`a`); + #""".} proc isWhitespace(text: cstring): bool {.asmNoStackFrame.} = {.emit: """ @@ -252,24 +251,29 @@ proc dosearch(value: cstring): Element = `stuff` = doc.documentElement; """.} - db = stuff.getElementsByClass"reference external" + db = stuff.getElementsByClass"reference" contents = @[] for ahref in db: - contents.add ahref.textContent.normalize + contents.add ahref.getAttribute("data-doc-search-tag") let ul = tree("UL") result = tree("DIV") result.setClass"search_results" var matches: seq[(Element, int)] = @[] - let key = value.normalize for i in 0.. int: - a[1] - b[1] - for i in 0..min( 0), + ) From 9c3336dcffcb10f662f5c358f63d073db1454116 Mon Sep 17 00:00:00 2001 From: andri lim Date: Sat, 21 Jul 2018 00:48:12 +0700 Subject: [PATCH 05/57] fixes #8371, macros.hasCustomPragma doesn't crash anymore (#8378) * fixes #8371, macros.hasCustomPragma doesn't crash anymore * fix macros.hasCustomPragma --- lib/core/macros.nim | 4 +++- tests/pragmas/tcustom_pragma.nim | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 8a1be3720b..345c53b088 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1284,7 +1284,7 @@ proc customPragmaNode(n: NimNode): NimNode = let typ = n.getTypeInst() - if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy: + if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy: return typ[1][1] elif typ.typeKind == ntyTypeDesc: let impl = typ[1].getImpl() @@ -1319,6 +1319,8 @@ proc customPragmaNode(n: NimNode): NimNode = if identDefs.kind == nnkRecCase: identDefsStack.add(identDefs[0]) for i in 1.. Date: Sat, 21 Jul 2018 04:47:19 +0900 Subject: [PATCH 06/57] Add -w flag to Switch compilation to prevent deadlock (#8372) See https://forum.nim-lang.org/t/4062. The summary is that there are warnings printed when compiling and that causes a deadlock, likely due to output buffers being filled up. With the `-w` flag, the compiler outputs no warnings and the compilation is allowed to finish. --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 575e30a794..34628e363a 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -92,7 +92,7 @@ compiler nintendoSwitchGCC: optSize: " -Os -ffast-math ", compilerExe: "aarch64-none-elf-gcc", cppCompiler: "aarch64-none-elf-g++", - compileTmpl: "-MMD -MP -MF $dfile -c $options $include -o $objfile $file", + compileTmpl: "-w -MMD -MP -MF $dfile -c $options $include -o $objfile $file", buildGui: " -mwindows", buildDll: " -shared", buildLib: "aarch64-none-elf-gcc-ar rcs $libfile $objfiles", From 5ea3b4d581c1997ba04ed6c7ba75623019afb95d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 21 Jul 2018 00:43:13 +0100 Subject: [PATCH 07/57] Implements alloc/dealloc counters for better leak debugging. (#8384) --- lib/system/alloc.nim | 13 +++++++++++++ lib/system/gc_common.nim | 3 +++ 2 files changed, 16 insertions(+) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 95becde229..ca2d76225b 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -116,6 +116,8 @@ type nextChunkSize: int bottomData: AvlNode heapLinks: HeapLinks + when defined(nimTypeNames): + allocCounter, deallocCounter: int const fsLookupTable: array[byte, int8] = [ @@ -737,6 +739,8 @@ when false: result = nil proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = + when defined(nimTypeNames): + inc(a.allocCounter) sysAssert(allocInv(a), "rawAlloc: begin") sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small") @@ -810,6 +814,8 @@ proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer = zeroMem(result, requestedSize) proc rawDealloc(a: var MemRegion, p: pointer) = + when defined(nimTypeNames): + inc(a.deallocCounter) #sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer") sysAssert(allocInv(a), "rawDealloc: begin") var c = pageAddr(p) @@ -975,6 +981,10 @@ proc getOccupiedMem(a: MemRegion): int {.inline.} = result = a.occ # a.currMem - a.freeMem +when defined(nimTypeNames): + proc getMemCounters(a: MemRegion): (int, int) {.inline.} = + (a.allocCounter, a.deallocCounter) + # ---------------------- thread memory region ------------------------------- template instantiateForRegion(allocator: untyped) = @@ -1018,6 +1028,9 @@ template instantiateForRegion(allocator: untyped) = proc getOccupiedMem(): int = return allocator.occ #getTotalMem() - getFreeMem() proc getMaxMem*(): int = return getMaxMem(allocator) + when defined(nimTypeNames): + proc getMemCounters*(): (int, int) = getMemCounters(allocator) + # -------------------- shared heap region ---------------------------------- when hasThreadSupport: var sharedHeap: MemRegion diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 711a610bfc..dcea0c4cc9 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -57,6 +57,9 @@ when defined(nimTypeNames): for i in 0 .. n-1: c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", a[i][0], a[i][1], a[i][2]) c_fprintf(stdout, "[Heap] total number of bytes: %ld\n", totalAllocated) + when defined(nimTypeNames): + let (allocs, deallocs) = getMemCounters() + c_fprintf(stdout, "[Heap] allocs/deallocs: %ld/%ld\n", allocs, deallocs) when defined(nimGcRefLeak): proc oomhandler() = From ec0294018570c5d0542904df7b01adaf05e3ac93 Mon Sep 17 00:00:00 2001 From: cooldome Date: Sat, 21 Jul 2018 13:01:47 +0200 Subject: [PATCH 08/57] Render bug: if expression with statement list expression as condition (#8375) * Fixes #8348 --- compiler/parser.nim | 1 + compiler/renderer.nim | 17 ++++++++++++----- tests/macros/tmacrostmt.nim | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index c513fac680..5664a9f67c 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -568,6 +568,7 @@ proc parsePar(p: var TParser): PNode = result = newNodeP(nkPar, p) getTok(p) optInd(p, result) + flexComment(p, result) if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, tkConst, tkLet, tkWhen, tkVar, diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ae5b05b182..ce27e1cd97 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -634,9 +634,16 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) = optNL(g) +proc gcond(g: var TSrcGen, n: PNode) = + if n.kind == nkStmtListExpr: + put(g, tkParLe, "(") + gsub(g, n) + if n.kind == nkStmtListExpr: + put(g, tkParRi, ")") + proc gif(g: var TSrcGen, n: PNode) = var c: TContext - gsub(g, n.sons[0].sons[0]) + gcond(g, n.sons[0].sons[0]) initContext(c) putWithSpace(g, tkColon, ":") if longMode(g, n) or (lsub(g, n.sons[0].sons[1]) + g.lineLen > MaxLineLen): @@ -651,7 +658,7 @@ proc gif(g: var TSrcGen, n: PNode) = proc gwhile(g: var TSrcGen, n: PNode) = var c: TContext putWithSpace(g, tkWhile, "while") - gsub(g, n.sons[0]) + gcond(g, n.sons[0]) putWithSpace(g, tkColon, ":") initContext(c) if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen): @@ -715,7 +722,7 @@ proc gcase(g: var TSrcGen, n: PNode) = var last = if n.sons[length-1].kind == nkElse: -2 else: -1 if longMode(g, n, 0, last): incl(c.flags, rfLongMode) putWithSpace(g, tkCase, "case") - gsub(g, n.sons[0]) + gcond(g, n.sons[0]) gcoms(g) optNL(g) gsons(g, n, c, 1, last) @@ -1102,13 +1109,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkAccent, "`") of nkIfExpr: putWithSpace(g, tkIf, "if") - if n.len > 0: gsub(g, n.sons[0], 0) + if n.len > 0: gcond(g, n.sons[0].sons[0]) putWithSpace(g, tkColon, ":") if n.len > 0: gsub(g, n.sons[0], 1) gsons(g, n, emptyContext, 1) of nkElifExpr: putWithSpace(g, tkElif, " elif") - gsub(g, n, 0) + gcond(g, n[0]) putWithSpace(g, tkColon, ":") gsub(g, n, 1) of nkElseExpr: diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim index abb4cc0505..9dbfbce43e 100644 --- a/tests/macros/tmacrostmt.nim +++ b/tests/macros/tmacrostmt.nim @@ -57,5 +57,21 @@ proc test_block(x, y : int): int = result = x result = y +#------------------------------------ +# bugs #8348 + +template `>`(x, y: untyped): untyped = + ## "is greater" operator. This is the same as ``y < x``. + y < x + +proc test_cond_stmtlist(x, y: int): int = + result = x + if x > y: + result = x + + repr_and_parse(one_if_proc) repr_and_parse(test_block) +repr_and_parse(test_cond_stmtlist) + + From 57f4a5d429b9593791c4544ebdb99ea034c44933 Mon Sep 17 00:00:00 2001 From: skilchen Date: Sat, 21 Jul 2018 19:16:05 +0200 Subject: [PATCH 09/57] sequtils: remove some aligning spaces around == to silence warnings --- lib/pure/collections/sequtils.nim | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 44c59c6279..db33e41afd 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -854,20 +854,20 @@ when isMainModule: doAssert numbers.distribute(6)[0] == @[1, 2] doAssert numbers.distribute(6)[5] == @[7] let a = @[1, 2, 3, 4, 5, 6, 7] - doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]] - doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]] - doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]] - doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]] - doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]] - doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] - doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] - doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] - doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]] - doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]] - doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]] - doAssert a.distribute(6, false) == @[ + doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]] + doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]] + doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]] + doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]] + doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]] + doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] + doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] + doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]] + doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]] + doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]] + doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]] + doAssert a.distribute(6, false) == @[ @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]] - doAssert a.distribute(8, false) == a.distribute(8, true) + doAssert a.distribute(8, false) == a.distribute(8, true) doAssert a.distribute(90, false) == a.distribute(90, true) var b = @[0] for f in 1 .. 25: b.add(f) From 8fe8bed9c3e94cf5f6068e652b99a050f84d6b3f Mon Sep 17 00:00:00 2001 From: skilchen Date: Sat, 21 Jul 2018 19:51:14 +0200 Subject: [PATCH 10/57] add sets.pop procedure (analogue to python) (#8383) --- lib/pure/collections/sets.nim | 12 ++++++++++++ tests/sets/tsetpop.nim | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/sets/tsetpop.nim diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 59c90bc2ba..fdc3b4b03a 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -347,6 +347,18 @@ proc excl*[A](s: var HashSet[A], other: HashSet[A]) = assert other.isValid, "The set `other` needs to be initialized." for item in other: discard exclImpl(s, item) +proc pop*[A](s: var HashSet[A]): A = + ## Remove and return an arbitrary element from the set `s`. + ## + ## Raises KeyError if the set `s` is empty. + ## + for h in 0..high(s.data): + if isFilled(s.data[h].hcode): + result = s.data[h].key + excl(s, result) + return result + raise newException(KeyError, "set is empty") + proc containsOrIncl*[A](s: var HashSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was added to `s`. ## diff --git a/tests/sets/tsetpop.nim b/tests/sets/tsetpop.nim new file mode 100644 index 0000000000..c37bda57d9 --- /dev/null +++ b/tests/sets/tsetpop.nim @@ -0,0 +1,22 @@ +discard """ + targets: "c c++ js" + output: '''1000 +0 +set is empty +''' +""" + +import sets + +var a = initSet[int]() +for i in 1..1000: + a.incl(i) +echo len(a) +for i in 1..1000: + discard a.pop() +echo len(a) + +try: + echo a.pop() +except KeyError as e: + echo e.msg \ No newline at end of file From 9379f9353a73acdb9744ab96c0544fb446b11a6a Mon Sep 17 00:00:00 2001 From: Zachary Carter Date: Sat, 21 Jul 2018 15:42:07 -0400 Subject: [PATCH 11/57] Add application/wasm to mimetypes.nim (#8389) ``` To serve wasm in the most efficient way over the network, make sure your web server has the proper MIME time for .wasm files, which is application/wasm. That will allow streaming compilation, where the browser can start to compile code as it downloads. ``` http://kripken.github.io/emscripten-site/docs/compiling/WebAssembly.html#web-server-setup --- lib/pure/mimetypes.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index ff69ba61e2..8f5f3a183f 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -231,6 +231,7 @@ const mimes* = { "xcf": "application/x-xcf", "fig": "application/x-xfig", "xpi": "application/x-xpinstall", + "wasm": "application/wasm", "amr": "audio/amr", "awb": "audio/amr-wb", "amr": "audio/amr", From 20942098378d12d2b2041cb916c0925b6f017a98 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sun, 22 Jul 2018 23:30:59 +0300 Subject: [PATCH 12/57] Fixed #8399 (#8401) --- compiler/closureiters.nim | 2 +- tests/async/t6100.nim | 15 ------------ tests/async/t7985.nim | 19 --------------- tests/async/tasync_misc.nim | 47 +++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 35 deletions(-) delete mode 100644 tests/async/t6100.nim delete mode 100644 tests/async/t7985.nim create mode 100644 tests/async/tasync_misc.nim diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 6fa856b2f9..9e4885b666 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -588,7 +588,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = let branch = n[i] case branch.kind of nkOfBranch: - branch[1] = ctx.convertExprBodyToAsgn(branch[1], tmp) + branch[^1] = ctx.convertExprBodyToAsgn(branch[^1], tmp) of nkElse: branch[0] = ctx.convertExprBodyToAsgn(branch[0], tmp) else: diff --git a/tests/async/t6100.nim b/tests/async/t6100.nim deleted file mode 100644 index b4dc0f1469..0000000000 --- a/tests/async/t6100.nim +++ /dev/null @@ -1,15 +0,0 @@ -discard """ - file: "t6100.nim" - exitcode: 0 - output: "10000000" -""" -import asyncdispatch - -let done = newFuture[int]() -done.complete(1) - -proc asyncSum: Future[int] {.async.} = - for _ in 1..10_000_000: - result += await done - -echo waitFor asyncSum() \ No newline at end of file diff --git a/tests/async/t7985.nim b/tests/async/t7985.nim deleted file mode 100644 index 0365499d3b..0000000000 --- a/tests/async/t7985.nim +++ /dev/null @@ -1,19 +0,0 @@ -discard """ - file: "t7985.nim" - exitcode: 0 - output: "(value: 1)" -""" -import json, asyncdispatch - -proc getData(): Future[JsonNode] {.async.} = - result = %*{"value": 1} - -type - MyData = object - value: BiggestInt - -proc main() {.async.} = - let data = to(await(getData()), MyData) - echo data - -waitFor(main()) diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim new file mode 100644 index 0000000000..695dcd98aa --- /dev/null +++ b/tests/async/tasync_misc.nim @@ -0,0 +1,47 @@ +discard """ + exitcode: 0 + output: "ok" +""" + +import json, asyncdispatch +block: #6100 + let done = newFuture[int]() + done.complete(1) + + proc asyncSum: Future[int] {.async.} = + for _ in 1..10_000_000: + result += await done + + let res = waitFor asyncSum() + doAssert(res == 10000000) + +block: #7985 + proc getData(): Future[JsonNode] {.async.} = + result = %*{"value": 1} + + type + MyData = object + value: BiggestInt + + proc main() {.async.} = + let data = to(await(getData()), MyData) + doAssert($data == "(value: 1)") + + waitFor(main()) + +block: #8399 + proc bar(): Future[string] {.async.} = discard + + proc foo(line: string) {.async.} = + var res = + case line[0] + of '+', '-': @[] + of '$': (let x = await bar(); @[""]) + else: + nil + + doAssert(res == @[""]) + + waitFor foo("$asd") + +echo "ok" From 503dc222366f7e5d0bbdd7de86a5de1735a17c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 23 Jul 2018 22:40:39 +0200 Subject: [PATCH 13/57] Use enum string values in times.nim (#8413) --- lib/pure/times.nim | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index bc4de7ee43..cdb7a44661 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -181,10 +181,27 @@ elif defined(windows): type Month* = enum ## Represents a month. Note that the enum starts at ``1``, so ``ord(month)`` will give ## the month number in the range ``[1..12]``. - mJan = 1, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec + mJan = (1, "January") + mFeb = "February" + mMar = "March" + mApr = "April" + mMay = "May" + mJun = "June" + mJul = "July" + mAug = "August" + mSep = "September" + mOct = "October" + mNov = "November" + mDec = "December" WeekDay* = enum ## Represents a weekday. - dMon, dTue, dWed, dThu, dFri, dSat, dSun + dMon = "Monday" + dTue = "Tuesday" + dWed = "Wednesday" + dThu = "Thursday" + dFri = "Friday" + dSat = "Saturday" + dSun = "Sunday" MonthdayRange* = range[1..31] HourRange* = range[0..23] @@ -1074,20 +1091,6 @@ proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) & ':' & intToStr(ti.second, 2) -proc `$`*(day: WeekDay): string = - ## Stringify operator for ``WeekDay``. - const lookup: array[WeekDay, string] = ["Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", "Sunday"] - return lookup[day] - -proc `$`*(m: Month): string = - ## Stringify operator for ``Month``. - const lookup: array[Month, string] = ["January", "February", "March", - "April", "May", "June", "July", "August", "September", "October", - "November", "December"] - return lookup[m] - - proc toParts* (ti: TimeInterval): TimeIntervalParts = ## Converts a `TimeInterval` into an array consisting of its time units, ## starting with nanoseconds and ending with years From 9249276db0ae2771a5b7fbe32bbe3b751f0a2711 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 23 Jul 2018 13:58:03 -0700 Subject: [PATCH 14/57] addresses issue #8391 show runtime context on some failed operations (#8393) --- lib/pure/includes/oserr.nim | 2 +- lib/pure/os.nim | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index eb350cbd44..493e8e174e 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -60,7 +60,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} = if additionalInfo.len == 0: e.msg = osErrorMsg(errorCode) else: - e.msg = osErrorMsg(errorCode) & "\nAdditional info: " & additionalInfo + e.msg = osErrorMsg(errorCode) & "\nAdditional info: '" & additionalInfo & "'" if e.msg == "": e.msg = "unknown OS error" raise e diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 84f492c9df..9cc83c372b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -971,7 +971,7 @@ proc rawCreateDir(dir: string): bool = elif errno in {EEXIST, ENOSYS}: result = false else: - raiseOSError(osLastError()) + raiseOSError(osLastError(), dir) elif defined(posix): let res = mkdir(dir, 0o777) if res == 0'i32: @@ -980,7 +980,7 @@ proc rawCreateDir(dir: string): bool = result = false else: #echo res - raiseOSError(osLastError()) + raiseOSError(osLastError(), dir) else: when useWinUnicode: wrapUnary(res, createDirectoryW, dir) @@ -992,7 +992,7 @@ proc rawCreateDir(dir: string): bool = elif getLastError() == 183'i32: result = false else: - raiseOSError(osLastError()) + raiseOSError(osLastError(), dir) proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect, ReadDirEffect].} = @@ -1005,7 +1005,7 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", if result: # path already exists - need to check that it is indeed a directory if not existsDir(dir): - raise newException(IOError, "Failed to create the directory") + raise newException(IOError, "Failed to create '" & dir & "'") proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect, ReadDirEffect].} = From 13df8075767c1559f71e7485a23dab3d337ffad1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 23 Jul 2018 17:26:49 -0700 Subject: [PATCH 15/57] fix issue #8349 FileSystemCaseSensitive should be false on OSX (#8411) --- lib/pure/ospaths.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 4ae5afd6cd..a7ebd9d158 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -147,7 +147,7 @@ else: # UNIX-like operating system DirSep* = '/' AltSep* = DirSep PathSep* = ':' - FileSystemCaseSensitive* = true + FileSystemCaseSensitive* = when defined(macosx): false else: true ExeExt* = "" ScriptExt* = "" DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so" @@ -410,6 +410,11 @@ proc cmpPaths*(pathA, pathB: string): int {. ## | 0 iff pathA == pathB ## | < 0 iff pathA < pathB ## | > 0 iff pathA > pathB + runnableExamples: + when defined(macosx): + doAssert cmpPaths("foo", "Foo") == 0 + elif defined(posix): + doAssert cmpPaths("foo", "Foo") > 0 if FileSystemCaseSensitive: result = cmp(pathA, pathB) else: From d5c9255cab9c111f8fa930e4cd42d6671877bd9d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 24 Jul 2018 08:25:08 +0200 Subject: [PATCH 16/57] Allow use of typedesc as type converters (#8409) Fixes #8403 --- compiler/semtypes.nim | 10 ++++++++-- tests/generics/t8403.nim | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/generics/t8403.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 05a9d9882a..1205cc406c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1577,8 +1577,14 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = prev of nkSym: let s = getGenSym(c, n.sym) - if s.kind == skType and s.typ != nil: - var t = s.typ + if s.kind == skType and s.typ != nil or + s.kind == skParam and s.typ.kind == tyTypeDesc: + var t = + if s.kind == skType: + s.typ + else: + internalAssert c.config, s.typ.base.kind != tyNone and prev == nil + s.typ.base let alias = maybeAliasType(c, t, prev) if alias != nil: result = alias diff --git a/tests/generics/t8403.nim b/tests/generics/t8403.nim new file mode 100644 index 0000000000..47ce9c4523 --- /dev/null +++ b/tests/generics/t8403.nim @@ -0,0 +1,11 @@ +discard """ + output: "6.0" +""" + +proc sum*[T](s: seq[T], R: typedesc): R = + var sum: R = 0 + for x in s: + sum += R(x) + return sum + +echo @[1, 2, 3].sum(float) From 34f398d010faa906004fb5802b095a213f083b9c Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Tue, 24 Jul 2018 23:24:14 +0300 Subject: [PATCH 17/57] Allow async stdin --- lib/pure/ioselects/ioselectors_epoll.nim | 29 ++++++++++------------- lib/pure/ioselects/ioselectors_kqueue.nim | 27 ++++++++++----------- lib/pure/ioselects/ioselectors_poll.nim | 25 +++++++++---------- lib/pure/ioselects/ioselectors_select.nim | 9 ++++--- lib/pure/selectors.nim | 9 +++++++ 5 files changed, 51 insertions(+), 48 deletions(-) diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 36145abc72..8b3f14f34e 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -92,6 +92,9 @@ proc newSelector*[T](): Selector[T] = result.maxFD = maxFD result.fds = newSeq[SelectorKey[T]](maxFD) + for i in 0 ..< maxFD: + result.fds[i].ident = InvalidIdent + proc close*[T](s: Selector[T]) = let res = posix.close(s.epollFD) when hasThreadSupport: @@ -100,12 +103,6 @@ proc close*[T](s: Selector[T]) = if res != 0: raiseIOSelectorsError(osLastError()) -template clearKey[T](key: ptr SelectorKey[T]) = - var empty: T - key.ident = 0 - key.events = {} - key.data = empty - proc newSelectEvent*(): SelectEvent = let fdci = eventfd(0, 0) if fdci == -1: @@ -135,7 +132,7 @@ proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event], data: T) = let fdi = int(fd) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0, "Descriptor $# already registered" % $fdi) + doAssert(s.fds[fdi].ident == InvalidIdent, "Descriptor $# already registered" % $fdi) s.setKey(fdi, events, 0, data) if events != {}: var epv = EpollEvent(events: EPOLLRDHUP) @@ -152,7 +149,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event] let fdi = int(fd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, + doAssert(pkey.ident != InvalidIdent, "Descriptor $# is not registered in the selector!" % $fdi) doAssert(pkey.events * maskEvents == {}) if pkey.events != events: @@ -180,7 +177,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) = let fdi = int(fd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, + doAssert(pkey.ident != InvalidIdent, "Descriptor $# is not registered in the selector!" % $fdi) if pkey.events != {}: when not defined(android): @@ -243,7 +240,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = let fdi = int(ev.efd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, "Event is not registered in the queue!") + doAssert(pkey.ident != InvalidIdent, "Event is not registered in the queue!") doAssert(Event.User in pkey.events) var epv = EpollEvent() if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0: @@ -262,7 +259,7 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool, setNonBlocking(fdi.cint) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) var events = {Event.Timer} var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP) @@ -307,7 +304,7 @@ when not defined(android): setNonBlocking(fdi.cint) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP) epv.data.u64 = fdi.uint @@ -334,7 +331,7 @@ when not defined(android): setNonBlocking(fdi.cint) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP) epv.data.u64 = fdi.uint @@ -347,7 +344,7 @@ when not defined(android): proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) = let fdi = int(ev.efd) - doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!") + doAssert(s.fds[fdi].ident == InvalidIdent, "Event is already registered in the queue!") s.setKey(fdi, {Event.User}, 0, data) var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP) epv.data.u64 = ev.efd.uint @@ -381,7 +378,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, let fdi = int(resTable[i].data.u64) let pevents = resTable[i].events var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0) + doAssert(pkey.ident != InvalidIdent) var rkey = ReadyKey(fd: fdi, events: {}) if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0: @@ -482,7 +479,7 @@ template isEmpty*[T](s: Selector[T]): bool = (s.count == 0) proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = - return s.fds[fd.int].ident != 0 + return s.fds[fd.int].ident != InvalidIdent proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 10e23c072b..58a3810429 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -114,6 +114,9 @@ proc newSelector*[T](): Selector[T] = result.fds = newSeq[SelectorKey[T]](maxFD) result.changes = newSeqOfCap[KEvent](MAX_KQUEUE_EVENTS) + for i in 0 ..< MAX_KQUEUE_EVENTS: + result.fds[i].ident = InvalidIdent + result.sock = usock result.kqFD = kqFD result.maxFD = maxFD.int @@ -128,12 +131,6 @@ proc close*[T](s: Selector[T]) = if res1 != 0 or res2 != 0: raiseIOSelectorsError(osLastError()) -template clearKey[T](key: ptr SelectorKey[T]) = - var empty: T - key.ident = 0 - key.events = {} - key.data = empty - proc newSelectEvent*(): SelectEvent = var fds: array[2, cint] if posix.pipe(fds) != 0: @@ -221,7 +218,7 @@ proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event], data: T) = let fdi = int(fd) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) s.setKey(fdi, events, 0, data) if events != {}: @@ -242,7 +239,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, let fdi = int(fd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, + doAssert(pkey.ident != InvalidIdent, "Descriptor $# is not registered in the queue!" % $fdi) doAssert(pkey.events * maskEvents == {}) @@ -269,7 +266,7 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool, data: T): int {.discardable.} = let fdi = getUnique(s) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) let events = if oneshot: {Event.Timer, Event.Oneshot} else: {Event.Timer} let flags: cushort = if oneshot: EV_ONESHOT or EV_ADD else: EV_ADD @@ -291,7 +288,7 @@ proc registerSignal*[T](s: Selector[T], signal: int, data: T): int {.discardable.} = let fdi = getUnique(s) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) s.setKey(fdi, {Event.Signal}, signal, data) var nmask, omask: Sigset @@ -315,7 +312,7 @@ proc registerProcess*[T](s: Selector[T], pid: int, data: T): int {.discardable.} = let fdi = getUnique(s) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) var kflags: cushort = EV_ONESHOT or EV_ADD setKey(s, fdi, {Event.Process, Event.Oneshot}, pid, data) @@ -331,7 +328,7 @@ proc registerProcess*[T](s: Selector[T], pid: int, proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) = let fdi = ev.rfd.int - doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!") + doAssert(s.fds[fdi].ident == InvalidIdent, "Event is already registered in the queue!") setKey(s, fdi, {Event.User}, 0, data) modifyKQueue(s, fdi.uint, EVFILT_READ, EV_ADD, 0, 0, nil) @@ -374,7 +371,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) = let fdi = int(fd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, + doAssert(pkey.ident != InvalidIdent, "Descriptor [" & $fdi & "] is not registered in the queue!") if pkey.events != {}: @@ -434,7 +431,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = let fdi = int(ev.rfd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, "Event is not registered in the queue!") + doAssert(pkey.ident != InvalidIdent, "Event is not registered in the queue!") doAssert(Event.User in pkey.events) modifyKQueue(s, uint(fdi), EVFILT_READ, EV_DELETE, 0, 0, nil) when not declared(CACHE_EVENTS): @@ -593,7 +590,7 @@ template isEmpty*[T](s: Selector[T]): bool = (s.count == 0) proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = - return s.fds[fd.int].ident != 0 + return s.fds[fd.int].ident != InvalidIdent proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index c36750c8d2..9d708b0c1d 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -70,6 +70,9 @@ proc newSelector*[T](): Selector[T] = result.fds = newSeq[SelectorKey[T]](maxFD) result.pollfds = newSeq[TPollFd](maxFD) + for i in 0 ..< maxFD: + result.fds[i].ident = InvalidIdent + proc close*[T](s: Selector[T]) = when hasThreadSupport: deinitLock(s.lock) @@ -77,12 +80,6 @@ proc close*[T](s: Selector[T]) = deallocSharedArray(s.pollfds) deallocShared(cast[pointer](s)) -template clearKey[T](key: ptr SelectorKey[T]) = - var empty: T - key.ident = 0 - key.events = {} - key.data = empty - template pollAdd[T](s: Selector[T], sock: cint, events: set[Event]) = withPollLock(s): var pollev: cshort = 0 @@ -135,7 +132,7 @@ proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event], data: T) = var fdi = int(fd) s.checkFd(fdi) - doAssert(s.fds[fdi].ident == 0) + doAssert(s.fds[fdi].ident == InvalidIdent) setKey(s, fdi, events, 0, data) if events != {}: s.pollAdd(fdi.cint, events) @@ -146,7 +143,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, let fdi = int(fd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, + doAssert(pkey.ident != InvalidIdent, "Descriptor [" & $fdi & "] is not registered in the queue!") doAssert(pkey.events * maskEvents == {}) @@ -162,7 +159,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) = var fdi = int(ev.rfd) - doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!") + doAssert(s.fds[fdi].ident == InvalidIdent, "Event is already registered in the queue!") var events = {Event.User} setKey(s, fdi, events, 0, data) events.incl(Event.Read) @@ -172,9 +169,9 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) = let fdi = int(fd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, + doAssert(pkey.ident != InvalidIdent, "Descriptor [" & $fdi & "] is not registered in the queue!") - pkey.ident = 0 + pkey.ident = InvalidIdent pkey.events = {} s.pollRemove(fdi.cint) @@ -182,9 +179,9 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) = let fdi = int(ev.rfd) s.checkFd(fdi) var pkey = addr(s.fds[fdi]) - doAssert(pkey.ident != 0, "Event is not registered in the queue!") + doAssert(pkey.ident != InvalidIdent, "Event is not registered in the queue!") doAssert(Event.User in pkey.events) - pkey.ident = 0 + pkey.ident = InvalidIdent pkey.events = {} s.pollRemove(fdi.cint) @@ -270,7 +267,7 @@ template isEmpty*[T](s: Selector[T]): bool = (s.count == 0) proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = - return s.fds[fd.int].ident != 0 + return s.fds[fd.int].ident != InvalidIdent proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T = let fdi = int(fd) diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index 7ed2503070..cd6a72b446 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -99,6 +99,9 @@ proc newSelector*[T](): Selector[T] = result = Selector[T]() result.fds = newSeq[SelectorKey[T]](FD_SETSIZE) + for i in 0 ..< FD_SETSIZE: + result.fds[i].ident = InvalidIdent + IOFD_ZERO(addr result.rSet) IOFD_ZERO(addr result.wSet) IOFD_ZERO(addr result.eSet) @@ -195,7 +198,7 @@ proc setSelectKey[T](s: Selector[T], fd: SocketHandle, events: set[Event], var i = 0 let fdi = int(fd) while i < FD_SETSIZE: - if s.fds[i].ident == 0: + if s.fds[i].ident == InvalidIdent: var pkey = addr(s.fds[i]) pkey.ident = fdi pkey.events = events @@ -221,7 +224,7 @@ proc delKey[T](s: Selector[T], fd: SocketHandle) = var i = 0 while i < FD_SETSIZE: if s.fds[i].ident == fd.int: - s.fds[i].ident = 0 + s.fds[i].ident = InvalidIdent s.fds[i].events = {} s.fds[i].data = empty break @@ -335,7 +338,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, var k = 0 while (i < FD_SETSIZE) and (k < count): - if s.fds[i].ident != 0: + if s.fds[i].ident != InvalidIdent: var flag = false var pkey = addr(s.fds[i]) var rkey = ReadyKey(fd: int(pkey.ident), events: {}) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 935250e085..e4c2b21244 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -261,6 +261,9 @@ else: param: int data: T + const + InvalidIdent = -1 + proc raiseIOSelectorsError[T](message: T) = var msg = "" when T is string: @@ -302,6 +305,12 @@ else: if posix.sigprocmask(SIG_UNBLOCK, newmask, oldmask) == -1: raiseIOSelectorsError(osLastError()) + template clearKey[T](key: ptr SelectorKey[T]) = + var empty: T + key.ident = InvalidIdent + key.events = {} + key.data = empty + when defined(linux): include ioselects/ioselectors_epoll elif bsdPlatform: From 3838e2a8d7dc4a0167d50231016177b4b9501fff Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 28 Jul 2018 18:13:37 +0200 Subject: [PATCH 18/57] Fix links to manual.html in the system module documentation (#8467) The HTML anchor IDs were changed, which made those links not link to the appropriate section anymore. --- lib/system.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index f96f97dd66..dae760ef82 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1465,8 +1465,8 @@ when defined(nimdoc): ## ## Note that this is a *runtime* call and using ``quit`` inside a macro won't ## have any compile time effect. If you need to stop the compiler inside a - ## macro, use the `error `_ or `fatal - ## `_ pragmas. + ## macro, use the `error `_ or `fatal + ## `_ pragmas. elif defined(genode): include genode/env @@ -2429,7 +2429,7 @@ iterator fieldPairs*[T: tuple|object](x: T): RootObj {. ## When you iterate over objects with different field types you have to use ## the compile time ``when`` instead of a runtime ``if`` to select the code ## you want to run for each type. To perform the comparison use the `is - ## operator `_. Example: + ## operator `_. Example: ## ## .. code-block:: Nim ## From d07d148597f999de873867dcafc39411b49d009d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 29 Jul 2018 22:39:58 -0700 Subject: [PATCH 19/57] fixes #7492 excessiveStackTrace:on shows non-absolute file in stacktrace (#8469) --- lib/system.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index dae760ef82..0cfa39e196 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3771,7 +3771,9 @@ template doAssert*(cond: bool, msg = "") = ## same as `assert` but is always turned on and not affected by the ## ``--assertions`` command line switch. bind instantiationInfo - {.line: instantiationInfo().}: + # NOTE: `true` is correct here; --excessiveStackTrace:on will control whether + # or not to output full paths. + {.line: instantiationInfo(-1, true).}: if not cond: raiseAssert(astToStr(cond) & ' ' & instantiationInfo(-1, false).fileName & '(' & From 1fc3a68205697c2ad33b2f0e1cfcb526e73b0677 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 30 Jul 2018 08:34:15 +0200 Subject: [PATCH 20/57] Access implicit `result` trough envP in closures (#8471) Reuse the existing machinery, most of the changes are only needed to handle the `result = result` node in nkReturnStmt produced by the closure iterator transform. Fixes #338 --- compiler/lambdalifting.nim | 14 +++++++++++++- tests/iter/t338.nim | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/iter/t338.nim diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 0a48011504..d8c0461ce8 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -222,7 +222,7 @@ proc interestingIterVar(s: PSym): bool {.inline.} = # XXX optimization: Only lift the variable if it lives across # yield/return boundaries! This can potentially speed up # closure iterators quite a bit. - result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags + result = s.kind in {skResult, skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags template isIterator*(owner: PSym): bool = owner.kind == skIterator and owner.typ.callConv == ccClosure @@ -458,6 +458,10 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = of nkLambdaKinds, nkIteratorDef, nkFuncDef: if n.typ != nil: detectCapturedVars(n[namePos], owner, c) + of nkReturnStmt: + if n[0].kind in {nkAsgn, nkFastAsgn}: + detectCapturedVars(n[0].sons[1], owner, c) + else: assert n[0].kind == nkEmpty else: for i in 0.. Date: Mon, 30 Jul 2018 09:54:52 +0300 Subject: [PATCH 21/57] Fixed typo introduced in #8428 that leads to InvalidIdent assertion failure (#8464) --- lib/pure/ioselects/ioselectors_kqueue.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 58a3810429..142e988d0c 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -114,7 +114,7 @@ proc newSelector*[T](): Selector[T] = result.fds = newSeq[SelectorKey[T]](maxFD) result.changes = newSeqOfCap[KEvent](MAX_KQUEUE_EVENTS) - for i in 0 ..< MAX_KQUEUE_EVENTS: + for i in 0 ..< maxFD: result.fds[i].ident = InvalidIdent result.sock = usock From 97ea18746beac4d08fd839a7d9de1407bcf9dc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 30 Jul 2018 09:07:11 +0200 Subject: [PATCH 22/57] Fix path resolution of submodules in the std namespace (#8453) --- compiler/modulepaths.nim | 20 ++++---------------- compiler/options.nim | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 87c7f35412..ef0831ad6f 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -45,13 +45,6 @@ when false: if best.len > 0 and fileExists(res): result = res -const stdlibDirs = [ - "pure", "core", "arch", - "pure/collections", - "pure/concurrency", "impure", - "wrappers", "wrappers/linenoise", - "windows", "posix", "js"] - when false: proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string = template attempt(a) = @@ -120,7 +113,9 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = case n.kind of nkStrLit, nkRStrLit, nkTripleStrLit: try: - result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir) + result = + pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir) + .replace(" ") except ValueError: localError(conf, n.info, "invalid path: " & n.strVal) result = n.strVal @@ -147,16 +142,9 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = result = "" else: let modname = getModuleName(conf, n[2]) - if $n1 == "std": - template attempt(a) = - let x = addFileExt(a, "nim") - if fileExists(x): return x - for candidate in stdlibDirs: - attempt(conf.libpath / candidate / modname) - # hacky way to implement 'x / y /../ z': result = getModuleName(conf, n1) - result.add renderTree(n0, {renderNoComments}) + result.add renderTree(n0, {renderNoComments}).replace(" ") result.add modname of nkPrefix: when false: diff --git a/compiler/options.nim b/compiler/options.nim index c6e5c5b9f0..7cca403212 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -556,13 +556,28 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): string {.pro result = rawFindFile2(conf, f.toLowerAscii) patchModule(conf) +const stdlibDirs = [ + "pure", "core", "arch", + "pure/collections", + "pure/concurrency", "impure", + "wrappers", "wrappers/linenoise", + "windows", "posix", "js"] + proc findModule*(conf: ConfigRef; modulename, currentModule: string): string = # returns path to module const pkgPrefix = "pkg/" - let m = addFileExt(modulename, NimExt) + const stdPrefix = "std/" + var m = addFileExt(modulename, NimExt) if m.startsWith(pkgPrefix): result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true) else: + if m.startsWith(stdPrefix): + let stripped = m.substr(stdPrefix.len) + for candidate in stdlibDirs: + let path = (conf.libpath / candidate / stripped) + if fileExists(path): + m = path + break let currentPath = currentModule.splitFile.dir result = currentPath / m if not existsFile(result): From 2569c749097135d5c9a8e2153bed6f0bad3a6684 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 30 Jul 2018 01:17:41 -0700 Subject: [PATCH 23/57] docs: document that --flag is same as flag in cfg config files (#8430) --- doc/mytest.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/mytest.cfg b/doc/mytest.cfg index be1118c46f..1385e493d4 100644 --- a/doc/mytest.cfg +++ b/doc/mytest.cfg @@ -3,6 +3,7 @@ [Common] cc=gcc # '=' and ':' are the same +--foo="bar" # '--cc' and 'cc' are the same, 'bar' and '"bar"' are the same --verbose [Windows] From a4c244aef08b25542323fed1da9d7dfa8f230cf1 Mon Sep 17 00:00:00 2001 From: Quelklef Date: Mon, 30 Jul 2018 04:19:11 -0400 Subject: [PATCH 24/57] Add checks for random.rand() (#8431) --- lib/pure/random.nim | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 01ea9c845f..e565fccf89 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -110,7 +110,7 @@ proc random*[T](a: openArray[T]): T {.deprecated.} = ## Use ``rand`` instead. result = a[random(a.low..a.len)] -proc rand*(r: var Rand; max: int): int {.benign.} = +proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random number in the range 0..max. The sequence of ## random number is always the same, unless `randomize` is called ## which initializes the random number generator with a "random" @@ -128,7 +128,7 @@ proc rand*(max: int): int {.benign.} = ## number, i.e. a tickcount. rand(state, max) -proc rand*(r: var Rand; max: float): float {.benign.} = +proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = ## Returns a random number in the range 0..max. The sequence of ## random number is always the same, unless `randomize` is called ## which initializes the random number generator with a "random" @@ -218,4 +218,17 @@ when isMainModule: doAssert rand(0) == 0 doAssert rand("a") == 'a' + when compileOption("rangeChecks"): + try: + discard rand(-1) + doAssert false + except RangeError: + discard + + try: + discard rand(-1.0) + doAssert false + except RangeError: + discard + main() From 06571f5495fd48ee1b98873d92c3506ff2b9d6b0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 30 Jul 2018 01:36:23 -0700 Subject: [PATCH 25/57] fixes #8323 : avoid polluting git status after `nim doc foo` (#8415) --- compiler/sem.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 0d484d2767..2c3fab5a58 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -608,16 +608,18 @@ proc myProcess(context: PPassContext, n: PNode): PNode = rod.storeNode(c.graph, c.module, result) proc testExamples(c: PContext) = + let outputDir = c.config.getNimcacheDir / "runnableExamples" + createDir(outputDir) let inp = toFullPath(c.config, c.module.info) - let outp = inp.changeFileExt"" & "_examples.nim" + let outp = outputDir / extractFilename(inp.changeFileExt"" & "_examples.nim") let nimcache = outp.changeFileExt"" & "_nimcache" - renderModule(c.runnableExamples, inp, outp) + renderModule(c.runnableExamples, inp, outp, conf = c.config) let backend = if isDefined(c.config, "js"): "js" elif isDefined(c.config, "cpp"): "cpp" elif isDefined(c.config, "objc"): "objc" else: "c" if os.execShellCmd(os.getAppFilename() & " " & backend & " --nimcache:" & nimcache & " -r " & outp) != 0: - quit "[Examples] failed" + quit "[Examples] failed: see " & outp else: removeFile(outp) removeFile(outp.changeFileExt(ExeExt)) From becb6743f8197f53897cef1b2fda97f1784f961c Mon Sep 17 00:00:00 2001 From: skilchen Date: Mon, 30 Jul 2018 10:41:59 +0200 Subject: [PATCH 26/57] fixes #8434 (incomplete info in errmsg about 'required type') (#8441) --- compiler/types.nim | 10 ++++++++-- tests/errmsgs/t8434.nim | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/errmsgs/t8434.nim diff --git a/compiler/types.nim b/compiler/types.nim index 4180d34a75..23fbc9f1b2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -496,9 +496,15 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = add(result, typeToString(t.sons[i])) result.add "]" of tyAnd: - result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) + for i, son in t.sons: + result.add(typeToString(son)) + if i < t.sons.high: + result.add(" and ") of tyOr: - result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1]) + for i, son in t.sons: + result.add(typeToString(son)) + if i < t.sons.high: + result.add(" or ") of tyNot: result = "not " & typeToString(t.sons[0]) of tyExpr: diff --git a/tests/errmsgs/t8434.nim b/tests/errmsgs/t8434.nim new file mode 100644 index 0000000000..60fe2e2df1 --- /dev/null +++ b/tests/errmsgs/t8434.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "type mismatch: got " + nimout: '''but expected one of: +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 + but expression 'byte(1)' is of type: byte + +expression: fun0(byte(1), 0) +''' +""" + +proc fun0[T1:int|float|object|array|seq](a1:T1, a2:int)=discard + +fun0(byte(1), 0) From c3a9ac4d352a84fb47da0a4d5fc6f963b651bbec Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 30 Jul 2018 10:51:14 +0200 Subject: [PATCH 27/57] Try conversion to static[T] in generic instantation (#8443) Fixes #8439 --- compiler/semcall.nim | 10 +++++++++- tests/generics/t8439.nim | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/generics/t8439.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 67fe992321..aa5394a719 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -505,7 +505,15 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = for i in 1..sonsLen(n)-1: let formal = s.ast.sons[genericParamsPos].sons[i-1].typ - let arg = n[i].typ + var arg = n[i].typ + # try transforming the argument into a static one before feeding it into + # typeRel + if formal.kind == tyStatic and arg.kind != tyStatic: + let evaluated = c.semTryConstExpr(c, n[i]) + if evaluated != nil: + arg = newTypeS(tyStatic, c) + arg.sons = @[evaluated.typ] + arg.n = evaluated let tm = typeRel(m, formal, arg) if tm in {isNone, isConvertible}: return nil var newInst = generateInstance(c, s, m.bindings, n.info) diff --git a/tests/generics/t8439.nim b/tests/generics/t8439.nim new file mode 100644 index 0000000000..69bd7cfcb8 --- /dev/null +++ b/tests/generics/t8439.nim @@ -0,0 +1,10 @@ +discard """ + output: "1" +""" + +type + Cardinal = enum + north, east, south, west + +proc foo[cardinal: static[Cardinal]](): int = 1 +echo(foo[north]()) From 404f0d64afa5cb18c54c52d261609f60a00cdb46 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 30 Jul 2018 11:00:06 +0200 Subject: [PATCH 28/57] Add sizeof for arrays of integral types (#8445) --- compiler/semfold.nim | 2 +- tests/misc/tsizeof.nim | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 2f495bc7f1..d2abfac13f 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -609,7 +609,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = if computeSize(g.config, a.typ) < 0: localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely") result = nil - elif skipTypes(a.typ, typedescInst+{tyRange}).kind in + elif skipTypes(a.typ, typedescInst+{tyRange, tyArray}).kind in IntegralTypes+NilableTypes+{tySet}: #{tyArray,tyObject,tyTuple}: result = newIntNodeT(getSize(g.config, a.typ), n, g) diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 4afd48472a..0597535f96 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -1,5 +1,7 @@ -# Test the sizeof proc - +discard """ + file: "tsize.nim" + output: "40 3 12 32" +""" type TMyRecord {.final.} = object x, y: int @@ -7,4 +9,20 @@ type r: float s: string + TMyEnum = enum + tmOne, tmTwo, tmThree, tmFour + + TMyArray1 = array[3, uint8] + TMyArray2 = array[1..3, int32] + TMyArray3 = array[TMyEnum, float64] + +const + mysize1 = sizeof(TMyArray1) + mysize2 = sizeof(TMyArray2) + mysize3 = sizeof(TMyArray3) + write(stdout, sizeof(TMyRecord)) +echo ' ', mysize1, ' ', mysize2, ' ',mysize3 + + + From 6b40114f21e681b0110a74add7a61b16df4d2fb8 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Mon, 30 Jul 2018 12:10:51 +0300 Subject: [PATCH 29/57] Added c_abort to ansi_c (#8449) --- lib/system/ansi_c.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 4d21f87479..f593d4c998 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -27,6 +27,9 @@ proc c_strcmp(a, b: cstring): cint {. importc: "strcmp", header: "", noSideEffect.} proc c_strlen(a: cstring): csize {. importc: "strlen", header: "", noSideEffect.} +proc c_abort() {. + importc: "abort", header: "", noSideEffect.} + when defined(linux) and defined(amd64): type From 2e6d073be11b6d365739f1cccefbcfe3055d8da7 Mon Sep 17 00:00:00 2001 From: andri lim Date: Mon, 30 Jul 2018 17:04:49 +0700 Subject: [PATCH 30/57] fixes #8468, stdlib.encodings.convert not crash anymore on windows (#8470) --- lib/pure/encodings.nim | 8 ++++---- tests/stdlib/tencoding.nim | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/stdlib/tencoding.nim diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index c67cd7579c..3c1cf73f4a 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -332,7 +332,7 @@ when defined(windows): if s.len == 0: return "" # educated guess of capacity: var cap = s.len + s.len shr 2 - result = newStringOfCap(cap*2) + result = newString(cap*2) # convert to utf-16 LE var m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32, lpMultiByteStr = cstring(s), @@ -347,7 +347,7 @@ when defined(windows): lpWideCharStr = nil, cchWideChar = cint(0)) # and do the conversion properly: - result = newStringOfCap(cap*2) + result = newString(cap*2) m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32, lpMultiByteStr = cstring(s), cbMultiByte = cint(s.len), @@ -364,7 +364,7 @@ when defined(windows): if int(c.dest) == 1200: return # otherwise the fun starts again: cap = s.len + s.len shr 2 - var res = newStringOfCap(cap) + var res = newString(cap) m = wideCharToMultiByte( codePage = c.dest, dwFlags = 0'i32, @@ -382,7 +382,7 @@ when defined(windows): lpMultiByteStr = nil, cbMultiByte = cint(0)) # and do the conversion properly: - res = newStringOfCap(cap) + res = newString(cap) m = wideCharToMultiByte( codePage = c.dest, dwFlags = 0'i32, diff --git a/tests/stdlib/tencoding.nim b/tests/stdlib/tencoding.nim new file mode 100644 index 0000000000..d6ff7ab329 --- /dev/null +++ b/tests/stdlib/tencoding.nim @@ -0,0 +1,21 @@ +discard """ + output: '''OK''' +""" + +#bug #8468 + +import encodings, strutils + +when defined(windows): + var utf16to8 = open(destEncoding = "utf-16", srcEncoding = "utf-8") + var s = "some string" + var c = utf16to8.convert(s) + + var z = newStringOfCap(s.len * 2) + for x in s: + z.add x + z.add chr(0) + + doAssert z == c + +echo "OK" From e86a0ecd8676c028b60673133d93f53dc12c1b4c Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Jul 2018 11:57:50 +0200 Subject: [PATCH 31/57] asyncdispatch: remove outdated documentation about its limitations --- bin/nim-gdb | 0 tests/untestable/gdb/gdb_pretty_printer_test_run.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bin/nim-gdb mode change 100755 => 100644 tests/untestable/gdb/gdb_pretty_printer_test_run.sh diff --git a/bin/nim-gdb b/bin/nim-gdb old mode 100755 new mode 100644 diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_run.sh b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh old mode 100755 new mode 100644 From d270245a0171c4532c9121e7e27dfd422f123840 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Jul 2018 12:04:00 +0200 Subject: [PATCH 32/57] disable --app:gui for non Windows targets; fixes #2576 --- compiler/extccomp.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 34628e363a..f4ef930707 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -668,8 +668,10 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe") if noAbsolutePaths(conf): result = linkerExe else: result = joinPath(conf.cCompilerpath, linkerExe) - let buildgui = if optGenGuiApp in conf.globalOptions: CC[conf.cCompiler].buildGui - else: "" + let buildgui = if optGenGuiApp in conf.globalOptions and conf.target.targetOS == osWindows: + CC[conf.cCompiler].buildGui + else: + "" var exefile, builddll: string if optGenDynLib in conf.globalOptions: exefile = platform.OS[conf.target.targetOS].dllFrmt % splitFile(projectfile).name From f2ddd995393bc485880d3e56b277bad6448ad0c3 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Jul 2018 12:07:01 +0200 Subject: [PATCH 33/57] fixes #8425 --- compiler/semtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 1205cc406c..24896e9444 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -136,7 +136,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType = addSonSkipIntLit(result, base) if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base) if base.kind != tyGenericParam: - if not isOrdinalType(base): + if not isOrdinalType(base, allowEnumWithHoles = true): localError(c.config, n.info, errOrdinalTypeExpected) elif lengthOrd(c.config, base) > MaxSetElements: localError(c.config, n.info, errSetTooBig) From c0f78ec0121c2578759e1b7cff561b75a58e3f97 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 30 Jul 2018 05:02:18 -0700 Subject: [PATCH 34/57] fixes #8419 fixes #8420 ; workaround #6071 workaround nim-lang/website#98 (#8423) add --git.devel option to override doc generated "edit" links; add --nimCompiler option to nimweb --- compiler/docgen.nim | 9 ++-- compiler/options.nim | 4 +- config/nimdoc.cfg | 4 +- koch.nim | 1 + tools/nimweb.nim | 104 +++++++++++++++++++++++++------------------ 5 files changed, 70 insertions(+), 52 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 75b599ae91..63883af5cb 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -517,12 +517,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = path = path[cwd.len+1 .. ^1].replace('\\', '/') let gitUrl = getConfigVar(d.conf, "git.url") if gitUrl.len > 0: - var commit = getConfigVar(d.conf, "git.commit") - if commit.len == 0: commit = "master" + let commit = getConfigVar(d.conf, "git.commit", "master") + let develBranch = getConfigVar(d.conf, "git.devel", "devel") dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, - ["path", "line", "url", "commit"], [rope path, - rope($n.info.line), rope gitUrl, - rope commit])]) + ["path", "line", "url", "commit", "devel"], [rope path, + rope($n.info.line), rope gitUrl, rope commit, rope develBranch])]) add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"), ["name", "header", "desc", "itemID", "header_plain", "itemSym", diff --git a/compiler/options.nim b/compiler/options.nim index 7cca403212..fcbb98fe63 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -406,8 +406,8 @@ proc mainCommandArg*(conf: ConfigRef): string = proc existsConfigVar*(conf: ConfigRef; key: string): bool = result = hasKey(conf.configVars, key) -proc getConfigVar*(conf: ConfigRef; key: string): string = - result = conf.configVars.getOrDefault key +proc getConfigVar*(conf: ConfigRef; key: string, default = ""): string = + result = conf.configVars.getOrDefault(key, default) proc setConfigVar*(conf: ConfigRef; key, val: string) = conf.configVars[key] = val diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 6b6ec2d833..96e91283a4 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -55,6 +55,8 @@ doc.item.toc = """ # HTML rendered for doc.item's seeSrc variable. Note that this will render to # the empty string if you don't pass anything through --docSeeSrcURL. Available # substitutaion variables here are: +# * $commit: branch/commit to use in source link. +# * $devel: branch to use in edit link. # * $path: relative path to the file being processed. # * $line: line of the item in the original source file. # * $url: whatever you did pass through the --docSeeSrcUrl switch (which also @@ -62,7 +64,7 @@ doc.item.toc = """ doc.item.seesrc = """  Source -Edit +Edit """ doc.toc = """ diff --git a/koch.nim b/koch.nim index 9411a95de3..133c7e32bd 100644 --- a/koch.nim +++ b/koch.nim @@ -50,6 +50,7 @@ Boot options: Commands for core developers: web [options] generates the website and the full documentation + (see `nimweb.nim` for cmd line options) website [options] generates only the website csource -d:release builds the C sources for installation pdf builds the PDF documentation diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 6e1d9d3596..e74b081eaf 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -13,16 +13,18 @@ import from xmltree import escape -const gitRepo = "https://github.com/nim-lang/Nim" - type TKeyValPair = tuple[key, id, val: string] TConfigData = object of RootObj tabs, links: seq[TKeyValPair] doc, srcdoc, srcdoc2, webdoc, pdf: seq[string] - authors, projectName, projectTitle, logo, infile, outdir, ticker: string + authors, projectName, projectTitle, logo, infile, ticker: string vars: StringTableRef + nimCompiler: string nimArgs: string + gitURL: string + docHTMLOutput: string + webUploadOutput: string quotations: Table[string, tuple[quote, author: string]] numProcessors: int # Set by parallelBuild:n, only works for values > 0. gaId: string # google analytics ID, nil means analytics are disabled @@ -51,8 +53,10 @@ proc initConfigData(c: var TConfigData) = c.webdoc = @[] c.pdf = @[] c.infile = "" - c.outdir = "" c.nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot " + c.gitURL = "https://github.com/nim-lang/Nim" + c.docHTMLOutput = "doc/html" + c.webUploadOutput = "web/upload" c.authors = "" c.projectTitle = "" c.projectName = "" @@ -79,14 +83,19 @@ const Usage: nimweb [options] ini-file[.ini] [compile_options] Options: - -o, --output:dir set the output directory (default: same as ini-file) - --var:name=value set the value of a variable -h, --help shows this help -v, --version shows the version + -o, --output overrides output directory instead of default + web/upload and doc/html + --nimCompiler overrides nim compiler; default = bin/nim + --var:name=value set the value of a variable --website only build the website, not the full documentation --pdf build the PDF version of the documentation --json2 build JSON of the documentation --onlyDocs build only the documentation + --git.url override base url in generated doc links + --git.commit override commit/branch in generated doc links 'source' + --git.devel override devel branch in generated doc links 'edit' Compile_options: will be passed to the Nim compiler """ @@ -145,7 +154,11 @@ proc parseCmdLine(c: var TConfigData) = of "version", "v": stdout.write(version & "\n") quit(0) - of "o", "output": c.outdir = val + of "output", "o": + c.webUploadOutput = val + c.docHTMLOutput = val / "docs" + of "nimcompiler": + c.nimCompiler = val of "parallelbuild": try: let num = parseInt(val) @@ -163,8 +176,14 @@ proc parseCmdLine(c: var TConfigData) = of "googleanalytics": c.gaId = val c.nimArgs.add("--doc.googleAnalytics:" & val & " ") + of "git.url": + c.gitURL = val + of "git.commit": + c.nimArgs.add("--git.commit:" & val & " ") + of "git.devel": + c.nimArgs.add("--git.devel:" & val & " ") else: - echo("Invalid argument $1" % [key]) + echo("Invalid argument '$1'" % [key]) quit(usage) of cmdEnd: break if c.infile.len == 0: quit(usage) @@ -244,15 +263,14 @@ proc parseIniFile(c: var TConfigData) = close(p) if c.projectName.len == 0: c.projectName = changeFileExt(extractFilename(c.infile), "") - if c.outdir.len == 0: - c.outdir = splitFile(c.infile).dir # ------------------- main ---------------------------------------------------- proc exe(f: string): string = return addFileExt(f, ExeExt) -proc findNim(): string = +proc findNim(c: TConfigData): string = + if c.nimCompiler.len > 0: return c.nimCompiler var nim = "nim".exe result = "bin" / nim if existsFile(result): return @@ -289,9 +307,9 @@ proc buildDocSamples(c: var TConfigData, destPath: string) = ## it didn't make much sense to integrate into the existing generic ## documentation builders. const src = "doc"/"docgen_sample.nim" - exec(findNim() & " doc $# -o:$# $#" % + exec(findNim(c) & " doc $# -o:$# $#" % [c.nimArgs, destPath / "docgen_sample.html", src]) - exec(findNim() & " doc2 $# -o:$# $#" % + exec(findNim(c) & " doc2 $# -o:$# $#" % [c.nimArgs, destPath / "docgen_sample2.html", src]) proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/') @@ -302,23 +320,23 @@ proc buildDoc(c: var TConfigData, destPath: string) = commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2)) i = 0 for d in items(c.doc): - commands[i] = findNim() & " rst2html $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, gitRepo, + commands[i] = findNim(c) & " rst2html $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(c.srcdoc): - commands[i] = findNim() & " doc0 $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, gitRepo, + commands[i] = findNim(c) & " doc0 $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(c.srcdoc2): - commands[i] = findNim() & " doc2 $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, gitRepo, + commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc mexec(commands, c.numProcessors) - exec(findNim() & " buildIndex -o:$1/theindex.html $1" % [destPath]) + exec(findNim(c) & " buildIndex -o:$1/theindex.html $1" % [destPath]) proc buildPdfDoc(c: var TConfigData, destPath: string) = createDir(destPath) @@ -327,7 +345,7 @@ proc buildPdfDoc(c: var TConfigData, destPath: string) = else: const pdflatexcmd = "pdflatex -interaction=nonstopmode " for d in items(c.pdf): - exec(findNim() & " rst2tex $# $#" % [c.nimArgs, d]) + exec(findNim(c) & " rst2tex $# $#" % [c.nimArgs, d]) # call LaTeX twice to get cross references right: exec(pdflatexcmd & changeFileExt(d, "tex")) exec(pdflatexcmd & changeFileExt(d, "tex")) @@ -347,8 +365,8 @@ proc buildAddDoc(c: var TConfigData, destPath: string) = # build additional documentation (without the index): var commands = newSeq[string](c.webdoc.len) for i, doc in pairs(c.webdoc): - commands[i] = findNim() & " doc2 $# --git.url:$# -o:$# $#" % - [c.nimArgs, gitRepo, + commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# $#" % + [c.nimArgs, c.gitURL, destPath / changeFileExt(splitFile(doc).name, "html"), doc] mexec(commands, c.numProcessors) @@ -431,9 +449,9 @@ proc buildNewsRss(c: var TConfigData, destPath: string) = generateRss(destFilename, parseNewsTitles(srcFilename)) -proc buildJS(destPath: string) = - exec(findNim() & " js -d:release --out:$1 web/nimblepkglist.nim" % - [destPath / "nimblepkglist.js"]) +proc buildJS(c: TConfigData) = + exec(findNim(c) & " js -d:release --out:$1 web/nimblepkglist.nim" % + [c.webUploadOutput / "nimblepkglist.js"]) proc readSponsors(sponsorsFile: string): seq[Sponsor] = result = @[] @@ -464,7 +482,7 @@ const cmdRst2Html = " rst2html --compileonly $1 -o:web/$2.temp web/$2.rst" proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") = - exec(findNim() & cmdRst2Html % [c.nimArgs, file]) + exec(findNim(c) & cmdRst2Html % [c.nimArgs, file]) var temp = "web" / changeFileExt(file, "temp") var content: string try: @@ -472,7 +490,7 @@ proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") = except IOError: quit("[Error] cannot open: " & temp) var f: File - var outfile = "web/upload/$#.html" % file + var outfile = c.webUploadOutput / "$#.html" % file if not existsDir(outfile.splitFile.dir): createDir(outfile.splitFile.dir) if open(f, outfile, fmWrite): @@ -502,27 +520,25 @@ proc buildWebsite(c: var TConfigData) = let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: "" if '.' in file: continue buildPage(c, file, if file == "question": "FAQ" else: file, rss) - copyDir("web/assets", "web/upload/assets") - buildNewsRss(c, "web/upload") - buildSponsors(c, "web/upload") - buildNews(c, "web/news", "web/upload/news") + copyDir("web/assets", c.webUploadOutput / "assets") + buildNewsRss(c, c.webUploadOutput) + buildSponsors(c, c.webUploadOutput) + buildNews(c, "web/news", c.webUploadOutput / "news") + +proc onlyDocs(c: var TConfigData) = + createDir(c.docHTMLOutput) + buildDocSamples(c, c.docHTMLOutput) + buildDoc(c, c.docHTMLOutput) proc main(c: var TConfigData) = buildWebsite(c) - buildJS("web/upload") - const docup = "web/upload/" & NimVersion + buildJS(c) + let docup = c.webUploadOutput / NimVersion createDir(docup) buildAddDoc(c, docup) buildDocSamples(c, docup) buildDoc(c, docup) - createDir("doc/html") - buildDocSamples(c, "doc/html") - buildDoc(c, "doc/html") - -proc onlyDocs(c: var TConfigData) = - createDir("doc/html") - buildDocSamples(c, "doc/html") - buildDoc(c, "doc/html") + onlyDocs(c) proc json2(c: var TConfigData) = const destPath = "web/json2" @@ -530,8 +546,8 @@ proc json2(c: var TConfigData) = var i = 0 for d in items(c.srcdoc2): createDir(destPath / splitFile(d).dir) - commands[i] = findNim() & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, gitRepo, + commands[i] = findNim(c) & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitURL, destPath / changeFileExt(d, "json"), d] i.inc From e11d52a4e8e3b7522a26721f604692691a5fbeca Mon Sep 17 00:00:00 2001 From: Euan T Date: Mon, 30 Jul 2018 13:39:32 +0100 Subject: [PATCH 35/57] Update example code for UDP sockets --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 5d2efebee6..771e7de10d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -41,7 +41,7 @@ ## immediately. ## ## .. code-block:: Nim -## var socket = newSocket() +## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) ## socket.sendTo("192.168.0.1", Port(27960), "status\n") ## ## Creating a server From 5491f1f53b4011785b41b30897b73538d564fd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 30 Jul 2018 15:24:16 +0200 Subject: [PATCH 36/57] Deprecate the dot style for import paths (#8474) --- changelog.md | 2 ++ compiler/modulepaths.nim | 1 + doc/manual.rst | 23 ++++++++++++----------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 43b351ef11..e0027d5044 100644 --- a/changelog.md +++ b/changelog.md @@ -22,6 +22,8 @@ become an error in the future. - The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to bring the language in line with the standard library (e.g. ``parseOct``). +- The dot style for import paths (e.g ``import path.to.module`` instead of + ``import path/to/module``) has been deprecated. #### Breaking changes in the standard library diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index ef0831ad6f..e5cbf3a2c7 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -155,6 +155,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = # hacky way to implement 'x / y /../ z': result = renderTree(n, {renderNoComments}).replace(" ") of nkDotExpr: + localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths") result = renderTree(n, {renderNoComments}).replace(".", "/") of nkImportAs: result = getModuleName(conf, n.sons[0]) diff --git a/doc/manual.rst b/doc/manual.rst index 7298b02a30..abdc4ce695 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6229,10 +6229,10 @@ imported: :test: "nim c $1" :status: 1 - import strutils except `%`, toUpper + import strutils except `%`, toUpperAscii # doesn't work then: - echo "$1" % "abc".toUpper + echo "$1" % "abc".toUpperAscii It is not checked that the ``except`` list is really exported from the module. @@ -6261,24 +6261,24 @@ A module alias can be introduced via the ``as`` keyword: echo su.format("$1", "lalelu") -The original module name is then not accessible. The -notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` -can be used to refer to a module in subdirectories: +The original module name is then not accessible. The notations +``path/to/module`` or ``"path/to/module"`` can be used to refer to a module +in subdirectories: .. code-block:: nim - import lib.pure.strutils, lib/pure/os, "lib/pure/times" + import lib/pure/os, "lib/pure/times" -Note that the module name is still ``strutils`` and not ``lib.pure.strutils`` +Note that the module name is still ``strutils`` and not ``lib/pure/strutils`` and so one **cannot** do: .. code-block:: nim - import lib.pure.strutils - echo lib.pure.strutils + import lib/pure/strutils + echo lib/pure/strutils.toUpperAscii("abc") Likewise the following does not make sense as the name is ``strutils`` already: .. code-block:: nim - import lib.pure.strutils as strutils + import lib/pure/strutils as strutils Collective imports from a directory @@ -6297,7 +6297,8 @@ name is not a valid Nim identifier it needs to be a string literal: Pseudo import/include paths ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A directory can also be a so called "pseudo directory". +A directory can also be a so called "pseudo directory". They can be used to +avoid ambiguity when there are multiple modules with the same path. There are two pseudo directories: From 931273cc6be25a4d2bc79e8a0eff8781c1f4855e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 30 Jul 2018 22:28:24 +0200 Subject: [PATCH 37/57] Fix ref bug in vmgen (#8424) --- compiler/vm.nim | 9 +---- compiler/vmgen.nim | 88 ++++++++++++++++++++++------------------------ tests/vm/tref.nim | 7 +++- 3 files changed, 50 insertions(+), 54 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 373a64e39d..d7e1b5da30 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -616,19 +616,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let rc = instr.regC case regs[ra].kind of rkNodeAddr: - # XXX: Workaround for vmgen bug: let n = regs[rc].regToNode - if (nfIsRef in regs[ra].nodeAddr[].flags or - regs[ra].nodeAddr[].kind == nkNilLit) and nfIsRef notin n.flags: - if regs[ra].nodeAddr[].kind == nkNilLit: - stackTrace(c, tos, pc, errNilAccess) - regs[ra].nodeAddr[][] = n[] - regs[ra].nodeAddr[].flags.incl nfIsRef # `var object` parameters are sent as rkNodeAddr. When they are mutated # vmgen generates opcWrDeref, which means that we must dereference # twice. # TODO: This should likely be handled differently in vmgen. - elif (nfIsRef notin regs[ra].nodeAddr[].flags and + if (nfIsRef notin regs[ra].nodeAddr[].flags and nfIsRef notin n.flags): regs[ra].nodeAddr[][] = n[] else: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index d2243376c1..31e04a6c07 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -37,7 +37,9 @@ when hasFFI: import evalffi type - TGenFlag = enum gfAddrOf, gfFieldAccess + TGenFlag = enum + gfNode # Affects how variables are loaded - always loads as rkNode + gfNodeAddr # Affects how variables are loaded - always loads as rkNodeAddr TGenFlags = set[TGenFlag] proc debugInfo(c: PCtx; info: TLineInfo): string = @@ -563,7 +565,7 @@ proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister = proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = case le.kind of nkBracketExpr: - let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess}) + let dest = c.genx(le.sons[0], {gfNode}) let idx = c.genIndex(le.sons[1], le.sons[0].typ) c.gABC(le, opcWrArr, dest, idx, value) c.freeTemp(dest) @@ -571,17 +573,17 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] - let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess}) + let dest = c.genx(left.sons[0], {gfNode}) let idx = genField(c, left.sons[1]) c.gABC(left, opcWrObj, dest, idx, value) c.freeTemp(dest) of nkDerefExpr, nkHiddenDeref: - let dest = c.genx(le.sons[0], {gfAddrOf}) + let dest = c.genx(le.sons[0], {gfNode}) c.gABC(le, opcWrDeref, dest, 0, value) c.freeTemp(dest) of nkSym: if le.sym.isGlobal: - let dest = c.genx(le, {gfAddrOf}) + let dest = c.genx(le, {gfNodeAddr}) c.gABC(le, opcWrDeref, dest, 0, value) c.freeTemp(dest) else: @@ -1252,41 +1254,21 @@ proc canElimAddr(n: PNode): PNode = # addr ( deref ( x )) --> x result = n.sons[0].sons[0] -proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; - flags: TGenFlags) = - # a nop for certain types - let isAddr = opc in {opcAddrNode, opcAddrReg} - if isAddr and (let m = canElimAddr(n); m != nil): +proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) = + if (let m = canElimAddr(n); m != nil): gen(c, m, dest, flags) return - let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess} - else: {gfAddrOf} - let newflags = if isAddr: flags+af else: flags - # consider: - # proc foo(f: var ref int) = - # f = new(int) - # proc blah() = - # var x: ref int - # foo x - # - # The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for - # nkAddr we must not use 'unneededIndirection', but for deref we use it. - if not isAddr and unneededIndirection(n.sons[0]): - gen(c, n.sons[0], dest, newflags) - if gfAddrOf notin flags and fitsRegister(n.typ): - c.gABC(n, opcNodeToReg, dest, dest) - elif isAddr and isGlobal(n.sons[0]): + let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfNode} + else: {gfNodeAddr} + let newflags = flags-{gfNode, gfNodeAddr}+af + + if isGlobal(n.sons[0]): gen(c, n.sons[0], dest, flags+af) else: let tmp = c.genx(n.sons[0], newflags) if dest < 0: dest = c.getTemp(n.typ) - if not isAddr: - gABC(c, n, opc, dest, tmp) - assert n.typ != nil - if gfAddrOf notin flags and fitsRegister(n.typ): - c.gABC(n, opcNodeToReg, dest, dest) - elif c.prc.slots[tmp].kind >= slotTempUnknown: + if c.prc.slots[tmp].kind >= slotTempUnknown: gABC(c, n, opcAddrNode, dest, tmp) # hack ahead; in order to fix bug #1781 we mark the temporary as # permanent, so that it's not used for anything else: @@ -1297,6 +1279,19 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; gABC(c, n, opcAddrReg, dest, tmp) c.freeTemp(tmp) +proc genDeref(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) = + if unneededIndirection(n.sons[0]): + gen(c, n.sons[0], dest, flags) + if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ): + c.gABC(n, opcNodeToReg, dest, dest) + else: + let tmp = c.genx(n.sons[0], flags) + if dest < 0: dest = c.getTemp(n.typ) + gABC(c, n, opcLdDeref, dest, tmp) + assert n.typ != nil + if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ): + c.gABC(n, opcNodeToReg, dest, dest) + proc whichAsgnOpc(n: PNode): TOpcode = case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64: @@ -1382,7 +1377,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode; proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = case le.kind of nkBracketExpr: - let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess}) + let dest = c.genx(le.sons[0], {gfNode}) let idx = c.genIndex(le.sons[1], le.sons[0].typ) let tmp = c.genx(ri) if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in { @@ -1394,13 +1389,13 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = of nkDotExpr, nkCheckedFieldExpr: # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] - let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess}) + let dest = c.genx(left.sons[0], {gfNode}) let idx = genField(c, left.sons[1]) let tmp = c.genx(ri) c.preventFalseAlias(left, opcWrObj, dest, idx, tmp) c.freeTemp(tmp) of nkDerefExpr, nkHiddenDeref: - let dest = c.genx(le.sons[0], {gfAddrOf}) + let dest = c.genx(le.sons[0], {gfNode}) let tmp = c.genx(ri) c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp) c.freeTemp(tmp) @@ -1409,7 +1404,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = checkCanEval(c, le) if s.isGlobal: withTemp(tmp, le.typ): - c.gen(le, tmp, {gfAddrOf}) + c.gen(le, tmp, {gfNodeAddr}) let val = c.genx(ri) c.preventFalseAlias(le, opcWrDeref, tmp, 0, val) c.freeTemp(val) @@ -1427,7 +1422,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = else: gen(c, ri, dest) else: - let dest = c.genx(le, {gfAddrOf}) + let dest = c.genx(le, {gfNodeAddr}) genAsgn(c, dest, ri, requiresCopy) proc genTypeLit(c: PCtx; t: PType; dest: var TDest) = @@ -1463,6 +1458,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = c.freeTemp(tmp) proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = + # gfNodeAddr and gfNode are mutually exclusive + assert card(flags * {gfNodeAddr, gfNode}) < 2 let s = n.sym if s.isGlobal: if sfCompileTime in s.flags or c.mode == emRepl: @@ -1474,13 +1471,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = else: genGlobalInit(c, n, s) if dest < 0: dest = c.getTemp(n.typ) assert s.typ != nil - if gfAddrOf notin flags and fitsRegister(s.typ): + if gfNodeAddr in flags: + c.gABx(n, opcLdGlobalAddr, dest, s.position) + elif fitsRegister(s.typ) and gfNode notin flags: var cc = c.getTemp(n.typ) c.gABx(n, opcLdGlobal, cc, s.position) c.gABC(n, opcNodeToReg, dest, cc) c.freeTemp(cc) - elif {gfAddrOf, gfFieldAccess} * flags == {gfAddrOf}: - c.gABx(n, opcLdGlobalAddr, dest, s.position) else: c.gABx(n, opcLdGlobal, dest, s.position) else: @@ -1498,7 +1495,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = cannotEval(c, n) template needsRegLoad(): untyped = - gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent})) + {gfNode, gfNodeAddr} * flags == {} and + fitsRegister(n.typ.skipTypes({tyVar, tyLent})) proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; flags: TGenFlags) = @@ -1634,7 +1632,7 @@ proc genVarSection(c: PCtx; n: PNode) = c.globals.add(sa) s.position = c.globals.len if a.sons[2].kind != nkEmpty: - let tmp = c.genx(a.sons[0], {gfAddrOf}) + let tmp = c.genx(a.sons[0], {gfNodeAddr}) let val = c.genx(a.sons[2]) c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val) c.freeTemp(val) @@ -1839,8 +1837,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of nkDotExpr: genObjAccess(c, n, dest, flags) of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags) of nkBracketExpr: genArrAccess(c, n, dest, flags) - of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags) - of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags) + of nkDerefExpr, nkHiddenDeref: genDeref(c, n, dest, flags) + of nkAddr, nkHiddenAddr: genAddr(c, n, dest, flags) of nkIfStmt, nkIfExpr: genIf(c, n, dest) of nkWhenStmt: # This is "when nimvm" node. Chose the first branch. diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim index 27b7bf3132..f5cd23da5d 100644 --- a/tests/vm/tref.nim +++ b/tests/vm/tref.nim @@ -54,4 +54,9 @@ static: new(s) var ss = s s[] = 1 - doAssert ss[] == 1 \ No newline at end of file + doAssert ss[] == 1 + +static: # bug #8402 + type R = ref object + var empty: R + let otherEmpty = empty \ No newline at end of file From 53566f716501fe906b8b2aa4ce050be5d6eb0364 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Jul 2018 23:27:01 +0200 Subject: [PATCH 38/57] fixes #7833; still to-do: fix setLen --- compiler/ccgexprs.nim | 17 ++++++++++------- compiler/condsyms.nim | 1 + lib/system/gc.nim | 5 ++++- tests/gc/growobjcrash.nim | 4 ++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2e9fb2cc2a..96f1724221 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1092,17 +1092,20 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; let seqAppendPattern = if not p.module.compileToCpp: - "$1 = ($2) #incrSeqV3(&($1)->Sup, $3);$n" + "($2) #incrSeqV3(&($1)->Sup, $3)" else: - "$1 = ($2) #incrSeqV3($1, $3);$n" - var a, b, dest, tmpL: TLoc + "($2) #incrSeqV3($1, $3)" + var a, b, dest, tmpL, call: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) let seqType = skipTypes(e.sons[1].typ, {tyVar}) - lineCg(p, cpsStmts, seqAppendPattern, [ - rdLoc(a), - getTypeDesc(p.module, e.sons[1].typ), - genTypeInfo(p.module, seqType, e.info)]) + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), + getTypeDesc(p.module, e.sons[1].typ), + genTypeInfo(p.module, seqType, e.info)]) + # emit the write barrier if required, but we can always move here, so + # use 'genRefAssign' for the seq. + genRefAssign(p, a, call, {}) #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) initLoc(dest, locExpr, e.sons[2], OnHeap) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 8b2d36722c..9dfe694426 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -72,3 +72,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNoZeroTerminator") defineSymbol("nimNotNil") defineSymbol("nimVmExportFixed") + defineSymbol("nimIncrSeqV3") diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 425963f3f9..74ac68eea5 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -548,7 +548,10 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = gcTrace(res, csAllocated) track("growObj old", ol, 0) track("growObj new", res, newsize) - when reallyDealloc: + when defined(nimIncrSeqV3): + # since we steal the old seq's contents, we set the old length to 0. + cast[PGenericSeq](old).len = 0 + elif reallyDealloc: sysAssert(allocInv(gch.region), "growObj before dealloc") if ol.refcount shr rcShift <=% 1: # free immediately to save space: diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index a16468c7e8..b8ff4f908a 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -14,11 +14,11 @@ proc handleRequest(query: string): StringTableRef = let x = foo result = x() -const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000 +const Limit = 5*1024*1024 proc main = var counter = 0 - for i in 0 .. 100_000: + for i in 0 .. 10_000_000: for k, v in handleRequest("nick=Elina2&type=activate"): inc counter if counter mod 100 == 0: From f5a19520276bc66abb39abf10e1efc730b0db820 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 31 Jul 2018 10:25:02 +0200 Subject: [PATCH 39/57] make tests green again --- tests/closure/tclosure3.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/closure/tclosure3.nim b/tests/closure/tclosure3.nim index d5ffb5ab20..4de07bdb5b 100644 --- a/tests/closure/tclosure3.nim +++ b/tests/closure/tclosure3.nim @@ -15,7 +15,7 @@ proc main = let val = s[i]() if val != $(i*i): echo "bug ", val - if getOccupiedMem() > 3000_000: quit("still a leak!") + if getOccupiedMem() > 5000_000: quit("still a leak!") echo "success" main() From 39192fa568a14f19eff20922b00219082de998f2 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 31 Jul 2018 15:46:00 +0200 Subject: [PATCH 40/57] also fixes setLen and string concats; refs #7833 --- compiler/ccgexprs.nim | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 96f1724221..4fa7dc2ca9 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1063,7 +1063,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = # appendChar(s, 'z'); # } var - a, dest: TLoc + a, dest, call: TLoc appends, lens: Rope assert(d.k == locNone) var L = 0 @@ -1082,8 +1082,9 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) add(appends, ropecg(p.module, "#appendString($1, $2);$n", rdLoc(dest), rdLoc(a))) - linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", - rdLoc(dest), lens, rope(L)) + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)]) + genAssignment(p, dest, call, {}) add(p.s(cpsStmts), appends) gcUsage(p.config, e) @@ -1512,7 +1513,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "genArrayLen()") proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = - var a, b: TLoc + var a, b, call: TLoc assert(d.k == locNone) var x = e.sons[1] if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] @@ -1520,17 +1521,27 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[2], b) let t = skipTypes(e.sons[1].typ, {tyVar}) let setLenPattern = if not p.module.compileToCpp: - "$1 = ($3) #setLengthSeqV2(&($1)->Sup, $4, $2);$n" + "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)" else: - "$1 = ($3) #setLengthSeqV2($1, $4, $2);$n" + "($3) #setLengthSeqV2($1, $4, $2)" - lineCg(p, cpsStmts, setLenPattern, [ + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) + genAssignment(p, a, call, {}) gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = - binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n") + var a, b, call: TLoc + if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, "#setLengthStr($1, $2)", [ + rdLoc(a), rdLoc(b)]) + genAssignment(p, a, call, {}) gcUsage(p.config, e) proc genSwap(p: BProc, e: PNode, d: var TLoc) = From 51db60afed5bf793ea88fce405a40f4bf480bb46 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 31 Jul 2018 22:52:34 +0200 Subject: [PATCH 41/57] change formating to avoid a compiler warning --- compiler/docgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 75b599ae91..2c0208b36e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -259,7 +259,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe of tkSpaces, tkInvalid: add(result, literal) of tkCurlyDotLe: - dispA(d.conf, result, "" & # This span is required for the JS to work properly + dispA(d.conf, result, "" & # This span is required for the JS to work properly """{...} From 818d9be31117a90c0707fdbb9e471abca2abac40 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 31 Jul 2018 14:02:04 -0700 Subject: [PATCH 42/57] `lineInfoObj` (and `check`, `expect`) now return absolute paths (#8466) --- changelog.md | 3 ++- compiler/vm.nim | 2 +- lib/core/macros.nim | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index e0027d5044..3dfe63f3bd 100644 --- a/changelog.md +++ b/changelog.md @@ -25,7 +25,6 @@ - The dot style for import paths (e.g ``import path.to.module`` instead of ``import path/to/module``) has been deprecated. - #### Breaking changes in the standard library - ``re.split`` for empty regular expressions now yields every character in @@ -61,6 +60,8 @@ 1-based coordinates on POSIX for correct behaviour; the Windows behaviour was always correct). +- ``lineInfoObj`` now returns absolute path instead of project path. + It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc. #### Breaking changes in the compiler diff --git a/compiler/vm.nim b/compiler/vm.nim index d7e1b5da30..f8b1cee731 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1409,7 +1409,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNGetFile: decodeB(rkNode) let n = regs[rb].node - regs[ra].node = newStrNode(nkStrLit, toFilename(c.config, n.info)) + regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info)) regs[ra].node.info = n.info regs[ra].node.typ = n.typ of opcNGetLine: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 345c53b088..17178a6342 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -425,6 +425,7 @@ proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.} proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} = + ## returns ``LineInfo`` of ``n``, using absolute path for ``filename`` result.filename = n.getFile result.line = n.getLine result.column = n.getColumn From 9e37e3e5e85a7be33b8d1a22c64540415282bafb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Aug 2018 00:22:51 -0700 Subject: [PATCH 43/57] add hintCC to optionally disable printing 'CC: filename' (#8479) --- compiler/extccomp.nim | 5 +++-- compiler/lineinfos.nim | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f4ef930707..a90442369e 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -645,7 +645,7 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var if optCompileOnly notin conf.globalOptions: add(cmds, compileCmd) let (_, name, _) = splitFile(it.cname) - add(prettyCmds, "CC: " & name) + add(prettyCmds, if hintCC in conf.notes: "CC: " & name else: "") if optGenScript in conf.globalOptions: add(script, compileCmd) add(script, "\n") @@ -773,7 +773,8 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) = var prettyCmds: TStringSeq = @[] let prettyCb = proc (idx: int) = when declared(echo): - echo prettyCmds[idx] + let cmd = prettyCmds[idx] + if cmd != "": echo cmd compileCFile(conf, conf.toCompile, script, cmds, prettyCmds) if optCompileOnly notin conf.globalOptions: execCmdsInParallel(conf, cmds, prettyCb) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index b8678e6ba7..261dcb44e2 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -37,7 +37,7 @@ type warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, warnInconsistentSpacing, warnUser, - hintSuccess, hintSuccessX, + hintSuccess, hintSuccessX, hintCC, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, @@ -94,6 +94,7 @@ const warnUser: "$1", hintSuccess: "operation successful", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", + hintCC: "CC: \'$1\'", # unused hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", hintConvToBaseNotNeeded: "conversion to base object is not needed", @@ -136,7 +137,7 @@ const "Spacing", "User"] HintsToStr* = [ - "Success", "SuccessX", "LineTooLong", + "Success", "SuccessX", "CC", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency", From 8f4c5a8955594b4f2dc31f9629af9ad3d4780c2c Mon Sep 17 00:00:00 2001 From: jcosborn Date: Wed, 1 Aug 2018 03:57:35 -0500 Subject: [PATCH 44/57] fixed #7894 (#8496) make system tests run properly --- lib/system/alloc.nim | 3 ++- tests/system/t7894.nim | 18 ++++++++++++++++ tests/system/talloc.nim | 43 ++++++++++++++++++++------------------ tests/system/talloc2.nim | 3 +++ tests/system/tdeepcopy.nim | 6 +++--- tests/system/tio.nim | 5 ++++- tests/system/tparams.nim | 15 +++++++------ 7 files changed, 62 insertions(+), 31 deletions(-) create mode 100644 tests/system/t7894.nim diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index ca2d76225b..ffb7aaf86c 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -436,8 +436,9 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = a.nextChunkSize = PageSize*4 else: a.nextChunkSize = min(roundup(usedMem shr 2, PageSize), a.nextChunkSize * 2) - var size = size + a.nextChunkSize = min(a.nextChunkSize, MaxBigChunkSize) + var size = size if size > a.nextChunkSize: result = cast[PBigChunk](osAllocPages(size)) else: diff --git a/tests/system/t7894.nim b/tests/system/t7894.nim new file mode 100644 index 0000000000..2808e50200 --- /dev/null +++ b/tests/system/t7894.nim @@ -0,0 +1,18 @@ +discard """ +""" + +import os + +const size = 250000000 +var saved = newSeq[seq[int8]]() + +for i in 0..22: + # one of these is 0.25GB. + #echo i + var x = newSeq[int8](size) + sleep(10) + saved.add(x) + +for x in saved: + #echo x.len + doAssert x.len == size diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim index 18396041d0..bf2cd97a86 100644 --- a/tests/system/talloc.nim +++ b/tests/system/talloc.nim @@ -1,54 +1,57 @@ +discard """ +""" + var x: ptr int x = cast[ptr int](alloc(7)) -assert x != nil +doAssert x != nil x = cast[ptr int](x.realloc(2)) -assert x != nil +doAssert x != nil x.dealloc() x = createU(int, 3) -assert x != nil +doAssert x != nil x.dealloc() x = create(int, 4) -assert cast[ptr array[4, int]](x)[0] == 0 -assert cast[ptr array[4, int]](x)[1] == 0 -assert cast[ptr array[4, int]](x)[2] == 0 -assert cast[ptr array[4, int]](x)[3] == 0 +doAssert cast[ptr array[4, int]](x)[0] == 0 +doAssert cast[ptr array[4, int]](x)[1] == 0 +doAssert cast[ptr array[4, int]](x)[2] == 0 +doAssert cast[ptr array[4, int]](x)[3] == 0 x = x.resize(4) -assert x != nil +doAssert x != nil x.dealloc() x = cast[ptr int](allocShared(100)) -assert x != nil +doAssert x != nil deallocShared(x) x = createSharedU(int, 3) -assert x != nil +doAssert x != nil x.deallocShared() x = createShared(int, 3) -assert x != nil -assert cast[ptr array[3, int]](x)[0] == 0 -assert cast[ptr array[3, int]](x)[1] == 0 -assert cast[ptr array[3, int]](x)[2] == 0 +doAssert x != nil +doAssert cast[ptr array[3, int]](x)[0] == 0 +doAssert cast[ptr array[3, int]](x)[1] == 0 +doAssert cast[ptr array[3, int]](x)[2] == 0 -assert x != nil +doAssert x != nil x = cast[ptr int](x.resizeShared(2)) -assert x != nil +doAssert x != nil x.deallocShared() x = create(int, 10) -assert x != nil +doAssert x != nil x = x.resize(12) -assert x != nil +doAssert x != nil x.dealloc() x = createShared(int, 1) -assert x != nil +doAssert x != nil x = x.resizeShared(1) -assert x != nil +doAssert x != nil x.deallocShared() x = cast[ptr int](alloc0(125 shl 23)) diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim index c8cab78a1c..0757c07246 100644 --- a/tests/system/talloc2.nim +++ b/tests/system/talloc2.nim @@ -1,3 +1,6 @@ +discard """ +""" + const nmax = 2*1024*1024*1024 diff --git a/tests/system/tdeepcopy.nim b/tests/system/tdeepcopy.nim index f7a6e87fa4..383d2e8d13 100644 --- a/tests/system/tdeepcopy.nim +++ b/tests/system/tdeepcopy.nim @@ -65,7 +65,7 @@ proc main() = for val in table.values(): if myObj2.isNil: myObj2 = val - assert(myObj == myObj2) # passes + doAssert(myObj == myObj2) # passes var tableCopy: ListTableRef[int, SomeObj] deepCopy(tableCopy, table) @@ -80,7 +80,7 @@ proc main() = #echo cast[int](myObjCopy) #echo cast[int](myObjCopy2) - assert(myObjCopy == myObjCopy2) # fails + doAssert(myObjCopy == myObjCopy2) # fails type @@ -88,7 +88,7 @@ type counter, max: int data: array[0..99, (pointer, pointer)] -assert(sizeof(PtrTable) == 2*sizeof(int)+sizeof(pointer)*2*100) +doAssert(sizeof(PtrTable) == 2*sizeof(int)+sizeof(pointer)*2*100) main() echo "ok" diff --git a/tests/system/tio.nim b/tests/system/tio.nim index 3d4df806bd..7e9e189500 100644 --- a/tests/system/tio.nim +++ b/tests/system/tio.nim @@ -1,3 +1,6 @@ +discard """ +""" + import unittest, osproc, streams, os, strformat const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." @@ -36,7 +39,7 @@ proc verifyFileSize(sz: int64) = discard execProcess(&"dd if=/dev/zero of={fn} bs=1000000 count={size_in_mb}") doAssert os.getFileSize(fn) == sz # Verify OS filesize by string - + var f = open(fn) doAssert f.getFileSize() == sz # Verify file handle filesize f.close() diff --git a/tests/system/tparams.nim b/tests/system/tparams.nim index 1358212f2f..dd5511b8f7 100644 --- a/tests/system/tparams.nim +++ b/tests/system/tparams.nim @@ -1,3 +1,6 @@ +discard """ +""" + import os import osproc import parseopt2 @@ -7,12 +10,12 @@ let argv = commandLineParams() if argv == @[]: # this won't work with spaces - assert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0 + doAssert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0 else: let f = toSeq(getopt()) echo f.repr - assert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == "" - assert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a" - assert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d" - assert f[3].kind == cmdLongOption and f[3].key == "ab" and f[3].val == "" - assert f[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == "" + doAssert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == "" + doAssert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a" + doAssert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d" + doAssert f[3].kind == cmdLongOption and f[3].key == "ab" and f[3].val == "" + doAssert f[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == "" From 674bd7bfad100a07e051e0a310bcf0a64c355a79 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 1 Aug 2018 16:19:29 -0700 Subject: [PATCH 45/57] fix wrong arch defined(osx) (#8492) --- tests/stdlib/tos.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 6ccc29bf65..10f439dfad 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -145,7 +145,7 @@ else: echo getLastModificationTime("a") == tm removeFile("a") -when defined(Linux) or defined(osx): +when defined(posix): block normalizedPath: block relative: From 78c0ac54070e860ec0ed8ac0b58658f7ad52227a Mon Sep 17 00:00:00 2001 From: andri lim Date: Thu, 2 Aug 2018 17:56:44 +0700 Subject: [PATCH 46/57] fixes #7827, bindSym enhancement (#8499) * bindSym power up, working prototype * update bindSym doc * add bindSym test * fix some typo * fix bindSym doc * get rid of specialops field from vm * add experimental: dynamicBindSym --- changelog.md | 5 +++ compiler/options.nim | 3 +- compiler/semmagic.nim | 67 ++++++++++++++++++++++++++++++++++++++- compiler/semtypes.nim | 1 + compiler/vm.nim | 18 ++++++++++- compiler/vmdef.nim | 5 +-- compiler/vmgen.nim | 45 ++++++++++++++++++++++---- lib/core/macros.nim | 10 +++++- tests/macros/tbindsym.nim | 42 ++++++++++++++++++++++++ 9 files changed, 183 insertions(+), 13 deletions(-) diff --git a/changelog.md b/changelog.md index 3dfe63f3bd..045286ef9c 100644 --- a/changelog.md +++ b/changelog.md @@ -196,4 +196,9 @@ - Nintendo Switch was added as a new platform target. See [the compiler user guide](https://nim-lang.org/docs/nimc.html) for more info. +- macros.bindSym now capable to accepts not only literal string or string constant expression. + bindSym enhancement make it also can accepts computed string or ident node inside macros / + compile time functions / static blocks. Only in templates / regular code it retains it's old behavior. + This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch + ### Bugfixes diff --git a/compiler/options.nim b/compiler/options.nim index fcbb98fe63..598adf27d2 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -116,7 +116,8 @@ type callOperator, parallel, destructor, - notnil + notnil, + dynamicBindSym SymbolFilesOption* = enum disabledSf, writeOnlySf, readOnlySf, v2Sf diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index b5875c67a9..8bfa5545e6 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -207,6 +207,67 @@ proc semBindSym(c: PContext, n: PNode): PNode = else: errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal) +proc opBindSym(c: PContext, scope: PScope, n: PNode, isMixin: int, info: PNode): PNode = + if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit, nkIdent}: + localError(c.config, info.info, errStringOrIdentNodeExpected) + return errorNode(c, n) + + if isMixin < 0 or isMixin > high(TSymChoiceRule).int: + localError(c.config, info.info, errConstExprExpected) + return errorNode(c, n) + + let id = if n.kind == nkIdent: n + else: newIdentNode(getIdent(c.cache, n.strVal), info.info) + + let tmpScope = c.currentScope + c.currentScope = scope + let s = qualifiedLookUp(c, id, {checkUndeclared}) + if s != nil: + # we need to mark all symbols: + result = symChoice(c, id, s, TSymChoiceRule(isMixin)) + else: + errorUndeclaredIdentifier(c, info.info, if n.kind == nkIdent: n.ident.s + else: n.strVal) + c.currentScope = tmpScope + +proc semDynamicBindSym(c: PContext, n: PNode): PNode = + # inside regular code, bindSym resolves to the sym-choice + # nodes (see tinspectsymbol) + if not (c.inStaticContext > 0 or getCurrOwner(c).isCompileTimeProc): + return semBindSym(c, n) + + if c.graph.vm.isNil: + setupGlobalCtx(c.module, c.graph) + + let + vm = PCtx c.graph.vm + # cache the current scope to + # prevent it lost into oblivion + scope = c.currentScope + + # cannot use this + # vm.config.features.incl dynamicBindSym + + proc bindSymWrapper(a: VmArgs) = + # capture PContext and currentScope + # param description: + # 0. ident, a string literal / computed string / or ident node + # 1. bindSym rule + # 2. info node + a.setResult opBindSym(c, scope, a.getNode(0), a.getInt(1).int, a.getNode(2)) + + let + # altough we use VM callback here, it is not + # executed like 'normal' VM callback + idx = vm.registerCallback("bindSymImpl", bindSymWrapper) + # dummy node to carry idx information to VM + idxNode = newIntTypeNode(nkIntLit, idx, c.graph.getSysType(TLineInfo(), tyInt)) + + result = copyNode(n) + for x in n: result.add x + result.add n # info node + result.add idxNode + proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode proc semOf(c: PContext, n: PNode): PNode = @@ -270,7 +331,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mOf: result = semOf(c, n) of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic) of mShallowCopy: result = semShallowCopy(c, n, flags) - of mNBindSym: result = semBindSym(c, n) + of mNBindSym: + if dynamicBindSym notin c.features: + result = semBindSym(c, n) + else: + result = semDynamicBindSym(c, n) of mProcCall: result = n result.typ = n[1].typ diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 24896e9444..972c8c709b 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -11,6 +11,7 @@ # included from sem.nim const + errStringOrIdentNodeExpected = "string or ident node expected" errStringLiteralExpected = "string literal expected" errIntLiteralExpected = "integer literal expected" errWrongNumberOfVariables = "wrong number of variables" diff --git a/compiler/vm.nim b/compiler/vm.nim index f8b1cee731..a6ec4788b3 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1222,9 +1222,25 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = node.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and node.sons[1].kind == nkNilLit)) of opcNBindSym: + # cannot use this simple check + # if dynamicBindSym notin c.config.features: + + # bindSym with static input decodeBx(rkNode) regs[ra].node = copyTree(c.constants.sons[rbx]) regs[ra].node.flags.incl nfIsRef + of opcNDynBindSym: + # experimental bindSym + let + rb = instr.regB + rc = instr.regC + idx = int(regs[rb+rc-1].intVal) + callback = c.callbacks[idx].value + args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs), + currentException: c.currentExceptionB, + currentLineInfo: c.debug[pc]) + callback(args) + regs[ra].node.flags.incl nfIsRef of opcNChild: decodeBC(rkNode) let idx = regs[rc].intVal.int @@ -1773,7 +1789,7 @@ proc getGlobalValue*(c: PCtx; s: PSym): PNode = include vmops -proc setupGlobalCtx(module: PSym; graph: ModuleGraph) = +proc setupGlobalCtx*(module: PSym; graph: ModuleGraph) = if graph.vm.isNil: graph.vm = newCtx(module, graph.cache, graph) registerAdditionalOps(PCtx graph.vm) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index f7466b3929..866b79568f 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -136,7 +136,7 @@ type opcLdGlobalAddr, # dest = addr(globals[Bx]) opcLdImmInt, # dest = immediate value - opcNBindSym, + opcNBindSym, opcNDynBindSym, opcSetType, # dest.typ = types[Bx] opcTypeTrait, opcMarshalLoad, opcMarshalStore, @@ -229,7 +229,8 @@ proc refresh*(c: PCtx, module: PSym) = c.prc = PProc(blocks: @[]) c.loopIterations = MaxLoopIterations -proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = +proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} = + result = c.callbacks.len c.callbacks.add((name, callback)) const diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 31e04a6c07..3b5ea4beb1 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -817,6 +817,43 @@ proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) = c.freeTemp(tmp2) c.freeTemp(tmp3) +proc genBindSym(c: PCtx; n: PNode; dest: var TDest) = + # nah, cannot use c.config.features because sempass context + # can have local experimental switch + # if dynamicBindSym notin c.config.features: + if n.len == 2: # hmm, reliable? + # bindSym with static input + if n[1].kind in {nkClosedSymChoice, nkOpenSymChoice, nkSym}: + let idx = c.genLiteral(n[1]) + if dest < 0: dest = c.getTemp(n.typ) + c.gABx(n, opcNBindSym, dest, idx) + else: + localError(c.config, n.info, "invalid bindSym usage") + else: + # experimental bindSym + if dest < 0: dest = c.getTemp(n.typ) + let x = c.getTempRange(n.len, slotTempUnknown) + + # callee symbol + var tmp0 = TDest(x) + c.genLit(n.sons[0], tmp0) + + # original parameters + for i in 1.. Date: Thu, 2 Aug 2018 04:33:46 -0700 Subject: [PATCH 47/57] fixes #8509 disable 4GB allocating test on windows that crashed appveyor (#8510) --- tests/fragmentation/tfragment_alloc.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/fragmentation/tfragment_alloc.nim b/tests/fragmentation/tfragment_alloc.nim index 5a44b7434d..80341d2dcb 100644 --- a/tests/fragmentation/tfragment_alloc.nim +++ b/tests/fragmentation/tfragment_alloc.nim @@ -16,9 +16,12 @@ proc main = dealloc p # c_fprintf(stdout, "iteration: %ld size: %ld\n", i, size) when defined(cpu64): - # bug #7120 - var x = alloc(((1 shl 29) - 4) * 8) - dealloc x + # see https://github.com/nim-lang/Nim/issues/8509 + # this often made appveyor (on windows) fail with out of memory + when defined(posix): + # bug #7120 + var x = alloc(((1 shl 29) - 4) * 8) + dealloc x main() From 1c80619ac528f4ec30ee882cb9232157a6763add Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 3 Aug 2018 18:30:45 +0200 Subject: [PATCH 48/57] WIP: avoid using the old growObj in order to fix the newly introduced seq leaks --- lib/system/sysstr.nim | 65 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 8e9e18b053..6faca4cdb2 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -184,8 +184,13 @@ proc addChar(s: NimString, c: char): NimString = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[NimString](growObj(result, - sizeof(TGenericSeq) + r + 1)) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(r) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + else: + result = cast[NimString](growObj(result, + sizeof(TGenericSeq) + r + 1)) result.reserved = r result.data[result.len] = c result.data[result.len+1] = '\0' @@ -229,7 +234,12 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = result = dest else: # slow path: var sp = max(resize(dest.space), dest.len + addlen) - result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = dest.len + copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1) + else: + result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) result.reserved = sp #result = rawNewString(sp) #copyMem(result, dest, dest.len + sizeof(TGenericSeq)) @@ -282,6 +292,9 @@ proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = GenericSeqSize)) result.reserved = r +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = if s == nil: result = cast[PGenericSeq](newSeq(typ, 1)) @@ -290,9 +303,16 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, typ.base.size * r + + when defined(nimIncrSeqV3): + result = cast[PGenericSeq](newSeq(typ, r)) + result.len = s.len + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + else: + result = cast[PGenericSeq](growObj(result, typ.base.size * r + GenericSeqSize)) - result.reserved = r + result.reserved = r proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. compilerRtl, inl.} = @@ -336,10 +356,43 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. compilerRtl.} = + sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq" if s == nil: result = cast[PGenericSeq](newSeq(typ, newLen)) else: - result = setLengthSeq(s, typ.base.size, newLen) + when defined(nimIncrSeqV3): + let elemSize = typ.base.size + if s.space < newLen: + let r = max(resize(s.space), newLen) + result = cast[PGenericSeq](newSeq(typ, r)) + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * elemSize) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + elif newLen < s.len: + result = s + # we need to decref here, otherwise the GC leaks! + when not defined(boehmGC) and not defined(nogc) and + not defined(gcMarkAndSweep) and not defined(gogc) and + not defined(gcRegions): + if ntfNoRefs notin typ.base.flags: + for i in newLen..result.len-1: + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% + GenericSeqSize +% (i*%elemSize)), + extGetCellType(result).base, waZctDecRef) + + # XXX: zeroing out the memory can still result in crashes if a wiped-out + # cell is aliased by another pointer (ie proc parameter or a let variable). + # This is a tough problem, because even if we don't zeroMem here, in the + # presence of user defined destructors, the user will expect the cell to be + # "destroyed" thus creating the same problem. We can destoy the cell in the + # finalizer of the sequence, but this makes destruction non-deterministic. + zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + (newLen*%elemSize)), (result.len-%newLen) *% elemSize) + else: + result = s + result.len = newLen + else: + result = setLengthSeq(s, typ.base.size, newLen) # --------------- other string routines ---------------------------------- proc add*(result: var string; x: int64) = From e403ef25aceed929a3118e0dc2104c29e824dfcd Mon Sep 17 00:00:00 2001 From: Charlie Barto Date: Fri, 3 Aug 2018 19:18:27 -0400 Subject: [PATCH 49/57] fix shell quoting error for static libraries (#8532) --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index a90442369e..16b0d614da 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -659,7 +659,7 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = libname = getCurrentDir() / libname else: libname = (libNameTmpl(conf) % splitFile(conf.projectName).name) - result = CC[conf.cCompiler].buildLib % ["libfile", libname, + result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname), "objfiles", objfiles] else: var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe") From f131867de79a2cdf8fe7e5cd5106dbcc86aa3284 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 4 Aug 2018 16:56:35 +0200 Subject: [PATCH 50/57] emit the write barrier also for addChar --- compiler/ccgexprs.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4fa7dc2ca9..3bcf2c29bc 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1858,7 +1858,13 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = getTypeDesc(p.module, ranged), res]) of mConStrStr: genStrConcat(p, e, d) - of mAppendStrCh: binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n") + of mAppendStrCh: + var dest, b, call: TLoc + initLoc(call, locCall, e, OnHeap) + initLocExpr(p, e.sons[1], dest) + initLocExpr(p, e.sons[2], b) + call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) + genAssignment(p, dest, call, {}) of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: genSeqElemAppend(p, e, d) of mEqStr: genStrEquals(p, e, d) From e6738ba9d9f7b1221320a1fe49e6abba236b07a0 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 4 Aug 2018 18:11:03 +0200 Subject: [PATCH 51/57] make 'echo' threadsafe on Windows; fixes #8511 --- lib/system/sysio.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 2ece56916f..7a10849ddf 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -417,12 +417,18 @@ proc setStdIoUnbuffered() = discard c_setvbuf(stdin, nil, IONBF, 0) when declared(stdout): + when defined(windows) and compileOption("threads"): + var echoLock: SysLock + initSysLock echoLock + proc echoBinSafe(args: openArray[string]) {.compilerProc.} = # flockfile deadlocks some versions of Android 5.x.x when not defined(windows) and not defined(android) and not defined(nintendoswitch): proc flockfile(f: File) {.importc, noDecl.} proc funlockfile(f: File) {.importc, noDecl.} flockfile(stdout) + when defined(windows) and compileOption("threads"): + acquireSys echoLock for s in args: discard c_fwrite(s.cstring, s.len, 1, stdout) const linefeed = "\n" # can be 1 or more chars @@ -430,5 +436,7 @@ when declared(stdout): discard c_fflush(stdout) when not defined(windows) and not defined(android) and not defined(nintendoswitch): funlockfile(stdout) + when defined(windows) and compileOption("threads"): + releaseSys echoLock {.pop.} From 8d2953e8051fb623edccb7ad2946d079f3655e95 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 4 Aug 2018 09:12:35 -0700 Subject: [PATCH 52/57] gitignore test.ini, generated by ./koch tests (#8529) --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fc090130bb..f2037c1b83 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ dist/ .*/ ~* -# testament cruft +# testament cruft; TODO: generate these in a gitignore'd dir in the first place. testresults/ test.txt +/test.ini From 25b4d26e22c9c92bcce0626a2b50fec92a0c8a77 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 4 Aug 2018 18:50:44 +0200 Subject: [PATCH 53/57] fixes yet another regression --- lib/system/sysstr.nim | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 6faca4cdb2..fe16e0d860 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -233,7 +233,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = elif dest.len + addlen <= dest.space: result = dest else: # slow path: - var sp = max(resize(dest.space), dest.len + addlen) + let sp = max(resize(dest.space), dest.len + addlen) when defined(nimIncrSeqV3): result = rawNewStringNoInit(sp) result.len = dest.len @@ -256,13 +256,22 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} = inc(dest.len) proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = - var n = max(newLen, 0) + let n = max(newLen, 0) if s == nil: result = mnewString(newLen) elif n <= s.space: result = s else: - result = resizeString(s, n) + let sp = max(resize(s.space), newLen) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + zeroMem(addr result.data[s.len], newLen - s.len) + else: + result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) + result.reserved = sp + #result = resizeString(s, n) result.len = n result.data[n] = '\0' From 1fa23e347eb6e61b7f0f1999c6802a60fdf213a8 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 4 Aug 2018 19:55:10 +0200 Subject: [PATCH 54/57] make 'koch xz' enforce a clean 'git diff'; fixes #7292 --- koch.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/koch.nim b/koch.nim index 133c7e32bd..ad6a774e86 100644 --- a/koch.nim +++ b/koch.nim @@ -242,7 +242,15 @@ proc zip(args: string) = exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" % ["tools/niminst/niminst".exe, VersionAsString]) +proc ensureCleanGit() = + let (outp, status) = osproc.execCmdEx("git diff") + if outp.len != 0: + quit "Not a clean git repository; 'git diff' not empty!" + if status != 0: + quit "Not a clean git repository; 'git diff' returned non-zero!" + proc xz(args: string) = + ensureCleanGit() bundleNimbleSrc() bundleNimsuggest(false) nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % From 96c6c82d5592a7a19006c0fb161a74178cea9700 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 4 Aug 2018 20:10:03 +0200 Subject: [PATCH 55/57] fixes #8425 --- compiler/semexprs.nim | 2 +- tests/sets/tsets.nim | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d7a0d7b8b8..c9f9eb33fc 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2127,7 +2127,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode = n.sons[i] = semExprWithType(c, n.sons[i]) if typ == nil: typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) - if not isOrdinalType(typ): + if not isOrdinalType(typ, allowEnumWithHoles=true): localError(c.config, n.info, errOrdinalTypeExpected) typ = makeRangeType(c, 0, MaxSetElements-1, n.info) elif lengthOrd(c.config, typ) > MaxSetElements: diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim index 96d5debc79..13a5f54e69 100644 --- a/tests/sets/tsets.nim +++ b/tests/sets/tsets.nim @@ -205,4 +205,12 @@ echo warnUninit in gNotes # 7555 doAssert {-1.int8, -2, -2}.card == 2 -doAssert {1, 2, 2, 3..5, 4..6}.card == 6 \ No newline at end of file +doAssert {1, 2, 2, 3..5, 4..6}.card == 6 + +type Foo = enum + Foo1 = 0 + Foo2 = 1 + Foo3 = 3 + +let x = { Foo1, Foo2 } +# bug #8425 From c9f2c16da14357ee5f05efb890ebb141258ab061 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 4 Aug 2018 23:23:10 +0200 Subject: [PATCH 56/57] make setLengthStr compile for the old version --- lib/system/sysstr.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index fe16e0d860..19c2c62ad8 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -268,10 +268,9 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = result.len = s.len copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) zeroMem(addr result.data[s.len], newLen - s.len) + result.reserved = sp else: - result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) - result.reserved = sp - #result = resizeString(s, n) + result = resizeString(s, n) result.len = n result.data[n] = '\0' From 74842ed4a981b6ff168d67d05ee92dce350549cb Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 5 Aug 2018 09:20:30 +0200 Subject: [PATCH 57/57] make growobjcrash complete earlier --- tests/gc/growobjcrash.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index b8ff4f908a..07f92b8f4a 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -18,7 +18,7 @@ const Limit = 5*1024*1024 proc main = var counter = 0 - for i in 0 .. 10_000_000: + for i in 0 .. 100_000: for k, v in handleRequest("nick=Elina2&type=activate"): inc counter if counter mod 100 == 0: