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:
Neelesh Chandola 2020-05-29 15:18:15 +05:30 • committed by GitHub
commit 4c08e64e98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 70 additions and 50 deletions

View file

@ -233,13 +233,15 @@ proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKi
flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, flags)
if t != nil:
var err: string
if t == typ:
localError(conf, info, "invalid type: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
err = "invalid type: '$1' for $2" % [typeToString(typ), toHumanStr(kind)]
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
err &= ". Did you mean to call the $1 with '()'?" % [toHumanStr(typ.owner.kind)]
else:
localError(conf, info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t),
typeToString(typ), toHumanStr(kind)]
localError(conf, info, err)
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(c.config, typ.n.info, typ, skProc)

View file

@ -36,8 +36,6 @@ const
errRecursiveDependencyX = "recursive dependency: '$1'"
errRecursiveDependencyIteratorX = "recursion is not supported in iterators: '$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 =
result = n
@ -491,19 +489,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
var typFlags: TTypeAllowedFlags
var def: PNode = c.graph.emptyNode
if a[^1].kind != nkEmpty:
def = semExprWithType(c, a[^1], {efAllowDestructor})
if def.typ.kind == tyProc and def.kind == nkSym:
if def.sym.kind in {skMacro, skTemplate}:
localError(c.config, def.info, errCannotAssignMacroSymbol % [
if def.sym.kind == skMacro: "macro" else: "template",
def.sym.name.s, a[0].ident.s])
def.typ = errorType(c)
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
typFlags.incl taIsTemplateOrMacro
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)
def.typ = errorType(c)
typFlags.incl taProcContextIsNotMacro
if typ != nil:
if typ.isMetaType:
@ -534,7 +529,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
# this can only happen for errornous var statements:
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)
instAllTypeBoundOp(c, a.info)
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
@ -642,18 +641,15 @@ proc semConst(c: PContext, n: PNode): PNode =
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
var typFlags: TTypeAllowedFlags
# don't evaluate here since the type compatibility check below may add a converter
var def = semExprWithType(c, a[^1])
if def.typ.kind == tyProc and def.kind == nkSym:
if def.sym.kind in {skMacro, skTemplate}:
localError(c.config, def.info, errCannotAssignMacroSymbol % [
if def.sym.kind == skMacro: "macro" else: "template",
def.sym.name.s, a[0].ident.s])
def.typ = errorType(c)
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
typFlags.incl taIsTemplateOrMacro
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)
def.typ = errorType(c)
typFlags.incl taProcContextIsNotMacro
# check type compatibility between def.typ and typ:
if typ != nil:
@ -670,9 +666,10 @@ proc semConst(c: PContext, n: PNode): PNode =
if def == nil:
localError(c.config, a[^1].info, errConstExprExpected)
continue
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
localError(c.config, a.info, "invalid type for const: " & typeToString(typ))
continue
if def.kind != nkNilLit:
if c.matchedConcept != nil:
typFlags.incl taConcept
typeAllowedCheck(c.config, a.info, typ, skConst, typFlags)
var b: PNode
if a.kind == nkVarTuple:

View file

@ -1246,6 +1246,8 @@ type
taConcept,
taIsOpenArray,
taNoUntyped
taIsTemplateOrMacro
taProcContextIsNotMacro
TTypeAllowedFlags* = set[TTypeAllowedFlag]
@ -1307,18 +1309,24 @@ 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.
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
result = t
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: 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)
else:
if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
# only closure iterators may be assigned to anything.
result = t
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: 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:
# XXX: This is still a horrible idea...
result = nil
if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags:
result = t
else:
# XXX: This is still a horrible idea...
result = nil
of tyUntyped, tyTyped:
if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
of tyStatic:
@ -1363,7 +1371,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
elif kind in {skVar, skLet}:
result = t[0]
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)
elif kind in {skVar, skLet}:
result = t[1]