diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-08-13 00:35:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-13 09:35:48 +0200 |
commit | b24812df5f952427c1266e48c40b7956bdf3d999 (patch) | |
tree | 9bbbb23a1446eedb10be7c52fe07013c4b172740 /compiler | |
parent | 3a1109a53be172a92c63ebc5bdb69c45e78e9ca6 (diff) | |
download | Nim-b24812df5f952427c1266e48c40b7956bdf3d999.tar.gz |
properly fix #10053 ; `FieldDefect` msg now shows discriminant value + lineinfo, in all backends (c,vm,js) (#11955)
* fix #10053 FieldError for vm * fixup * FieldError now also shows runtime value of discriminant * fix field error reporting in vm * also report culprit line info in err msg * fix errors for newruntime 2 * fix for js * fixup * PRTEMP4 * works * works * works perfect * refactor * std/private/repr_impl * suppport --gc:arc * cleanup * refactor * simplify * simplify * simplify * fixup * move out compiler.vmgen.genCustom * fixup * fixup * add tests * revert compiler/debugutils.nim * simplify reprDiscriminant * fixup * lib/std/private/repr_impl.nim -> lib/system/repr_impl.nim * try to fix D20210812T165220 * honor --declaredlocs * control toFileLineCol via --declaredlocs
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/astmsgs.nim | 11 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 41 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 6 | ||||
-rw-r--r-- | compiler/cgen.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 11 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/renderer.nim | 12 | ||||
-rw-r--r-- | compiler/vm.nim | 5 | ||||
-rw-r--r-- | compiler/vmgen.nim | 14 |
9 files changed, 66 insertions, 38 deletions
diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim index d9105b761..a9027126a 100644 --- a/compiler/astmsgs.nim +++ b/compiler/astmsgs.nim @@ -26,3 +26,14 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) = if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ) + +template quoteExpr*(a: string): untyped = + ## can be used for quoting expressions in error msgs. + "'" & a & "'" + +proc genFieldDefect*(conf: ConfigRef, field: string, disc: PSym): string = + let obj = disc.owner.name.s # `types.typeToString` might be better, eg for generics + result = "field '$#' is not accessible for type '$#'" % [field, obj] + if optDeclaredLocs in conf.globalOptions: + result.add " [discriminant declared in $#]" % toFileLineCol(conf, disc.info) + result.add " using '$# = " % disc.name.s diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index acf83f966..7eb4a7a1d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -18,6 +18,8 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, # -------------------------- constant expressions ------------------------ +proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType): Rope + proc int64Literal(i: BiggestInt): Rope = if i > low(int64): result = "IL64($1)" % [rope(i)] @@ -873,16 +875,34 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = v.r.add(".") v.r.add(disc.sym.loc.r) genInExprAux(p, it, u, v, test) - let msg = genFieldDefect(field, disc.sym) + var msg = "" + if optDeclaredLocs in p.config.globalOptions: + # xxx this should be controlled by a separate flag, and + # used for other similar defects so that location information is shown + # even without the expensive `--stacktrace`; binary size could be optimized + # by encoding the file names separately from `file(line:col)`, essentially + # passing around `TLineInfo` + the set of files in the project. + msg.add toFileLineCol(p.config, e.info) & " " + msg.add genFieldDefect(p.config, field.name.s, disc.sym) let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg)) - if op.magic == mNot: - linefmt(p, cpsStmts, - "if ($1){ #raiseFieldError($2); $3}$n", - [rdLoc(test), strLit, raiseInstr(p)]) + + ## discriminant check + template fun(code) = linefmt(p, cpsStmts, code, [rdLoc(test)]) + if op.magic == mNot: fun("if ($1) ") else: fun("if (!($1)) ") + + ## call raiseFieldError2 on failure + let discIndex = rdSetElemLoc(p.config, v, u.t) + if optTinyRtti in p.config.globalOptions: + # not sure how to use `genEnumToStr` here + const code = "{ #raiseFieldError2($1, (NI)$3); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex]) else: - linefmt(p, cpsStmts, - "if (!($1)){ #raiseFieldError($2); $3}$n", - [rdLoc(test), strLit, raiseInstr(p)]) + # complication needed for signed types + let first = p.config.firstOrd(disc.sym.typ) + let firstLit = int64Literal(cast[int](first)) + let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info) + const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$3) + (NI)$4, $5)); $2} $n" + linefmt(p, cpsStmts, code, [strLit, raiseInstr(p), discIndex, firstLit, discName]) proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = assert e[0].kind == nkDotExpr @@ -1565,10 +1585,7 @@ proc genNewFinalize(p: BProc, e: PNode) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], f) initLoc(b, locExpr, a.lode, OnHeap) - if optTinyRtti in p.config.globalOptions: - ti = genTypeInfoV2(p.module, refType, e.info) - else: - ti = genTypeInfoV1(p.module, refType, e.info) + ti = genTypeInfo(p.config, p.module, refType, e.info) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 67e701804..d05c4cd8b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1514,3 +1514,9 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = proc genTypeSection(m: BModule, n: PNode) = discard + +proc genTypeInfo*(config: ConfigRef, m: BModule, t: PType; info: TLineInfo): Rope = + if optTinyRtti in config.globalOptions: + result = genTypeInfoV2(m, t, info) + else: + result = genTypeInfoV1(m, t, info) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3b004d399..f55da7f65 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -15,7 +15,7 @@ import ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, rodutils, renderer, cgendata, aliases, lowerings, tables, sets, ndi, lineinfos, pathutils, transf, - injectdestructors + injectdestructors, astmsgs when not defined(leanCompiler): import spawn, semparallel diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 49a57b4a6..3aa5c474e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -33,7 +33,7 @@ import nversion, msgs, idents, types, ropes, passes, ccgutils, wordrecg, renderer, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - transf, injectdestructors, sourcemap + transf, injectdestructors, sourcemap, astmsgs import json, sets, math, tables, intsets, strutils @@ -1208,12 +1208,13 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) = let tmp = p.getTemp() lineF(p, "var $1 = $2;$n", tmp, obj.res) - useMagic(p, "raiseFieldError") + useMagic(p, "raiseFieldError2") useMagic(p, "makeNimstrLit") - let msg = genFieldDefect(field, disc) - lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n", + useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen + let msg = genFieldDefect(p.config, field.name.s, disc) + lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n", setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===", - makeJSString(msg)) + makeJSString(msg), genTypeInfo(p, disc.typ)) if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex: r.typ = etyBaseIndex diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 8ae931d84..6637a8673 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -699,7 +699,7 @@ proc typeBorrow(c: PContext; sym: PSym, n: PNode) = incl(sym.typ.flags, tfBorrowDot) proc markCompilerProc(c: PContext; s: PSym) = - # minor hack ahead: FlowVar is the only generic .compilerProc type which + # minor hack ahead: FlowVar is the only generic .compilerproc type which # should not have an external name set: if s.kind != skType or s.name.s != "FlowVar": makeExternExport(c, s, "$1", s.info) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 3346e629c..393f35289 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1758,15 +1758,3 @@ proc getTokSym*(r: TSrcGen): PSym = result = r.tokens[r.idx-1].sym else: result = nil - -proc quoteExpr*(a: string): string {.inline.} = - ## can be used for quoting expressions in error msgs. - "'" & a & "'" - -proc genFieldDefect*(field: PSym, disc: PSym): string = - ## this needs to be in a module accessible by jsgen, ccgexprs, and vm to - ## provide this error msg FieldDefect; msgs would be better but it does not - ## import ast - result = field.name.s.quoteExpr & " is not accessible using discriminant " & - disc.name.s.quoteExpr & " of type " & - disc.owner.name.s.quoteExpr diff --git a/compiler/vm.nim b/compiler/vm.nim index 73a228b6c..9fa25efbe 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1472,7 +1472,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: return TFullReg(kind: rkNone) of opcInvalidField: - stackTrace(c, tos, pc, errFieldXNotFound & regs[ra].node.strVal) + let msg = regs[ra].node.strVal + let disc = regs[instr.regB].regToNode + let msg2 = formatFieldDefect(msg, $disc) + stackTrace(c, tos, pc, msg2) of opcSetLenStr: decodeB(rkNode) #createStrKeepNode regs[ra] diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 4957a3339..725afdd3f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -31,7 +31,7 @@ import tables import strutils, ast, types, msgs, renderer, vmdef, - intsets, magicsys, options, lowerings, lineinfos, transf + intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs from modulegraphs import getBody @@ -1742,12 +1742,14 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs) c.freeTemp(rs) let strType = getSysType(c.graph, n.info, tyString) - var fieldNameRegister: TDest = c.getTemp(strType) - let strLit = newStrNode($accessExpr[1], accessExpr[1].info) + var msgReg: TDest = c.getTemp(strType) + let fieldName = $accessExpr[1] + let msg = genFieldDefect(c.config, fieldName, disc.sym) + let strLit = newStrNode(msg, accessExpr[1].info) strLit.typ = strType - c.genLit(strLit, fieldNameRegister) - c.gABC(n, opcInvalidField, fieldNameRegister) - c.freeTemp(fieldNameRegister) + c.genLit(strLit, msgReg) + c.gABC(n, opcInvalidField, msgReg, discVal) + c.freeTemp(msgReg) c.patch(lab1) proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = |