summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2014-01-24 14:13:32 +0200
committerZahary Karadjov <zahary@gmail.com>2014-01-24 14:13:32 +0200
commita6a18be0899ff0445128c614f285be1924ec5281 (patch)
treea2d49244bded0fbe6c8cbdc3019c26b4cd1d51f3 /compiler
parent3c840102bcb3daca6f7c275c2c21183be7a145cb (diff)
downloadNim-a6a18be0899ff0445128c614f285be1924ec5281.tar.gz
support for parametric user-defined type classes
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim21
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semtypes.nim9
-rw-r--r--compiler/semtypinst.nim5
-rw-r--r--compiler/sigmatch.nim129
-rw-r--r--compiler/types.nim5
6 files changed, 102 insertions, 71 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 0e351a31a..4a3f1e894 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -337,12 +337,20 @@ type
     tyIter, # unused
     tyProxy # used as errornous type (for idetools)
     tyTypeClass
-    tyParametricTypeClass # structured similarly to tyGenericInst
-                          # lastSon is the body of the type class
+    tyBuiltInTypeClass  # Type such as the catch-all object, tuple, seq, etc
+    tyUserTypeClass
+    tyUserTypeClassInst # \
+      # Instance of a parametric user-defined type class.
+      # Structured similarly to tyGenericInst.
+      # tyGenericInst represents concrete types, while
+      # this is still a "generic param" that will bind types
+      # and resolves them during sigmatch and instantiation.
     
-    tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc
-    
-    tyCompositeTypeClass # 
+    tyCompositeTypeClass # Type such as seq[Number]
+                         # The notes for tyUserTypeClassInst apply here as well 
+                         # sons[0]: the original expression used by the user.
+                         # sons[1]: fully expanded and instantiated meta type
+                         # (potentially following aliases)
     
     tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`,
                        # `Sortable and Enumable`, etc
@@ -365,7 +373,8 @@ const
   tyUnknownTypes* = {tyError, tyFromExpr}
 
   tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
-                    tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
+                    tyUserTypeClass, tyUserTypeClassInst,
+                    tyAnd, tyOr, tyNot, tyAnything}
 
   tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
  
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 6e2d777fb..37fdf8b34 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -322,12 +322,12 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
                                         tfIterator in t.flags))
   else:
     var match: bool
-    let t2 = n[2].typ
+    let t2 = n[2].typ.skipTypes({tyTypeDesc})
     case t2.kind
     of tyTypeClasses:
       var m: TCandidate
       initCandidate(c, m, t2)
-      match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
+      match = typeRel(m, t2, t1) != isNone
     of tyOrdinal:
       var m: TCandidate
       initCandidate(c, m, t2)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index d5a938a12..4bcaf55d6 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -710,6 +710,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     result = addImplicitGeneric(result)
   
   of tyGenericInst:
+    if paramType.lastSon.kind == tyUserTypeClass:
+      var cp = copyType(paramType, getCurrOwner(), false)
+      cp.kind = tyUserTypeClassInst
+      return addImplicitGeneric(cp)
+
     for i in 1 .. (paramType.sons.len - 2):
       var lifted = liftingWalk(paramType.sons[i])
       if lifted != nil:
@@ -731,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                                         allowMetaTypes = true)
     result = liftingWalk(expanded)
 
-  of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
+  of tyUserTypeClass, tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
     result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
   
   of tyExpr:
@@ -923,7 +928,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
 
 proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
   # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
-  result = newOrPrevType(tyTypeClass, prev, c)
+  result = newOrPrevType(tyUserTypeClass, prev, c)
   result.n = n
 
   let
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index ac14179cd..a9322c1f4 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -360,7 +360,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       if tfUnresolved in t.flags: result = result.base
     elif t.sonsLen > 0:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
-  
+ 
+  of tyUserTypeClass:
+    result = t
+
   of tyGenericInst:
     result = instCopyType(cl, t)
     for i in 1 .. <result.sonsLen:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index bb70e0d6b..d0a832147 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -399,6 +399,69 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
   else:
     result = isNone
 
+proc matchUserTypeClass*(c: PContext, m: var TCandidate,
+                         ff, a: PType): TTypeRelation =
+  #if f.n == nil:
+  #  let r = typeRel(m, f, a)
+  #  return if r == isGeneric: arg else: nil
+
+  var body = ff.skipTypes({tyUserTypeClassInst})
+
+  # var prev = PType(idTableGet(m.bindings, f))
+  # if prev != nil:
+  #   if sameType(prev, a): return arg
+  #   else: return nil
+
+  # pushInfoContext(arg.info)
+  openScope(c)
+  inc c.inTypeClass
+
+  finally:
+    dec c.inTypeClass
+    closeScope(c)
+
+  if ff.kind == tyUserTypeClassInst:
+    for i in 1 .. <(ff.len - 1):
+      var
+        typeParamName = ff.base.sons[i-1].sym.name
+        typ = ff.sons[i]
+        param = newSym(skType, typeParamName, body.sym, body.sym.info)
+        
+      param.typ = makeTypeDesc(c, typ)
+      addDecl(c, param)
+
+  for param in body.n[0]:
+    var
+      dummyName: PNode
+      dummyType: PType
+    
+    if param.kind == nkVarTy:
+      dummyName = param[0]
+      dummyType = makeVarType(c, a)
+    else:
+      dummyName = param
+      dummyType = a
+
+    internalAssert dummyName.kind == nkIdent
+    var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info)
+    dummyParam.typ = dummyType
+    addDecl(c, dummyParam)
+
+  for stmt in body.n[3]:
+    var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
+    m.errors = bufferedMsgs
+    clearBufferedMsgs()
+    if e == nil: return isNone
+
+    case e.kind
+    of nkReturnStmt: discard
+    of nkTypeSection: discard
+    of nkConstDef: discard
+    else: discard
+  
+  return isGeneric
+  # put(m.bindings, f, a)
+
 proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
   #
@@ -751,6 +814,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       else:
         return isNone
 
+  of tyUserTypeClassInst:
+    considerPreviousT:
+      result = matchUserTypeClass(c.c, c, f, a)
+      if result == isGeneric:
+        put(c.bindings, f, a)
+
   of tyCompositeTypeClass:
     considerPreviousT:
       if typeRel(c, f.sons[1], a) != isNone:
@@ -904,57 +973,6 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       result.typ = getInstantiatedType(c, arg, m, base(f))
     m.baseTypeMatch = true
 
-proc matchUserTypeClass*(c: PContext, m: var TCandidate,
-                         arg: PNode, f, a: PType): PNode =
-  if f.n == nil:
-    let r = typeRel(m, f, a)
-    return if r == isGeneric: arg else: nil
- 
-  var prev = PType(idTableGet(m.bindings, f))
-  if prev != nil:
-    if sameType(prev, a): return arg
-    else: return nil
-
-  # pushInfoContext(arg.info)
-  openScope(c)
-  inc c.inTypeClass
-
-  finally:
-    dec c.inTypeClass
-    closeScope(c)
-
-  for param in f.n[0]:
-    var
-      dummyName: PNode
-      dummyType: PType
-    
-    if param.kind == nkVarTy:
-      dummyName = param[0]
-      dummyType = makeVarType(c, a)
-    else:
-      dummyName = param
-      dummyType = a
-
-    internalAssert dummyName.kind == nkIdent
-    var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info)
-    dummyParam.typ = dummyType
-    addDecl(c, dummyParam)
-
-  for stmt in f.n[3]:
-    var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
-    m.errors = bufferedMsgs
-    clearBufferedMsgs()
-    if e == nil: return nil
-
-    case e.kind
-    of nkReturnStmt: discard
-    of nkTypeSection: discard
-    of nkConstDef: discard
-    else: discard
-  
-  result = arg
-  put(m.bindings, f, a)
-
 proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
                         argSemantized, argOrig: PNode): PNode =
   var
@@ -980,14 +998,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
         else: argType
  
   case fMaybeStatic.kind
-  of tyTypeClass, tyParametricTypeClass:
+  of tyTypeClass:
     if fMaybeStatic.n != nil:
-      let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a)
-      if match != nil:
-        r = isGeneric
-        arg = match
-      else:
-        r = isNone
+      r = matchUserTypeClass(c, m, fMaybeStatic, a)
     else:
       r = typeRel(m, f, a)
   of tyExpr:
diff --git a/compiler/types.nim b/compiler/types.nim
index d7310596f..cc066a36d 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -404,8 +404,9 @@ const
     "float", "float32", "float64", "float128",
     "uint", "uint8", "uint16", "uint32", "uint64",
     "bignum", "const ",
-    "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass",
-    "ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass",
+    "!", "varargs[$1]", "iter[$1]", "Error Type",
+    "TypeClass", "BuiltInTypeClass", "UserTypeClass",
+    "UserTypeClassInst", "CompositeTypeClass",
     "and", "or", "not", "any", "static", "TypeFromExpr"]
 
 proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =