summary refs log tree commit diff stats
path: root/compiler/semtypinst.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/semtypinst.nim')
-rw-r--r--compiler/semtypinst.nim119
1 files changed, 71 insertions, 48 deletions
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index c53464f80..c5caf8b92 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -16,9 +16,9 @@ const
 
 proc sharedPtrCheck(info: TLineInfo, t: PType) =
   if t.kind == tyPtr and t.len > 1:
-    if t.sons[0].sym.magic in {mShared, mGuarded}:
+    if t.sons[0].sym.magic == mShared:
       incl(t.flags, tfShared)
-      if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
+      #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
       if tfHasGCedMem in t.flags or t.isGCedMem:
         localError(info, errGenerated,
                    "shared memory may not refer to GC'ed thread local memory")
@@ -34,9 +34,9 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
 proc checkConstructedType*(info: TLineInfo, typ: PType) =
   var t = typ.skipTypes({tyDistinct})
   if t.kind in tyTypeClasses: discard
-  elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: 
+  elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
     localError(info, errInvalidPragmaX, "acyclic")
-  elif t.kind == tyVar and t.sons[0].kind == tyVar: 
+  elif t.kind == tyVar and t.sons[0].kind == tyVar:
     localError(info, errVarVarTypeNotAllowed)
   elif computeSize(t) == szIllegalRecursion:
     localError(info, errIllegalRecursionInTypeX, typeToString(t))
@@ -44,7 +44,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
     sharedPtrCheck(info, t)
   when false:
     if t.kind == tyObject and t.sons[0] != nil:
-      if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: 
+      if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
         localError(info, errInheritanceOnlyWithNonFinalObjects)
 
 proc searchInstTypes*(key: PType): PType =
@@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType =
     if inst.sons.len < key.sons.len:
       # XXX: This happens for prematurely cached
       # types such as TChannel[empty]. Why?
-      # See the notes for PActor in handleGenericInvokation
+      # See the notes for PActor in handleGenericInvocation
       return
     block matchType:
       for j in 1 .. high(key.sons):
@@ -69,7 +69,7 @@ proc searchInstTypes*(key: PType): PType =
         if not compareTypes(inst.sons[j], key.sons[j],
                             flags = {ExactGenericParams}):
           break matchType
-       
+
       return inst
 
 proc cacheTypeInst*(inst: PType) =
@@ -79,7 +79,7 @@ proc cacheTypeInst*(inst: PType) =
   genericTyp.sym.typeInstCache.safeAdd(inst)
 
 type
-  TReplTypeVars* {.final.} = object 
+  TReplTypeVars* {.final.} = object
     c*: PContext
     typeMap*: TIdTable        # map PType to PType
     symMap*: TIdTable         # map PSym to PSym
@@ -89,6 +89,7 @@ type
     info*: TLineInfo
     allowMetaTypes*: bool     # allow types such as seq[Number]
                               # i.e. the result contains unresolved generics
+    skipTypedesc*: bool       # wether we should skip typeDescs
 
 proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
 proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
@@ -101,7 +102,6 @@ template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
       echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1)
       debug t
       writeStackTrace()
-      quit 1
 
 proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   result = replaceTypeVarsTAux(cl, t)
@@ -152,7 +152,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
     if needsFixing:
       n.sons[0] = newSymNode(n.sons[0].sym.owner)
       return cl.c.semOverloadedCall(cl.c, n, n, {skProc})
-  
+
   for i in 0 .. <n.safeLen:
     n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
 
@@ -204,18 +204,18 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
       newSons(result, length)
       for i in countup(0, length - 1):
         result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
-  
-proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = 
+
+proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
   if s == nil: return nil
   result = PSym(idTableGet(cl.symMap, s))
-  if result == nil: 
+  if result == nil:
     result = copySym(s, false)
     incl(result.flags, sfFromGeneric)
     idTablePut(cl.symMap, s, result)
     result.owner = s.owner
     result.typ = replaceTypeVarsT(cl, s.typ)
     result.ast = replaceTypeVarsN(cl, s.ast)
-    
+
 proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
   result = PType(idTableGet(cl.typeMap, t))
   if result == nil:
@@ -224,7 +224,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
     result = errorType(cl.c)
     # In order to prevent endless recursions, we must remember
     # this bad lookup and replace it with errorType everywhere.
-    # These code paths are only active in nimrod check
+    # These code paths are only active in "nim check"
     idTablePut(cl.typeMap, t, result)
   elif result.kind == tyGenericParam and not cl.allowMetaTypes:
     internalError(cl.info, "substitution with generic parameter")
@@ -233,11 +233,13 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
   # XXX: relying on allowMetaTypes is a kludge
   result = copyType(t, t.owner, cl.allowMetaTypes)
   result.flags.incl tfFromGeneric
-  result.flags.excl tfInstClearedFlags
+  if not (t.kind in tyMetaTypes or
+         (t.kind == tyStatic and t.n == nil)):
+    result.flags.excl tfInstClearedFlags
 
-proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = 
-  # tyGenericInvokation[A, tyGenericInvokation[A, B]]
-  # is difficult to handle: 
+proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
+  # tyGenericInvocation[A, tyGenericInvocation[A, B]]
+  # is difficult to handle:
   var body = t.sons[0]
   if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
   var header: PType = t
@@ -246,7 +248,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
     result = PType(idTableGet(cl.localCache, t))
   else:
     result = searchInstTypes(t)
-  if result != nil: return
+  if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
   for i in countup(1, sonsLen(t) - 1):
     var x = t.sons[i]
     if x.kind == tyGenericParam:
@@ -257,14 +259,14 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
         propagateToOwner(header, x)
     else:
       propagateToOwner(header, x)
-  
+
   if header != t:
     # search again after first pass:
     result = searchInstTypes(header)
-    if result != nil: return
+    if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
   else:
     header = instCopyType(cl, t)
-  
+
   result = newType(tyGenericInst, t.sons[0].owner)
   result.flags = header.flags
   # be careful not to propagate unnecessary flags here (don't use rawAddSon)
@@ -277,25 +279,29 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
   else:
     idTablePut(cl.localCache, t, result)
 
+  let oldSkipTypedesc = cl.skipTypedesc
+  cl.skipTypedesc = true
   for i in countup(1, sonsLen(t) - 1):
     var x = replaceTypeVarsT(cl, t.sons[i])
-    assert x.kind != tyGenericInvokation
+    assert x.kind != tyGenericInvocation
     header.sons[i] = x
     propagateToOwner(header, x)
     idTablePut(cl.typeMap, body.sons[i-1], x)
-  
+
   for i in countup(1, sonsLen(t) - 1):
     # if one of the params is not concrete, we cannot do anything
     # but we already raised an error!
     rawAddSon(result, header.sons[i])
 
   var newbody = replaceTypeVarsT(cl, lastSon(body))
+  cl.skipTypedesc = oldSkipTypedesc
   newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
   result.flags = result.flags + newbody.flags - tfInstClearedFlags
-  newbody.callConv = body.callConv
+  # This is actually wrong: tgeneric_closure fails with this line:
+  #newbody.callConv = body.callConv
   # This type may be a generic alias and we want to resolve it here.
   # One step is enough, because the recursive nature of
-  # handleGenericInvokation will handle the alias-to-alias-to-alias case
+  # handleGenericInvocation will handle the alias-to-alias-to-alias case
   if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
   rawAddSon(result, newbody)
   checkPartialConstructedType(cl.info, newbody)
@@ -303,14 +309,20 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
   if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
     # 'deepCopy' needs to be instantiated for
     # generics *when the type is constructed*:
-    newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
+    newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
+                                            attachedDeepCopy)
+  let asgn = newbody.assignment
+  if asgn != nil and sfFromGeneric notin asgn.flags:
+    # '=' needs to be instantiated for generics when the type is constructed:
+    newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
+                                              attachedAsgn)
 
 proc eraseVoidParams*(t: PType) =
   # transform '(): void' into '()' because old parts of the compiler really
-  # doesn't deal with '(): void':
+  # don't deal with '(): void':
   if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
     t.sons[0] = nil
-  
+
   for i in 1 .. <t.sonsLen:
     # don't touch any memory unless necessary
     if t.sons[i].kind == tyEmpty:
@@ -332,7 +344,7 @@ proc skipIntLiteralParams*(t: PType) =
     if skipped != p:
       t.sons[i] = skipped
       if i > 0: t.n.sons[i].sym.typ = skipped
-  
+
   # when the typeof operator is used on a static input
   # param, the results gets infected with static as well:
   if t.sons[0] != nil and t.sons[0].kind == tyStatic:
@@ -341,6 +353,8 @@ proc skipIntLiteralParams*(t: PType) =
 proc propagateFieldFlags(t: PType, n: PNode) =
   # This is meant for objects and tuples
   # The type must be fully instantiated!
+  if n.isNil:
+    return
   internalAssert n.kind != nkRecWhen
   case n.kind
   of nkSym:
@@ -357,10 +371,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
   if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
     let lookup = PType(idTableGet(cl.typeMap, t))
     if lookup != nil: return lookup
-  
+
   case t.kind
-  of tyGenericInvokation:
-    result = handleGenericInvokation(cl, t)
+  of tyGenericInvocation:
+    result = handleGenericInvocation(cl, t)
 
   of tyGenericBody:
     localError(cl.info, errCannotInstantiateX, typeToString(t))
@@ -369,8 +383,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
 
   of tyFromExpr:
     if cl.allowMetaTypes: return
+    assert t.n.typ != t
     var n = prepareNode(cl, t.n)
-    n = cl.c.semConstExpr(cl.c, n)
+    if n.kind != nkEmpty:
+      n = cl.c.semConstExpr(cl.c, n)
     if n.typ.kind == tyTypeDesc:
       # XXX: sometimes, chained typedescs enter here.
       # It may be worth investigating why this is happening,
@@ -389,51 +405,58 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       else:
         result = n.typ
 
-  of tyInt:
+  of tyInt, tyFloat:
     result = skipIntLit(t)
-    # XXX now there are also float literals
-  
+
   of tyTypeDesc:
     let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
     if lookup != nil:
       result = lookup
-      if tfUnresolved in t.flags: result = result.base
+      if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
     elif t.sons[0].kind != tyNone:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
- 
+
   of tyUserTypeClass:
     result = t
 
   of tyGenericInst:
+    result = PType(idTableGet(cl.localCache, t))
+    if result != nil: return result
     result = instCopyType(cl, t)
+    idTablePut(cl.localCache, t, result)
     for i in 1 .. <result.sonsLen:
       result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
     propagateToOwner(result, result.lastSon)
-  
+
   else:
     if containsGenericType(t):
+      #if not cl.allowMetaTypes:
+      result = PType(idTableGet(cl.localCache, t))
+      if result != nil: return result
       result = instCopyType(cl, t)
       result.size = -1 # needs to be recomputed
-      
+      #if not cl.allowMetaTypes:
+      idTablePut(cl.localCache, t, result)
+
       for i in countup(0, sonsLen(result) - 1):
         if result.sons[i] != nil:
           result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
           propagateToOwner(result, result.sons[i])
 
       result.n = replaceTypeVarsN(cl, result.n)
-     
+
       case result.kind
       of tyArray:
         let idx = result.sons[0]
         internalAssert idx.kind != tyStatic
-       
+
       of tyObject, tyTuple:
         propagateFieldFlags(result, result.n)
-      
+
       of tyProc:
         eraseVoidParams(result)
         skipIntLiteralParams(result)
-      
+
       else: discard
 
 proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
@@ -448,7 +471,7 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
   pushInfoContext(n.info)
   result = replaceTypeVarsN(cl, n)
   popInfoContext()
-  
+
 proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
                            t: PType): PType =
   var cl = initTypeVars(p, pt, info)