Fixes #3060 and adds error checking for invalid else branches in object variants (#9957)

* Fix semRecordCase

* Fix ftpclient.nim

* Check for ordinal type

* Check tyRange for exhaustiveness
This commit is contained in:
Andreas Rumpf 2018-12-19 10:03:22 +01:00 • committed by GitHub
commit 72500420d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 18 deletions

View file

@ -95,13 +95,6 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
elif efInTypeof in flags: elif efInTypeof in flags:
result.typ = n[1].typ result.typ = n[1].typ
proc toCover(c: PContext, t: PType): BiggestInt =
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n)
else:
result = lengthOrd(c.config, skipTypes(t, abstractVar-{tyTypeDesc}))
proc semProc(c: PContext, n: PNode): PNode proc semProc(c: PContext, n: PNode): PNode
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode = proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =

View file

@ -591,6 +591,13 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
for i in lastIndex.succ..(sonsLen(branch) - 2): for i in lastIndex.succ..(sonsLen(branch) - 2):
checkForOverlap(c, t, i, branchIndex) checkForOverlap(c, t, i, branchIndex)
proc toCover(c: PContext, t: PType): BiggestInt =
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
if t2.kind == tyEnum and enumHasHoles(t2):
result = sonsLen(t2.n)
else:
result = lengthOrd(c.config, skipTypes(t, abstractVar-{tyTypeDesc}))
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 semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
@ -603,15 +610,16 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
return return
incl(a.sons[0].sym.flags, sfDiscriminant) incl(a.sons[0].sym.flags, sfDiscriminant)
var covered: BiggestInt = 0 var covered: BiggestInt = 0
var chckCovered = false
var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc}) var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
if not isOrdinalType(typ): case typ.kind
localError(c.config, n.info, "selector must be of an ordinal type") of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool, tyRange:
elif firstOrd(c.config, typ) != 0: chckCovered = true
localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s & of tyFloat..tyFloat128, tyString, tyError:
") must be 0 for discriminant") discard
elif lengthOrd(c.config, typ) > 0x00007FFF: else:
localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s) if not isOrdinalType(typ):
var chckCovered = true localError(c.config, n.info, "selector must be of an ordinal type, float or string")
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var b = copyTree(n.sons[i]) var b = copyTree(n.sons[i])
addSon(a, b) addSon(a, b)
@ -620,12 +628,14 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
checkMinSonsLen(b, 2, c.config) checkMinSonsLen(b, 2, c.config)
semCaseBranch(c, a, b, i, covered) semCaseBranch(c, a, b, i, covered)
of nkElse: of nkElse:
chckCovered = false
checkSonsLen(b, 1, c.config) checkSonsLen(b, 1, c.config)
if chckCovered and covered == toCover(c, a.sons[0].typ):
localError(c.config, b.info, "invalid else, all cases are already covered")
chckCovered = false
else: illFormedAst(n, c.config) else: illFormedAst(n, c.config)
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 != lengthOrd(c.config, a.sons[0].typ): if chckCovered and covered != toCover(c, a.sons[0].typ):
localError(c.config, a.info, "not all cases are covered") localError(c.config, a.info, "not all cases are covered")
addSon(father, a) addSon(father, a)

View file

@ -81,7 +81,6 @@ type
oneSecond: BiggestInt # Bytes transferred in one second. oneSecond: BiggestInt # Bytes transferred in one second.
lastProgressReport: float # Time lastProgressReport: float # Time
toStore: string # Data left to upload (Only used with async) toStore: string # Data left to upload (Only used with async)
else: nil
FtpClientObj* = FtpBaseObj[Socket] FtpClientObj* = FtpBaseObj[Socket]
FtpClient* = ref FtpClientObj FtpClient* = ref FtpClientObj