summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2019-02-18 15:23:05 +0100
committerGitHub <noreply@github.com>2019-02-18 15:23:05 +0100
commit2deb1e354fb7eba063c125579af04911f14382ed (patch)
treed27830529923022bd975fac7b23a606b7d1fcb28
parent1d66222901f0812bf5ffd5fc4e8175acb1948c9e (diff)
downloadNim-2deb1e354fb7eba063c125579af04911f14382ed.tar.gz
fixes #10702 (#10705)
* --define:nimQuirky exception handling for Nim; in preparation of a blog post
* make it work with latest system.nim
* make code more readable
* fixes #10702
-rw-r--r--compiler/ccgstmts.nim58
-rw-r--r--compiler/lineinfos.nim2
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/semcall.nim1
-rw-r--r--compiler/semstmts.nim41
-rw-r--r--compiler/vmdeps.nim6
-rw-r--r--lib/system.nim20
-rw-r--r--lib/system/excpt.nim2
-rw-r--r--tests/macros/tmacrotypes.nim34
9 files changed, 118 insertions, 50 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 382ad6a8e..bc8735397 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -168,7 +168,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
     let tryStmt = p.nestedTryStmts.pop
     if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
       # Pop safe points generated by try
-      if not tryStmt.inExcept:
+      if not tryStmt.inExcept and not isDefined(p.config, "nimQuirky"):
         linefmt(p, cpsStmts, "#popSafePoint();$n")
 
     # Pop this try-stmt of the list of nested trys
@@ -383,7 +383,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
   blockLeaveActions(p,
     howManyTrys    = p.nestedTryStmts.len,
     howManyExcepts = p.inExceptBlockLen)
-  if (p.finallySafePoints.len > 0):
+  if (p.finallySafePoints.len > 0) and not isDefined(p.config, "nimQuirky"):
     # If we're in a finally block, and we came here by exception
     # consume it before we return.
     var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
@@ -920,29 +920,38 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   #
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
-  p.module.includeHeader("<setjmp.h>")
+  let quirkyExceptions = isDefined(p.config, "nimQuirky")
+  if not quirkyExceptions:
+    p.module.includeHeader("<setjmp.h>")
   genLineDir(p, t)
-  var safePoint = getTempName(p.module)
   discard cgsym(p.module, "Exception")
-  linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
-  linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
-  if isDefined(p.config, "nimStdSetjmp"):
-    linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
-  elif isDefined(p.config, "nimSigSetjmp"):
-    linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
-  elif isDefined(p.config, "nimRawSetjmp"):
-    linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
-  else:
-    linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
-  startBlock(p, "if ($1.status == 0) {$n", [safePoint])
+  var safePoint: Rope
+  if not quirkyExceptions:
+    safePoint = getTempName(p.module)
+    linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
+    linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
+    if isDefined(p.config, "nimStdSetjmp"):
+      linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
+    elif isDefined(p.config, "nimSigSetjmp"):
+      linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
+    elif isDefined(p.config, "nimRawSetjmp"):
+      linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
+    else:
+      linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
+    startBlock(p, "if ($1.status == 0) {$n", [safePoint])
   var length = sonsLen(t)
   add(p.nestedTryStmts, (t, false))
   expr(p, t.sons[0], d)
-  linefmt(p, cpsStmts, "#popSafePoint();$n")
-  endBlock(p)
-  startBlock(p, "else {$n")
-  linefmt(p, cpsStmts, "#popSafePoint();$n")
-  genRestoreFrameAfterException(p)
+  if not quirkyExceptions:
+    linefmt(p, cpsStmts, "#popSafePoint();$n")
+    endBlock(p)
+    startBlock(p, "else {$n")
+    linefmt(p, cpsStmts, "#popSafePoint();$n")
+    genRestoreFrameAfterException(p)
+  elif 1 < length and t.sons[1].kind == nkExceptBranch:
+    startBlock(p, "if (#getCurrentException()) {$n")
+  else:
+    startBlock(p)
   p.nestedTryStmts[^1].inExcept = true
   var i = 1
   while (i < length) and (t.sons[i].kind == nkExceptBranch):
@@ -953,7 +962,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
       # general except section:
       if i > 1: lineF(p, cpsStmts, "else", [])
       startBlock(p)
-      linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
+      if not quirkyExceptions:
+        linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
       expr(p, t.sons[i].sons[0], d)
       linefmt(p, cpsStmts, "#popCurrentException();$n")
       endBlock(p)
@@ -969,7 +979,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
               [genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
       if i > 1: line(p, cpsStmts, "else ")
       startBlock(p, "if ($1) {$n", [orExpr])
-      linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
+      if not quirkyExceptions:
+        linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
       expr(p, t.sons[i].sons[blen-1], d)
       linefmt(p, cpsStmts, "#popCurrentException();$n")
       endBlock(p)
@@ -980,7 +991,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
     p.finallySafePoints.add(safePoint)
     genSimpleBlock(p, t.sons[i].sons[0])
     discard pop(p.finallySafePoints)
-  linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
+  if not quirkyExceptions:
+    linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
 
 proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
   var res = ""
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index 165d75821..f3aba49b4 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -224,7 +224,7 @@ type
 
 proc `==`*(a, b: FileIndex): bool {.borrow.}
 
-proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
+proc raiseRecoverableError*(msg: string) {.noinline.} =
   raise newException(ERecoverableError, msg)
 
 const
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 3eedf15a9..9b3c66104 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -875,7 +875,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         incl(sym.flags, sfSideEffect)
       of wNoreturn:
         noVal(c, it)
-        incl(sym.flags, sfNoReturn)
+        # Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode!
+        if not isDefined(c.config, "nimQuirky"):
+          incl(sym.flags, sfNoReturn)
         if sym.typ[0] != nil:
           localError(c.config, sym.ast[paramsPos][0].info,
             ".noreturn with return type not allowed")
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 950acb48f..05bfae0df 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -239,6 +239,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   if c.config.m.errorOutputs == {}:
     # fail fast:
     globalError(c.config, n.info, "type mismatch")
+    return
   if errors.len == 0:
     localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
     return
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 5b7556b2e..cd570caad 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1136,7 +1136,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       # its evaluated result here so that we don't execute it once again in the
       # final pass
       if a[2].kind in nkCallKinds:
-        a[2] = newNodeIT(nkType, a[2].info, t)
+        incl a[2].flags, nfSem # bug #10548
     if sfExportc in s.flags and s.typ.kind == tyAlias:
       localError(c.config, name.info, "{.exportc.} not allowed for type aliases")
     let aa = a.sons[2]
@@ -1191,24 +1191,27 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
     # compute the type's size and check for illegal recursions:
     if a.sons[1].kind == nkEmpty:
       var x = a[2]
-      while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
-        x = x.lastSon
-      if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
-          s.typ.kind notin {tyObject, tyEnum}:
-        # type aliases are hard:
-        var t = semTypeNode(c, x, nil)
-        assert t != nil
-        if s.typ != nil and s.typ.kind notin {tyAlias, tySink}:
-          if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
-            assignType(s.typ, t)
-            s.typ.id = t.id
-          elif t.kind in {tyObject, tyEnum, tyDistinct}:
-            assert s.typ != nil
-            assignType(s.typ, t)
-            s.typ.id = t.id     # same id
-      checkConstructedType(c.config, s.info, s.typ)
-      if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
-        checkForMetaFields(c, s.typ.n)
+      if x.kind in nkCallKinds and nfSem in x.flags:
+        discard "already semchecked, see line marked with bug #10548"
+      else:
+        while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
+          x = x.lastSon
+        if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
+            s.typ.kind notin {tyObject, tyEnum}:
+          # type aliases are hard:
+          var t = semTypeNode(c, x, nil)
+          assert t != nil
+          if s.typ != nil and s.typ.kind notin {tyAlias, tySink}:
+            if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
+              assignType(s.typ, t)
+              s.typ.id = t.id
+            elif t.kind in {tyObject, tyEnum, tyDistinct}:
+              assert s.typ != nil
+              assignType(s.typ, t)
+              s.typ.id = t.id     # same id
+        checkConstructedType(c.config, s.info, s.typ)
+        if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
+          checkForMetaFields(c, s.typ.n)
   instAllTypeBoundOp(c, n.info)
 
 
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index f160a3096..edbed5ca1 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -297,14 +297,14 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyOptAsRef: assert(false, "mapTypeToAstX")
 
 proc opMapTypeToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode =
-  result = mapTypeToAstX(cache, t, info, false, true)
+  result = mapTypeToAstX(cache, t, info, inst=false, allowRecursionX=true)
 
 # the "Inst" version includes generic parameters in the resulting type tree
 # and also tries to look like the corresponding Nim type declaration
 proc opMapTypeInstToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode =
-  result = mapTypeToAstX(cache, t, info, true, false)
+  result = mapTypeToAstX(cache, t, info, inst=true, allowRecursionX=false)
 
 # the "Impl" version includes generic parameters in the resulting type tree
 # and also tries to look like the corresponding Nim type implementation
 proc opMapTypeImplToAst*(cache: IdentCache; t: PType; info: TLineInfo): PNode =
-  result = mapTypeToAstX(cache, t, info, true, true)
+  result = mapTypeToAstX(cache, t, info, inst=true, allowRecursionX=true)
diff --git a/lib/system.nim b/lib/system.nim
index d92848d40..268d6ccd3 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -3015,6 +3015,9 @@ template newException*(exceptn: typedesc, message: string;
 when hostOS == "standalone":
   include "$projectpath/panicoverride"
 
+when not defined(js) and not defined(nimscript):
+  include "system/ansi_c"
+
 when not declared(sysFatal):
   {.push profiler: off.}
   when hostOS == "standalone":
@@ -3024,6 +3027,22 @@ when not declared(sysFatal):
     proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
       rawoutput(message)
       panic(arg)
+  elif defined(nimQuirky) and not defined(nimscript):
+    proc name(t: typedesc): string {.magic: "TypeTrait".}
+
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
+      var buf = newStringOfCap(200)
+      add(buf, "Error: unhandled exception: ")
+      add(buf, message)
+      add(buf, arg)
+      add(buf, " [")
+      add(buf, name exceptn)
+      add(buf, "]")
+      cstderr.rawWrite buf
+      quit 1
+
+    proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
+      sysFatal(exceptn, message, "")
   else:
     proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
       var e: ref exceptn
@@ -3170,7 +3189,6 @@ when not defined(JS): #and not defined(nimscript):
       {.pop.}
 
   when not defined(nimscript):
-    include "system/ansi_c"
     include "system/memory"
 
     proc zeroMem(p: pointer, size: Natural) =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index dbdd038a4..93fd693e0 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -354,6 +354,8 @@ proc raiseExceptionAux(e: ref Exception) =
       raiseCounter.inc # skip zero at overflow
     e.raiseId = raiseCounter
     {.emit: "`e`->raise();".}
+  elif defined(nimQuirky):
+    pushCurrentException(e)
   else:
     if excHandler != nil:
       if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
index b4d708240..ab8bcfa95 100644
--- a/tests/macros/tmacrotypes.nim
+++ b/tests/macros/tmacrotypes.nim
@@ -14,10 +14,10 @@ macro checkType(ex: typed; expected: string): untyped =
 macro checkProcType(fn: typed): untyped =
   let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn
   echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr
-  
+
 
 proc voidProc = echo "hello"
-proc intProc(a: int, b: float): int {.checkProcType.} = 10 
+proc intProc(a: int, b: float): int {.checkProcType.} = 10
 
 checkType(voidProc(), "void")
 checkType(intProc(10, 20.0), "int")
@@ -38,3 +38,33 @@ block:
     Club = Blub
 
   static: doAssert(c == 1)
+
+# bug #10702
+type
+  VectorElementType = SomeNumber | bool
+  Vec*[N : static[int], T: VectorElementType] = object
+    arr*: array[N, T]
+
+type
+  Vec4*[T: VectorElementType] = Vec[4,T]
+  Vec3*[T: VectorElementType] = Vec[3,T]
+  Vec2*[T: VectorElementType] = Vec[2,T]
+
+template vecGen(U:untyped,V:typed):typed=
+  ## ``U`` suffix
+  ## ``V`` valType
+  ##
+  type
+    `Vec2 U`* {.inject.} = Vec2[V]
+    `Vec3 U`* {.inject.} = Vec3[V]
+    `Vec4 U`* {.inject.} = Vec4[V]
+
+vecGen(f, float32)
+
+macro foobar(arg: typed): untyped =
+  let typ = arg.getTypeInst
+  doAssert typ.getImpl[^1].kind == nnkCall
+
+var x: Vec2f
+
+foobar(x)