disallow typedesc in arrays & move existing checks to types.typeAllowedAux (#13261)
* disallow typedesc in arrays and move previous checks to types.typeAllowedAux
This commit is contained in:
parent
579456d520
commit
4c08e64e98
12 changed files with 70 additions and 50 deletions
|
|
@ -233,13 +233,15 @@ proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKi
|
||||||
flags: TTypeAllowedFlags = {}) =
|
flags: TTypeAllowedFlags = {}) =
|
||||||
let t = typeAllowed(typ, kind, flags)
|
let t = typeAllowed(typ, kind, flags)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
|
var err: string
|
||||||
if t == typ:
|
if t == typ:
|
||||||
localError(conf, info, "invalid type: '" & typeToString(typ) &
|
err = "invalid type: '$1' for $2" % [typeToString(typ), toHumanStr(kind)]
|
||||||
"' for " & substr($kind, 2).toLowerAscii)
|
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
|
||||||
|
err &= ". Did you mean to call the $1 with '()'?" % [toHumanStr(typ.owner.kind)]
|
||||||
else:
|
else:
|
||||||
localError(conf, info, "invalid type: '" & typeToString(t) &
|
err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t),
|
||||||
"' in this context: '" & typeToString(typ) &
|
typeToString(typ), toHumanStr(kind)]
|
||||||
"' for " & substr($kind, 2).toLowerAscii)
|
localError(conf, info, err)
|
||||||
|
|
||||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||||
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
|
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,6 @@ const
|
||||||
errRecursiveDependencyX = "recursive dependency: '$1'"
|
errRecursiveDependencyX = "recursive dependency: '$1'"
|
||||||
errRecursiveDependencyIteratorX = "recursion is not supported in iterators: '$1'"
|
errRecursiveDependencyIteratorX = "recursion is not supported in iterators: '$1'"
|
||||||
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 $1 '$2' to '$3'. Did you mean to call the $1 with '()'?"
|
|
||||||
errInvalidTypeDescAssign = "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
|
|
||||||
|
|
||||||
proc semDiscard(c: PContext, n: PNode): PNode =
|
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -491,19 +489,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if a[^2].kind != nkEmpty:
|
if a[^2].kind != nkEmpty:
|
||||||
typ = semTypeNode(c, a[^2], nil)
|
typ = semTypeNode(c, a[^2], nil)
|
||||||
|
|
||||||
|
var typFlags: TTypeAllowedFlags
|
||||||
|
|
||||||
var def: PNode = c.graph.emptyNode
|
var def: PNode = c.graph.emptyNode
|
||||||
if a[^1].kind != nkEmpty:
|
if a[^1].kind != nkEmpty:
|
||||||
def = semExprWithType(c, a[^1], {efAllowDestructor})
|
def = semExprWithType(c, a[^1], {efAllowDestructor})
|
||||||
if def.typ.kind == tyProc and def.kind == nkSym:
|
|
||||||
if def.sym.kind in {skMacro, skTemplate}:
|
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||||
localError(c.config, def.info, errCannotAssignMacroSymbol % [
|
typFlags.incl taIsTemplateOrMacro
|
||||||
if def.sym.kind == skMacro: "macro" else: "template",
|
|
||||||
def.sym.name.s, a[0].ident.s])
|
|
||||||
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:
|
typFlags.incl taProcContextIsNotMacro
|
||||||
localError(c.config, def.info, errInvalidTypeDescAssign)
|
|
||||||
def.typ = errorType(c)
|
|
||||||
|
|
||||||
if typ != nil:
|
if typ != nil:
|
||||||
if typ.isMetaType:
|
if typ.isMetaType:
|
||||||
|
|
@ -534,7 +529,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
|
|
||||||
# this can only happen for errornous var statements:
|
# this can only happen for errornous var statements:
|
||||||
if typ == nil: continue
|
if typ == nil: continue
|
||||||
typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {})
|
|
||||||
|
if c.matchedConcept != nil:
|
||||||
|
typFlags.incl taConcept
|
||||||
|
typeAllowedCheck(c.config, a.info, typ, symkind, typFlags)
|
||||||
|
|
||||||
when false: liftTypeBoundOps(c, typ, a.info)
|
when false: liftTypeBoundOps(c, typ, a.info)
|
||||||
instAllTypeBoundOp(c, a.info)
|
instAllTypeBoundOp(c, a.info)
|
||||||
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
|
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
|
||||||
|
|
@ -642,18 +641,15 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if a[^2].kind != nkEmpty:
|
if a[^2].kind != nkEmpty:
|
||||||
typ = semTypeNode(c, a[^2], nil)
|
typ = semTypeNode(c, a[^2], nil)
|
||||||
|
|
||||||
|
var typFlags: TTypeAllowedFlags
|
||||||
|
|
||||||
# don't evaluate here since the type compatibility check below may add a converter
|
# don't evaluate here since the type compatibility check below may add a converter
|
||||||
var def = semExprWithType(c, a[^1])
|
var def = semExprWithType(c, a[^1])
|
||||||
if def.typ.kind == tyProc and def.kind == nkSym:
|
|
||||||
if def.sym.kind in {skMacro, skTemplate}:
|
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||||
localError(c.config, def.info, errCannotAssignMacroSymbol % [
|
typFlags.incl taIsTemplateOrMacro
|
||||||
if def.sym.kind == skMacro: "macro" else: "template",
|
|
||||||
def.sym.name.s, a[0].ident.s])
|
|
||||||
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:
|
typFlags.incl taProcContextIsNotMacro
|
||||||
localError(c.config, def.info, errInvalidTypeDescAssign)
|
|
||||||
def.typ = errorType(c)
|
|
||||||
|
|
||||||
# check type compatibility between def.typ and typ:
|
# check type compatibility between def.typ and typ:
|
||||||
if typ != nil:
|
if typ != nil:
|
||||||
|
|
@ -670,9 +666,10 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if def == nil:
|
if def == nil:
|
||||||
localError(c.config, a[^1].info, errConstExprExpected)
|
localError(c.config, a[^1].info, errConstExprExpected)
|
||||||
continue
|
continue
|
||||||
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
|
if def.kind != nkNilLit:
|
||||||
localError(c.config, a.info, "invalid type for const: " & typeToString(typ))
|
if c.matchedConcept != nil:
|
||||||
continue
|
typFlags.incl taConcept
|
||||||
|
typeAllowedCheck(c.config, a.info, typ, skConst, typFlags)
|
||||||
|
|
||||||
var b: PNode
|
var b: PNode
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
|
|
|
||||||
|
|
@ -1246,6 +1246,8 @@ type
|
||||||
taConcept,
|
taConcept,
|
||||||
taIsOpenArray,
|
taIsOpenArray,
|
||||||
taNoUntyped
|
taNoUntyped
|
||||||
|
taIsTemplateOrMacro
|
||||||
|
taProcContextIsNotMacro
|
||||||
|
|
||||||
TTypeAllowedFlags* = set[TTypeAllowedFlag]
|
TTypeAllowedFlags* = set[TTypeAllowedFlag]
|
||||||
|
|
||||||
|
|
@ -1307,18 +1309,24 @@ 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}:
|
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
|
||||||
# only closure iterators my be assigned to anything.
|
|
||||||
result = t
|
result = t
|
||||||
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
|
else:
|
||||||
for i in 1..<t.len:
|
if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
|
||||||
if result != nil: break
|
# only closure iterators may be assigned to anything.
|
||||||
result = typeAllowedAux(marker, t[i], skParam, f-{taIsOpenArray})
|
result = t
|
||||||
if result.isNil and t[0] != nil:
|
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
|
||||||
result = typeAllowedAux(marker, t[0], skResult, flags)
|
for i in 1..<t.len:
|
||||||
|
if result != nil: break
|
||||||
|
result = typeAllowedAux(marker, t[i], skParam, f-{taIsOpenArray})
|
||||||
|
if result.isNil and t[0] != nil:
|
||||||
|
result = typeAllowedAux(marker, t[0], skResult, flags)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
# XXX: This is still a horrible idea...
|
if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags:
|
||||||
result = nil
|
result = t
|
||||||
|
else:
|
||||||
|
# XXX: This is still a horrible idea...
|
||||||
|
result = nil
|
||||||
of tyUntyped, tyTyped:
|
of tyUntyped, tyTyped:
|
||||||
if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
|
if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
|
|
@ -1363,7 +1371,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
elif kind in {skVar, skLet}:
|
elif kind in {skVar, skLet}:
|
||||||
result = t[0]
|
result = t[0]
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if t[1].kind != tyEmpty:
|
if t[1].kind == tyTypeDesc:
|
||||||
|
result = t[1]
|
||||||
|
elif t[1].kind != tyEmpty:
|
||||||
result = typeAllowedAux(marker, t[1], kind, flags)
|
result = typeAllowedAux(marker, t[1], kind, flags)
|
||||||
elif kind in {skVar, skLet}:
|
elif kind in {skVar, skLet}:
|
||||||
result = t[1]
|
result = t[1]
|
||||||
|
|
|
||||||
11
tests/array/t9932.nim
Normal file
11
tests/array/t9932.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim check $file"
|
||||||
|
errormsg: "invalid type: 'type int' in this context: 'array[0..0, type int]' for var"
|
||||||
|
nimout: '''
|
||||||
|
t9932.nim(10, 5) Error: invalid type: 'type' in this context: 'array[0..0, type]' for var
|
||||||
|
t9932.nim(11, 5) Error: invalid type: 'type int' in this context: 'array[0..0, type int]' for var
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
var y: array[1,type]
|
||||||
|
var x = [int]
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "cannot assign macro 'm' to 'x1'. Did you mean to call the macro with '()'?"
|
errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe, locks: 0.}' for let. Did you mean to call the macro with '()'?"
|
||||||
line: 9
|
line: 9
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "cannot assign macro 'm' to 'x2'. Did you mean to call the macro with '()'?"
|
errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe, locks: 0.}' for const. Did you mean to call the macro with '()'?"
|
||||||
line: 9
|
line: 9
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: "nim check $file"
|
cmd: "nim check $file"
|
||||||
errormsg: "cannot assign template 'z' to 'y'. Did you mean to call the template with '()'?"
|
errormsg: "invalid type: 'template (args: varargs[string])' for var. Did you mean to call the template with '()'?"
|
||||||
nimout: '''
|
nimout: '''
|
||||||
t12844.nim(11, 11) Error: cannot assign template 'z' to 'x'. Did you mean to call the template with '()'?
|
t12844.nim(11, 7) Error: invalid type: 'template (args: varargs[string])' for const. Did you mean to call the template with '()'?
|
||||||
t12844.nim(12, 9) Error: cannot assign template 'z' to 'y'. Did you mean to call the template with '()'?'''
|
t12844.nim(12, 5) Error: invalid type: 'template (args: varargs[string])' for var. Did you mean to call the template with '()'?'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template z*(args: varargs[string, `$`]) =
|
template z*(args: varargs[string, `$`]) =
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "invalid type for const: seq[SomeRefObj]"
|
errormsg: "invalid type: 'SomeRefObj' in this context: 'seq[SomeRefObj]' for const"
|
||||||
line: 14
|
line: 14
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errmsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
|
errmsg: "invalid type: 'type int' for const"
|
||||||
"""
|
"""
|
||||||
## issue #8610
|
## issue #8610
|
||||||
const Foo = int
|
const Foo = int
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ cmd: "nim check $file"
|
||||||
errmsg: ""
|
errmsg: ""
|
||||||
nimout: '''
|
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(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(17, 7) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for const
|
||||||
ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for var
|
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
|
ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for result
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
|
errormsg: "invalid type: 'type int' for var"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
|
errormsg: "invalid type: 'type Table' for const"
|
||||||
file: "typedescs2.nim"
|
file: "typedescs2.nim"
|
||||||
line: 16
|
line: 16
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue