refactor illegal iterator assignment detection (#12212)

* refactor illegal iterator assignment detection

* delete crappy test
This commit is contained in:
Arne Döring
2019-10-11 08:43:58 +02:00
committed by Andreas Rumpf
parent 245a954b25
commit 7cf3395d85
9 changed files with 54 additions and 54 deletions

View File

@@ -1810,11 +1810,11 @@ template getBody*(s: PSym): PNode = s.ast[bodyPos]
template detailedInfo*(sym: PSym): string =
sym.name.s
proc isInlineIterator*(s: PSym): bool {.inline.} =
s.kind == skIterator and s.typ.callConv != ccClosure
proc isInlineIterator*(typ: PType): bool {.inline.} =
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv != ccClosure
proc isClosureIterator*(s: PSym): bool {.inline.} =
s.kind == skIterator and s.typ.callConv == ccClosure
proc isClosureIterator*(typ: PType): bool {.inline.} =
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure
proc isSinkParam*(s: PSym): bool {.inline.} =
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)

View File

@@ -636,7 +636,7 @@ proc reverseDestroys(destroys: seq[PNode]): seq[PNode] =
result.add destroys[i]
proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n
if sfGeneratedOp in owner.flags or (owner.kind == skIterator and isInlineIterator(owner.typ)): return n
var c: Con
c.owner = owner
c.destroys = newNodeI(nkStmtList, n.info)

View File

@@ -1724,7 +1724,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
result = n
checkSonsLen(n, 1, c.config)
if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or
isClosureIterator(c.p.owner):
isClosureIterator(c.p.owner.typ):
if n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil:
@@ -1771,7 +1771,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
else:
localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
c.p.owner.name.s)
if isInlineIterator(c.p.owner) and c.p.owner.typ.sons[0] != nil and
if isInlineIterator(c.p.owner.typ) and c.p.owner.typ.sons[0] != nil and
c.p.owner.typ.sons[0].kind == tyUntyped:
localError(c.config, c.p.owner.info, errCannotInferReturnType %
c.p.owner.name.s)

View File

@@ -38,7 +38,6 @@ const
errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1"
errCannotAssignMacroSymbol = "cannot assign macro symbol to $1 here. Forgot to invoke the macro with '()'?"
errInvalidTypeDescAssign = "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
errInlineIteratorNotFirstClass = "inline iterators are not first-class / cannot be assigned to variables"
proc semDiscard(c: PContext, n: PNode): PNode =
result = n
@@ -456,9 +455,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if def.sym.kind == skMacro:
localError(c.config, def.info, errCannotAssignMacroSymbol % "variable")
def.typ = errorType(c)
elif isInlineIterator(def.sym):
localError(c.config, def.info, errInlineIteratorNotFirstClass)
def.typ = errorType(c)
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
# prevent the all too common 'var x = int' bug:
localError(c.config, def.info, errInvalidTypeDescAssign)
@@ -601,9 +597,6 @@ proc semConst(c: PContext, n: PNode): PNode =
if def.sym.kind == skMacro:
localError(c.config, def.info, errCannotAssignMacroSymbol % "constant")
def.typ = errorType(c)
elif isInlineIterator(def.sym):
localError(c.config, def.info, errInlineIteratorNotFirstClass)
def.typ = errorType(c)
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
# prevent the all too common 'const x = int' bug:
localError(c.config, def.info, errInvalidTypeDescAssign)
@@ -1589,7 +1582,7 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
let resultType = sysTypeFromName(c.graph, n.info, "NimNode")
addResult(c, resultType, n.info, s.kind)
addResultNode(c, n)
elif s.typ.sons[0] != nil and not isInlineIterator(s):
elif s.typ.sons[0] != nil and not isInlineIterator(s.typ):
addResult(c, s.typ.sons[0], n.info, s.kind)
addResultNode(c, n)
@@ -1969,7 +1962,6 @@ proc determineType(c: PContext, s: PSym) =
proc semIterator(c: PContext, n: PNode): PNode =
# gensym'ed iterator?
let isAnon = n[namePos].kind == nkEmpty
if n[namePos].kind == nkSym:
# gensym'ed iterators might need to become closure iterators:
n[namePos].sym.owner = getCurrOwner(c)
@@ -1983,8 +1975,6 @@ proc semIterator(c: PContext, n: PNode): PNode =
var t = s.typ
if t.sons[0] == nil and s.typ.callConv != ccClosure:
localError(c.config, n.info, "iterator needs a return type")
if isAnon and s.typ.callConv == ccInline:
localError(c.config, n.info, errInlineIteratorNotFirstClass)
# iterators are either 'inline' or 'closure'; for backwards compatibility,
# we require first class iterators to be marked with 'closure' explicitly
# -- at least for 0.9.2.

View File

@@ -1280,10 +1280,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
if kind notin {skParam, skResult}: result = t
else: result = typeAllowedAux(marker, t2, kind, flags)
of tyProc:
if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
# only closure iterators my be assigned to anything.
result = t
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
for i in 1 ..< len(t):
result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray})
if result != nil: break
result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray})
if result.isNil and t.sons[0] != nil:
result = typeAllowedAux(marker, t.sons[0], skResult, flags)
of tyTypeDesc:

View File

@@ -1,27 +0,0 @@
discard """
output: '''(1, 1)
(2, 2)
(3, 3)
@[1, 2, 3, 4]
'''
"""
iterator zip[T1, T2](a: openarray[T1], b: openarray[T2]): iterator() {.inline.} =
let len = min(a.len, b.len)
for i in 0..<len:
echo (a[i], b[i])
proc foo(args: varargs[int]) =
for i in zip(args,args):
discard
foo(1,2,3)
# 10999
proc varargsToSeq(vals: varargs[int32]): seq[int32] =
result = newSeqOfCap[int32](vals.len)
for v in vals:
result.add v
echo varargsToSeq(1, 2, 3, 4)

View File

@@ -0,0 +1,14 @@
discard """
output: '''
@[1, 2, 3, 4]
'''
"""
# issue #10999
proc varargsToSeq(vals: varargs[int32]): seq[int32] =
result = newSeqOfCap[int32](vals.len)
for v in vals:
result.add v
echo varargsToSeq(1, 2, 3, 4)

View File

@@ -0,0 +1,28 @@
discard """
cmd: "nim check $file"
errmsg: ""
nimout: '''
ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for let
ttypeAllowed.nim(17, 7) Error: invalid type for const: iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}
ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for var
ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for result
'''
"""
let f1 = case true
of true: countup[int]
of false: countdown[int]
const f2 = case true
of true: countup[int]
of false: countdown[int]
var f3 = case true
of true: countup[int]
of false: countdown[int]
proc foobar(): auto =
result = case true
of true: countup[int]
of false: countdown[int]

View File

@@ -1,8 +0,0 @@
discard """
errormsg: "inline iterators are not first-class / cannot be assigned to variables"
line: 8
"""
iterator foo: int =
yield 2
let x = foo