summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-01-21 12:58:18 +0100
committerAraq <rumpf_a@web.de>2015-01-23 00:36:56 +0100
commit5ae8689b63526e4e898aa08a69c0107662a7349d (patch)
tree07d385d968976b1315ef730b37e27043f5813bea
parentdb4d315cf4f551954ef83067fa967b6a3ef9babb (diff)
downloadNim-5ae8689b63526e4e898aa08a69c0107662a7349d.tar.gz
better error message for 'invalid type'
-rw-r--r--compiler/sem.nim10
-rw-r--r--compiler/semexprs.nim6
-rw-r--r--compiler/semstmts.nim7
-rw-r--r--compiler/types.nim101
-rw-r--r--tests/generics/tgeneric_inheritance.nim2
5 files changed, 67 insertions, 59 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 9ac7ad139..5e7ce6bb7 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -175,9 +175,15 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym
 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.} =
-  if not typeAllowed(typ, skConst):
-    localError(typ.n.info, errXisNoType, typeToString(typ))
+  typeAllowedCheck(typ.n.info, typ, skConst)
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9d9a5a50c..8221ed372 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -214,9 +214,9 @@ proc isCastable(dst, src: PType): bool =
     result = false
   elif srcSize < 0:
     result = false
-  elif not typeAllowed(dst, skParam):
+  elif typeAllowed(dst, skParam) != nil:
     result = false
-  else: 
+  else:
     result = (dstSize >= srcSize) or
         (skipTypes(dst, abstractInst).kind in IntegralTypes) or
         (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
@@ -692,7 +692,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
       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)
     call.add(n.sons[0])
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 3b90337e5..fe12d9610 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -380,8 +380,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       
     # this can only happen for errornous var statements:
     if typ == nil: continue
-    if not typeAllowed(typ, symkind): 
-      localError(a.info, errXisNoType, typeToString(typ))
+    typeAllowedCheck(a.info, typ, symkind)
     var tup = skipTypes(typ, {tyGenericInst})
     if a.kind == nkVarTuple: 
       if tup.kind != tyTuple: 
@@ -456,7 +455,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     if typ == nil:
       localError(a.sons[2].info, errConstExprExpected)
       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))
       continue
     v.typ = typ
@@ -1187,6 +1186,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
+  #echo "semStaticStmt"
+  #writeStackTrace()
   let a = semStmt(c, n.sons[0])
   n.sons[0] = a
   evalStaticStmt(c.module, a, c.p.owner)
diff --git a/compiler/types.nim b/compiler/types.nim
index e7841a9ab..78d390f13 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -85,8 +85,6 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
   # 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
   # at all in this type.
-proc typeAllowed*(t: PType, kind: TSymKind): bool
-# implementation
 
 proc invalidGenericInst(f: PType): bool = 
   result = f.kind == tyGenericInst and lastSon(f) == nil
@@ -1027,22 +1025,21 @@ type
   TTypeAllowedFlags = set[TTypeAllowedFlag]
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
-                    flags: TTypeAllowedFlags = {}): bool
+                    flags: TTypeAllowedFlags = {}): PType
 
 proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
-                     flags: TTypeAllowedFlags = {}): bool =
-  result = true
+                     flags: TTypeAllowedFlags = {}): PType =
   if n != nil: 
     result = typeAllowedAux(marker, n.typ, kind, flags)
     #if not result: debug(n.typ)
-    if result: 
+    if result == nil:
       case n.kind
       of nkNone..nkNilLit: 
         discard
-      else: 
-        for i in countup(0, sonsLen(n) - 1): 
+      else:
+        for i in countup(0, sonsLen(n) - 1):
           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]],
                 last: TTypeKind): bool =
@@ -1054,84 +1051,88 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
   result = a.kind == last
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
-                    flags: TTypeAllowedFlags = {}): bool =
+                    flags: TTypeAllowedFlags = {}): PType =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the
   # evaluation if something is wrong:
-  result = true
+  result = nil
   if typ == nil: return
-  if containsOrIncl(marker, typ.id): return 
+  if containsOrIncl(marker, typ.id): return
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
   case t.kind
   of tyVar:
-    if kind == skConst: return false
+    if kind == skConst: return t
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
     of tyVar: 
-      result = taHeap in flags # ``var var`` is illegal on the heap:
-    of tyOpenArray: 
-      result = kind == skParam and typeAllowedAux(marker, t2, kind, flags)
+      if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
+    of tyOpenArray:
+      if kind != skParam: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
     else:
-      result = kind in {skParam, skResult} and
-               typeAllowedAux(marker, t2, kind, flags)
-  of tyProc: 
+      if kind notin {skParam, skResult}: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
+  of tyProc:
     for i in countup(1, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], skParam, flags)
-      if not result: break 
-    if result and t.sons[0] != nil:
+      if result != nil: break 
+    if result.isNil and t.sons[0] != nil:
       result = typeAllowedAux(marker, t.sons[0], skResult, flags)
   of tyExpr, tyStmt, tyTypeDesc, tyStatic:
-    result = true
+    result = nil
     # XXX er ... no? these should not be allowed!
   of tyEmpty:
-    result = taField in flags
+    if taField notin flags: result = t
   of tyTypeClasses:
-    result = tfGenericTypeParam in t.flags or
-             taField notin flags
+    if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
   of tyGenericBody, tyGenericParam, tyGenericInvokation,
      tyNone, tyForward, tyFromExpr, tyFieldAccessor:
-    result = false
+    result = t
   of tyNil:
-    result = kind == skConst
+    if kind != skConst: result = t
   of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: 
-    result = true
-  of tyOrdinal: 
-    result = kind == skParam
-  of tyGenericInst, tyDistinct: 
+    result = nil
+  of tyOrdinal:
+    if kind != skParam: result = t
+  of tyGenericInst, tyDistinct:
     result = typeAllowedAux(marker, lastSon(t), kind, flags)
-  of tyRange: 
-    result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
-        {tyChar, tyEnum, tyInt..tyFloat128}
-  of tyOpenArray, tyVarargs: 
-    result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
-  of tySequence: 
-    result = t.sons[0].kind == tyEmpty or 
-        typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
+  of tyRange:
+    if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
+        {tyChar, tyEnum, tyInt..tyFloat128}: result = t
+  of tyOpenArray, tyVarargs:
+    if kind != skParam: result = t
+    else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
+  of tySequence:
+    if t.sons[0].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
   of tyArray:
-    result = t.sons[1].kind == tyEmpty or
-        typeAllowedAux(marker, t.sons[1], skVar, flags)
+    if t.sons[1].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[1], skVar, flags)
   of tyRef:
-    if kind == skConst: return false
-    result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
+    if kind == skConst: result = t
+    else: result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
   of tyPtr:
     result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
   of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
     for i in countup(0, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
-      if not result: break
+      if result != nil: break
   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}
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
-      if not result: break
-    if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags)
+      if result != nil: break
+    if result.isNil and t.n != nil:
+      result = typeAllowedNode(marker, t.n, kind, flags)
   of tyProxy:
     # for now same as error node; we say it's a valid type as it should
     # 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()
   result = typeAllowedAux(marker, t, kind, {})
 
diff --git a/tests/generics/tgeneric_inheritance.nim b/tests/generics/tgeneric_inheritance.nim
index 66b5a6c69..432228797 100644
--- a/tests/generics/tgeneric_inheritance.nim
+++ b/tests/generics/tgeneric_inheritance.nim
@@ -1,5 +1,5 @@
 discard """
-  output: '0.0'
+  output: "0.0"
 """
 
 # bug #1919