refactor illegal iterator assignment detection (#12212)
* refactor illegal iterator assignment detection * delete crappy test
This commit is contained in:
parent
245a954b25
commit
7cf3395d85
9 changed files with 54 additions and 54 deletions
|
|
@ -1810,11 +1810,11 @@ template getBody*(s: PSym): PNode = s.ast[bodyPos]
|
||||||
template detailedInfo*(sym: PSym): string =
|
template detailedInfo*(sym: PSym): string =
|
||||||
sym.name.s
|
sym.name.s
|
||||||
|
|
||||||
proc isInlineIterator*(s: PSym): bool {.inline.} =
|
proc isInlineIterator*(typ: PType): bool {.inline.} =
|
||||||
s.kind == skIterator and s.typ.callConv != ccClosure
|
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv != ccClosure
|
||||||
|
|
||||||
proc isClosureIterator*(s: PSym): bool {.inline.} =
|
proc isClosureIterator*(typ: PType): bool {.inline.} =
|
||||||
s.kind == skIterator and s.typ.callConv == ccClosure
|
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure
|
||||||
|
|
||||||
proc isSinkParam*(s: PSym): bool {.inline.} =
|
proc isSinkParam*(s: PSym): bool {.inline.} =
|
||||||
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)
|
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)
|
||||||
|
|
|
||||||
|
|
@ -636,7 +636,7 @@ proc reverseDestroys(destroys: seq[PNode]): seq[PNode] =
|
||||||
result.add destroys[i]
|
result.add destroys[i]
|
||||||
|
|
||||||
proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
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
|
var c: Con
|
||||||
c.owner = owner
|
c.owner = owner
|
||||||
c.destroys = newNodeI(nkStmtList, n.info)
|
c.destroys = newNodeI(nkStmtList, n.info)
|
||||||
|
|
|
||||||
|
|
@ -1724,7 +1724,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1, c.config)
|
checkSonsLen(n, 1, c.config)
|
||||||
if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or
|
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:
|
if n.sons[0].kind != nkEmpty:
|
||||||
# transform ``return expr`` to ``result = expr; return``
|
# transform ``return expr`` to ``result = expr; return``
|
||||||
if c.p.resultSym != nil:
|
if c.p.resultSym != nil:
|
||||||
|
|
@ -1771,7 +1771,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
|
localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
|
||||||
c.p.owner.name.s)
|
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:
|
c.p.owner.typ.sons[0].kind == tyUntyped:
|
||||||
localError(c.config, c.p.owner.info, errCannotInferReturnType %
|
localError(c.config, c.p.owner.info, errCannotInferReturnType %
|
||||||
c.p.owner.name.s)
|
c.p.owner.name.s)
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ const
|
||||||
errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1"
|
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 '()'?"
|
errCannotAssignMacroSymbol = "cannot assign macro symbol to $1 here. Forgot to invoke the macro with '()'?"
|
||||||
errInvalidTypeDescAssign = "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
|
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 =
|
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -456,9 +455,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if def.sym.kind == skMacro:
|
if def.sym.kind == skMacro:
|
||||||
localError(c.config, def.info, errCannotAssignMacroSymbol % "variable")
|
localError(c.config, def.info, errCannotAssignMacroSymbol % "variable")
|
||||||
def.typ = errorType(c)
|
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:
|
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
||||||
# prevent the all too common 'var x = int' bug:
|
# prevent the all too common 'var x = int' bug:
|
||||||
localError(c.config, def.info, errInvalidTypeDescAssign)
|
localError(c.config, def.info, errInvalidTypeDescAssign)
|
||||||
|
|
@ -601,9 +597,6 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if def.sym.kind == skMacro:
|
if def.sym.kind == skMacro:
|
||||||
localError(c.config, def.info, errCannotAssignMacroSymbol % "constant")
|
localError(c.config, def.info, errCannotAssignMacroSymbol % "constant")
|
||||||
def.typ = errorType(c)
|
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:
|
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
||||||
# prevent the all too common 'const x = int' bug:
|
# prevent the all too common 'const x = int' bug:
|
||||||
localError(c.config, def.info, errInvalidTypeDescAssign)
|
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")
|
let resultType = sysTypeFromName(c.graph, n.info, "NimNode")
|
||||||
addResult(c, resultType, n.info, s.kind)
|
addResult(c, resultType, n.info, s.kind)
|
||||||
addResultNode(c, n)
|
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)
|
addResult(c, s.typ.sons[0], n.info, s.kind)
|
||||||
addResultNode(c, n)
|
addResultNode(c, n)
|
||||||
|
|
||||||
|
|
@ -1969,7 +1962,6 @@ proc determineType(c: PContext, s: PSym) =
|
||||||
|
|
||||||
proc semIterator(c: PContext, n: PNode): PNode =
|
proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
# gensym'ed iterator?
|
# gensym'ed iterator?
|
||||||
let isAnon = n[namePos].kind == nkEmpty
|
|
||||||
if n[namePos].kind == nkSym:
|
if n[namePos].kind == nkSym:
|
||||||
# gensym'ed iterators might need to become closure iterators:
|
# gensym'ed iterators might need to become closure iterators:
|
||||||
n[namePos].sym.owner = getCurrOwner(c)
|
n[namePos].sym.owner = getCurrOwner(c)
|
||||||
|
|
@ -1983,8 +1975,6 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
if t.sons[0] == nil and s.typ.callConv != ccClosure:
|
if t.sons[0] == nil and s.typ.callConv != ccClosure:
|
||||||
localError(c.config, n.info, "iterator needs a return type")
|
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,
|
# iterators are either 'inline' or 'closure'; for backwards compatibility,
|
||||||
# we require first class iterators to be marked with 'closure' explicitly
|
# we require first class iterators to be marked with 'closure' explicitly
|
||||||
# -- at least for 0.9.2.
|
# -- at least for 0.9.2.
|
||||||
|
|
|
||||||
|
|
@ -1280,10 +1280,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
if kind notin {skParam, skResult}: result = t
|
if kind notin {skParam, skResult}: result = t
|
||||||
else: result = typeAllowedAux(marker, t2, kind, flags)
|
else: result = typeAllowedAux(marker, t2, kind, flags)
|
||||||
of tyProc:
|
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
|
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
|
||||||
for i in 1 ..< len(t):
|
for i in 1 ..< len(t):
|
||||||
result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray})
|
|
||||||
if result != nil: break
|
if result != nil: break
|
||||||
|
result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray})
|
||||||
if result.isNil and t.sons[0] != nil:
|
if result.isNil and t.sons[0] != nil:
|
||||||
result = typeAllowedAux(marker, t.sons[0], skResult, flags)
|
result = typeAllowedAux(marker, t.sons[0], skResult, flags)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
14
tests/ccgbugs/tccgissues.nim
Normal file
14
tests/ccgbugs/tccgissues.nim
Normal 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)
|
||||||
28
tests/errmsgs/ttypeAllowed.nim
Normal file
28
tests/errmsgs/ttypeAllowed.nim
Normal 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]
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue