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
parent ba6e11fc88
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]
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 =
# here we can do better than converting it into a compact set
# 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,
covered: var BiggestInt) =
for i in countup(0, sonsLen(branch) - 2):
let lastIndex = sonsLen(branch) - 2
for i in 0..lastIndex:
var b = branch.sons[i]
if b.kind == nkRange:
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))
inc(covered)
else:
if r.kind == nkCurly:
r = r.deduplicate
# first element is special and will overwrite: branch.sons[i]:
branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
# other elements have to be added to ``branch``
for j in 1 ..< r.len:
branch.add(semCaseBranchSetElem(c, t, r[j], covered))
# caution! last son of branch must be the actions to execute:
var L = branch.len
swap(branch.sons[L-2], branch.sons[L-1])
swap(branch.sons[^2], branch.sons[^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)
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