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
This commit is contained in:
parent
3a1109a53b
commit
b24812df5f
18 changed files with 151 additions and 43 deletions
|
|
@ -26,3 +26,14 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
|
||||||
|
|
||||||
proc addDeclaredLocMaybe*(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)
|
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
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode,
|
||||||
|
|
||||||
# -------------------------- constant expressions ------------------------
|
# -------------------------- constant expressions ------------------------
|
||||||
|
|
||||||
|
proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType): Rope
|
||||||
|
|
||||||
proc int64Literal(i: BiggestInt): Rope =
|
proc int64Literal(i: BiggestInt): Rope =
|
||||||
if i > low(int64):
|
if i > low(int64):
|
||||||
result = "IL64($1)" % [rope(i)]
|
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(".")
|
||||||
v.r.add(disc.sym.loc.r)
|
v.r.add(disc.sym.loc.r)
|
||||||
genInExprAux(p, it, u, v, test)
|
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))
|
let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg))
|
||||||
if op.magic == mNot:
|
|
||||||
linefmt(p, cpsStmts,
|
## discriminant check
|
||||||
"if ($1){ #raiseFieldError($2); $3}$n",
|
template fun(code) = linefmt(p, cpsStmts, code, [rdLoc(test)])
|
||||||
[rdLoc(test), strLit, raiseInstr(p)])
|
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:
|
else:
|
||||||
linefmt(p, cpsStmts,
|
# complication needed for signed types
|
||||||
"if (!($1)){ #raiseFieldError($2); $3}$n",
|
let first = p.config.firstOrd(disc.sym.typ)
|
||||||
[rdLoc(test), strLit, raiseInstr(p)])
|
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) =
|
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
assert e[0].kind == nkDotExpr
|
assert e[0].kind == nkDotExpr
|
||||||
|
|
@ -1565,10 +1585,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||||
initLocExpr(p, e[1], a)
|
initLocExpr(p, e[1], a)
|
||||||
initLocExpr(p, e[2], f)
|
initLocExpr(p, e[2], f)
|
||||||
initLoc(b, locExpr, a.lode, OnHeap)
|
initLoc(b, locExpr, a.lode, OnHeap)
|
||||||
if optTinyRtti in p.config.globalOptions:
|
ti = genTypeInfo(p.config, p.module, refType, e.info)
|
||||||
ti = genTypeInfoV2(p.module, refType, e.info)
|
|
||||||
else:
|
|
||||||
ti = genTypeInfoV1(p.module, refType, e.info)
|
|
||||||
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
|
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
|
||||||
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
|
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
|
||||||
getTypeDesc(p.module, refType),
|
getTypeDesc(p.module, refType),
|
||||||
|
|
|
||||||
|
|
@ -1514,3 +1514,9 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||||
|
|
||||||
proc genTypeSection(m: BModule, n: PNode) =
|
proc genTypeSection(m: BModule, n: PNode) =
|
||||||
discard
|
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)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import
|
||||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||||
rodutils, renderer, cgendata, aliases,
|
rodutils, renderer, cgendata, aliases,
|
||||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
|
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
|
||||||
injectdestructors
|
injectdestructors, astmsgs
|
||||||
|
|
||||||
when not defined(leanCompiler):
|
when not defined(leanCompiler):
|
||||||
import spawn, semparallel
|
import spawn, semparallel
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import
|
||||||
nversion, msgs, idents, types,
|
nversion, msgs, idents, types,
|
||||||
ropes, passes, ccgutils, wordrecg, renderer,
|
ropes, passes, ccgutils, wordrecg, renderer,
|
||||||
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||||
transf, injectdestructors, sourcemap
|
transf, injectdestructors, sourcemap, astmsgs
|
||||||
|
|
||||||
import json, sets, math, tables, intsets, strutils
|
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()
|
let tmp = p.getTemp()
|
||||||
lineF(p, "var $1 = $2;$n", tmp, obj.res)
|
lineF(p, "var $1 = $2;$n", tmp, obj.res)
|
||||||
|
|
||||||
useMagic(p, "raiseFieldError")
|
useMagic(p, "raiseFieldError2")
|
||||||
useMagic(p, "makeNimstrLit")
|
useMagic(p, "makeNimstrLit")
|
||||||
let msg = genFieldDefect(field, disc)
|
useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen
|
||||||
lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n",
|
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: ~"===",
|
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:
|
if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex:
|
||||||
r.typ = etyBaseIndex
|
r.typ = etyBaseIndex
|
||||||
|
|
|
||||||
|
|
@ -699,7 +699,7 @@ proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
|
||||||
incl(sym.typ.flags, tfBorrowDot)
|
incl(sym.typ.flags, tfBorrowDot)
|
||||||
|
|
||||||
proc markCompilerProc(c: PContext; s: PSym) =
|
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:
|
# should not have an external name set:
|
||||||
if s.kind != skType or s.name.s != "FlowVar":
|
if s.kind != skType or s.name.s != "FlowVar":
|
||||||
makeExternExport(c, s, "$1", s.info)
|
makeExternExport(c, s, "$1", s.info)
|
||||||
|
|
|
||||||
|
|
@ -1758,15 +1758,3 @@ proc getTokSym*(r: TSrcGen): PSym =
|
||||||
result = r.tokens[r.idx-1].sym
|
result = r.tokens[r.idx-1].sym
|
||||||
else:
|
else:
|
||||||
result = nil
|
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
|
|
||||||
|
|
|
||||||
|
|
@ -1472,7 +1472,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
else:
|
else:
|
||||||
return TFullReg(kind: rkNone)
|
return TFullReg(kind: rkNone)
|
||||||
of opcInvalidField:
|
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:
|
of opcSetLenStr:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
#createStrKeepNode regs[ra]
|
#createStrKeepNode regs[ra]
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import tables
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, ast, types, msgs, renderer, vmdef,
|
strutils, ast, types, msgs, renderer, vmdef,
|
||||||
intsets, magicsys, options, lowerings, lineinfos, transf
|
intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs
|
||||||
|
|
||||||
from modulegraphs import getBody
|
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)
|
let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
|
||||||
c.freeTemp(rs)
|
c.freeTemp(rs)
|
||||||
let strType = getSysType(c.graph, n.info, tyString)
|
let strType = getSysType(c.graph, n.info, tyString)
|
||||||
var fieldNameRegister: TDest = c.getTemp(strType)
|
var msgReg: TDest = c.getTemp(strType)
|
||||||
let strLit = newStrNode($accessExpr[1], accessExpr[1].info)
|
let fieldName = $accessExpr[1]
|
||||||
|
let msg = genFieldDefect(c.config, fieldName, disc.sym)
|
||||||
|
let strLit = newStrNode(msg, accessExpr[1].info)
|
||||||
strLit.typ = strType
|
strLit.typ = strType
|
||||||
c.genLit(strLit, fieldNameRegister)
|
c.genLit(strLit, msgReg)
|
||||||
c.gABC(n, opcInvalidField, fieldNameRegister)
|
c.gABC(n, opcInvalidField, msgReg, discVal)
|
||||||
c.freeTemp(fieldNameRegister)
|
c.freeTemp(msgReg)
|
||||||
c.patch(lab1)
|
c.patch(lab1)
|
||||||
|
|
||||||
proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,18 @@ proc raiseIndexError() {.compilerproc, noinline.} =
|
||||||
sysFatal(IndexDefect, "index out of bounds")
|
sysFatal(IndexDefect, "index out of bounds")
|
||||||
|
|
||||||
proc raiseFieldError(f: string) {.compilerproc, noinline.} =
|
proc raiseFieldError(f: string) {.compilerproc, noinline.} =
|
||||||
|
## remove after bootstrap > 1.5.1
|
||||||
sysFatal(FieldDefect, f)
|
sysFatal(FieldDefect, f)
|
||||||
|
|
||||||
|
when defined(gcdestructors):
|
||||||
|
proc raiseFieldError2(f: string, discVal: int) {.compilerproc, noinline.} =
|
||||||
|
## raised when field is inaccessible given runtime value of discriminant
|
||||||
|
sysFatal(FieldError, f & $discVal & "'")
|
||||||
|
else:
|
||||||
|
proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noinline.} =
|
||||||
|
## raised when field is inaccessible given runtime value of discriminant
|
||||||
|
sysFatal(FieldError, formatFieldDefect(f, discVal))
|
||||||
|
|
||||||
proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} =
|
proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} =
|
||||||
when defined(standalone):
|
when defined(standalone):
|
||||||
sysFatal(RangeDefect, "value out of range")
|
sysFatal(RangeDefect, "value out of range")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# imported by other modules, unlike helpers.nim which is included
|
# imported by other modules, unlike helpers.nim which is included
|
||||||
|
# xxx this is now included instead of imported, we should import instead
|
||||||
|
|
||||||
template formatErrorIndexBound*[T](i, a, b: T): string =
|
template formatErrorIndexBound*[T](i, a, b: T): string =
|
||||||
when defined(standalone):
|
when defined(standalone):
|
||||||
|
|
@ -9,3 +10,6 @@ template formatErrorIndexBound*[T](i, a, b: T): string =
|
||||||
|
|
||||||
template formatErrorIndexBound*[T](i, n: T): string =
|
template formatErrorIndexBound*[T](i, n: T): string =
|
||||||
formatErrorIndexBound(i, 0, n)
|
formatErrorIndexBound(i, 0, n)
|
||||||
|
|
||||||
|
template formatFieldDefect*(f, discVal): string =
|
||||||
|
f & discVal & "'"
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,8 @@ proc raiseRangeError() {.compilerproc, noreturn.} =
|
||||||
proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} =
|
proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} =
|
||||||
raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b)))
|
raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b)))
|
||||||
|
|
||||||
proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
|
proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} =
|
||||||
raise newException(FieldDefect, f)
|
raise newException(FieldDefect, formatFieldDefect(f, discVal))
|
||||||
|
|
||||||
proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||||
|
|
||||||
result = $e & " (invalid data!)"
|
result = $e & " (invalid data!)"
|
||||||
|
|
||||||
|
include system/repr_impl
|
||||||
|
|
||||||
type
|
type
|
||||||
PByteArray = ptr UncheckedArray[byte] # array[0xffff, byte]
|
PByteArray = ptr UncheckedArray[byte] # array[0xffff, byte]
|
||||||
|
|
||||||
|
|
|
||||||
15
lib/system/repr_impl.nim
Normal file
15
lib/system/repr_impl.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#[
|
||||||
|
other APIs common to system/repr and system/reprjs could be refactored here, eg:
|
||||||
|
* reprChar
|
||||||
|
* reprBool
|
||||||
|
* reprStr
|
||||||
|
|
||||||
|
Another possibility in future work would be to have a single include file instead
|
||||||
|
of system/repr and system/reprjs, and use `when defined(js)` inside it.
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc reprDiscriminant*(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||||
|
case typ.kind
|
||||||
|
of tyEnum: reprEnum(e, typ)
|
||||||
|
of tyBool: $(e != 0)
|
||||||
|
else: $e
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
include system/inclrtl
|
||||||
|
|
||||||
proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
|
proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
|
||||||
## imported from typetraits
|
## imported from typetraits
|
||||||
|
|
||||||
|
|
@ -66,6 +68,11 @@ proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
|
||||||
## If a `repr` operator for a concrete enumeration is provided, this is
|
## If a `repr` operator for a concrete enumeration is provided, this is
|
||||||
## used instead. (In other words: *Overwriting* is possible.)
|
## used instead. (In other words: *Overwriting* is possible.)
|
||||||
|
|
||||||
|
proc reprDiscriminant*(e: int): string {.compilerproc.} =
|
||||||
|
# repr and reprjs can use `PNimType` to symbolize `e`; making this work here
|
||||||
|
# would require a way to pass the set of enum stringified values to cgen.
|
||||||
|
$e
|
||||||
|
|
||||||
proc repr*(p: pointer): string =
|
proc repr*(p: pointer): string =
|
||||||
## repr of pointer as its hexadecimal value
|
## repr of pointer as its hexadecimal value
|
||||||
if p == nil:
|
if p == nil:
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||||
else:
|
else:
|
||||||
result = $e & " (invalid data!)"
|
result = $e & " (invalid data!)"
|
||||||
|
|
||||||
|
include system/repr_impl
|
||||||
|
|
||||||
proc reprChar(x: char): string {.compilerRtl.} =
|
proc reprChar(x: char): string {.compilerRtl.} =
|
||||||
result = "\'"
|
result = "\'"
|
||||||
case x
|
case x
|
||||||
|
|
|
||||||
30
tests/misc/mfield_defect.nim
Normal file
30
tests/misc/mfield_defect.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#[
|
||||||
|
ran from trunner
|
||||||
|
]#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# line 10
|
||||||
|
type Kind = enum k0, k1, k2, k3, k4
|
||||||
|
|
||||||
|
type Foo = object
|
||||||
|
case kind: Kind
|
||||||
|
of k0: f0: int
|
||||||
|
of k1: f1: int
|
||||||
|
of k2: f2: int
|
||||||
|
of k3: f3: int
|
||||||
|
of k4: f4: int
|
||||||
|
|
||||||
|
proc main()=
|
||||||
|
var foo = Foo(kind: k3, f3: 3)
|
||||||
|
let s1 = foo.f3
|
||||||
|
doAssert s1 == 3
|
||||||
|
let s2 = foo.f2
|
||||||
|
|
||||||
|
when defined case1:
|
||||||
|
static: main()
|
||||||
|
when defined case2:
|
||||||
|
main()
|
||||||
|
|
@ -37,9 +37,9 @@ proc runNimCmd(file, options = "", rtarg = ""): auto =
|
||||||
echo cmd
|
echo cmd
|
||||||
echo result[0] & "\n" & $result[1]
|
echo result[0] & "\n" & $result[1]
|
||||||
|
|
||||||
proc runNimCmdChk(file, options = "", rtarg = ""): string =
|
proc runNimCmdChk(file, options = "", rtarg = "", status = 0): string =
|
||||||
let (ret, status) = runNimCmd(file, options, rtarg = rtarg)
|
let (ret, status2) = runNimCmd(file, options, rtarg = rtarg)
|
||||||
doAssert status == 0, $(file, options) & "\n" & ret
|
doAssert status2 == status, $(file, options, status, status2) & "\n" & ret
|
||||||
ret
|
ret
|
||||||
|
|
||||||
proc genShellCmd(filename: string): string =
|
proc genShellCmd(filename: string): string =
|
||||||
|
|
@ -376,5 +376,15 @@ mused3.nim(13, 8) Warning: imported and not used: 'mused3b' [UnusedImport]
|
||||||
mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport]
|
mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
block: # FieldDefect
|
||||||
|
proc fn(opt: string, expected: string) =
|
||||||
|
let output = runNimCmdChk("misc/mfield_defect.nim", fmt"-r --warning:all:off --declaredlocs {opt}", status = 1)
|
||||||
|
doAssert expected in output, opt & "\noutput:\n" & output & "expected:\n" & expected
|
||||||
|
fn("-d:case1"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
|
||||||
|
fn("-d:case2 --gc:refc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
|
||||||
|
fn("-d:case1 -b:js"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
|
||||||
|
fn("-d:case2 -b:js"): """field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
|
||||||
|
# 3 instead of k3, because of lack of RTTI
|
||||||
|
fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = 3'"""
|
||||||
else:
|
else:
|
||||||
discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled
|
discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue