mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-13 06:43:52 +00:00
refactor illegal iterator assignment detection (#12212)
* refactor illegal iterator assignment detection * delete crappy test
This commit is contained in:
committed by
Andreas Rumpf
parent
245a954b25
commit
7cf3395d85
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user