fixes #2287
This commit is contained in:
parent
970e98718d
commit
5a21892da0
6 changed files with 345 additions and 280 deletions
|
|
@ -15,11 +15,11 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
|
||||||
const
|
const
|
||||||
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||||
mEqUntracedRef, mEqStr, mEqSet, mEqCString}
|
mEqUntracedRef, mEqStr, mEqSet, mEqCString}
|
||||||
|
|
||||||
# set excluded here as the semantics are vastly different:
|
# set excluded here as the semantics are vastly different:
|
||||||
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||||
mLeCh, mLeB, mLePtr, mLeStr}
|
mLeCh, mLeB, mLePtr, mLeStr}
|
||||||
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||||
mLtCh, mLtB, mLtPtr, mLtStr}
|
mLtCh, mLtB, mLtPtr, mLtStr}
|
||||||
|
|
||||||
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
|
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
|
||||||
|
|
@ -44,7 +44,7 @@ proc isLet(n: PNode): bool =
|
||||||
if n.kind == nkSym:
|
if n.kind == nkSym:
|
||||||
if n.sym.kind in {skLet, skTemp, skForVar}:
|
if n.sym.kind in {skLet, skTemp, skForVar}:
|
||||||
result = true
|
result = true
|
||||||
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
||||||
abstractInst).kind != tyVar:
|
abstractInst).kind != tyVar:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ proc neg(n: PNode): PNode =
|
||||||
result.sons[0] = n.sons[0]
|
result.sons[0] = n.sons[0]
|
||||||
result.sons[2] = n.sons[2]
|
result.sons[2] = n.sons[2]
|
||||||
if t.kind == tyEnum:
|
if t.kind == tyEnum:
|
||||||
var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
|
var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
|
||||||
for e in t.n:
|
for e in t.n:
|
||||||
let eAsNode = newIntNode(nkIntLit, e.sym.position)
|
let eAsNode = newIntNode(nkIntLit, e.sym.position)
|
||||||
if not inSet(n.sons[1], eAsNode): s.add eAsNode
|
if not inSet(n.sons[1], eAsNode): s.add eAsNode
|
||||||
|
|
@ -189,13 +189,17 @@ proc zero(): PNode = nkIntLit.newIntNode(0)
|
||||||
proc one(): PNode = nkIntLit.newIntNode(1)
|
proc one(): PNode = nkIntLit.newIntNode(1)
|
||||||
proc minusOne(): PNode = nkIntLit.newIntNode(-1)
|
proc minusOne(): PNode = nkIntLit.newIntNode(-1)
|
||||||
|
|
||||||
proc lowBound*(x: PNode): PNode =
|
proc lowBound*(x: PNode): PNode =
|
||||||
result = nkIntLit.newIntNode(firstOrd(x.typ))
|
result = nkIntLit.newIntNode(firstOrd(x.typ))
|
||||||
result.info = x.info
|
result.info = x.info
|
||||||
|
|
||||||
proc highBound*(x: PNode): PNode =
|
proc highBound*(x: PNode): PNode =
|
||||||
result = if x.typ.skipTypes(abstractInst).kind == tyArray:
|
let typ = x.typ.skipTypes(abstractInst)
|
||||||
nkIntLit.newIntNode(lastOrd(x.typ))
|
result = if typ.kind in {tyArrayConstr, tyArray}:
|
||||||
|
nkIntLit.newIntNode(lastOrd(typ))
|
||||||
|
elif typ.kind == tySequence and x.kind == nkSym and
|
||||||
|
x.sym.kind == skConst:
|
||||||
|
nkIntLit.newIntNode(x.sym.ast.len-1)
|
||||||
else:
|
else:
|
||||||
opAdd.buildCall(opLen.buildCall(x), minusOne())
|
opAdd.buildCall(opLen.buildCall(x), minusOne())
|
||||||
result.info = x.info
|
result.info = x.info
|
||||||
|
|
@ -205,21 +209,32 @@ proc reassociation(n: PNode): PNode =
|
||||||
# (foo+5)+5 --> foo+10; same for '*'
|
# (foo+5)+5 --> foo+10; same for '*'
|
||||||
case result.getMagic
|
case result.getMagic
|
||||||
of someAdd:
|
of someAdd:
|
||||||
if result[2].isValue and
|
if result[2].isValue and
|
||||||
result[1].getMagic in someAdd and result[1][2].isValue:
|
result[1].getMagic in someAdd and result[1][2].isValue:
|
||||||
result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
|
result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
|
||||||
of someMul:
|
of someMul:
|
||||||
if result[2].isValue and
|
if result[2].isValue and
|
||||||
result[1].getMagic in someMul and result[1][2].isValue:
|
result[1].getMagic in someMul and result[1][2].isValue:
|
||||||
result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2])
|
result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2])
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
|
proc pred(n: PNode): PNode =
|
||||||
|
if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
|
||||||
|
result = copyNode(n)
|
||||||
|
dec result.intVal
|
||||||
|
else:
|
||||||
|
result = n
|
||||||
|
|
||||||
proc canon*(n: PNode): PNode =
|
proc canon*(n: PNode): PNode =
|
||||||
# XXX for now only the new code in 'semparallel' uses this
|
# XXX for now only the new code in 'semparallel' uses this
|
||||||
if n.safeLen >= 1:
|
if n.safeLen >= 1:
|
||||||
result = shallowCopy(n)
|
result = shallowCopy(n)
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
result.sons[i] = canon(n.sons[i])
|
result.sons[i] = canon(n.sons[i])
|
||||||
|
elif n.kind == nkSym and n.sym.kind == skLet and
|
||||||
|
n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
|
||||||
|
someMax + someHigh + {mUnaryLt} + someSub + someLen):
|
||||||
|
result = n.sym.ast.copyTree
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
case result.getMagic
|
case result.getMagic
|
||||||
|
|
@ -231,34 +246,40 @@ proc canon*(n: PNode): PNode =
|
||||||
of someHigh:
|
of someHigh:
|
||||||
# high == len+(-1)
|
# high == len+(-1)
|
||||||
result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
|
result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
|
||||||
of mUnaryMinusI, mUnaryMinusI64:
|
of mUnaryLt:
|
||||||
result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1))
|
result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1))
|
||||||
of someSub:
|
of someSub:
|
||||||
# x - 4 --> x + (-4)
|
# x - 4 --> x + (-4)
|
||||||
result = negate(result[1], result[2], result)
|
result = negate(result[1], result[2], result)
|
||||||
of someLen:
|
of someLen:
|
||||||
result.sons[0] = opLen.newSymNode
|
result.sons[0] = opLen.newSymNode
|
||||||
|
of someLt:
|
||||||
|
# x < y same as x <= y-1:
|
||||||
|
let y = n[2].canon
|
||||||
|
let p = pred(y)
|
||||||
|
let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon
|
||||||
|
result = opLe.buildCall(n[1].canon, minus)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
result = skipConv(result)
|
result = skipConv(result)
|
||||||
result = reassociation(result)
|
result = reassociation(result)
|
||||||
# most important rule: (x-4) < a.len --> x < a.len+4
|
# most important rule: (x-4) <= a.len --> x <= a.len+4
|
||||||
case result.getMagic
|
case result.getMagic
|
||||||
of someLe, someLt:
|
of someLe:
|
||||||
let x = result[1]
|
let x = result[1]
|
||||||
let y = result[2]
|
let y = result[2]
|
||||||
if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and
|
if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and
|
||||||
isLetLocation(x[1], true):
|
isLetLocation(x[1], true):
|
||||||
case x.getMagic
|
case x.getMagic
|
||||||
of someSub:
|
of someSub:
|
||||||
result = buildCall(result[0].sym, x[1],
|
result = buildCall(result[0].sym, x[1],
|
||||||
reassociation(opAdd.buildCall(y, x[2])))
|
reassociation(opAdd.buildCall(y, x[2])))
|
||||||
of someAdd:
|
of someAdd:
|
||||||
# Rule A:
|
# Rule A:
|
||||||
let plus = negate(y, x[2], nil).reassociation
|
let plus = negate(y, x[2], nil).reassociation
|
||||||
if plus != nil: result = buildCall(result[0].sym, x[1], plus)
|
if plus != nil: result = buildCall(result[0].sym, x[1], plus)
|
||||||
else: discard
|
else: discard
|
||||||
elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
|
elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
|
||||||
isLetLocation(y[1], true):
|
isLetLocation(y[1], true):
|
||||||
# a.len < x-3
|
# a.len < x-3
|
||||||
case y.getMagic
|
case y.getMagic
|
||||||
|
|
@ -317,7 +338,7 @@ proc usefulFact(n: PNode): PNode =
|
||||||
of mOr:
|
of mOr:
|
||||||
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
|
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
|
||||||
# with that knowledge...
|
# with that knowledge...
|
||||||
# DeMorgan helps a little though:
|
# DeMorgan helps a little though:
|
||||||
# not a or not b --> not (a and b)
|
# not a or not b --> not (a and b)
|
||||||
# (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
|
# (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
|
||||||
# not (x != 3 and y != 2)
|
# not (x != 3 and y != 2)
|
||||||
|
|
@ -348,11 +369,11 @@ proc addFact*(m: var TModel, n: PNode) =
|
||||||
let n = usefulFact(n)
|
let n = usefulFact(n)
|
||||||
if n != nil: m.add n
|
if n != nil: m.add n
|
||||||
|
|
||||||
proc addFactNeg*(m: var TModel, n: PNode) =
|
proc addFactNeg*(m: var TModel, n: PNode) =
|
||||||
let n = n.neg
|
let n = n.neg
|
||||||
if n != nil: addFact(m, n)
|
if n != nil: addFact(m, n)
|
||||||
|
|
||||||
proc sameTree*(a, b: PNode): bool =
|
proc sameTree*(a, b: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
if a == b:
|
if a == b:
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -382,8 +403,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
|
||||||
# 'while p != nil: f(p); p = p.next'
|
# 'while p != nil: f(p); p = p.next'
|
||||||
# This is actually quite easy to do:
|
# This is actually quite easy to do:
|
||||||
# Re-assignments (incl. pass to a 'var' param) trigger an invalidation
|
# Re-assignments (incl. pass to a 'var' param) trigger an invalidation
|
||||||
# of every fact that contains 'v'.
|
# of every fact that contains 'v'.
|
||||||
#
|
#
|
||||||
# if x < 4:
|
# if x < 4:
|
||||||
# if y < 5
|
# if y < 5
|
||||||
# x = unknown()
|
# x = unknown()
|
||||||
|
|
@ -402,16 +423,9 @@ proc valuesUnequal(a, b: PNode): bool =
|
||||||
if a.isValue and b.isValue:
|
if a.isValue and b.isValue:
|
||||||
result = not sameValue(a, b)
|
result = not sameValue(a, b)
|
||||||
|
|
||||||
proc pred(n: PNode): PNode =
|
|
||||||
if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
|
|
||||||
result = copyNode(n)
|
|
||||||
dec result.intVal
|
|
||||||
else:
|
|
||||||
result = n
|
|
||||||
|
|
||||||
proc impliesEq(fact, eq: PNode): TImplication =
|
proc impliesEq(fact, eq: PNode): TImplication =
|
||||||
let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
|
let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
|
||||||
|
|
||||||
case fact.sons[0].sym.magic
|
case fact.sons[0].sym.magic
|
||||||
of someEq:
|
of someEq:
|
||||||
if sameTree(fact.sons[1], eq.sons[loc]):
|
if sameTree(fact.sons[1], eq.sons[loc]):
|
||||||
|
|
@ -428,12 +442,12 @@ proc impliesEq(fact, eq: PNode): TImplication =
|
||||||
else: result = impNo
|
else: result = impNo
|
||||||
of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
|
of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
||||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||||
# fact: x <= 4; question x in {56}?
|
# fact: x <= 4; question x in {56}?
|
||||||
# --> true if every value <= 4 is in the set {56}
|
# --> true if every value <= 4 is in the set {56}
|
||||||
#
|
#
|
||||||
var value = newIntNode(c.kind, firstOrd(x.typ))
|
var value = newIntNode(c.kind, firstOrd(x.typ))
|
||||||
# don't iterate too often:
|
# don't iterate too often:
|
||||||
if c.intVal - value.intVal < 1000:
|
if c.intVal - value.intVal < 1000:
|
||||||
|
|
@ -449,7 +463,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||||
# fact: x >= 4; question x in {56}?
|
# fact: x >= 4; question x in {56}?
|
||||||
# --> true iff every value >= 4 is in the set {56}
|
# --> true iff every value >= 4 is in the set {56}
|
||||||
#
|
#
|
||||||
var value = newIntNode(c.kind, c.intVal)
|
var value = newIntNode(c.kind, c.intVal)
|
||||||
let max = lastOrd(x.typ)
|
let max = lastOrd(x.typ)
|
||||||
# don't iterate too often:
|
# don't iterate too often:
|
||||||
|
|
@ -568,19 +582,19 @@ proc impliesLe(fact, x, c: PNode): TImplication =
|
||||||
# fact: x < 4; question x <= 2? --> we don't know
|
# fact: x < 4; question x <= 2? --> we don't know
|
||||||
elif sameTree(fact.sons[2], x):
|
elif sameTree(fact.sons[2], x):
|
||||||
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
|
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
|
||||||
if isValue(fact.sons[1]) and isValue(c):
|
if isValue(fact.sons[1]) and isValue(c):
|
||||||
if leValue(c, fact.sons[1]): result = impNo
|
if leValue(c, fact.sons[1]): result = impNo
|
||||||
|
|
||||||
of someLe:
|
of someLe:
|
||||||
if sameTree(fact.sons[1], x):
|
if sameTree(fact.sons[1], x):
|
||||||
if isValue(fact.sons[2]) and isValue(c):
|
if isValue(fact.sons[2]) and isValue(c):
|
||||||
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
|
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
|
||||||
if leValue(fact.sons[2], c): result = impYes
|
if leValue(fact.sons[2], c): result = impYes
|
||||||
# fact: x <= 4; question x <= 2? --> we don't know
|
# fact: x <= 4; question x <= 2? --> we don't know
|
||||||
|
|
||||||
elif sameTree(fact.sons[2], x):
|
elif sameTree(fact.sons[2], x):
|
||||||
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
|
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
|
||||||
if isValue(fact.sons[1]) and isValue(c):
|
if isValue(fact.sons[1]) and isValue(c):
|
||||||
if leValue(c, fact.sons[1].pred): result = impNo
|
if leValue(c, fact.sons[1].pred): result = impNo
|
||||||
|
|
||||||
of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
|
of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
|
||||||
|
|
@ -614,7 +628,7 @@ proc factImplies(fact, prop: PNode): TImplication =
|
||||||
# it's provably wrong if every value > 4 is in the set {56}
|
# it's provably wrong if every value > 4 is in the set {56}
|
||||||
# That's because we compute the implication and 'a -> not b' cannot
|
# That's because we compute the implication and 'a -> not b' cannot
|
||||||
# be treated the same as 'not a -> b'
|
# be treated the same as 'not a -> b'
|
||||||
|
|
||||||
# (not a) -> b compute as not (a -> b) ???
|
# (not a) -> b compute as not (a -> b) ???
|
||||||
# == not a or not b == not (a and b)
|
# == not a or not b == not (a and b)
|
||||||
let arg = fact.sons[1]
|
let arg = fact.sons[1]
|
||||||
|
|
@ -635,7 +649,7 @@ proc factImplies(fact, prop: PNode): TImplication =
|
||||||
if result != impUnknown: return result
|
if result != impUnknown: return result
|
||||||
return factImplies(fact.sons[2], prop)
|
return factImplies(fact.sons[2], prop)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
case prop.sons[0].sym.magic
|
case prop.sons[0].sym.magic
|
||||||
of mNot: result = ~fact.factImplies(prop.sons[1])
|
of mNot: result = ~fact.factImplies(prop.sons[1])
|
||||||
of mIsNil: result = impliesIsNil(fact, prop)
|
of mIsNil: result = impliesIsNil(fact, prop)
|
||||||
|
|
@ -671,6 +685,7 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
|
||||||
|
|
||||||
proc ple(m: TModel; a, b: PNode): TImplication =
|
proc ple(m: TModel; a, b: PNode): TImplication =
|
||||||
template `<=?`(a,b): expr = ple(m,a,b) == impYes
|
template `<=?`(a,b): expr = ple(m,a,b) == impYes
|
||||||
|
|
||||||
# 0 <= 3
|
# 0 <= 3
|
||||||
if a.isValue and b.isValue:
|
if a.isValue and b.isValue:
|
||||||
return if leValue(a, b): impYes else: impNo
|
return if leValue(a, b): impYes else: impNo
|
||||||
|
|
@ -744,16 +759,21 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
|
||||||
# mark as used:
|
# mark as used:
|
||||||
m[i] = nil
|
m[i] = nil
|
||||||
if ple(m, a, x) == impYes:
|
if ple(m, a, x) == impYes:
|
||||||
if ple(m, y, b) == impYes: return impYes
|
if ple(m, y, b) == impYes:
|
||||||
|
return impYes
|
||||||
#if pleViaModelRec(m, y, b): return impYes
|
#if pleViaModelRec(m, y, b): return impYes
|
||||||
# fact: 16 <= i
|
# fact: 16 <= i
|
||||||
# x y
|
# x y
|
||||||
# question: i <= 15? no!
|
# question: i <= 15? no!
|
||||||
result = impliesLe(fact, a, b)
|
result = impliesLe(fact, a, b)
|
||||||
if result != impUnknown: return result
|
if result != impUnknown:
|
||||||
if sameTree(y, a):
|
return result
|
||||||
result = ple(m, b, x)
|
when false:
|
||||||
if result != impUnknown: return result
|
# given: x <= y; y==a; x <= a this means: a <= b if x <= b
|
||||||
|
if sameTree(y, a):
|
||||||
|
result = ple(m, b, x)
|
||||||
|
if result != impUnknown:
|
||||||
|
return result
|
||||||
|
|
||||||
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
|
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
|
||||||
# compute replacements:
|
# compute replacements:
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -37,7 +37,7 @@ is valid, but
|
||||||
spawn f(a[i])
|
spawn f(a[i])
|
||||||
spawn f(a[i])
|
spawn f(a[i])
|
||||||
inc i
|
inc i
|
||||||
is not! However,
|
is not! However,
|
||||||
spawn f(a[i])
|
spawn f(a[i])
|
||||||
if guard: inc i
|
if guard: inc i
|
||||||
spawn f(a[i])
|
spawn f(a[i])
|
||||||
|
|
@ -460,7 +460,7 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
|
||||||
# - detect used slices
|
# - detect used slices
|
||||||
# - detect used arguments
|
# - detect used arguments
|
||||||
#echo "PAR ", renderTree(n)
|
#echo "PAR ", renderTree(n)
|
||||||
|
|
||||||
var a = initAnalysisCtx()
|
var a = initAnalysisCtx()
|
||||||
let body = n.lastSon
|
let body = n.lastSon
|
||||||
analyse(a, body)
|
analyse(a, body)
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||||
defs[0] = newSymNode(newVar).PTransNode
|
defs[0] = newSymNode(newVar).PTransNode
|
||||||
defs[1] = it.sons[1].PTransNode
|
defs[1] = it.sons[1].PTransNode
|
||||||
defs[2] = transform(c, it.sons[2])
|
defs[2] = transform(c, it.sons[2])
|
||||||
|
newVar.ast = defs[2].PNode
|
||||||
result[i] = defs
|
result[i] = defs
|
||||||
else:
|
else:
|
||||||
if it.kind != nkVarTuple:
|
if it.kind != nkVarTuple:
|
||||||
|
|
|
||||||
41
tests/parallel/tsimple_array_checks.nim
Normal file
41
tests/parallel/tsimple_array_checks.nim
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# bug #2287
|
||||||
|
|
||||||
|
import threadPool
|
||||||
|
|
||||||
|
# If `nums` is an array instead of seq,
|
||||||
|
# NONE of the iteration ways below work (including high / len-1)
|
||||||
|
let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
||||||
|
proc log(n:int) =
|
||||||
|
echo n
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
parallel:
|
||||||
|
for n in nums: # Error: cannot prove: i <= len(nums) + -1
|
||||||
|
spawn log(n)
|
||||||
|
#for i in 0 .. <nums.len: # Error: cannot prove: i <= len(nums) + -1
|
||||||
|
#for i in 0 .. nums.len-1: # WORKS!
|
||||||
|
#for i in 0 .. <nums.len: # WORKS!
|
||||||
|
# spawn log(nums[i])
|
||||||
|
|
||||||
|
# Array needs explicit size to work, probably related to issue #2287
|
||||||
|
#const a: array[0..5, int] = [1,2,3,4,5,6]
|
||||||
|
|
||||||
|
#const a = [1,2,3,4,5,6] # Doesn't work
|
||||||
|
const a = @[1,2,3,4,5,6] # Doesn't work
|
||||||
|
proc f(n: int) = echo "Hello ", n
|
||||||
|
|
||||||
|
proc maino =
|
||||||
|
parallel:
|
||||||
|
# while loop doesn't work:
|
||||||
|
var i = 0
|
||||||
|
while i < a.high:
|
||||||
|
#for i in countup(0, a.high-1, 2):
|
||||||
|
spawn f(a[i])
|
||||||
|
spawn f(a[i+1])
|
||||||
|
i += 2
|
||||||
|
|
||||||
|
maino() # Doesn't work outside a proc
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
main()
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -54,6 +54,7 @@ Bugs
|
||||||
- VM: ptr/ref T cannot work in general
|
- VM: ptr/ref T cannot work in general
|
||||||
- scopes are still broken for generic instantiation!
|
- scopes are still broken for generic instantiation!
|
||||||
- blocks can "export" an identifier but the CCG generates {} for them ...
|
- blocks can "export" an identifier but the CCG generates {} for them ...
|
||||||
|
- ConcreteTypes in a 'case' means we don't check for duplicated case branches
|
||||||
|
|
||||||
|
|
||||||
version 0.9.x
|
version 0.9.x
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue