better error message for 'invalid type'

This commit is contained in:
Araq 2015-01-21 12:58:18 +01:00
commit 5ae8689b63
5 changed files with 67 additions and 59 deletions

View file

@ -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

View file

@ -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])

View file

@ -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)

View file

@ -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, {})

View file

@ -1,5 +1,5 @@
discard """ discard """
output: '0.0' output: "0.0"
""" """
# bug #1919 # bug #1919