summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/commands.nim5
-rw-r--r--compiler/docgen.nim8
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--compiler/layouter.nim8
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semfold.nim2
-rw-r--r--compiler/semstmts.nim11
-rw-r--r--compiler/types.nim2
-rw-r--r--compiler/vm.nim47
-rw-r--r--compiler/vmdef.nim1
-rw-r--r--nimpretty/tests/exhaustive.nim2
-rw-r--r--tests/concepts/treversable.nim31
-rw-r--r--tests/vm/tnilref.nim7
-rw-r--r--tests/vm/tref.nim47
16 files changed, 142 insertions, 41 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 82cc3a1fb..0e8af5af5 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -59,7 +59,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
     else:
       result = rope("NIM_NIL")
   of nkStrLit..nkTripleStrLit:
-    case skipTypes(ty, abstractVarRange).kind
+    case skipTypes(ty, abstractVarRange + {tyStatic}).kind
     of tyNil:
       result = genNilStringLiteral(p.module, n.info)
     of tyString:
@@ -385,7 +385,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
     else:
       addrLoc(p.config, a)
 
-  var ty = skipTypes(dest.t, abstractVarRange)
+  var ty = skipTypes(dest.t, abstractVarRange + {tyStatic})
   case ty.kind
   of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray:
     # XXX optimize this
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 330504a76..866405f9f 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -606,7 +606,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     incl(conf.globalOptions, optRun)
   of "verbosity":
     expectArg(conf, switch, arg, pass, info)
-    conf.verbosity = parseInt(arg)
+    let verbosity = parseInt(arg)
+    if verbosity notin {0..3}:
+      localError(conf, info, "invalid verbosity level: '$1'" % arg)
+    conf.verbosity = verbosity
     conf.notes = NotesVerbosity[conf.verbosity]
     incl(conf.notes, conf.enableNotes)
     excl(conf.notes, conf.disableNotes)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index d463dc3c0..db4e301d4 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -582,7 +582,7 @@ proc traceDeps(d: PDoc, it: PNode) =
     if d.section[k] != nil: add(d.section[k], ", ")
     dispA(d.conf, d.section[k],
           "<a class=\"reference external\" href=\"$1.html\">$1</a>",
-          "$1", [rope(getModuleName(d.conf, it))])
+          "$1", [rope(splitFile(getModuleName(d.conf, it)).name)])
 
 proc generateDoc*(d: PDoc, n: PNode) =
   case n.kind
@@ -780,13 +780,11 @@ proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
 proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
   var content = genOutFile(d)
   var success = true
-  var filename: string
   if optStdout in d.conf.globalOptions:
     writeRope(stdout, content)
-    filename = "<stdout>"
   else:
-    filename = getOutFile2(d.conf, filename, outExt, "htmldocs")
-    success = writeRope(content, filename)
+    let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs")
+    success = writeRope(content, outfile)
   if not success:
     rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, filename)
 
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 615b8c1e1..17133624b 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -603,7 +603,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
 
 proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
   var c = Cfile(cname: filename,
-    obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)),
+    obj: toObjFile(conf, completeCFilePath(conf, filename, false)),
     flags: {CfileFlag.External})
   addExternalFileToCompile(conf, c)
 
diff --git a/compiler/layouter.nim b/compiler/layouter.nim
index 62844db4b..36ad08696 100644
--- a/compiler/layouter.nim
+++ b/compiler/layouter.nim
@@ -20,11 +20,15 @@ type
   SplitKind = enum
     splitComma, splitParLe, splitAnd, splitOr, splitIn, splitBinary
 
+  SemicolonKind = enum
+    detectSemicolonKind, useSemicolon, dontTouch
+
   Emitter* = object
     config: ConfigRef
     fid: FileIndex
     lastTok: TTokType
     inquote: bool
+    semicolons: SemicolonKind
     col, lastLineNumber, lineSpan, indentLevel, indWidth: int
     nested: int
     doIndentMore*: int
@@ -258,7 +262,9 @@ proc starWasExportMarker*(em: var Emitter) =
     dec em.col, 2
 
 proc commaWasSemicolon*(em: var Emitter) =
-  if em.content.endsWith(", "):
+  if em.semicolons == detectSemicolonKind:
+    em.semicolons = if em.content.endsWith(", "): dontTouch else: useSemicolon
+  if em.semicolons == useSemicolon and em.content.endsWith(", "):
     setLen(em.content, em.content.len-2)
     em.content.add("; ")
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c78a3519c..afe60e9dd 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -466,7 +466,7 @@ proc processCompile(c: PContext, n: PNode) =
       else:
         found = findFile(c.config, s)
         if found.len == 0: found = s
-    let obj = toObjFile(c.config, completeCFilePath(c.config, changeFileExt(found, ""), false))
+    let obj = toObjFile(c.config, completeCFilePath(c.config, found, false))
     docompile(c, it, found, obj)
 
 proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9d7c493a7..d7b5667b9 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -271,7 +271,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
     localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
   else:
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
-    var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc})
+    var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
     case typ.kind
     of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
       n.typ = getSysType(c.graph, n.info, tyInt)
@@ -1261,7 +1261,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # make sure we don't evaluate generic macros/templates
   n.sons[0] = semExprWithType(c, n.sons[0],
                               {efNoEvaluateGeneric})
-  let arr = skipTypes(n.sons[0].typ, {tyGenericInst,
+  let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyUserTypeClassInst,
                                       tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
   case arr.kind
   of tyArray, tyOpenArray, tyVarargs, tySequence, tyString,
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index eceb10470..2f495bc7f 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -619,7 +619,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
       of mLow:
         result = newIntNodeT(firstOrd(g.config, n.sons[1].typ), n, g)
       of mHigh:
-        if skipTypes(n.sons[1].typ, abstractVar).kind notin
+        if skipTypes(n.sons[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin
             {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
           result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, g)
         else:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index fe4318de5..945bcd9e1 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -519,7 +519,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         localError(c.config, a.info, errWrongNumberOfVariables)
       b = newNodeI(nkVarTuple, a.info)
       newSons(b, length)
-      b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
+      # keep type desc for doc generator
+      # NOTE: at the moment this is always ast.emptyNode, see parser.nim
+      b.sons[length-2] = a.sons[length-2]
       b.sons[length-1] = def
       addToVarSection(c, result, n, b)
     elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and
@@ -558,7 +560,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           # keep documentation information:
           b.comment = a.comment
         addSon(b, newSymNode(v))
-        addSon(b, a.sons[length-2])      # keep type desc for doc generator
+        # keep type desc for doc generator, but only if the user explicitly
+        # added it
+        if a.sons[length-2].kind != nkEmpty:
+          addSon(b, newNodeIT(nkType, a.info, typ))
+        else:
+          addSon(b, a.sons[length-2])
         addSon(b, copyTree(def))
         addToVarSection(c, result, n, b)
       else:
diff --git a/compiler/types.nim b/compiler/types.nim
index 98343c688..a1bdc7730 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -615,7 +615,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt =
     else:
       assert(t.n.sons[0].kind == nkSym)
       result = t.n.sons[0].sym.position
-  of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred:
+  of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred, tyUserTypeClassInst:
     result = firstOrd(conf, lastSon(t))
   of tyOrdinal:
     if t.len > 0: result = firstOrd(conf, lastSon(t))
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 3e33e8256..b16eb0fd4 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -204,22 +204,14 @@ proc asgnComplex(x: var TFullReg, y: TFullReg) =
   of rkRegisterAddr: x.regAddr = y.regAddr
   of rkNodeAddr: x.nodeAddr = y.nodeAddr
 
-proc putIntoNode(n: var PNode; x: TFullReg) =
+proc writeField(n: var PNode, x: TFullReg) =
   case x.kind
   of rkNone: discard
   of rkInt: n.intVal = x.intVal
   of rkFloat: n.floatVal = x.floatVal
-  of rkNode:
-    if nfIsRef in x.node.flags:
-      n = x.node
-    else:
-      let destIsRef = nfIsRef in n.flags
-      n[] = x.node[]
-      # Ref-ness must be kept for the destination
-      if destIsRef:
-        n.flags.incl nfIsRef
-  of rkRegisterAddr: putIntoNode(n, x.regAddr[])
-  of rkNodeAddr: n[] = x.nodeAddr[][]
+  of rkNode: n = x.node
+  of rkRegisterAddr: writeField(n, x.regAddr[])
+  of rkNodeAddr: n = x.nodeAddr[]
 
 proc putIntoReg(dest: var TFullReg; n: PNode) =
   case n.kind
@@ -498,9 +490,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       asgnComplex(regs[ra], regs[instr.regB])
     of opcAsgnRef:
       asgnRef(regs[ra], regs[instr.regB])
-    of opcRegToNode:
-      decodeB(rkNode)
-      putIntoNode(regs[ra].node, regs[rb])
     of opcNodeToReg:
       let ra = instr.regA
       let rb = instr.regB
@@ -559,7 +548,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         else:
           stackTrace(c, tos, pc, errIndexOutOfBounds)
       elif idx <% arr.len:
-        putIntoNode(arr.sons[idx], regs[rc])
+        writeField(arr.sons[idx], regs[rc])
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcLdObj:
@@ -579,9 +568,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if dest.kind == nkNilLit:
         stackTrace(c, tos, pc, errNilAccess)
       elif dest.sons[shiftedRb].kind == nkExprColonExpr:
-        putIntoNode(dest.sons[shiftedRb].sons[1], regs[rc])
+        writeField(dest.sons[shiftedRb].sons[1], regs[rc])
       else:
-        putIntoNode(dest.sons[shiftedRb], regs[rc])
+        writeField(dest.sons[shiftedRb], regs[rc])
     of opcWrStrIdx:
       decodeBC(rkNode)
       let idx = regs[rb].intVal.int
@@ -624,9 +613,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let ra = instr.regA
       let rc = instr.regC
       case regs[ra].kind
-      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rc])
+      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
+        else:
+          regs[ra].nodeAddr[] = n
       of rkRegisterAddr: regs[ra].regAddr[] = regs[rc]
-      of rkNode: putIntoNode(regs[ra].node, regs[rc])
+      of rkNode:
+        if regs[ra].node.kind == nkNilLit:
+          stackTrace(c, tos, pc, errNilAccess)
+        assert nfIsRef in regs[ra].node.flags
+        regs[ra].node[] = regs[rc].regToNode[]
+        regs[ra].node.flags.incl nfIsRef
       else: stackTrace(c, tos, pc, errNilAccess)
     of opcAddInt:
       decodeBC(rkInt)
@@ -1211,6 +1215,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNBindSym:
       decodeBx(rkNode)
       regs[ra].node = copyTree(c.constants.sons[rbx])
+      regs[ra].node.flags.incl nfIsRef
     of opcNChild:
       decodeBC(rkNode)
       let idx = regs[rc].intVal.int
@@ -1572,7 +1577,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       var sym = newSym(k.TSymKind, getIdent(c.cache, name), c.module.owner, c.debug[pc])
       incl(sym.flags, sfGenSym)
       regs[ra].node = newSymNode(sym)
-
+      regs[ra].node.flags.incl nfIsRef
     of opcNccValue:
       decodeB(rkInt)
       let destKey = regs[rb].node.strVal
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index cec61ade5..f7466b392 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -36,7 +36,6 @@ type
     opcAsgnFloat,
     opcAsgnRef,
     opcAsgnComplex,
-    opcRegToNode,
     opcNodeToReg,
 
     opcLdArr,  # a = b[c]
diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim
index 9f2141fbb..a2501a193 100644
--- a/nimpretty/tests/exhaustive.nim
+++ b/nimpretty/tests/exhaustive.nim
@@ -122,7 +122,7 @@ type
     fixedUntil: int # marks where we must not go in the content
     altSplitPos: array[SplitKind, int] # alternative split positions
 
-proc openEmitter*[T, S](em: var Emitter, config: ConfigRef, fileIdx: FileIndex) {.pragmaHereWrongCurlyEnd} =
+proc openEmitter*[T, S](em: var Emitter; config: ConfigRef, fileIdx: FileIndex) {.pragmaHereWrongCurlyEnd} =
   let outfile = changeFileExt(config.toFullPath(fileIdx), ".pretty.nim")
   em.f = llStreamOpen(outfile, fmWrite)
   em.config = config
diff --git a/tests/concepts/treversable.nim b/tests/concepts/treversable.nim
new file mode 100644
index 000000000..6ebc077d9
--- /dev/null
+++ b/tests/concepts/treversable.nim
@@ -0,0 +1,31 @@
+# issue 7705, 7703, 7702
+discard """
+  output: '''
+z
+e
+  '''
+"""
+
+type
+  Reversable*[T] = concept a
+    a[int] is T
+    a.high is int
+    a.len is int
+    a.low is int
+
+proc get[T](s: Reversable[T], n: int): T =
+  s[n]
+
+proc hi[T](s: Reversable[T]): int =
+  s.high
+
+proc lo[T](s: Reversable[T]): int =
+  s.low
+
+iterator reverse*[T](s: Reversable[T]): T =
+  assert hi(s) - lo(s) == len(s) - 1
+  for z in hi(s).countdown(lo(s)):
+    yield s.get(z)
+
+for s in @["e", "z"].reverse:
+  echo s
diff --git a/tests/vm/tnilref.nim b/tests/vm/tnilref.nim
new file mode 100644
index 000000000..5e27cf0cb
--- /dev/null
+++ b/tests/vm/tnilref.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "attempt to access a nil address"
+"""
+
+static:
+    var s: ref int
+    s[] = 1
\ No newline at end of file
diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim
index 517a67fb0..27b7bf313 100644
--- a/tests/vm/tref.nim
+++ b/tests/vm/tref.nim
@@ -9,4 +9,49 @@ static:
 
   b[5] = 'c'
   doAssert a[] == "Hellocworld"
-  doAssert b[] == "Hellocworld"
\ No newline at end of file
+  doAssert b[] == "Hellocworld"
+
+  proc notGlobal() =
+    var
+      a: ref string
+      b: ref string
+    new a
+
+    a[] = "Hello world"
+    b = a
+
+    b[5] = 'c'
+    doAssert a[] == "Hellocworld"
+    doAssert b[] == "Hellocworld"
+  notGlobal()
+
+static: # bug 6081
+  block:
+    type Obj = object
+      field: ref int
+    var i: ref int
+    new(i)
+    var r = Obj(field: i)
+    var rr = r
+    r.field = nil
+    doAssert rr.field != nil
+
+  proc foo() = # Proc to avoid special global logic
+    var s: seq[ref int]
+    var i: ref int
+    new(i)
+    s.add(i)
+    var head = s[0]
+    s[0] = nil
+    doAssert head != nil
+
+  foo()
+
+static:
+
+  block: # global alias
+    var s: ref int
+    new(s)
+    var ss = s
+    s[] = 1
+    doAssert ss[] == 1
\ No newline at end of file