summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim34
-rw-r--r--compiler/cgen.nim3
-rw-r--r--compiler/cgendata.nim10
-rw-r--r--compiler/pragmas.nim8
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semtempl.nim10
-rw-r--r--compiler/trees.nim19
-rw-r--r--compiler/vmdeps.nim22
-rw-r--r--compiler/vmgen.nim3
-rw-r--r--lib/pure/math.nim4
-rw-r--r--lib/pure/memfiles.nim34
-rw-r--r--tests/ccgbugs/tescaping_temps.nim20
-rw-r--r--tests/ccgbugs/tinefficient_const_table.nim27
-rw-r--r--tests/lookups/tprefer_proc.nim4
14 files changed, 148 insertions, 54 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 75a7cb3bb..a86409e50 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1151,7 +1151,25 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
               genTypeInfo(p.module, seqtype), a.rdLoc]))
   gcUsage(e)
 
+proc genConstExpr(p: BProc, n: PNode): Rope
+proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
+  if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
+    var t = getUniqueType(n.typ)
+    discard getTypeDesc(p.module, t) # so that any fields are initialized
+    let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+    fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
+    if id == p.module.labels:
+      # expression not found in the cache:
+      inc(p.module.labels)
+      addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+           [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
+    result = true
+  else:
+    result = false
+
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
+  if handleConstExpr(p, e, d): return
+  #echo rendertree e, " ", e.isDeepConstExpr
   var tmp: TLoc
   var t = e.typ.skipTypes(abstractInst)
   getTemp(p, t, tmp)
@@ -1769,22 +1787,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mDotDot, mEqCString: genCall(p, e, d)
   else: internalError(e.info, "genMagicExpr: " & $op)
 
-proc genConstExpr(p: BProc, n: PNode): Rope
-proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
-  if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
-    var t = getUniqueType(n.typ)
-    discard getTypeDesc(p.module, t) # so that any fields are initialized
-    let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
-    fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
-    if id == p.module.labels:
-      # expression not found in the cache:
-      inc(p.module.labels)
-      addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
-           [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
-    result = true
-  else:
-    result = false
-
 proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
   # example: { a..b, c, d, e, f..g }
   # we have to emit an expression of the form:
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 4dbe8572e..9851ab0e2 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -328,7 +328,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
 proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
   inc(p.labels)
   result.r = "LOC" & rope(p.labels)
-  linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
+  addf(p.blocks[0].sections[cpsLocals],
+     "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
   result.k = locTemp
   #result.a = - 1
   result.t = t
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index c027bb451..a94950029 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -15,7 +15,7 @@ import
 from msgs import TLineInfo
 
 type
-  TLabel* = Rope             # for the C generator a label is just a rope
+  TLabel* = Rope              # for the C generator a label is just a rope
   TCFileSection* = enum       # the sections a generated C file consists of
     cfsMergeInfo,             # section containing merge information
     cfsHeaders,               # section for C include file headers
@@ -89,7 +89,7 @@ type
                               # requires 'T x = T()' to become 'T x; x = T()'
                               # (yes, C++ is weird like that)
     gcFrameId*: Natural       # for the GC stack marking
-    gcFrameType*: Rope       # the struct {} we put the GC markers into
+    gcFrameType*: Rope        # the struct {} we put the GC markers into
 
   TTypeSeq* = seq[PType]
 
@@ -111,10 +111,10 @@ type
     tmpBase*: Rope            # base for temp identifier generation
     typeCache*: TIdTable      # cache the generated types
     forwTypeCache*: TIdTable  # cache for forward declarations of types
-    declaredThings*: IntSet  # things we have declared in this .c file
-    declaredProtos*: IntSet  # prototypes we have declared in this .c file
+    declaredThings*: IntSet   # things we have declared in this .c file
+    declaredProtos*: IntSet   # prototypes we have declared in this .c file
     headerFiles*: TLinkedList # needed headers to include
-    typeInfoMarker*: IntSet  # needed for generating type information
+    typeInfoMarker*: IntSet   # needed for generating type information
     initProc*: BProc          # code for init procedure
     postInitProc*: BProc      # code to be executed after the init proc
     preInitProc*: BProc       # code executed before the init proc
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 781aab687..354e5bdc6 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -400,8 +400,12 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
     s = addFileExt(s, ext)
   result = parentDir(n.info.toFullPath) / s
   if not fileExists(result):
-    if isAbsolute(s): result = s
-    else: result = findFile(s)
+    if isAbsolute(s):
+      result = s
+    else:
+      result = findFile(s)
+      if result.len == 0:
+        result = s
 
 proc processCompile(c: PContext, n: PNode) =
   let found = relativeFile(c, n)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index fd18dc3d7..fc31829ba 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -2216,7 +2216,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   if nfSem in n.flags: return
   case n.kind
   of nkIdent, nkAccQuoted:
-    var s = lookUp(c, n)
+    let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
+                 else: {checkUndeclared, checkModule, checkAmbiguity}
+    var s = qualifiedLookUp(c, n, checks)
     if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
     result = semSym(c, n, s, flags)
     if s.kind in {skProc, skMethod, skConverter, skIterator}:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 4d3b6d038..20b5071ac 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -51,9 +51,10 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
   var i = 0
   a = initOverloadIter(o, c, n)
   while a != nil:
+    if a.kind != skModule:
+      inc(i)
+      if i > 1: break
     a = nextOverloadIter(o, c, n)
-    inc(i)
-    if i > 1: break
   if i <= 1 and r != scForceOpen:
     # XXX this makes more sense but breaks bootstrapping for now:
     # (s.kind notin routineKinds or s.magic != mNone):
@@ -68,8 +69,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
     a = initOverloadIter(o, c, n)
     while a != nil:
-      incl(a.flags, sfUsed)
-      addSon(result, newSymNode(a, n.info))
+      if a.kind != skModule:
+        incl(a.flags, sfUsed)
+        addSon(result, newSymNode(a, n.info))
       a = nextOverloadIter(o, c, n)
 
 proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 659df334b..fdd88c348 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -103,14 +103,16 @@ proc getMagic*(op: PNode): TMagic =
     else: result = mNone
   else: result = mNone
 
-proc treeToSym*(t: PNode): PSym =
-  result = t.sym
-
 proc isConstExpr*(n: PNode): bool =
   result = (n.kind in
       {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
        nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
 
+proc isCaseObj*(n: PNode): bool =
+  if n.kind == nkRecCase: return true
+  for i in 0..<safeLen(n):
+    if n[i].isCaseObj: return true
+
 proc isDeepConstExpr*(n: PNode): bool =
   case n.kind
   of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
@@ -119,11 +121,14 @@ proc isDeepConstExpr*(n: PNode): bool =
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
     result = isDeepConstExpr(n.sons[1])
   of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
-    for i in 0 .. <n.len:
+    for i in ord(n.kind == nkObjConstr) .. <n.len:
       if not isDeepConstExpr(n.sons[i]): return false
-    # XXX once constant objects are supported by the codegen this needs to be
-    # weakened:
-    result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
+    if n.typ.isNil: result = true
+    else:
+      let t = n.typ.skipTypes({tyGenericInst, tyDistinct})
+      if t.kind in {tyRef, tyPtr}: return false
+      if t.kind != tyObject or not isCaseObj(t.n):
+        result = true
   else: discard
 
 proc flattenTreeAux(d, a: PNode, op: TMagic) =
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 18c5ae832..7dbf6f801 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -85,6 +85,17 @@ proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo;
     else:
       result.add mapTypeToAstX(t.sons[i], info, inst)
 
+proc objectNode(n: PNode): PNode =
+  if n.kind == nkSym:
+    result = newNodeI(nkIdentDefs, n.info)
+    result.add n  # name
+    result.add mapTypeToAstX(n.sym.typ, n.info, true, false)  # type
+    result.add ast.emptyNode  # no assigned value
+  else:
+    result = copyNode(n)
+    for i in 0 ..< n.safeLen:
+      result.add objectNode(n[i])
+
 proc mapTypeToAstX(t: PType; info: TLineInfo;
                    inst=false; allowRecursionX=false): PNode =
   var allowRecursion = allowRecursionX
@@ -167,7 +178,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       result = newNodeX(nkDistinctTy)
       result.add mapTypeToAst(t.sons[0], info)
     else:
-      if allowRecursion or t.sym==nil:
+      if allowRecursion or t.sym == nil:
         result = mapTypeToBracket("distinct", mDistinct, t, info)
       else:
         result = atomicType(t.sym.name.s, t.sym.magic)
@@ -177,16 +188,13 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
     if inst:
       result = newNodeX(nkObjectTy)
       result.add ast.emptyNode  # pragmas not reconstructed yet
-      if t.sons[0]==nil: result.add ast.emptyNode  # handle parent object
+      if t.sons[0] == nil: result.add ast.emptyNode  # handle parent object
       else:
         var nn = newNodeX(nkOfInherit)
         nn.add mapTypeToAst(t.sons[0], info)
         result.add nn
-      if t.n.sons.len>0:
-        var rl = copyNode(t.n)  # handle nkRecList
-        for s in t.n.sons:
-          rl.add newIdentDefs(s)
-        result.add rl
+      if t.n.len > 0:
+        result.add objectNode(t.n)
       else:
         result.add ast.emptyNode
     else:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 366662258..61ab65360 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -664,8 +664,7 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
   let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
   # uint is uint64 in the VM, we we only need to mask the result for
   # other unsigned types:
-  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
-      (t.kind == tyInt and t.size == 4):
+  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
     c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
 
 proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index c088e3d7d..58d9879b2 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -219,7 +219,7 @@ when not defined(JS):
     ##
     ## .. code-block:: nim
     ##  echo ceil(-2.1) ## -2.0
-  
+
   when defined(windows) and defined(vcc):
     proc round0[T: float32|float64](x: T): T =
       ## Windows compilers prior to MSVC 2012 do not implement 'round',
@@ -360,7 +360,7 @@ proc `mod`*[T: float32|float64](x, y: T): T =
 proc `^`*[T](x, y: T): T =
   ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
   ## `pow <#pow,float,float>` for negative exponents.
-  assert y >= 0
+  assert y >= T(0)
   var (x, y) = (x, y)
   result = 1
 
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index ff3e74d59..aa32778c5 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -42,6 +42,10 @@ type
 
 proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
              mappedSize = -1, offset = 0): pointer =
+  ## returns a pointer to a mapped portion of MemFile `m`
+  ##
+  ## ``mappedSize`` of ``-1`` maps to the whole file, and
+  ## ``offset`` must be multiples of the PAGE SIZE of your OS
   var readonly = mode == fmRead
   when defined(windows):
     result = mapViewOfFileEx(
@@ -68,7 +72,9 @@ proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
 proc unmapMem*(f: var MemFile, p: pointer, size: int) =
   ## unmaps the memory region ``(p, <p+size)`` of the mapped file `f`.
   ## All changes are written back to the file system, if `f` was opened
-  ## with write access. ``size`` must be of exactly the size that was requested
+  ## with write access.
+  ##
+  ## ``size`` must be of exactly the size that was requested
   ## via ``mapMem``.
   when defined(windows):
     if unmapViewOfFile(p) == 0: raiseOSError(osLastError())
@@ -79,9 +85,17 @@ proc unmapMem*(f: var MemFile, p: pointer, size: int) =
 proc open*(filename: string, mode: FileMode = fmRead,
            mappedSize = -1, offset = 0, newFileSize = -1): MemFile =
   ## opens a memory mapped file. If this fails, ``EOS`` is raised.
-  ## `newFileSize` can only be set if the file does not exist and is opened
-  ## with write access (e.g., with fmReadWrite). `mappedSize` and `offset`
-  ## can be used to map only a slice of the file. Example:
+  ##
+  ## ``newFileSize`` can only be set if the file does not exist and is opened
+  ## with write access (e.g., with fmReadWrite).
+  ##
+  ##``mappedSize`` and ``offset``
+  ## can be used to map only a slice of the file.
+  ##
+  ## ``offset`` must be multiples of the PAGE SIZE of your OS
+  ## (usually 4K or 8K but is unique to your OS)
+  ##
+  ## Example:
   ##
   ## .. code-block:: nim
   ##   var
@@ -285,7 +299,9 @@ iterator memSlices*(mfile: MemFile, delim='\l', eat='\r'): MemSlice {.inline.} =
   ## iterate over line-like records in a file.  However, returned (data,size)
   ## objects are not Nim strings, bounds checked Nim arrays, or even terminated
   ## C strings.  So, care is required to access the data (e.g., think C mem*
-  ## functions, not str* functions).  Example:
+  ## functions, not str* functions).
+  ##
+  ## Example:
   ##
   ## .. code-block:: nim
   ##   var count = 0
@@ -318,7 +334,9 @@ iterator lines*(mfile: MemFile, buf: var TaintedString, delim='\l', eat='\r'): T
   ## Replace contents of passed buffer with each new line, like
   ## `readLine(File) <system.html#readLine,File,TaintedString>`_.
   ## `delim`, `eat`, and delimiting logic is exactly as for
-  ## `memSlices <#memSlices>`_, but Nim strings are returned.  Example:
+  ## `memSlices <#memSlices>`_, but Nim strings are returned.
+  ##
+  ## Example:
   ##
   ## .. code-block:: nim
   ##   var buffer: TaintedString = ""
@@ -335,7 +353,9 @@ iterator lines*(mfile: MemFile, delim='\l', eat='\r'): TaintedString {.inline.}
   ## Return each line in a file as a Nim string, like
   ## `lines(File) <system.html#lines.i,File>`_.
   ## `delim`, `eat`, and delimiting logic is exactly as for
-  ## `memSlices <#memSlices>`_, but Nim strings are returned.  Example:
+  ## `memSlices <#memSlices>`_, but Nim strings are returned.
+  ##
+  ## Example:
   ##
   ## .. code-block:: nim
   ##   for line in lines(memfiles.open("foo")):
diff --git a/tests/ccgbugs/tescaping_temps.nim b/tests/ccgbugs/tescaping_temps.nim
new file mode 100644
index 000000000..ef078913b
--- /dev/null
+++ b/tests/ccgbugs/tescaping_temps.nim
@@ -0,0 +1,20 @@
+
+# bug #4505
+
+proc f(t: tuple[]) = discard
+f((block: ()))
+
+# bug #4230
+# If we make `test` function return nothing - the bug disappears
+proc test(dothejob: proc()): int {.discardable.} =
+    dothejob()
+
+test proc() =
+    let f = 15
+    if f > 10:
+        test proc() = discard
+    # If we remove elif branch of the condition - the bug disappears
+    elif f < 3:
+        test proc() = discard
+    else:
+        test proc() = discard
diff --git a/tests/ccgbugs/tinefficient_const_table.nim b/tests/ccgbugs/tinefficient_const_table.nim
new file mode 100644
index 000000000..149b8bcff
--- /dev/null
+++ b/tests/ccgbugs/tinefficient_const_table.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''a
+long
+list
+of
+words'''
+  cmd: r"nim c --hints:on $options -d:release $file"
+  ccodecheck: "! @'genericSeqAssign'"
+"""
+
+
+# bug #4354
+import tables
+import sets
+import strutils
+
+#const FRUITS = ["banana", "apple", "grapes"]
+#let FRUITS = ["banana", "apple", "grapes"].toSet
+const FRUITS = {"banana":0, "apple":0, "grapes":0}.toTable
+
+proc main() =
+    let L = "a long list of words".split()
+    for word in L:
+        if word notin FRUITS:
+            echo(word)
+
+main()
diff --git a/tests/lookups/tprefer_proc.nim b/tests/lookups/tprefer_proc.nim
new file mode 100644
index 000000000..57ee8e539
--- /dev/null
+++ b/tests/lookups/tprefer_proc.nim
@@ -0,0 +1,4 @@
+
+# bug #4353
+import random
+echo random[int](low(int) .. high(int))