better error message for 'invalid type'
This commit is contained in:
parent
db4d315cf4
commit
5ae8689b63
5 changed files with 67 additions and 59 deletions
|
|
@ -175,9 +175,15 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
proc semStmtScope(c: PContext, n: PNode): PNode
|
proc semStmtScope(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
|
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
|
||||||
|
let t = typeAllowed(typ, kind)
|
||||||
|
if t != nil:
|
||||||
|
if t == typ: localError(info, "invalid type: " & typeToString(typ))
|
||||||
|
else: localError(info, "invalid type: " & typeToString(t) &
|
||||||
|
" in this context: " & typeToString(typ))
|
||||||
|
|
||||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||||
if not typeAllowed(typ, skConst):
|
typeAllowedCheck(typ.n.info, typ, skConst)
|
||||||
localError(typ.n.info, errXisNoType, typeToString(typ))
|
|
||||||
|
|
||||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
||||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ proc isCastable(dst, src: PType): bool =
|
||||||
result = false
|
result = false
|
||||||
elif srcSize < 0:
|
elif srcSize < 0:
|
||||||
result = false
|
result = false
|
||||||
elif not typeAllowed(dst, skParam):
|
elif typeAllowed(dst, skParam) != nil:
|
||||||
result = false
|
result = false
|
||||||
else:
|
else:
|
||||||
result = (dstSize >= srcSize) or
|
result = (dstSize >= srcSize) or
|
||||||
|
|
@ -692,7 +692,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
|
if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
|
||||||
return
|
return
|
||||||
|
|
||||||
if n.typ != nil and not typeAllowed(n.typ, skConst): return
|
if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
|
||||||
|
|
||||||
var call = newNodeIT(nkCall, n.info, n.typ)
|
var call = newNodeIT(nkCall, n.info, n.typ)
|
||||||
call.add(n.sons[0])
|
call.add(n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -380,8 +380,7 @@ 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
|
||||||
if not typeAllowed(typ, symkind):
|
typeAllowedCheck(a.info, typ, symkind)
|
||||||
localError(a.info, errXisNoType, typeToString(typ))
|
|
||||||
var tup = skipTypes(typ, {tyGenericInst})
|
var tup = skipTypes(typ, {tyGenericInst})
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
if tup.kind != tyTuple:
|
if tup.kind != tyTuple:
|
||||||
|
|
@ -456,7 +455,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
localError(a.sons[2].info, errConstExprExpected)
|
localError(a.sons[2].info, errConstExprExpected)
|
||||||
continue
|
continue
|
||||||
if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
|
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
|
||||||
localError(a.info, errXisNoType, typeToString(typ))
|
localError(a.info, errXisNoType, typeToString(typ))
|
||||||
continue
|
continue
|
||||||
v.typ = typ
|
v.typ = typ
|
||||||
|
|
@ -1187,6 +1186,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
|
#echo "semStaticStmt"
|
||||||
|
#writeStackTrace()
|
||||||
let a = semStmt(c, n.sons[0])
|
let a = semStmt(c, n.sons[0])
|
||||||
n.sons[0] = a
|
n.sons[0] = a
|
||||||
evalStaticStmt(c.module, a, c.p.owner)
|
evalStaticStmt(c.module, a, c.p.owner)
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,6 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
|
||||||
# this does a complex analysis whether a call to ``objectInit`` needs to be
|
# this does a complex analysis whether a call to ``objectInit`` needs to be
|
||||||
# made or intializing of the type field suffices or if there is no type field
|
# made or intializing of the type field suffices or if there is no type field
|
||||||
# at all in this type.
|
# at all in this type.
|
||||||
proc typeAllowed*(t: PType, kind: TSymKind): bool
|
|
||||||
# implementation
|
|
||||||
|
|
||||||
proc invalidGenericInst(f: PType): bool =
|
proc invalidGenericInst(f: PType): bool =
|
||||||
result = f.kind == tyGenericInst and lastSon(f) == nil
|
result = f.kind == tyGenericInst and lastSon(f) == nil
|
||||||
|
|
@ -1027,22 +1025,21 @@ type
|
||||||
TTypeAllowedFlags = set[TTypeAllowedFlag]
|
TTypeAllowedFlags = set[TTypeAllowedFlag]
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
flags: TTypeAllowedFlags = {}): bool
|
flags: TTypeAllowedFlags = {}): PType
|
||||||
|
|
||||||
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
|
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
|
||||||
flags: TTypeAllowedFlags = {}): bool =
|
flags: TTypeAllowedFlags = {}): PType =
|
||||||
result = true
|
|
||||||
if n != nil:
|
if n != nil:
|
||||||
result = typeAllowedAux(marker, n.typ, kind, flags)
|
result = typeAllowedAux(marker, n.typ, kind, flags)
|
||||||
#if not result: debug(n.typ)
|
#if not result: debug(n.typ)
|
||||||
if result:
|
if result == nil:
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkNone..nkNilLit:
|
of nkNone..nkNilLit:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
result = typeAllowedNode(marker, n.sons[i], kind, flags)
|
result = typeAllowedNode(marker, n.sons[i], kind, flags)
|
||||||
if not result: break
|
if result != nil: break
|
||||||
|
|
||||||
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
last: TTypeKind): bool =
|
last: TTypeKind): bool =
|
||||||
|
|
@ -1054,84 +1051,88 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
result = a.kind == last
|
result = a.kind == last
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
flags: TTypeAllowedFlags = {}): bool =
|
flags: TTypeAllowedFlags = {}): PType =
|
||||||
assert(kind in {skVar, skLet, skConst, skParam, skResult})
|
assert(kind in {skVar, skLet, skConst, skParam, skResult})
|
||||||
# if we have already checked the type, return true, because we stop the
|
# if we have already checked the type, return true, because we stop the
|
||||||
# evaluation if something is wrong:
|
# evaluation if something is wrong:
|
||||||
result = true
|
result = nil
|
||||||
if typ == nil: return
|
if typ == nil: return
|
||||||
if containsOrIncl(marker, typ.id): return
|
if containsOrIncl(marker, typ.id): return
|
||||||
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
|
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyVar:
|
of tyVar:
|
||||||
if kind == skConst: return false
|
if kind == skConst: return t
|
||||||
var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
|
var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
|
||||||
case t2.kind
|
case t2.kind
|
||||||
of tyVar:
|
of tyVar:
|
||||||
result = taHeap in flags # ``var var`` is illegal on the heap:
|
if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
|
||||||
of tyOpenArray:
|
of tyOpenArray:
|
||||||
result = kind == skParam and typeAllowedAux(marker, t2, kind, flags)
|
if kind != skParam: result = t
|
||||||
|
else: result = typeAllowedAux(marker, t2, kind, flags)
|
||||||
else:
|
else:
|
||||||
result = kind in {skParam, skResult} and
|
if kind notin {skParam, skResult}: result = t
|
||||||
typeAllowedAux(marker, t2, kind, flags)
|
else: result = typeAllowedAux(marker, t2, kind, flags)
|
||||||
of tyProc:
|
of tyProc:
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], skParam, flags)
|
result = typeAllowedAux(marker, t.sons[i], skParam, flags)
|
||||||
if not result: break
|
if result != nil: break
|
||||||
if result 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 tyExpr, tyStmt, tyTypeDesc, tyStatic:
|
of tyExpr, tyStmt, tyTypeDesc, tyStatic:
|
||||||
result = true
|
result = nil
|
||||||
# XXX er ... no? these should not be allowed!
|
# XXX er ... no? these should not be allowed!
|
||||||
of tyEmpty:
|
of tyEmpty:
|
||||||
result = taField in flags
|
if taField notin flags: result = t
|
||||||
of tyTypeClasses:
|
of tyTypeClasses:
|
||||||
result = tfGenericTypeParam in t.flags or
|
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
||||||
taField notin flags
|
|
||||||
of tyGenericBody, tyGenericParam, tyGenericInvokation,
|
of tyGenericBody, tyGenericParam, tyGenericInvokation,
|
||||||
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
|
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
|
||||||
result = false
|
result = t
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = kind == skConst
|
if kind != skConst: result = t
|
||||||
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
|
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
|
||||||
result = true
|
result = nil
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
result = kind == skParam
|
if kind != skParam: result = t
|
||||||
of tyGenericInst, tyDistinct:
|
of tyGenericInst, tyDistinct:
|
||||||
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
|
if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
|
||||||
{tyChar, tyEnum, tyInt..tyFloat128}
|
{tyChar, tyEnum, tyInt..tyFloat128}: result = t
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
|
if kind != skParam: result = t
|
||||||
|
else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
result = t.sons[0].kind == tyEmpty or
|
if t.sons[0].kind != tyEmpty:
|
||||||
typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
|
result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
|
||||||
of tyArray:
|
of tyArray:
|
||||||
result = t.sons[1].kind == tyEmpty or
|
if t.sons[1].kind != tyEmpty:
|
||||||
typeAllowedAux(marker, t.sons[1], skVar, flags)
|
result = typeAllowedAux(marker, t.sons[1], skVar, flags)
|
||||||
of tyRef:
|
of tyRef:
|
||||||
if kind == skConst: return false
|
if kind == skConst: result = t
|
||||||
result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
|
else: result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
|
result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
|
||||||
of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
|
of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
||||||
if not result: break
|
if result != nil: break
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
if kind == skConst and t.kind == tyObject: return false
|
if kind == skConst and t.kind == tyObject: return t
|
||||||
let flags = flags+{taField}
|
let flags = flags+{taField}
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
||||||
if not result: break
|
if result != nil: break
|
||||||
if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags)
|
if result.isNil and t.n != nil:
|
||||||
|
result = typeAllowedNode(marker, t.n, kind, flags)
|
||||||
of tyProxy:
|
of tyProxy:
|
||||||
# for now same as error node; we say it's a valid type as it should
|
# for now same as error node; we say it's a valid type as it should
|
||||||
# prevent cascading errors:
|
# prevent cascading errors:
|
||||||
result = true
|
result = nil
|
||||||
|
|
||||||
proc typeAllowed(t: PType, kind: TSymKind): bool =
|
proc typeAllowed*(t: PType, kind: TSymKind): PType =
|
||||||
|
# returns 'nil' on success and otherwise the part of the type that is
|
||||||
|
# wrong!
|
||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
result = typeAllowedAux(marker, t, kind, {})
|
result = typeAllowedAux(marker, t, kind, {})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
output: '0.0'
|
output: "0.0"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #1919
|
# bug #1919
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue