summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-12-05 22:03:36 +0100
committerAraq <rumpf_a@web.de>2012-12-05 22:03:36 +0100
commit38ab30d153f7ae3b1b2b74329092ffb7ca781ead (patch)
treed39dc114db80ccdd50534dbf26f9133ef119405a /compiler
parent7171ae62cb94bf5e7ed426ec0679e4247c993121 (diff)
downloadNim-38ab30d153f7ae3b1b2b74329092ffb7ca781ead.tar.gz
implemented generic converters
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/semcall.nim12
-rwxr-xr-xcompiler/semstmts.nim4
-rwxr-xr-xcompiler/sigmatch.nim19
3 files changed, 30 insertions, 5 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index a5107bf64..962e4d3cc 100755
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -84,6 +84,16 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
         args])
 
+proc instantiateGenericConverters(c: PContext, n: PNode, x: TCandidate) {.
+                                  noinline.}=
+  for i in 1 .. <n.len:
+    var a = n.sons[i]
+    if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and
+        isGenericRoutine(a.sons[0].sym):
+      let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, n.info)
+      a.sons[0].sym = finalCallee
+      a.sons[0].typ = finalCallee.typ
+
 proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   assert x.state == csMatch
   var finalCallee = x.calleeSym
@@ -101,6 +111,8 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
       if ContainsGenericType(result.typ): result.typ = errorType(c)
       return
   result = x.call
+  if x.genericConverter:
+    instantiateGenericConverters(c, result, x)
   result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
   result.typ = finalCallee.typ.sons[0]
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index d68d0da1a..c5b226004 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -869,8 +869,8 @@ proc semMethod(c: PContext, n: PNode): PNode =
 proc semConverterDef(c: PContext, n: PNode): PNode = 
   if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
   checkSonsLen(n, bodyPos + 1)
-  if n.sons[genericParamsPos].kind != nkEmpty: 
-    LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
+  #if n.sons[genericParamsPos].kind != nkEmpty: 
+  #  LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
   result = semProcAux(c, n, skConverter, converterPragmas)
   var s = result.sons[namePos].sym
   var t = s.typ
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 8913b6d5d..c48434eb7 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -33,6 +33,8 @@ type
     baseTypeMatch: bool      # needed for conversions from T to openarray[T]
                              # for example
     proxyMatch*: bool        # to prevent instantiations
+    genericConverter*: bool  # true if a generic converter needs to
+                             # be instantiated
     inheritancePenalty: int  # to prefer closest father object type
   
   TTypeRelation* = enum      # order is important!
@@ -57,6 +59,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
   c.callee = callee
   c.call = nil
   c.baseTypeMatch = false
+  c.genericConverter = false
   c.inheritancePenalty = 0
 
 proc initCandidate*(c: var TCandidate, callee: PType) = 
@@ -571,16 +574,26 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
   for i in countup(0, len(c.converters) - 1): 
     var src = c.converters[i].typ.sons[1]
     var dest = c.converters[i].typ.sons[0]
-    if (typeRel(m, f, dest) == isEqual) and
-        (typeRel(m, src, a) == isEqual):
+    # for generic type converters we need to check 'src <- a' before
+    # 'f <- dest' in order to not break the unification:
+    # see tests/tgenericconverter:
+    let srca = typeRel(m, src, a)
+    if srca notin {isEqual, isGeneric}: continue
+    
+    let destIsGeneric = containsGenericType(dest)
+    if destIsGeneric:
+      dest = generateTypeInstance(c, m.bindings, arg, dest)
+    let fdest = typeRel(m, f, dest)
+    if fdest in {isEqual, isGeneric}: 
       markUsed(arg, c.converters[i])
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
       s.info = arg.info
-      result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0])
+      result = newNodeIT(nkHiddenCallConv, arg.info, dest)
       addSon(result, s)
       addSon(result, copyTree(arg))
       inc(m.convMatches)
+      m.genericConverter = srca == isGeneric or destIsGeneric
       return
 
 proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,