summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-05-27 23:20:41 +0200
committerAraq <rumpf_a@web.de>2013-05-27 23:20:41 +0200
commita8ba628bcd2535bc55e3bf67737e93ae99906a63 (patch)
tree73ba562525b0c97bd2a3a5702c33585b2a810c22
parent75c586bbe1cc649b36fc00362ab40ebb1d163d9f (diff)
downloadNim-a8ba628bcd2535bc55e3bf67737e93ae99906a63.tar.gz
Revert "fixes #267"
This reverts commit 7fccdedcb5d1e583039b2ea2ae6564412a0f5104.
-rw-r--r--compiler/ast.nim15
-rw-r--r--compiler/semdata.nim5
-rw-r--r--compiler/seminst.nim103
-rw-r--r--compiler/semtypes.nim156
-rw-r--r--compiler/types.nim2
5 files changed, 97 insertions, 184 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index e35bf25ef..d4d5bce9c 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -365,8 +365,12 @@ type
     tfFromGeneric,    # type is an instantiation of a generic; this is needed
                       # because for instantiations of objects, structural
                       # type equality has to be used
-    tfUnresolved,     # marks unresolved typedesc params: e.g.
-                      # proc foo(T: typedesc, list: seq[T]): var T
+    tfInstantiated,   # XXX: used to mark generic params after instantiation.
+                      # if the concrete type happens to be an implicit generic
+                      # this can lead to invalid proc signatures in the second
+                      # pass of semProcTypeNode performed after instantiation.
+                      # this won't be needed if we don't perform this redundant
+                      # second pass (stay tuned).
     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)
@@ -1003,8 +1007,8 @@ proc NewType(kind: TTypeKind, owner: PSym): PType =
   result.size = - 1
   result.align = 2            # default alignment
   result.id = getID()
-  when debugIds:
-    RegisterId(result)
+  when debugIds: 
+    RegisterId(result)        
   #if result.id < 2000 then
   #  MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
   
@@ -1041,6 +1045,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
   if keepId: 
     result.id = t.id
   else: 
+    result.id = getID()
     when debugIds: RegisterId(result)
   result.sym = t.sym          # backend-info should not be copied
   
@@ -1285,7 +1290,7 @@ proc isGenericRoutine*(s: PSym): bool =
   of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter:
     result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty
   else: nil
-  
+
 proc isRoutine*(s: PSym): bool {.inline.} =
   result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
                       skConverter}
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 127842a5a..4c94d0812 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -207,11 +207,6 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
 proc newTypeS(kind: TTypeKind, c: PContext): PType = 
   result = newType(kind, getCurrOwner())
 
-proc newTypeWithSons*(c: PContext, kind: TTypeKind,
-                      sons: seq[PType]): PType =
-  result = newType(kind, getCurrOwner())
-  result.sons = sons
-
 proc errorType*(c: PContext): PType =
   ## creates a type representing an error state
   result = newTypeS(tyError, c)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 35ed00965..9dc99d173 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -38,6 +38,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
       #t = instGenericContainer(c, a, t)
       t = generateTypeInstance(c, pt, a, t)
       #t = ReplaceTypeVarsT(cl, t)
+    t.flags.incl tfInstantiated
     s.typ = t
     addDecl(c, s)
     entry.concreteTypes[i] = t
@@ -83,28 +84,11 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
   else:
     for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
 
-proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
-
 proc instantiateBody(c: PContext, n: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
     # add it here, so that recursive generic procs are possible:
     addDecl(c, result)
     pushProcCon(c, result)
-    # add params to scope
-    let origFormalParams = result.typ.n
-    result.typ.n = newNodeI(nkFormalParams,
-                            origFormalParams.info,
-                            origFormalParams.len)
-    result.typ.n.sons[0] = copyNode(origFormalParams.sons[0])
-    for i in 1 .. <result.typ.len:
-      let origParam = origFormalParams[i].sym
-      var param = copySym(origParam)
-      result.typ.n.sons[i] = newSymNode(param)
-      param.typ = result.typ.sons[i]
-      param.ast = origParam.ast
-      param.owner = result
-      addParamOrResult(c, param, result.kind)
-    # debug result.typ.n
     maybeAddResult(c, result, n)
     var b = n.sons[bodyPos]
     var symMap: TIdTable
@@ -139,71 +123,7 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
       s.ast.sons[genericParamsPos].kind == nkEmpty:
     c.threadEntries.add(s)
 
-proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
-  var cl: TReplTypeVars
-  InitIdTable(cl.symMap)
-  InitIdTable(cl.typeMap)
-  cl.info = info
-  cl.c = c
-  result = ReplaceTypeVarsT(cl, header)
-
-proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
-  result = instGenericContainer(c, n.info, header)
-
-proc fixupProcTypeR(c: PContext, genericType: PType,
-                    inst: TInstantiation): PType =
-  result = genericType
-  if result == nil: return
-
-  case genericType.kind
-  of tyGenericParam, tyTypeClass:
-    result = inst.concreteTypes[genericType.sym.position]
-  of tyTypeDesc:
-    result = inst.concreteTypes[genericType.sym.position]
-    if tfUnresolved in genericType.flags:
-      result = result.sons[0]
-  of tyExpr:
-    result = inst.concreteTypes[genericType.sym.position]
-  of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc,
-     tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs:
-    if genericType.sons == nil: return
-    for i in 0 .. <genericType.sons.len:
-      let changed = fixupProcTypeR(c, genericType.sons[i], inst)
-      if changed != genericType.sons[i]:
-        if result == genericType:
-          # the first detected change initializes the result
-          result = copyType(genericType, genericType.owner, true)
-          if genericType.n != nil:
-            result.n = copyTree(genericType.n)
-        result.sons[i] = changed
-        if result.n != nil:
-          if result.n.kind == nkRecList:
-            result.n.sons[i].typ = changed
-          if result.n.kind == nkFormalParams:
-            if i == 0:
-              nil
-            else:
-              let origParam = result.n.sons[i].sym
-              var param = copySym(origParam)
-              param.typ = changed
-              param.ast = origParam.ast
-              result.n.sons[i] = newSymNode(param)
-              
-  of tyGenericInvokation:
-    result = newTypeWithSons(c, tyGenericInvokation, genericType.sons)
-    for i in 1 .. <genericType.sons.len:
-      result.sons[i] = fixupProcTypeR(c, result.sons[i], inst)
-    result = instGenericContainer(c, getInfoContext(-1), result)
-  else:
-    nil
-
-proc fixupProcType(c: PContext, genericType: PType,
-                   inst: TInstantiation): PType =
-  result = copyType(genericType, genericType.owner, false)
-  for i in 0 .. <result.sons.len:
-    result.sons[i] = fixupProcTypeR(c, result.sons[i], inst)
-  
-proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
+proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, 
                       info: TLineInfo): PSym =
   # no need to instantiate generic templates/macros:
   if fn.kind in {skTemplate, skMacro}: return fn
@@ -232,8 +152,16 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   var entry = TInstantiation.new
   entry.sym = result
   instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
-  result.typ = fixupProcType(c, fn.typ, entry[])
   n.sons[genericParamsPos] = ast.emptyNode
+  # semantic checking for the parameters:
+  if n.sons[paramsPos].kind != nkEmpty:
+    removeDefaultParamValues(n.sons[ParamsPos])
+    semParamList(c, n.sons[ParamsPos], nil, result)
+  else:
+    result.typ = newTypeS(tyProc, c)
+    rawAddSon(result.typ, nil)
+  result.typ.callConv = fn.typ.callConv
+  if result.kind == skIterator: result.typ.flags.incl(tfIterator)
   var oldPrc = GenericCacheGet(fn, entry[])
   if oldPrc == nil:
     fn.procInstCache.safeAdd(entry)
@@ -254,5 +182,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   c.friendModule = oldFriend
   dec(c.InstCounter)
   if result.kind == skMethod: finishMethod(c, result)
-
+  
+proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = 
+  var cl: TReplTypeVars
+  InitIdTable(cl.symMap)
+  InitIdTable(cl.typeMap)
+  cl.info = n.info
+  cl.c = c
+  result = ReplaceTypeVarsT(cl, header)
 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index c975abb26..658b3507f 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -216,7 +216,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
   else:
     LocalError(n.info, errXExpectsOneTypeParam, "ordinal")
     result = newOrPrevType(tyError, prev, c)
-
+  
 proc semTypeIdent(c: PContext, n: PNode): PSym =
   if n.kind == nkSym: 
     result = n.sym
@@ -235,9 +235,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
         if result.typ.sym == nil:
           LocalError(n.info, errTypeExpected)
           return errorSym(c, n)
-        result = result.typ.sym.copySym
-        result.typ = copyType(result.typ, result.typ.owner, true)
-        result.typ.flags.incl tfUnresolved
+        return result.typ.sym
       if result.kind != skType: 
         # this implements the wanted ``var v: V, x: V`` feature ...
         var ov: TOverloadIter
@@ -575,95 +573,81 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
   else:
     if sfGenSym notin param.flags: addDecl(c, param)
 
-proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
-                   paramType: PType, paramName: string,
-                   info: TLineInfo, anon = false): PType =
-  if procKind in {skMacro, skTemplate}:
-    # generic param types in macros and templates affect overload
-    # resolution, but don't work as generic params when it comes
-    # to proc instantiation. We don't need to lift such params here.  
-    return
-
-  proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
-    let finalTypId = if typId != nil: typId
-                     else: getIdent(paramName & ":type")
-    # 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:
-        return genericParams.sons[i].typ
-
-    var s = newSym(skType, finalTypId, getCurrOwner(), info)
-    if typId == nil: s.flags.incl(sfAnon)
-    s.linkTo(typeClass)
-    s.position = genericParams.len
-    genericParams.addSon(newSymNode(s))
-    result = typeClass
-
-  # XXX: There are codegen errors if this is turned into a nested proc
-  template liftingWalk(typ: PType, anonFlag = false): expr =
-    liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
-  #proc liftingWalk(paramType: PType, anon = false): PType =
-
-  var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
-                   else: nil
-
-  template addImplicitGeneric(e: expr): expr =
-    addImplicitGenericImpl(e, paramTypId)
-
+proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
+  tuple[typ: PType, id: PIdent] =
+  # if typ is not-nil, the param should be turned into a generic param
+  # if id is not nil, the generic param will bind just once (see below)
   case paramType.kind:
   of tyExpr:
     if paramType.sonsLen == 0:
       # proc(a, b: expr)
       # no constraints, treat like generic param
-      result = addImplicitGeneric(newTypeS(tyGenericParam, c))
+      result.typ = newTypeS(tyGenericParam, c)
     else:
       # proc(a: expr{string}, b: expr{nkLambda})
       # overload on compile time values and AST trees
-      result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
+      result.typ = newTypeS(tyExpr, c)
+      result.typ.sons = paramType.sons
   of tyTypeDesc:
-    if tfUnresolved notin paramType.flags:
-      result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
+     if tfInstantiated notin paramType.flags:
+      result.typ = newTypeS(tyTypeDesc, c)
+      result.typ.sons = paramType.sons
   of tyDistinct:
-    if paramType.sonsLen == 1:
-      # disable the bindOnce behavior for the type class
-      result = liftingWalk(paramType.sons[0], true)
-  of tySequence, tySet, tyArray, tyOpenArray:
-    # XXX: this is a bit strange, but proc(s: seq)
-    # produces tySequence(tyGenericParam, null).
-    # This also seems to be true when creating aliases
-    # like: type myseq = distinct seq.
-    # Maybe there is another better place to associate
-    # the seq type class with the seq identifier.
-    if paramType.lastSon == nil:
-      let typ = c.newTypeWithSons(tyTypeClass, @[newTypeS(paramType.kind, c)])
-      result = addImplicitGeneric(typ)
-    else:
-      for i in 0 .. <paramType.sons.len:
-        var lifted = liftingWalk(paramType.sons[i])
-        if lifted != nil:
-          paramType.sons[i] = lifted
-          result = paramType
+    result = paramTypeClass(c, paramType.lastSon, procKind)
+    # disable the bindOnce behavior for the type class
+    result.id = nil
+    return
   of tyGenericBody:
     # type Foo[T] = object
     # proc x(a: Foo, b: Foo) 
-    var typ = newTypeS(tyTypeClass, c)
-    typ.addSonSkipIntLit(paramType)
-    result = addImplicitGeneric(typ)
-  of tyGenericInst:
-    for i in 1 .. (paramType.sons.len - 2):
-      var lifted = liftingWalk(paramType.sons[i])
-      if lifted != nil:
-        paramType.sons[i] = lifted
-        result = paramType
-    
-    if result != nil:
-      result.kind = tyGenericInvokation
-      result.sons.setLen(result.sons.len - 1)
+    result.typ = newTypeS(tyTypeClass, c)
+    result.typ.addSonSkipIntLit(paramType)
   of tyTypeClass:
-    result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false))
+    result.typ = copyType(paramType, getCurrOwner(), false)
   else: nil
+  # bindOnce by default
+  if paramType.sym != nil: result.id = paramType.sym.name
+
+proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
+                   paramType: PType, paramName: string,
+                   info: TLineInfo): PType =
+  result = paramType
+  if procKind in {skMacro, skTemplate}:
+    # generic param types in macros and templates affect overload
+    # resolution, but don't work as generic params when it comes
+    # to proc instantiation. We don't need to lift such params here.  
+    return
+  ## Params having implicit generic types or pseudo types such as 'expr'
+  ## need to be added to the generic params lists. 
+  ## 'expr' is different from 'expr{string}' so we must first call 
+  ## paramTypeClass to get the actual type we are going to use.
+  var (typeClass, paramTypId) = paramTypeClass(c, paramType, procKind)
+  let isAnon = paramTypId == nil
+  if typeClass != nil:
+    if isAnon: paramTypId = getIdent(paramName & ":type")
+    if genericParams == nil:
+      # genericParams is nil when the proc is being instantiated
+      # the resolved type will be in scope then
+      let s = searchInScopes(c, paramTypId)
+      # tests/run/tinterf triggers this:
+      if s != nil: result = s.typ
+      else:
+        LocalError(info, errCannotInstantiateX, paramName)
+        result = errorType(c)
+    else:
+      block addImplicitGeneric:
+        # 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 == paramTypId.id:
+            result = genericParams.sons[i].typ
+            break addImplicitGeneric
 
-  # result = liftingWalk(paramType)
+        var s = newSym(skType, paramTypId, getCurrOwner(), info)
+        if isAnon: s.flags.incl(sfAnon)
+        s.linkTo(typeClass)
+        s.position = genericParams.len
+        genericParams.addSon(newSymNode(s))
+        result = typeClass
 
 proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
   if n.kind == nkCurlyExpr:
@@ -702,9 +686,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       length = sonsLen(a)
       hasType = a.sons[length-2].kind != nkEmpty
       hasDefault = a.sons[length-1].kind != nkEmpty
+
     if hasType:
       typ = semParamType(c, a.sons[length-2], constraint)
-
+      
     if hasDefault:
       def = semExprWithType(c, a.sons[length-1]) 
       # check type compability between def.typ and typ:
@@ -722,9 +707,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
     for j in countup(0, length-3): 
       var arg = newSymG(skParam, a.sons[j], c)
-      let lifted = liftParamType(c, kind, genericParams, typ,
-                                 arg.name.s, arg.info)
-      let finalType = if lifted != nil: lifted else: typ.skipIntLit
+      var finalType = liftParamType(c, kind, genericParams, typ,
+                                    arg.name.s, arg.info).skipIntLit
       arg.typ = finalType
       arg.position = counter
       arg.constraint = constraint
@@ -742,13 +726,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
       if r.sym == nil or sfAnon notin r.sym.flags:
-        let lifted = liftParamType(c, kind, genericParams, r, "result",
-                                   n.sons[0].info)
-        if lifted != nil: r = lifted
+        r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
         r.flags.incl tfRetType
       result.sons[0] = skipIntLit(r)
       res.typ = result.sons[0]
- 
+
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
   checkMinSonsLen(n, 1)
   var length = sonsLen(n)
@@ -1030,7 +1012,6 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
   if n.kind != nkGenericParams: 
     illFormedAst(n)
     return
-  var position = 0
   for i in countup(0, sonsLen(n)-1): 
     var a = n.sons[i]
     if a.kind != nkIdentDefs: illFormedAst(n)
@@ -1068,7 +1049,6 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
       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 = i
       addSon(result, newSymNode(s))
       if sfGenSym notin s.flags: addDecl(c, s)
diff --git a/compiler/types.nim b/compiler/types.nim
index 731c1f12a..3096b73c8 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -982,8 +982,6 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
   # 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