summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/vm.nim18
-rw-r--r--lib/pure/options.nim34
-rw-r--r--tests/vm/tsetlen.nim30
5 files changed, 50 insertions, 36 deletions
diff --git a/changelog.md b/changelog.md
index 6dbfa1a2d..093ea7ae2 100644
--- a/changelog.md
+++ b/changelog.md
@@ -29,6 +29,8 @@
 
 - `osproc.execProcess` now also takes a `workingDir` parameter.
 
+- `options.UnpackError` is no longer a ref type and inherits from `System.Defect` instead of `System.ValueError`.
+
 #### Breaking changes in the compiler
 
 - The compiler now implements the "generic symbol prepass" for `when` statements
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 3d8e5645b..247f6ad54 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -1138,7 +1138,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
             internalError(c.config, n.info, "implicitPragmas")
           inc i
         popInfoContext(c.config)
-        if sym.kind in routineKinds: mergePragmas(sym.ast, o)
+        if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
 
     if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
       localError(c.config, n.info, ".dynlib requires .exportc")
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 7e7ec8903..c8784c3e7 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -413,26 +413,12 @@ proc recSetFlagIsRef(arg: PNode) =
     arg.sons[i].recSetFlagIsRef
 
 proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
-  # FIXME: this doesn't attempt to solve incomplete
-  # support of tyPtr, tyRef in VM.
   let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
-  let typeEntry = typ.sons[0].skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
-  let typeKind = case typeEntry.kind
-                 of tyUInt..tyUInt64: nkUIntLit
-                 of tyRange, tyEnum, tyBool, tyChar, tyInt..tyInt64: nkIntLit
-                 of tyFloat..tyFloat128: nkFloatLit
-                 of tyString: nkStrLit
-                 of tyObject: nkObjConstr
-                 of tySequence: nkNilLit
-                 of tyProc, tyTuple: nkTupleConstr
-                 else: nkEmpty
-
   let oldLen = node.len
   setLen(node.sons, newLen)
   if oldLen < newLen:
-    # TODO: This is still not correct for tyPtr, tyRef default value
     for i in oldLen ..< newLen:
-      node.sons[i] = newNodeI(typeKind, info)
+      node.sons[i] = getNullValue(typ.sons[0], info, c.config)
 
 const
   errIndexOutOfBounds = "index out of bounds"
@@ -458,7 +444,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     #if c.traceActive:
     when traceCode:
       echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
-    #  message(c.config, c.debug[pc], warnUser, "Trace")
+      # message(c.config, c.debug[pc], warnUser, "Trace")
 
     case instr.opcode
     of opcEof: return regs[ra]
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index 12e38d8b5..b827e1aa3 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -39,17 +39,18 @@
 ##
 ## .. code-block:: nim
 ##
-##   try:
-##     assert("abc".find('c').get() == 2)  # Immediately extract the value
-##   except UnpackError:  # If there is no value
-##     assert false  # This will not be reached, because the value is present
-##
+##    let found = "abc".find('c')
+##    assert found.isSome and found.get() == 2
+##   
 ## The ``get`` operation demonstrated above returns the underlying value, or
-## raises ``UnpackError`` if there is no value. There is another option for
-## obtaining the value: ``unsafeGet``, but you must only use it when you are
-## absolutely sure the value is present (e.g. after checking ``isSome``). If
-## you do not care about the tiny overhead that ``get`` causes, you should
-## simply never use ``unsafeGet``.
+## raises ``UnpackError`` if there is no value. Note that ``UnpackError`` inherits
+## from ``system.Defect``, and should therefore never be catched. Instead, rely on
+## checking if the option contains a value with ``isSome`` and ``isNone``.
+##
+## There is another option for obtaining the value: ``unsafeGet``, but you must
+## only use it when you are absolutely sure the value is present (e.g. after
+## checking ``isSome``). If you do not care about the tiny overhead that ``get``
+## causes, you should simply never use ``unsafeGet``.
 ##
 ## How to deal with an absence of a value:
 ##
@@ -61,12 +62,7 @@
 ##   assert(result == none(int))
 ##   # It has no value:
 ##   assert(result.isNone)
-##
-##   try:
-##     echo result.get()
-##     assert(false)  # This will not be reached
-##   except UnpackError:  # Because an exception is raised
-##     discard
+
 import typetraits
 
 type
@@ -81,7 +77,7 @@ type
       val: T
       has: bool
 
-  UnpackError* = ref object of ValueError
+  UnpackError* = object of Defect
 
 proc some*[T](val: T): Option[T] =
   ## Returns a ``Option`` that has this value.
@@ -129,7 +125,7 @@ proc get*[T](self: Option[T]): T =
   ## Returns contents of the Option. If it is none, then an exception is
   ## thrown.
   if self.isNone:
-    raise UnpackError(msg: "Can't obtain a value from a `none`")
+    raise newException(UnpackError, "Can't obtain a value from a `none`")
   self.val
 
 proc get*[T](self: Option[T], otherwise: T): T =
@@ -143,7 +139,7 @@ proc get*[T](self: var Option[T]): var T =
   ## Returns contents of the Option. If it is none, then an exception is
   ## thrown.
   if self.isNone:
-    raise UnpackError(msg: "Can't obtain a value from a `none`")
+    raise newException(UnpackError, "Can't obtain a value from a `none`")
   return self.val
 
 proc map*[T](self: Option[T], callback: proc (input: T)) =
diff --git a/tests/vm/tsetlen.nim b/tests/vm/tsetlen.nim
new file mode 100644
index 000000000..9fd30f331
--- /dev/null
+++ b/tests/vm/tsetlen.nim
@@ -0,0 +1,30 @@
+type Foo = object
+  index: int
+
+block:
+  proc fun[T]() =
+    var foo: T
+    var n = 10
+
+    var foos: seq[T]
+    foos.setLen n
+
+    n.inc
+    foos.setLen n
+
+    for i in 0 ..< n:
+      let temp = foos[i]
+      when T is object:
+        doAssert temp.index == 0
+      when T is ref object:
+        doAssert temp == nil
+      doAssert temp == foo
+
+  static:
+    fun[Foo]()
+    fun[int]()
+    fun[float]()
+    fun[string]()
+    fun[(int, string)]()
+    fun[ref Foo]()
+    fun[seq[int]]()