summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2013-12-25 19:25:04 +0200
committerZahary Karadjov <zahary@gmail.com>2013-12-25 19:25:04 +0200
commit1d02f2ea531ad14f686a75c30af9228ba84fa194 (patch)
tree086123d4040d4de250147ae0faae4bc1c5e4e325
parent299cefdc984ef756ffb8dabb4e961a8d2505104f (diff)
downloadNim-1d02f2ea531ad14f686a75c30af9228ba84fa194.tar.gz
wip type class reforms (the compiler bootstraps fine)
* replace tfAny and tfAll with tyAnd and tyOr
* integrate matchTypeClass into typeRel
* introduce tyBuiltInTypeClass to handle types such as tuple, object, proc, etc
-rw-r--r--compiler/ast.nim8
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/semdata.nim15
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semtypes.nim53
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/sigmatch.nim40
-rw-r--r--compiler/types.nim71
8 files changed, 94 insertions, 99 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 462bad24f..64f959fe2 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -339,6 +339,7 @@ type
     tyTypeClass
     tyParametricTypeClass # structured similarly to tyGenericInst
                           # lastSon is the body of the type class
+    tyBuiltInTypeClass
     tyAnd
     tyOr
     tyNot
@@ -349,7 +350,8 @@ const
   tyPureObject* = tyTuple
   GcTypeKinds* = {tyRef, tySequence, tyString}
   tyError* = tyProxy # as an errornous node should match everything
-  tyTypeClasses* = {tyTypeClass, tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
+  tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass,
+                    tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
 
 type
   TTypeKinds* = set[TTypeKind]
@@ -384,9 +386,6 @@ type
                       # proc foo(T: typedesc, list: seq[T]): var T
     tfRetType,        # marks return types in proc (used to detect type classes 
                       # used as return types for return type inference)
-    tfAll,            # type class requires all constraints to be met (default)
-    tfAny,            # type class requires any constraint to be met
-    tfNot,            # type class with a negative check
     tfCapturesEnv,    # whether proc really captures some environment
     tfByCopy,         # pass object/tuple by copy (C backend)
     tfByRef,          # pass object/tuple by reference (C backend)
@@ -399,6 +398,7 @@ type
     tfHasShared,      # type constains a "shared" constraint modifier somewhere
     tfHasMeta,        # type has "typedesc" or "expr" somewhere; or uses '|'
     tfHasGCedMem,     # type contains GC'ed memory
+    tfGenericTypeParam
 
   TTypeFlags* = set[TTypeFlag]
 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 895ba71f3..9c24295a6 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -643,6 +643,8 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
 proc toFileLineCol*(info: TLineInfo): string {.inline.} =
   result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
 
+template `$`*(info: TLineInfo): expr = toFileLineCol(info)
+
 proc `??`* (info: TLineInfo, filename: string): bool =
   # only for debugging purposes
   result = filename in info.toFilename
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index d02359d4c..1984bfccb 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -213,6 +213,21 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
   let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
   return newSymNode(sym, info)
 
+proc makeAndType*(c: PContext, t1, t2: PType): PType =
+  result = newTypeS(tyAnd, c)
+  result.sons = @[t1, t2]
+  result.flags.incl tfHasMeta
+
+proc makeOrType*(c: PContext, t1, t2: PType): PType =
+  result = newTypeS(tyOr, c)
+  result.sons = @[t1, t2]
+  result.flags.incl tfHasMeta
+
+proc makeNotType*(c: PContext, t1: PType): PType =
+  result = newTypeS(tyNot, c)
+  result.sons = @[t1]
+  result.flags.incl tfHasMeta
+
 proc newTypeS(kind: TTypeKind, c: PContext): PType = 
   result = newType(kind, getCurrOwner())
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 67373c303..fde09400d 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1163,7 +1163,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     if lhsIsResult:
       n.typ = EnforceVoidContext
       if lhs.sym.typ.kind == tyGenericParam:
-        if matchTypeClass(lhs.typ, rhs.typ):
+        if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric:
           InternalAssert c.p.resultSym != nil
           lhs.typ = rhs.typ
           c.p.resultSym.typ = rhs.typ
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 7e76e950b..17b7687b4 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -18,7 +18,7 @@ proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
     if result.kind == tyForward: result.kind = kind
 
 proc newConstraint(c: PContext, k: TTypeKind): PType = 
-  result = newTypeS(tyTypeClass, c)
+  result = newTypeS(tyBuiltInTypeClass, c)
   result.addSonSkipIntLit(newTypeS(k, c))
 
 proc semEnum(c: PContext, n: PNode, prev: PType): PType =
@@ -603,6 +603,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
     let finalTypId = if typId != nil: typId
                      else: getIdent(paramName & ":type")
+    if genericParams == nil:
+      # This happens with anonymous proc types appearing in signatures
+      # XXX: we need to lift these earlier
+      return
     # is this a bindOnce type class already present in the param list?
     for i in countup(0, genericParams.len - 1):
       if genericParams.sons[i].sym.name.id == finalTypId.id:
@@ -674,7 +678,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
         paramType.sons[i] = lifted
         result = paramType
 
-    if paramType.lastSon.kind == tyTypeClass:
+    if paramType.lastSon.kind == tyTypeClass and false:
       result = paramType
       result.kind = tyParametricTypeClass
       result = addImplicitGeneric(copyType(result,
@@ -682,10 +686,16 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     elif result != nil:
       result.kind = tyGenericInvokation
       result.sons.setLen(result.sons.len - 1)
-  of tyTypeClass:
+  of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
     result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false))
   of tyExpr:
     result = addImplicitGeneric(newTypeS(tyGenericParam, c))
+  of tyGenericParam:
+    if tfGenericTypeParam in paramType.flags and false:
+      if paramType.sonsLen > 0:
+        result = liftingWalk(paramType.lastSon)
+      else:
+        result = addImplicitGeneric(newTypeS(tyGenericParam, c))
   else: nil
 
   # result = liftingWalk(paramType)
@@ -917,24 +927,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         var
           t1 = semTypeNode(c, n.sons[1], nil)
           t2 = semTypeNode(c, n.sons[2], nil)
-        if t1 == nil: 
+        if t1 == nil:
           LocalError(n.sons[1].info, errTypeExpected)
           result = newOrPrevType(tyError, prev, c)
-        elif t2 == nil: 
+        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)
-          result.flags.incl(tfHasMeta)
+          result = if op.id == ord(wAnd): makeAndType(c, t1, t2)
+                   else: makeOrType(c, t1, t2)
       elif op.id == ord(wNot):
-        checkSonsLen(n, 3)
-        result = semTypeNode(c, n.sons[1], prev)
-        if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
-          result = freshType(result, prev)
-          result.flags.incl(tfNotNil)
+        case n.len
+        of 3:
+          result = semTypeNode(c, n.sons[1], prev)
+          if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
+            result = freshType(result, prev)
+            result.flags.incl(tfNotNil)
+          else:
+            LocalError(n.info, errGenerated, "invalid type")
+        of 2:
+          let negated = semTypeNode(c, n.sons[1], prev)
+          result = makeNotType(c, negated)
         else:
           LocalError(n.info, errGenerated, "invalid type")
       else:
@@ -1088,11 +1101,7 @@ proc processMagicType(c: PContext, m: PSym) =
   else: LocalError(m.info, errTypeExpected)
   
 proc semGenericConstraints(c: PContext, x: PType): PType =
-  if x.kind in StructuralEquivTypes and (
-      sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
-    result = newConstraint(c, x.kind)
-  else:
-    result = newTypeWithSons(c, tyGenericParam, @[x])
+  result = newTypeWithSons(c, tyGenericParam, @[x])
 
 proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
   result = copyNode(n)
@@ -1127,7 +1136,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
     
     if typ == nil:
       typ = newTypeS(tyGenericParam, c)
-    
+
+    typ.flags.incl tfGenericTypeParam
+
     for j in countup(0, L-3):
       let finalType = if j == 0: typ
                       else: copyType(typ, typ.owner, false)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index d05d063aa..f23d87763 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -19,7 +19,7 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
 
 proc checkConstructedType*(info: TLineInfo, typ: PType) = 
   var t = typ.skipTypes({tyDistinct})
-  if t.kind in {tyTypeClass}: nil
+  if t.kind in tyTypeClasses: nil
   elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: 
     LocalError(info, errInvalidPragmaX, "acyclic")
   elif t.kind == tyVar and t.sons[0].kind == tyVar: 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 42eefec5a..03c37438c 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -370,10 +370,6 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyNil: result = f.allowsNil
   else: nil
 
-proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
-  result = if matchTypeClass(c.bindings, f, a): isGeneric
-           else: isNone
-
 proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
   let
     a0 = firstOrd(a)
@@ -406,7 +402,7 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
   # order to give preferrence to the most specific one:
   #
   # seq[seq[any]] is a strict subset of seq[any] and hence more specific.
-  
+
   result = isNone
   assert(f != nil)
   assert(a != nil)
@@ -462,10 +458,10 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
   else: nil
 
   case f.kind
-  of tyEnum: 
+  of tyEnum:
     if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
     elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype
-  of tyBool, tyChar: 
+  of tyBool, tyChar:
     if a.kind == f.kind: result = isEqual
     elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
   of tyRange:
@@ -706,7 +702,20 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
       return isGeneric
     else:
       return typeRel(c, prev, a)
-    
+
+  of tyBuiltInTypeClass:
+    var prev = PType(idTableGet(c.bindings, f))
+    if prev == nil:
+      let targetKind = f.sons[0].kind
+      if targetKind == a.skipTypes({tyRange}).kind or
+         (targetKind in {tyProc, tyPointer} and a.kind == tyNil):
+        put(c.bindings, f, a)
+        return isGeneric
+      else:
+        return isNone
+    else:
+      result = typeRel(c, prev, a)
+
   of tyGenericParam, tyTypeClass:
     var x = PType(idTableGet(c.bindings, f))
     if x == nil:
@@ -727,11 +736,11 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
         else:
           result = isNone
       else:
-        if a.kind == tyTypeClass:
-          result = isGeneric
+        if f.sonsLen > 0:
+          result = typeRel(c, f.lastSon, a)
         else:
-          result = matchTypeClass(c, f, a)
-        
+          result = isGeneric
+
       if result == isGeneric:
         var concrete = concreteType(c, a)
         if concrete == nil:
@@ -751,7 +760,7 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
         if f.sonsLen == 0:
           result = isGeneric
         else:
-          result = matchTypeClass(c, f, a.sons[0])
+          result = typeRel(c, f, a.sons[0])
         if result == isGeneric:
           put(c.bindings, f, a)
       else:
@@ -911,9 +920,8 @@ proc ParamTypesMatchAux(m: var TCandidate, f, argType: PType,
       InternalAssert a.len > 0
       r = typeRel(m, f.lastSon, a.lastSon)
     else:
-      let match = matchTypeClass(m.bindings, fMaybeStatic, a)
-      if not match: r = isNone
-      else:
+      r = typeRel(m, fMaybeStatic, a)
+      if r != isNone:
         # XXX: Ideally, this should happen much earlier somewhere near 
         # semOpAux, but to do that, we need to be able to query the 
         # overload set to determine whether compile-time value is expected
diff --git a/compiler/types.nim b/compiler/types.nim
index 5fe128bbb..872834810 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -409,18 +409,8 @@ const
     "uint", "uint8", "uint16", "uint32", "uint64",
     "bignum", "const ",
     "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass",
-    "ParametricTypeClass", "and", "or", "not", "any", "static"]
-
-proc consToStr(t: PType): string =
-  if t.len > 0: result = t.typeToString
-  else: result = typeToStr[t.kind].strip
-
-proc constraintsToStr(t: PType): string =
-  let sep = if tfAny in t.flags: " or " else: " and "
-  result = ""
-  for i in countup(0, t.len - 1):
-    if i > 0: result.add(sep)
-    result.add(t.sons[i].consToStr)
+    "ParametricTypeClass", "BuiltInTypeClass",
+    "and", "or", "not", "any", "static"]
 
 proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   var t = typ
@@ -444,19 +434,24 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     add(result, ']')
   of tyTypeDesc:
     if t.len == 0: result = "typedesc"
-    else: result = "typedesc[" & constraintsToStr(t) & "]"
+    else: result = "typedesc[" & typeToString(t) & "]"
   of tyStatic:
     InternalAssert t.len > 0
-    result = "static[" & constraintsToStr(t) & "]"
+    result = "static[" & typeToString(t) & "]"
   of tyTypeClass:
-    if t.n != nil: return t.sym.owner.name.s
-    case t.len
-    of 0: result = "typeclass[]"
-    of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
-    else: result = constraintsToStr(t)
+    InternalAssert t.sym != nil and t.sym.owner != nil
+    return t.sym.owner.name.s
+  of tyBuiltInTypeClass:
+    return "TypeClass"
+  of tyAnd:
+    result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
+  of tyOr:
+    result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
+  of tyNot:
+    result = "not " & typeToString(t.sons[0])
   of tyExpr:
     if t.len == 0: result = "expr"
-    else: result = "expr[" & constraintsToStr(t) & "]"
+    else: result = "expr[" & typeToString(t) & "]"
   of tyArray: 
     if t.sons[0].kind == tyRange: 
       result = "array[" & rangeToStr(t.sons[0].n) & ", " &
@@ -978,42 +973,6 @@ proc isGenericAlias*(t: PType): bool =
 proc skipGenericAlias*(t: PType): PType =
   return if t.isGenericAlias: t.lastSon else: t
 
-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)
-      elif t.kind == tyTypeClass:
-        match = matchTypeClass(bindings, t, req)
-          
-    elif t.kind in {tyObject} and req.len != 0:
-      # empty 'object' is fine as constraint in a type class
-      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
-  if result == true:
-    IdTablePut(bindings, typeClass, t)
-
-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,
                     flags: TTypeAllowedFlags = {}): bool =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})