summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-12-06 07:10:19 +0100
committerAraq <rumpf_a@web.de>2012-12-06 07:10:19 +0100
commit1d842e8b75aa95670386b2ac4613932d2e01b9a3 (patch)
tree0c664c8676a53cbeb709d8a1377cac8906492932 /compiler
parentb602c04c4adc803b432e360d33cf54dad0b02def (diff)
parent6431e602160a5f2e1323a057e9c0166431e5a002 (diff)
downloadNim-1d842e8b75aa95670386b2ac4613932d2e01b9a3.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/docgen.nim3
-rw-r--r--compiler/parampatterns.nim4
-rw-r--r--compiler/patterns.nim4
-rwxr-xr-xcompiler/rodread.nim6
-rwxr-xr-xcompiler/rodwrite.nim6
-rwxr-xr-xcompiler/semcall.nim12
-rwxr-xr-xcompiler/semstmts.nim4
-rwxr-xr-xcompiler/semtypes.nim27
-rwxr-xr-xcompiler/sigmatch.nim25
10 files changed, 66 insertions, 27 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index f4ba1ef70..82a20c312 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -624,6 +624,7 @@ type
     loc*: TLoc
     annex*: PLib              # additional fields (seldom used, so we use a
                               # reference to another object to safe space)
+    constraint*: PNode        # additional constraints like 'lit|result'
   
   TTypeSeq* = seq[PType]
   TType* = object of TIdObj   # types are identical iff they have the
@@ -650,7 +651,6 @@ type
     align*: int               # the type's alignment requirements
     containerID*: int         # used for type checking of generics
     loc*: TLoc
-    constraint*: PNode        # additional constraints like 'lit|result'
 
   TPair*{.final.} = object 
     key*, val*: PObject
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index e06277f91..aff77cc1f 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -145,6 +145,9 @@ proc isVisible(n: PNode): bool =
       var v = n.sons[0].ident
       result = v.id == ord(wStar) or v.id == ord(wMinus)
   elif n.kind == nkSym:
+    # we cannot generate code for forwarded symbols here as we have no
+    # exception tracking information here. Instead we copy over the comment
+    # from the proc header.
     result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
   elif n.kind == nkPragmaExpr:
     result = isVisible(n.sons[0])
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index ee1f69818..21c7faf19 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -48,8 +48,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
   add(code, chr(ord(op)))
 
 proc whichAlias*(p: PSym): TAliasRequest =
-  if p.typ.constraint != nil:
-    result = TAliasRequest(p.typ.constraint.strVal[0].ord)
+  if p.constraint != nil:
+    result = TAliasRequest(p.constraint.strVal[0].ord)
 
 proc compileConstraints(p: PNode, result: var TPatternCode) =
   case p.kind
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index af259c916..b7792100f 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -71,8 +71,8 @@ proc inSymChoice(sc, x: PNode): bool =
   
 proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
   # check param constraints first here as this is quite optimized:
-  if p.typ.constraint != nil:
-    result = matchNodeKinds(p.typ.constraint, n)
+  if p.constraint != nil:
+    result = matchNodeKinds(p.constraint, n)
     if not result: return
   if isNil(n.typ):
     result = p.typ.kind in {tyEmpty, tyStmt}
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 4461641db..722887299 100755
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -330,9 +330,6 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
   if r.s[r.pos] == '@': 
     inc(r.pos)
     result.containerID = decodeVInt(r.s, r.pos)
-  if r.s[r.pos] == '`':
-    inc(r.pos)
-    result.constraint = decodeNode(r, UnknownLineInfo())
   decodeLoc(r, result.loc, info)
   while r.s[r.pos] == '^': 
     inc(r.pos)
@@ -423,6 +420,9 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
     result.offset = - 1
   decodeLoc(r, result.loc, result.info)
   result.annex = decodeLib(r, info)
+  if r.s[r.pos] == '#':
+    inc(r.pos)
+    result.constraint = decodeNode(r, UnknownLineInfo())
   if r.s[r.pos] == '(':
     if result.kind in routineKinds:
       result.ast = decodeNodeLazyBody(r, result.info, result)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 5be9a2439..0a361d4dd 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -233,9 +233,6 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
   if t.containerID != 0: 
     add(result, '@')
     encodeVInt(t.containerID, result)
-  if t.constraint != nil:
-    add(result, '`')
-    encodeNode(w, UnknownLineInfo(), t.constraint, result)
   encodeLoc(w, t.loc, result)
   for i in countup(0, sonsLen(t) - 1): 
     if t.sons[i] == nil: 
@@ -295,6 +292,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
     encodeVInt(s.offset, result)
   encodeLoc(w, s.loc, result)
   if s.annex != nil: encodeLib(w, s.annex, s.info, result)
+  if s.constraint != nil:
+    add(result, '#')
+    encodeNode(w, UnknownLineInfo(), s.constraint, result)
   # lazy loading will soon reload the ast lazily, so the ast needs to be
   # the last entry of a symbol:
   if s.ast != nil:
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..68d485f48 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -780,6 +780,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
     if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux")
     n.sons[namePos].sym = proto
+    if gCmd == cmdDoc and not isNil(proto.ast.comment):
+      n.comment = proto.ast.comment
     proto.ast = n             # needed for code generation
     popOwner()
     pushOwner(s)
@@ -869,8 +871,6 @@ 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")
   result = semProcAux(c, n, skConverter, converterPragmas)
   var s = result.sons[namePos].sym
   var t = s.typ
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 9efeba5b7..3da2a95b7 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -635,6 +635,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
         genericParams.addSon(newSymNode(s))
         result = typeClass
 
+proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
+  if n.kind == nkCurlyExpr:
+    result = semTypeNode(c, n.sons[0], nil)
+    constraint = semNodeKindConstraints(n)
+  else:
+    result = semTypeNode(c, n, nil)
+
 proc semProcTypeNode(c: PContext, n, genericParams: PNode, 
                      prev: PType, kind: TSymKind): PType = 
   var
@@ -660,13 +667,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     checkMinSonsLen(a, 3)
     var
       typ: PType = nil
-      def: PNode = nil      
+      def: PNode = nil
+      constraint: PNode = nil
       length = sonsLen(a)
       hasType = a.sons[length-2].kind != nkEmpty
       hasDefault = a.sons[length-1].kind != nkEmpty
 
     if hasType:
-      typ = semTypeNode(c, a.sons[length-2], nil)
+      typ = semParamType(c, a.sons[length-2], constraint)
       
     if hasDefault:
       def = semExprWithType(c, a.sons[length-1]) 
@@ -689,6 +697,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
                                     arg.name.s, arg.info).skipIntLit
       arg.typ = finalType
       arg.position = counter
+      arg.constraint = constraint
       inc(counter)
       if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
       if ContainsOrIncl(check, arg.name.id): 
@@ -787,6 +796,12 @@ proc semTypeExpr(c: PContext, n: PNode): PType =
   else:
     LocalError(n.info, errTypeExpected, n.renderTree)
 
+proc freshType(res, prev: PType): PType {.inline.} =
+  if prev.isNil:
+    result = copyType(result, result.owner, keepId=false)
+  else:
+    result = res
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   if gCmd == cmdIdeTools: suggestExpr(c, n)
@@ -825,7 +840,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         checkSonsLen(n, 3)
         result = semTypeNode(c, n.sons[1], prev)
         if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
-          # XXX this is wrong for tyString at least
+          result = freshType(result, prev)
           result.flags.incl(tfNotNil)
         else:
           LocalError(n.info, errGenerated, "invalid type")
@@ -833,11 +848,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = semTypeExpr(c, n)
     else:
       result = semTypeExpr(c, n)
-  of nkCurlyExpr:
-    result = semTypeNode(c, n.sons[0], nil)
-    if result != nil:
-      result = copyType(result, getCurrOwner(), true)
-      result.constraint = semNodeKindConstraints(n)
   of nkWhenStmt:
     var whenResult = semWhen(c, n, false)
     if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
@@ -920,6 +930,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkSharedTy:
     checkSonsLen(n, 1)
     result = semTypeNode(c, n.sons[0], prev)
+    result = freshType(result, prev)
     result.flags.incl(tfShared)
   else:
     LocalError(n.info, errTypeExpected)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 799622355..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, 
@@ -837,10 +850,10 @@ proc matchesAux*(c: PContext, n, nOrig: PNode,
         m.baseTypeMatch = false
         var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
                                   n.sons[a], nOrig.sons[a])
-        if arg == nil: 
+        if arg == nil:
           m.state = csNoMatch
-          return 
-        if m.baseTypeMatch: 
+          return
+        if m.baseTypeMatch:
           assert(container == nil)
           container = newNodeI(nkBracket, n.sons[a].info)
           addSon(container, arg)