summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2014-01-06 00:15:55 +0200
committerZahary Karadjov <zahary@gmail.com>2014-01-06 00:15:55 +0200
commit1ffae7cbafd63ed5d8546dcda1a0e5ec883fd00b (patch)
treec553bf1a94197b95a0fdf54b8cc2885c3b16a128 /compiler
parent789ba107cf3bcc1a87d896fc7cbfa11e151898c2 (diff)
downloadNim-1ffae7cbafd63ed5d8546dcda1a0e5ec883fd00b.tar.gz
progress towards fixing tgenericshardcases
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/semdata.nim15
-rw-r--r--compiler/semexprs.nim10
-rw-r--r--compiler/seminst.nim3
-rw-r--r--compiler/semtypes.nim28
-rw-r--r--compiler/semtypinst.nim104
-rw-r--r--compiler/types.nim2
7 files changed, 130 insertions, 33 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2f6b6fc9f..1d356b6d8 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -418,6 +418,7 @@ type
     tfHasGCedMem,     # type contains GC'ed memory
     tfHasStatic
     tfGenericTypeParam
+    tfImplicitTypeParam
 
   TTypeFlags* = set[TTypeFlag]
 
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 2e920d9cf..980abb865 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -218,6 +218,16 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
   result = newTypeS(tyFromExpr, c)
   result.n = n
 
+proc newTypeWithSons*(c: PContext, kind: TTypeKind,
+                      sons: seq[PType]): PType =
+  result = newType(kind, getCurrOwner())
+  result.sons = sons
+
+proc makeStaticExpr*(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkStaticExpr, n.info)
+  result.sons = @[n]
+  result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
+
 proc makeAndType*(c: PContext, t1, t2: PType): PType =
   result = newTypeS(tyAnd, c)
   result.sons = @[t1, t2]
@@ -238,11 +248,6 @@ proc makeNotType*(c: PContext, t1: 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/semexprs.nim b/compiler/semexprs.nim
index 00c0e0f78..1f7803c95 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -231,7 +231,7 @@ proc semCast(c: PContext, n: PNode): PNode =
   if not isCastable(result.typ, result.sons[1].typ): 
     localError(result.info, errExprCannotBeCastedToX, 
                typeToString(result.typ))
-  
+
 proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = 
   const 
     opToStr: array[mLow..mHigh, string] = ["low", "high"]
@@ -239,7 +239,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
     localError(n.info, errXExpectsTypeOrValue, opToStr[m])
   else: 
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
-    var typ = skipTypes(n.sons[1].typ, abstractVarRange)
+    var typ = skipTypes(n.sons[1].typ, abstractVarRange+{tyTypeDesc})
     case typ.kind
     of tySequence, tyString, tyOpenArray, tyVarargs: 
       n.typ = getSysType(tyInt)
@@ -249,8 +249,10 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
       # do not skip the range!
       n.typ = n.sons[1].typ.skipTypes(abstractVar)
     of tyGenericParam:
-      # leave it for now, it will be resolved in semtypinst
-      n.typ = getSysType(tyInt)
+      # prepare this for resolving in semtypinst:
+      # we must use copyTree here in order to avoid creating a cycle
+      # that could easily turn into an infinite recursion in semtypinst
+      n.typ = makeTypeFromExpr(c, n.copyTree)
     else:
       localError(n.info, errInvalidArgForX, opToStr[m])
   result = n
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 370d59b10..8faf1d21a 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -167,8 +167,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   result.ast = n
   pushOwner(result)
   openScope(c)
-  if n.sons[genericParamsPos].kind == nkEmpty: 
-    internalError(n.info, "generateInstance")
+  internalAssert n.sons[genericParamsPos].kind != nkEmpty
   n.sons[namePos] = newSymNode(result)
   pushInfoContext(info)
   var entry = TInstantiation.new
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 79147ab82..64c8f81e2 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -186,6 +186,11 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
     localError(n.info, errXExpectsOneTypeParam, "range")
     result = newOrPrevType(tyError, prev, c)
 
+proc nMinusOne(n: PNode): PNode =
+  result = newNode(nkCall, n.info, @[
+    newSymNode(getSysMagic("<", mUnaryLt)),
+    n])
+
 proc semArray(c: PContext, n: PNode, prev: PType): PType = 
   var indx, base: PType
   result = newOrPrevType(tyArray, prev, c)
@@ -194,7 +199,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
     if isRange(n[1]): indx = semRangeAux(c, n[1], nil)
     else:
       let e = semExprWithType(c, n.sons[1], {efDetermineType})
-      if e.kind in {nkIntLit..nkUInt64Lit}:
+      if e.typ.kind == tyFromExpr:
+        indx = e.typ
+      elif e.kind in {nkIntLit..nkUInt64Lit}:
         indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
       elif e.kind == nkSym and e.typ.kind == tyStatic:
         if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
@@ -202,11 +209,25 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
         if not isOrdinalType(e.typ.lastSon):
           localError(n[1].info, errOrdinalTypeExpected)
         indx = e.typ
+      elif e.kind in nkCallKinds and hasGenericArguments(e):
+        if not isOrdinalType(e.typ):
+          localError(n[1].info, errOrdinalTypeExpected)
+        # This is an int returning call, depending on an
+        # yet unknown generic param (see tgenericshardcases).
+        # We are going to construct a range type that will be
+        # properly filled-out in semtypinst (see how tyStaticExpr
+        # is handled there).
+        let intType = getSysType(tyInt)
+        indx = newTypeS(tyRange, c)
+        indx.sons = @[intType]
+        indx.n = newNode(nkRange, n.info, @[
+          newIntTypeNode(nkIntLit, 0, intType),
+          makeStaticExpr(c, e.nMinusOne)])
       else:
         indx = e.typ.skipTypes({tyTypeDesc})
     addSonSkipIntLit(result, indx)
     if indx.kind == tyGenericInst: indx = lastSon(indx)
-    if indx.kind notin {tyGenericParam, tyStatic}:
+    if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
       if not isOrdinalType(indx):
         localError(n.sons[1].info, errOrdinalTypeExpected)
       elif enumHasHoles(indx): 
@@ -619,6 +640,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     var s = newSym(skType, finalTypId, owner, info)
     if typId == nil: s.flags.incl(sfAnon)
     s.linkTo(typeClass)
+    typeClass.flags.incl tfImplicitTypeParam
     s.position = genericParams.len
     genericParams.addSon(newSymNode(s))
     result = typeClass
@@ -844,7 +866,7 @@ 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
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 75d266679..b08119d4a 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -98,11 +98,50 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   result = copyNode(n)
   result.typ = replaceTypeVarsT(cl, n.typ)
   if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
-  for i in 0 .. safeLen(n)-1: 
-    # XXX HACK: ``f(a, b)``, avoid to instantiate `f` 
-    if i == 0: result.add(n[i])
+  let isCall = result.kind in nkCallKinds
+  for i in 0 .. <n.safeLen:
+    # XXX HACK: ``f(a, b)``, avoid to instantiate `f`
+    if isCall and i == 0: result.add(n[i])
     else: result.add(prepareNode(cl, n[i]))
 
+proc isTypeParam(n: PNode): bool =
+  # XXX: generic params should use skGenericParam instead of skType
+  return n.kind == nkSym and
+         (n.sym.kind == skGenericParam or
+           (n.sym.kind == skType and sfFromGeneric in n.sym.flags))
+
+proc hasGenericArguments*(n: PNode): bool =
+  if n.kind == nkSym:
+    return n.sym.kind == skGenericParam or
+           (n.sym.kind == skType and
+            n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
+  else:
+    for s in n.sons:
+      if hasGenericArguments(s): return true
+    return false
+
+proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
+  # This is needed fo tgenericshardcases
+  # It's possible that a generic param will be used in a proc call to a
+  # typedesc accepting proc. After generic param substitution, such procs
+  # should be optionally instantiated with the correct type. In order to
+  # perform this instantiation, we need to re-run the generateInstance path
+  # in the compiler, but it's quite complicated to do so at the moment so we
+  # resort to a mild hack; the head symbol of the call is temporary reset and
+  # overload resolution is executed again (which may trigger generateInstance).
+  if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags:
+    var needsFixing = false
+    for i in 1 .. <n.safeLen:
+      if isTypeParam(n[i]): needsFixing = true
+    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])
+
+  return n
+
 proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
   if n == nil: return
   result = copyNode(n)
@@ -135,6 +174,10 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
       result = replaceTypeVarsN(cl, branch)
     else:
       result = newNodeI(nkRecList, n.info)
+  of nkStaticExpr:
+    var n = prepareNode(cl, n)
+    n = reResolveCallsWithTypedescParams(cl, n)
+    result = cl.c.semExpr(cl.c, n)
   else:
     var length = sonsLen(n)
     if length > 0:
@@ -273,45 +316,58 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
   result = t
   if t == nil: return
 
-  #if t.kind == tyStatic and t.sym != nil and t.sym.kind == skGenericParam:
-  #  let s = lookupTypeVar(cl, t)
-  #  return if s != nil: s else: t
-
   if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
     let lookup = PType(idTableGet(cl.typeMap, t))
     if lookup != nil: return lookup
- 
+  
   case t.kind
   of tyGenericInvokation:
     result = handleGenericInvokation(cl, t)
+
   of tyGenericBody:
     internalError(cl.info, "ReplaceTypeVarsT: tyGenericBody" )
     result = replaceTypeVarsT(cl, lastSon(t))
+
   of tyFromExpr:
     var n = prepareNode(cl, t.n)
-    n = cl.c.semExpr(cl.c, n, {})
-    result = n.typ.skipTypes({tyTypeDesc})
+    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,
+      # because it may cause other bugs elsewhere.
+      result = n.typ.skipTypes({tyTypeDesc})
+      # result = n.typ.base
+    else:
+      if n.typ.kind != tyStatic:
+        # XXX: In the future, semConstExpr should
+        # return tyStatic values to let anyone make
+        # use of this knowledge. The patching here
+        # won't be necessary then.
+        result = newTypeS(tyStatic, cl.c)
+        result.sons = @[n.typ]
+        result.n = n
+      else:
+        result = n.typ
+
   of tyInt:
     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
+    elif t.sonsLen > 0:
+      result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
+  
   of tyGenericInst:
     result = instCopyType(cl, t)
     for i in 1 .. <result.sonsLen:
       result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
     propagateToOwner(result, result.lastSon)
+  
   else:
-    if t.kind == tyArray:
-      let idxt = t.sons[0]
-      if idxt.kind == tyStatic and 
-         idxt.sym != nil and idxt.sym.kind == skGenericParam:
-        let value = lookupTypeVar(cl, idxt).n
-        t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
-    
     if containsGenericType(t):
       result = instCopyType(cl, t)
       result.size = -1 # needs to be recomputed
@@ -326,13 +382,25 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       # XXX: This is not really needed?
       # if result.kind in GenericTypes:
       #   localError(cl.info, errCannotInstantiateX, typeToString(t, preferName))
-  
+
       case result.kind
+      of tyArray:
+        let idx = result.sons[0]
+        if idx.kind == tyStatic:
+          if idx.n == nil:
+            let lookup = lookupTypeVar(cl, idx)
+            internalAssert lookup != nil
+            idx.n = lookup.n
+
+          result.sons[0] = makeRangeType(cl.c, 0, idx.n.intVal - 1, idx.n.info)
+       
       of tyObject, tyTuple:
         propagateFieldFlags(result, result.n)
+      
       of tyProc:
         eraseVoidParams(result)
         skipIntLiteralParams(result)
+      
       else: discard
 
 proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
diff --git a/compiler/types.nim b/compiler/types.nim
index dd808915e..36c9f1934 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1231,7 +1231,7 @@ proc getSize(typ: PType): BiggestInt =
   if result < 0: internalError("getSize: " & $typ.kind)
 
 proc containsGenericTypeIter(t: PType, closure: PObject): bool =
-  result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc} or
+  result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc,tyFromExpr} or
            t.kind == tyStatic and t.n == nil
 
 proc containsGenericType*(t: PType): bool =