summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-10-02 16:45:34 +0300
committerZahary Karadjov <zahary@gmail.com>2012-10-03 01:59:49 +0300
commit9c8bc3a244b4bbcdc56fdd255bb4e1a7ed30f781 (patch)
treec5d561cdd51566a5f46c2c2558b36ffdd24f42b5 /compiler
parent770d4a997eab25a04cdfd83b325491a2e63bea08 (diff)
downloadNim-9c8bc3a244b4bbcdc56fdd255bb4e1a7ed30f781.tar.gz
the `is` operator now works with type classes and type variables
bugfixes:
the DLL tests were failing on Mac OS X, due to an incorrect DynlibFormat
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/evals.nim26
-rwxr-xr-xcompiler/semexprs.nim29
-rwxr-xr-xcompiler/semfold.nim11
-rwxr-xr-xcompiler/semgnrc.nim20
-rwxr-xr-xcompiler/semtypes.nim33
-rwxr-xr-xcompiler/semtypinst.nim3
-rwxr-xr-xcompiler/sigmatch.nim37
-rwxr-xr-xcompiler/types.nim33
8 files changed, 112 insertions, 80 deletions
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 9c73a6b78..0886b1ef5 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -521,7 +521,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
   else: result = nil
   if result == nil or {sfImportc, sfForward} * s.flags != {}:
     result = raiseCannotEval(c, n.info)
-  
+
 proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode = 
   result = evalAux(c, n.sons[1], {efLValue})
   if isSpecial(result): return 
@@ -875,6 +875,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
   else:
     internalAssert false
 
+proc evalIsOp*(n: PNode): PNode =
+  InternalAssert n.sonsLen == 3 and
+    n[1].kind == nkSym and n[1].sym.kind == skType and
+    n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
+  
+  let t1 = n[1].sym.typ
+
+  if n[2].kind in {nkStrLit..nkTripleStrLit}:
+    case n[2].strVal.normalize
+    of "closure":
+      let t = skipTypes(t1, abstractRange)
+      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
+                                        t.callConv == ccClosure))
+  else:
+    let t2 = n[2].typ
+    var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
+                else: sameType(t1, t2)
+    result = newIntNode(nkIntLit, ord(match))
+
+  result.typ = n.typ
+
 proc expectString(n: PNode) =
   if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
     GlobalError(n.info, errStringLiteralExpected)
@@ -968,6 +989,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
   of mTypeTrait:
     n.sons[1] = evalAux(c, n.sons[1], {})
     result = evalTypeTrait(n, c.module)
+  of mIs:
+    n.sons[1] = evalAux(c, n.sons[1], {})
+    result = evalIsOp(n)
   of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
   of mStaticExec:
     let cmd = evalAux(c, n.sons[1], {})
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a658f7f44..51ede1614 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -281,18 +281,29 @@ proc semOf(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyBool)
   result = n
 
-proc semIs(c: PContext, n: PNode): PNode = 
-  if sonsLen(n) == 3:
-    n.typ = getSysType(tyBool)
-    let a = semTypeNode(c, n[1], nil)
-    n.sons[1] = newNodeIT(nkType, n[1].info, a)
-    if n[2].kind notin {nkStrLit..nkTripleStrLit}:
-      let b = semTypeNode(c, n[2], nil)
-      n.sons[2] = newNodeIT(nkType, n[2].info, b)
-  else:
+proc semIs(c: PContext, n: PNode): PNode =
+  if sonsLen(n) != 3:
     LocalError(n.info, errXExpectsTwoArguments, "is")
+
   result = n
+  n.typ = getSysType(tyBool)
+  
+  n.sons[1] = semExprWithType(c, n[1])
+  if n[1].typ.kind != tyTypeDesc:
+    LocalError(n[0].info, errTypeExpected)
 
+  if n[2].kind notin {nkStrLit..nkTripleStrLit}:
+    let t2 = semTypeNode(c, n[2], nil)
+    n.sons[2] = newNodeIT(nkType, n[2].info, t2)
+
+  if n[1].typ.sonsLen == 0:
+    # this is a typedesc variable, leave for evals
+    return
+  else:
+    let t1 = n[1].typ.sons[0]
+    # BUGFIX: don't evaluate this too early: ``T is void``
+    if not containsGenericType(t1): result = evalIsOp(n)
+  
 proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
   for i in countup(1, sonsLen(n) - tailToExclude):
     var a = n.sons[i]
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c2958ca5e..d0805d921 100755
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -610,17 +610,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
           result = newIntNodeT(sonsLen(a), n)
         else:
           result = magicCall(m, n)
-      of mIs:
-        # BUGFIX: don't evaluate this too early: ``T is void``
-        if not containsGenericType(n[1].typ):
-          if n[2].kind in {nkStrLit..nkTripleStrLit}:
-            case n[2].strVal.normalize
-            of "closure":
-              let t = skipTypes(n[1].typ, abstractRange)
-              result = newIntNodeT(ord(t.kind == tyProc and
-                                       t.callConv == ccClosure), n)
-          elif not containsGenericType(n[2].typ):
-            result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
       of mAstToStr:
         result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
       of mConStrStr:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index dde799ab3..bffa8ad8e 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -261,16 +261,16 @@ proc semGenericStmt(c: PContext, n: PNode,
       else: 
         a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
   of nkEnumTy: 
-    checkMinSonsLen(n, 1)
-    if n.sons[0].kind != nkEmpty: 
-      n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
-    for i in countup(1, sonsLen(n) - 1): 
-      var a: PNode
-      case n.sons[i].kind
-      of nkEnumFieldDef: a = n.sons[i].sons[0]
-      of nkIdent: a = n.sons[i]
-      else: illFormedAst(n)
-      addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
+    if n.sonsLen > 0:
+      if n.sons[0].kind != nkEmpty: 
+        n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
+      for i in countup(1, sonsLen(n) - 1): 
+        var a: PNode
+        case n.sons[i].kind
+        of nkEnumFieldDef: a = n.sons[i].sons[0]
+        of nkIdent: a = n.sons[i]
+        else: illFormedAst(n)
+        addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
   of nkObjectTy, nkTupleTy: 
     nil
   of nkFormalParams: 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index eeb48a647..c41727b10 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -799,22 +799,25 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       LocalError(n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
   of nkCallKinds:
-    let op = n.sons[0].ident
-    if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
-      var
-        t1 = semTypeNode(c, n.sons[1], nil)
-        t2 = semTypeNode(c, n.sons[2], nil)
-      if   t1 == nil: 
-        LocalError(n.sons[1].info, errTypeExpected)
-        result = newOrPrevType(tyError, prev, c)
-      elif t2 == nil: 
-        LocalError(n.sons[2].info, errTypeExpected)
-        result = newOrPrevType(tyError, prev, c)
+    if n[0].kind == nkIdent:
+      let op = n.sons[0].ident
+      if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
+        var
+          t1 = semTypeNode(c, n.sons[1], nil)
+          t2 = semTypeNode(c, n.sons[2], nil)
+        if   t1 == nil: 
+          LocalError(n.sons[1].info, errTypeExpected)
+          result = newOrPrevType(tyError, prev, c)
+        elif t2 == nil: 
+          LocalError(n.sons[2].info, errTypeExpected)
+          result = newOrPrevType(tyError, prev, c)
+        else:
+          result = newTypeS(tyTypeClass, c)
+          result.addSonSkipIntLit(t1)
+          result.addSonSkipIntLit(t2)
+          result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
       else:
-        result = newTypeS(tyTypeClass, c)
-        result.addSonSkipIntLit(t1)
-        result.addSonSkipIntLit(t2)
-        result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
+        result = semTypeExpr(c, n)
     else:
       result = semTypeExpr(c, n)
   of nkCurlyExpr:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index d75594dff..70453c6db 100755
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -59,6 +59,7 @@ type
 
 proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
 proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
+proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
 
 proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   result = copyNode(n)
@@ -66,7 +67,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   for i in 0 .. safeLen(n)-1: 
     # XXX HACK: ``f(a, b)``, avoid to instantiate `f` 
     if i == 0: result.add(n[i])
-    else: result.add(prepareNode(cl, n[i]))
+    else: result.add(ReplaceTypeVarsN(cl, n[i]))
 
 proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
   if n == nil: return
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 82a8c9399..8f1ca5f36 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -11,7 +11,7 @@
 ## the call to overloaded procs, generic procs and operators.
 
 import 
-  intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, 
+  intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options
 
 type
@@ -257,37 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
           var y = a.n.sons[i].sym
           if x.name.id != y.name.id: return isNone
 
-proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
-  for i in countup(0, typeClass.sonsLen - 1):
-    let req = typeClass.sons[i]
-    var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
-      
-    if not match:
-      case req.kind
-      of tyGenericBody:
-        if t.kind == tyGenericInst and t.sons[0] == req:
-          match = true
-          put(c.bindings, typeClass, t)
-      of tyTypeClass:
-        match = matchTypeClass(c, req, t) == isGeneric
-      else: nil
-    elif t.kind in {tyObject}:
-      match = sameType(t, req)
-
-    if tfAny in typeClass.flags:
-      if match: return isGeneric
-    else:
-      if not match: return isNone
-
-  # if the loop finished without returning, either all constraints matched
-  # or none of them matched.
-  result = if tfAny in typeClass.flags: isNone else: isGeneric
-
-proc matchTypeClass*(typeClass, typ: PType): bool =
-  var c: TCandidate
-  InitCandidate(c, typeClass)
-  result = matchTypeClass(c, typeClass, typ) == isGeneric
-
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
     result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
@@ -330,6 +299,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         result = isNone
   else: nil
 
+proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
+  result = if matchTypeClass(c.bindings, f, a): isGeneric
+           else: isNone
+
 proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = 
   # is a subtype of f?
   result = isNone
diff --git a/compiler/types.nim b/compiler/types.nim
index b650b49b8..e02d93233 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -904,7 +904,38 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
     if i >= a.sonslen or a.sons[i] == nil: return false
     a = a.sons[i]
   result = a.kind == last
-  
+
+proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
+  for i in countup(0, typeClass.sonsLen - 1):
+    let req = typeClass.sons[i]
+    var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
+      
+    if not match:
+      case req.kind
+      of tyGenericBody:
+        if t.kind == tyGenericInst and t.sons[0] == req:
+          match = true
+          IdTablePut(bindings, typeClass, t)
+      of tyTypeClass:
+        match = matchTypeClass(bindings, req, t)
+      else: nil
+    elif t.kind in {tyObject}:
+      match = sameType(t, req)
+
+    if tfAny in typeClass.flags:
+      if match: return true
+    else:
+      if not match: return false
+
+  # if the loop finished without returning, either all constraints matched
+  # or none of them matched.
+  result = if tfAny in typeClass.flags: false else: true
+
+proc matchTypeClass*(typeClass, typ: PType): bool =
+  var bindings: TIdTable
+  initIdTable(bindings)
+  result = matchTypeClass(bindings, typeClass, typ)
+
 proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the