summary refs log tree commit diff stats
diff options
context:
space:
mode:
-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, 61 insertions, 92 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 174c3f94b..e35bf25ef 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -674,8 +674,6 @@ 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 9ae8aaca6..b63c20548 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -710,8 +710,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       #   TGObj[T] = object
       #   TAlias[T] = TGObj[T]
       # 
-      s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
-      a.sons[1] = s.typ.n
+      a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
       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 351794435..c975abb26 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -794,44 +794,29 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
 
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 
   result = newOrPrevType(tyGenericInvokation, prev, c)
-  addSonSkipIntLit(result, s.typ)
-  
-  template addToResult(typ) =
-    if typ.isNil:
-      InternalAssert false
-      rawAddSon(result, typ)
-    else: addSonSkipIntLit(result, typ)
-
+  var isConcrete = true
   if s.typ == nil:
     LocalError(n.info, errCannotInstantiateX, s.name.s)
     return newOrPrevType(tyError, prev, c)
-  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)
+  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)
 
 proc semTypeExpr(c: PContext, n: PNode): PType =
   var n = semExprWithType(c, n, {efDetermineType})
@@ -1033,61 +1018,57 @@ proc processMagicType(c: PContext, m: PSym) =
   of mPNimrodNode: nil
   else: LocalError(m.info, errTypeExpected)
   
-proc semGenericConstraints(c: PContext, x: PType): PType =
+proc semGenericConstraints(c: PContext, n: PNode, result: PType) = 
+  var x = semTypeNode(c, n, nil)
   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])
+    x = newConstraint(c, x.kind)
+  result.addSonSkipIntLit(x)
 
 proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
   result = copyNode(n)
   if n.kind != nkGenericParams: 
     illFormedAst(n)
     return
-  for i in countup(0, sonsLen(n)-1):
+  var position = 0
+  for i in countup(0, sonsLen(n)-1): 
     var a = n.sons[i]
     if a.kind != nkIdentDefs: illFormedAst(n)
-    let L = a.len
-    var def = a{-1}
-    let constraint = a{-2}
+    var L = sonsLen(a)
+    var def = a.sons[L-1]
     var typ: PType
-    
-    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 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 typ == nil:
-        if def.typ.kind != tyTypeDesc:
-          typ = newTypeWithSons(c, tyExpr, @[def.typ])
+        s = newSymG(skType, a.sons[j], c)
+        s.typ = newTypeS(tyGenericParam, c)
       else:
-        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
+        case typ.kind
+        of tyTypeDesc: 
+          s = newSymG(skType, a.sons[j], c)
+          s.typ = newTypeS(tyGenericParam, c)
         of tyExpr:
-          newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
+          #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
         else:
-          newSymG(skType, a.sons[j], c).linkTo(finalType)
+          # 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
       if def.kind != nkEmpty: s.ast = def
+      s.typ.sym = s
       if father != nil: addSonSkipIntLit(father, s.typ)
-      s.position = result.len
+      s.position = position
+      inc position
       addSon(result, newSymNode(s))
       if sfGenSym notin s.flags: addDecl(c, s)
-
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 048067a44..4ca3e9d43 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -84,9 +84,6 @@ 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
@@ -864,22 +861,16 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       else:
         m.state = csNoMatch
         return
-
-  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
+  
+  var f = 1 # iterates over formal parameters
+  var a = 1 # iterates over the actual given arguments
+  m.state = csMatch           # until proven otherwise
   m.call = newNodeI(n.kind, n.info)
   m.call.typ = base(m.callee) # may be nil
-  var formalLen = m.callee.n.len
+  var formalLen = sonsLen(m.callee.n)
   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