Print missing case labels (#10600)
This commit is contained in:
parent
048a7a6539
commit
43a0dd42bc
4 changed files with 142 additions and 2 deletions
|
|
@ -873,6 +873,9 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
if chckCovered:
|
if chckCovered:
|
||||||
if covered == toCover(c, n.sons[0].typ):
|
if covered == toCover(c, n.sons[0].typ):
|
||||||
hasElse = true
|
hasElse = true
|
||||||
|
elif n.sons[0].typ.kind == tyEnum:
|
||||||
|
localError(c.config, n.info, "not all cases are covered; missing: {$1}" %
|
||||||
|
formatMissingEnums(n))
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, "not all cases are covered")
|
localError(c.config, n.info, "not all cases are covered")
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
|
||||||
|
|
@ -608,6 +608,24 @@ proc toCover(c: PContext, t: PType): BiggestInt =
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType, hasCaseFields = false)
|
father: PNode, rectype: PType, hasCaseFields = false)
|
||||||
|
|
||||||
|
proc formatMissingEnums(n: PNode): string =
|
||||||
|
var coveredCases = initIntSet()
|
||||||
|
for i in 1 ..< n.len:
|
||||||
|
let ofBranch = n[i]
|
||||||
|
for j in 0 ..< ofBranch.len - 1:
|
||||||
|
let child = ofBranch[j]
|
||||||
|
if child.kind == nkIntLit:
|
||||||
|
coveredCases.incl(child.intVal.int)
|
||||||
|
elif child.kind == nkRange:
|
||||||
|
for k in child[0].intVal.int .. child[1].intVal.int:
|
||||||
|
coveredCases.incl k
|
||||||
|
for child in n[0].typ.n.sons:
|
||||||
|
if child.sym.position notin coveredCases:
|
||||||
|
if result.len > 0:
|
||||||
|
result.add ", "
|
||||||
|
result.add child.sym.name.s
|
||||||
|
|
||||||
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType) =
|
father: PNode, rectype: PType) =
|
||||||
var a = copyNode(n)
|
var a = copyNode(n)
|
||||||
|
|
@ -644,7 +662,11 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
delSon(b, sonsLen(b) - 1)
|
delSon(b, sonsLen(b) - 1)
|
||||||
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype, hasCaseFields = true)
|
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype, hasCaseFields = true)
|
||||||
if chckCovered and covered != toCover(c, a.sons[0].typ):
|
if chckCovered and covered != toCover(c, a.sons[0].typ):
|
||||||
localError(c.config, a.info, "not all cases are covered")
|
if a.sons[0].typ.kind == tyEnum:
|
||||||
|
localError(c.config, a.info, "not all cases are covered; missing: {$1}" %
|
||||||
|
formatMissingEnums(a))
|
||||||
|
else:
|
||||||
|
localError(c.config, a.info, "not all cases are covered")
|
||||||
addSon(father, a)
|
addSon(father, a)
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ discard """
|
||||||
line: 33
|
line: 33
|
||||||
file: "tcaseexpr1.nim"
|
file: "tcaseexpr1.nim"
|
||||||
|
|
||||||
errormsg: "not all cases are covered"
|
errormsg: "not all cases are covered; missing: {C}"
|
||||||
line: 27
|
line: 27
|
||||||
file: "tcaseexpr1.nim"
|
file: "tcaseexpr1.nim"
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
115
tests/casestmt/tincompletecaseobject.nim
Normal file
115
tests/casestmt/tincompletecaseobject.nim
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
discard """
|
||||||
|
errormsg: '''
|
||||||
|
not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArglist, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr}
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# this isn't imported from macros.nim to make it robust against possible changes in the ast.
|
||||||
|
|
||||||
|
type
|
||||||
|
NimNodeKind* = enum
|
||||||
|
nnkNone, nnkEmpty, nnkIdent, nnkSym,
|
||||||
|
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
|
||||||
|
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
|
||||||
|
nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
|
||||||
|
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
|
||||||
|
nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall,
|
||||||
|
nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
|
||||||
|
nnkPrefix, nnkPostfix, nnkHiddenCallConv,
|
||||||
|
nnkExprEqExpr,
|
||||||
|
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
|
||||||
|
nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
|
||||||
|
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
|
||||||
|
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
|
||||||
|
nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,
|
||||||
|
nnkTableConstr, nnkBind,
|
||||||
|
nnkClosedSymChoice,
|
||||||
|
nnkOpenSymChoice,
|
||||||
|
nnkHiddenStdConv,
|
||||||
|
nnkHiddenSubConv, nnkConv, nnkCast, nnkStaticExpr,
|
||||||
|
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
|
||||||
|
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
|
||||||
|
nnkStringToCString, nnkCStringToString, nnkAsgn,
|
||||||
|
nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
|
||||||
|
nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef,
|
||||||
|
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||||
|
nnkElifBranch, nnkExceptBranch, nnkElse,
|
||||||
|
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
|
||||||
|
nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||||
|
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
||||||
|
nnkConstDef, nnkTypeDef,
|
||||||
|
nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||||
|
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
|
||||||
|
nnkDiscardStmt, nnkStmtList,
|
||||||
|
nnkImportStmt = 1337, # make a hole just for fun
|
||||||
|
nnkImportExceptStmt,
|
||||||
|
nnkExportStmt,
|
||||||
|
nnkExportExceptStmt,
|
||||||
|
nnkFromStmt,
|
||||||
|
nnkIncludeStmt,
|
||||||
|
nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
|
||||||
|
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||||
|
nnkStmtListType, nnkBlockType,
|
||||||
|
nnkWith, nnkWithout,
|
||||||
|
nnkTypeOfExpr, nnkObjectTy,
|
||||||
|
nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
|
||||||
|
nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
|
nnkConstTy, nnkMutableTy,
|
||||||
|
nnkDistinctTy,
|
||||||
|
nnkProcTy,
|
||||||
|
nnkIteratorTy, # iterator type
|
||||||
|
nnkSharedTy, # 'shared T'
|
||||||
|
nnkEnumTy,
|
||||||
|
nnkEnumFieldDef,
|
||||||
|
nnkArglist, nnkPattern
|
||||||
|
nnkReturnToken,
|
||||||
|
nnkClosure,
|
||||||
|
nnkGotoState,
|
||||||
|
nnkState,
|
||||||
|
nnkBreakState,
|
||||||
|
nnkFuncDef,
|
||||||
|
nnkTupleConstr
|
||||||
|
|
||||||
|
const
|
||||||
|
nnkLiterals* = {nnkCharLit..nnkNilLit}
|
||||||
|
|
||||||
|
nnkSomething* = {nnkStmtList, nnkStmtListExpr, nnkDiscardStmt, nnkVarSection, nnkLetSection,
|
||||||
|
nnkConstSection, nnkPar, nnkAccQuoted, nnkAsgn, nnkDefer, nnkCurly, nnkBracket,
|
||||||
|
nnkStaticStmt, nnkTableConstr, nnkExprColonExpr, nnkInfix, nnkPrefix,
|
||||||
|
nnkRaiseStmt, nnkYieldStmt, nnkBracketExpr, nnkDotExpr, nnkCast, nnkBlockStmt,
|
||||||
|
nnkExprEqExpr}
|
||||||
|
|
||||||
|
type
|
||||||
|
MyFictionalType = object
|
||||||
|
a: int
|
||||||
|
case n: NimNodeKind
|
||||||
|
of nnkLiterals, nnkCommentStmt, nnkNone, nnkEmpty, nnkIdent, nnkSym,
|
||||||
|
nnkType, nnkBindStmt, nnkMixinStmt, nnkTypeSection, nnkPragmaBlock,
|
||||||
|
nnkPragmaExpr, nnkPragma, nnkBreakStmt, nnkCallStrLit, nnkPostfix,
|
||||||
|
nnkOpenSymChoice:
|
||||||
|
b: int
|
||||||
|
of nnkCall, nnkCommand:
|
||||||
|
c: int
|
||||||
|
of nnkReturnStmt:
|
||||||
|
d: int
|
||||||
|
of nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkProcDef, nnkMethodDef:
|
||||||
|
e: int
|
||||||
|
of nnkSomething, nnkRefTy, nnkPtrTy, nnkHiddenStdConv:
|
||||||
|
f: int
|
||||||
|
of nnkObjConstr:
|
||||||
|
g: int
|
||||||
|
of nnkIfStmt, nnkIfExpr, nnkWhenStmt:
|
||||||
|
# if when and case statements are branching statements. So a
|
||||||
|
# single function call is allowed to be in all of the braches and
|
||||||
|
# the entire expression can still be considered as a forwarding
|
||||||
|
# template.
|
||||||
|
h: int
|
||||||
|
of nnkCaseStmt:
|
||||||
|
i: int
|
||||||
|
of nnkTryStmt:
|
||||||
|
j: int
|
||||||
|
of nnkIdentDefs:
|
||||||
|
k: int
|
||||||
|
of nnkConstDef:
|
||||||
|
l: int
|
||||||
Loading…
Add table
Add a link
Reference in a new issue