Improve semchecking for duplicate cases in case statements (#7176)

* Improve semchecking for duplicate cases in case statements

* Revert to previous solution

* Improve test
This commit is contained in:
Oscar Nihlgård 2018-02-24 14:56:17 +01:00 • committed by Andreas Rumpf
commit e4515f304a
3 changed files with 66 additions and 4 deletions

View file

@ -151,6 +151,11 @@ proc complement*(a: PNode): PNode =
for i in countup(0, high(x)): x[i] = not x[i] for i in countup(0, high(x)): x[i] = not x[i]
result = toTreeSet(x, a.typ, a.info) result = toTreeSet(x, a.typ, a.info)
proc deduplicate*(a: PNode): PNode =
var x: TBitSet
toBitSet(a, x)
result = toTreeSet(x, a.typ, a.info)
proc cardSet(s: PNode): BiggestInt = proc cardSet(s: PNode): BiggestInt =
# here we can do better than converting it into a compact set # here we can do better than converting it into a compact set
# we just count the elements directly # we just count the elements directly

View file

@ -497,8 +497,8 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
covered: var BiggestInt) = covered: var BiggestInt) =
let lastIndex = sonsLen(branch) - 2
for i in countup(0, sonsLen(branch) - 2): for i in 0..lastIndex:
var b = branch.sons[i] var b = branch.sons[i]
if b.kind == nkRange: if b.kind == nkRange:
branch.sons[i] = b branch.sons[i] = b
@ -516,14 +516,21 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info)) branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info))
inc(covered) inc(covered)
else: else:
if r.kind == nkCurly:
r = r.deduplicate
# first element is special and will overwrite: branch.sons[i]: # first element is special and will overwrite: branch.sons[i]:
branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered) branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
# other elements have to be added to ``branch`` # other elements have to be added to ``branch``
for j in 1 ..< r.len: for j in 1 ..< r.len:
branch.add(semCaseBranchSetElem(c, t, r[j], covered)) branch.add(semCaseBranchSetElem(c, t, r[j], covered))
# caution! last son of branch must be the actions to execute: # caution! last son of branch must be the actions to execute:
var L = branch.len swap(branch.sons[^2], branch.sons[^1])
swap(branch.sons[L-2], branch.sons[L-1]) checkForOverlap(c, t, i, branchIndex)
# Elements added above needs to be checked for overlaps.
for i in lastIndex.succ..(sonsLen(branch) - 2):
checkForOverlap(c, t, i, branchIndex) checkForOverlap(c, t, i, branchIndex)
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,

View file

@ -0,0 +1,50 @@
discard """
output: '''
OK
OK
OK
'''
"""
type Kind = enum A, B
var k = A
template reject(b) =
static: doAssert(not compiles(b))
reject:
var i = 2
case i
of [1, 1]: discard
else: discard
reject:
var i = 2
case i
of 1, { 1..2 }: discard
else: discard
reject:
var i = 2
case i
of { 1, 1 }: discard
of { 1, 1 }: discard
else: discard
reject:
case k
of [A, A]: discard
var i = 2
case i
of { 1, 1 }: discard
of { 2, 2 }: echo "OK"
else: discard
case i
of { 10..30, 15..25, 5..15, 25..35 }: discard
else: echo "OK"
case k
of {A, A..A}: echo "OK"
of B: discard