diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-02-18 15:23:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-18 15:23:05 +0100 |
commit | 2deb1e354fb7eba063c125579af04911f14382ed (patch) | |
tree | d27830529923022bd975fac7b23a606b7d1fcb28 | |
parent | 1d66222901f0812bf5ffd5fc4e8175acb1948c9e (diff) | |
download | Nim-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.nim | 58 | ||||
-rw-r--r-- | compiler/lineinfos.nim | 2 | ||||
-rw-r--r-- | compiler/pragmas.nim | 4 | ||||
-rw-r--r-- | compiler/semcall.nim | 1 | ||||
-rw-r--r-- | compiler/semstmts.nim | 41 | ||||
-rw-r--r-- | compiler/vmdeps.nim | 6 | ||||
-rw-r--r-- | lib/system.nim | 20 | ||||
-rw-r--r-- | lib/system/excpt.nim | 2 | ||||
-rw-r--r-- | tests/macros/tmacrotypes.nim | 34 |
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) |