Print missing case labels (#10600)

This commit is contained in:
Arne Döring
2019-02-09 07:36:30 +01:00
committed by Andreas Rumpf
parent 048a7a6539
commit 43a0dd42bc
4 changed files with 142 additions and 2 deletions

View File

@@ -873,6 +873,9 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
if chckCovered:
if covered == toCover(c, n.sons[0].typ):
hasElse = true
elif n.sons[0].typ.kind == tyEnum:
localError(c.config, n.info, "not all cases are covered; missing: {$1}" %
formatMissingEnums(n))
else:
localError(c.config, n.info, "not all cases are covered")
closeScope(c)

View File

@@ -608,6 +608,24 @@ proc toCover(c: PContext, t: PType): BiggestInt =
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
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,
father: PNode, rectype: PType) =
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)
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype, hasCaseFields = true)
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)
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,

View File

@@ -3,7 +3,7 @@ discard """
line: 33
file: "tcaseexpr1.nim"
errormsg: "not all cases are covered"
errormsg: "not all cases are covered; missing: {C}"
line: 27
file: "tcaseexpr1.nim"
"""

View 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