summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2013-05-26 11:14:03 +0300
committerZahary Karadjov <zahary@gmail.com>2013-05-26 13:59:39 +0300
commit46813bbe4e1423181521d4792b9af7593f48fa1f (patch)
tree8a56266270506f483ba93c71ac34d491b6f2e4dd /compiler
parentbfff1ac8b2435595351194f6c4b1268d38301401 (diff)
downloadNim-46813bbe4e1423181521d4792b9af7593f48fa1f.tar.gz
static and default params for generics
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/semstmts.nim3
-rw-r--r--compiler/semtypes.nim129
-rw-r--r--compiler/sigmatch.nim19
4 files changed, 92 insertions, 61 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index e35bf25ef..174c3f94b 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -674,6 +674,8 @@ type
                               # for record types a nkRecord node
                               # for enum types a list of symbols
                               # for tyInt it can be the int literal
+                              # for procs and tyGenericBody, it's the
+                              # formal param list
                               # else: unused
     destructor*: PSym         # destructor. warning: nil here may not necessary
                               # mean that there is no destructor.
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index b63c20548..9ae8aaca6 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -710,7 +710,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       #   TGObj[T] = object
       #   TAlias[T] = TGObj[T]
       # 
-      a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
+      s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
+      a.sons[1] = s.typ.n
       s.typ.size = -1 # could not be computed properly
       # we fill it out later. For magic generics like 'seq', it won't be filled
       # so we use tyEmpty instead of nil to not crash for strange conversions
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index c975abb26..351794435 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -794,29 +794,44 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
 
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 
   result = newOrPrevType(tyGenericInvokation, prev, c)
-  var isConcrete = true
+  addSonSkipIntLit(result, s.typ)
+  
+  template addToResult(typ) =
+    if typ.isNil:
+      InternalAssert false
+      rawAddSon(result, typ)
+    else: addSonSkipIntLit(result, typ)
+
   if s.typ == nil:
     LocalError(n.info, errCannotInstantiateX, s.name.s)
     return newOrPrevType(tyError, prev, c)
-  elif s.typ.kind != tyGenericBody:
-    isConcrete = false
-  elif sonsLen(n) != sonsLen(s.typ): 
-    LocalError(n.info, errWrongNumberOfArguments)
-    return newOrPrevType(tyError, prev, c)
-  addSonSkipIntLit(result, s.typ)
-  # iterate over arguments:
-  for i in countup(1, sonsLen(n)-1):
-    var elem = semGenericParamInInvokation(c, n.sons[i])
-    if containsGenericType(elem): isConcrete = false
-    #if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
-    if elem.isNil: rawAddSon(result, elem)
-    else: addSonSkipIntLit(result, elem)
-  if isConcrete:
-    if s.ast == nil: 
-      LocalError(n.info, errCannotInstantiateX, s.name.s)
-      result = newOrPrevType(tyError, prev, c)
-    else:
-      result = instGenericContainer(c, n, result)
+  elif s.typ.kind == tyForward:
+    for i in countup(1, sonsLen(n)-1):
+      var elem = semGenericParamInInvokation(c, n.sons[i])
+      addToResult(elem)
+  else:
+    internalAssert s.typ.kind == tyGenericBody
+
+    var m = newCandidate(s, n)
+    matches(c, n, copyTree(n), m)
+    
+    if m.state != csMatch:
+      LocalError(n.info, errWrongNumberOfArguments)
+      return newOrPrevType(tyError, prev, c)
+
+    var isConcrete = true
+  
+    for i in 1 .. <m.call.len:
+      let typ = m.call[i].typ.skipTypes({tyTypeDesc})
+      if containsGenericType(typ): isConcrete = false
+      addToResult(typ)
+    
+    if isConcrete:
+      if s.ast == nil:
+        LocalError(n.info, errCannotInstantiateX, s.name.s)
+        result = newOrPrevType(tyError, prev, c)
+      else:
+        result = instGenericContainer(c, n, result)
 
 proc semTypeExpr(c: PContext, n: PNode): PType =
   var n = semExprWithType(c, n, {efDetermineType})
@@ -1018,57 +1033,61 @@ proc processMagicType(c: PContext, m: PSym) =
   of mPNimrodNode: nil
   else: LocalError(m.info, errTypeExpected)
   
-proc semGenericConstraints(c: PContext, n: PNode, result: PType) = 
-  var x = semTypeNode(c, n, nil)
+proc semGenericConstraints(c: PContext, x: PType): PType =
   if x.kind in StructuralEquivTypes and (
       sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
-    x = newConstraint(c, x.kind)
-  result.addSonSkipIntLit(x)
+    result = newConstraint(c, x.kind)
+  else:
+    result = newTypeWithSons(c, tyGenericParam, @[x])
 
 proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
   result = copyNode(n)
   if n.kind != nkGenericParams: 
     illFormedAst(n)
     return
-  var position = 0
-  for i in countup(0, sonsLen(n)-1): 
+  for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
     if a.kind != nkIdentDefs: illFormedAst(n)
-    var L = sonsLen(a)
-    var def = a.sons[L-1]
+    let L = a.len
+    var def = a{-1}
+    let constraint = a{-2}
     var typ: PType
-    if a.sons[L-2].kind != nkEmpty: 
-      typ = newTypeS(tyGenericParam, c)
-      semGenericConstraints(c, a.sons[L-2], typ)
-      if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc:
-        typ = typ.sons[0]
-    elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
-    else: typ = nil
-    for j in countup(0, L-3): 
-      var s: PSym
+    
+    if constraint.kind != nkEmpty:
+      typ = semTypeNode(c, constraint, nil)
+      if typ.kind != tyExpr or typ.len == 0:
+        if typ.len == 0 and typ.kind == tyTypeDesc:
+          typ = newTypeS(tyGenericParam, c)
+        else:
+          typ = semGenericConstraints(c, typ)
+    
+    if def.kind != nkEmpty:
+      def = semConstExpr(c, def)
       if typ == nil:
-        s = newSymG(skType, a.sons[j], c)
-        s.typ = newTypeS(tyGenericParam, c)
+        if def.typ.kind != tyTypeDesc:
+          typ = newTypeWithSons(c, tyExpr, @[def.typ])
       else:
-        case typ.kind
-        of tyTypeDesc: 
-          s = newSymG(skType, a.sons[j], c)
-          s.typ = newTypeS(tyGenericParam, c)
+        if not containsGenericType(def.typ):
+          def = fitNode(c, typ, def)
+    
+    if typ == nil:
+      typ = newTypeS(tyGenericParam, c)
+    
+    for j in countup(0, L-3):
+      let finalType = if j == 0: typ
+                      else: copyType(typ, typ.owner, false)
+                      # it's important the we create an unique
+                      # type for each generic param. the index
+                      # of the parameter will be stored in the
+                      # attached symbol.
+      var s = case finalType.kind
         of tyExpr:
-          #echo "GENERIC EXPR ", a.info.toFileLineCol
-          # not a type param, but an expression
-          # proc foo[x: expr](bar: int) what is this?
-          s = newSymG(skGenericParam, a.sons[j], c)
-          s.typ = typ
+          newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
         else:
-          # This handles cases like proc foo[t: tuple] 
-          # XXX: we want to turn that into a type class
-          s = newSymG(skType, a.sons[j], c)
-          s.typ = typ
+          newSymG(skType, a.sons[j], c).linkTo(finalType)
       if def.kind != nkEmpty: s.ast = def
-      s.typ.sym = s
       if father != nil: addSonSkipIntLit(father, s.typ)
-      s.position = position
-      inc position
+      s.position = result.len
       addSon(result, newSymNode(s))
       if sfGenSym notin s.flags: addDecl(c, s)
+
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 4ca3e9d43..048067a44 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -84,6 +84,9 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
       #debug(formalTypeParam)
       put(c.bindings, formalTypeParam, binding[i].typ)
 
+proc newCandidate*(callee: PSym, binding: PNode, calleeScope = -1): TCandidate =
+  initCandidate(result, callee, binding, calleeScope)
+
 proc copyCandidate(a: var TCandidate, b: TCandidate) = 
   a.exactMatches = b.exactMatches
   a.subtypeMatches = b.subtypeMatches
@@ -861,16 +864,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       else:
         m.state = csNoMatch
         return
-  
-  var f = 1 # iterates over formal parameters
-  var a = 1 # iterates over the actual given arguments
-  m.state = csMatch           # until proven otherwise
+
+  var
+    # iterates over formal parameters
+    f = if m.callee.kind != tyGenericBody: 1
+        else: 0
+    # iterates over the actual given arguments
+    a = 1
+
+  m.state = csMatch # until proven otherwise
   m.call = newNodeI(n.kind, n.info)
   m.call.typ = base(m.callee) # may be nil
-  var formalLen = sonsLen(m.callee.n)
+  var formalLen = m.callee.n.len
   addSon(m.call, copyTree(n.sons[0]))
   var container: PNode = nil # constructed container
   var formal: PSym = nil
+
   while a < n.len:
     if n.sons[a].kind == nkExprEqExpr:
       # named param