summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim7
-rw-r--r--compiler/evals.nim21
-rw-r--r--compiler/options.nim2
-rw-r--r--compiler/semdata.nim10
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semfold.nim16
-rw-r--r--compiler/seminst.nim49
-rw-r--r--compiler/semmagic.nim2
-rw-r--r--compiler/semstmts.nim16
-rw-r--r--compiler/semtypes.nim35
-rw-r--r--compiler/semtypinst.nim10
-rw-r--r--compiler/sigmatch.nim8
12 files changed, 124 insertions, 54 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index bb015ea27..bb06e7163 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -626,6 +626,7 @@ type
     case kind*: TSymKind
     of skType:
       typeInstCache*: seq[PType]
+      typScope*: PScope
     of routineKinds:
       procInstCache*: seq[PInstantiation]
       scope*: PScope          # the scope where the proc was defined
@@ -799,9 +800,9 @@ const
     # imported via 'importc: "fullname"' and no format string.
 
 # creator procs:
-proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
+proc newSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
              info: TLineInfo): PSym
-proc NewType*(kind: TTypeKind, owner: PSym): PType
+proc newType*(kind: TTypeKind, owner: PSym): PType
 proc newNode*(kind: TNodeKind): PNode
 proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
 proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
@@ -1111,7 +1112,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
   result.loc = s.loc
   result.annex = s.annex      # BUGFIX
   
-proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
+proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
             info: TLineInfo): PSym = 
   # generates a symbol and initializes the hash field too
   new(result)
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 3f09664a7..053068ea4 100644
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -904,18 +904,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
                        code.info.line.int)
   #result.typ = newType(tyStmt, c.module)
  
-proc evalTypeTrait*(n: PNode, context: PSym): PNode =
-  ## XXX: This should be pretty much guaranteed to be true
-  # by the type traits procs' signatures, but until the
-  # code is more mature it doesn't hurt to be extra safe
-  internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
-
-  let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
-  case n.sons[0].sym.name.s.normalize
+proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
+  InternalAssert operand.kind == nkSym
+
+  let typ = operand.sym.typ.skipTypes({tyTypeDesc})
+  case trait.sym.name.s.normalize
   of "name":
-    result = newStrNode(nkStrLit, typ.typeToString(preferExported))
+    result = newStrNode(nkStrLit, typ.typeToString(preferName))
     result.typ = newType(tyString, context)
-    result.info = n.info
+    result.info = trait.info
   else:
     internalAssert false
 
@@ -1037,8 +1034,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
   of mParseStmtToAst: result = evalParseStmt(c, n)
   of mExpandToAst: result = evalExpandToAst(c, n)
   of mTypeTrait:
-    n.sons[1] = evalAux(c, n.sons[1], {})
-    result = evalTypeTrait(n, c.module)
+    let operand = evalAux(c, n.sons[1], {})
+    result = evalTypeTrait(n[0], operand, c.module)
   of mIs:
     n.sons[1] = evalAux(c, n.sons[1], {})
     result = evalIsOp(n)
diff --git a/compiler/options.nim b/compiler/options.nim
index 5f173d240..2b25b2650 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -156,6 +156,8 @@ var
 
 const oKeepVariableNames* = true
 
+const oUseLateInstantiation* = false
+
 proc mainCommandArg*: string =
   ## This is intended for commands like check or parse
   ## which will work on the main project file unless
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index b9c32a680..8b04f4af5 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -225,14 +225,14 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
   dest.owner = getCurrOwner()
   dest.size = - 1
 
-proc makeRangeType*(c: PContext, first, last: biggestInt, 
-                    info: TLineInfo): PType = 
+proc makeRangeType*(c: PContext; first, last: biggestInt;
+                    info: TLineInfo; intType = getSysType(tyInt)): PType =
   var n = newNodeI(nkRange, info)
-  addSon(n, newIntNode(nkIntLit, first))
-  addSon(n, newIntNode(nkIntLit, last))
+  addSon(n, newIntTypeNode(nkIntLit, first, intType))
+  addSon(n, newIntTypeNode(nkIntLit, last, intType))
   result = newTypeS(tyRange, c)
   result.n = n
-  rawAddSon(result, getSysType(tyInt)) # basetype of range
+  addSonSkipIntLit(result, intType) # basetype of range
 
 proc markIndirect*(c: PContext, s: PSym) {.inline.} =
   if s.kind in {skProc, skConverter, skMethod, skIterator}:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 354cbcbd1..4d7ceffa9 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -113,7 +113,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of skGenericParam:
     if s.typ.kind == tyExpr:
       result = newSymNode(s, n.info)
-      result.typ = s.typ.lastSon
+      result.typ = s.typ
     elif s.ast != nil:
       result = semExpr(c, s.ast)
     else:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 634ea8395..ca06ea1b6 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -561,9 +561,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   case n.kind
   of nkSym: 
     var s = n.sym
-    if s.kind == skEnumField: 
+    case s.kind
+    of skEnumField:
       result = newIntNodeT(s.position, n)
-    elif s.kind == skConst: 
+    of skConst:
       case s.magic
       of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
       of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
@@ -581,10 +582,17 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       of mNegInf: result = newFloatNodeT(NegInf, n)
       else:
         if sfFakeConst notin s.flags: result = copyTree(s.ast)
-    elif s.kind in {skProc, skMethod}: # BUGFIX
+    of {skProc, skMethod}:
       result = n
-    elif s.kind in {skType, skGenericParam}:
+    of skType:
       result = newSymNodeTypeDesc(s, n.info)
+    of skGenericParam:
+      if s.typ.kind == tyExpr:
+        result = s.typ.n
+        result.typ = s.typ.sons[0]
+      else:
+        result = newSymNodeTypeDesc(s, n.info)
+    else: nil
   of nkCharLit..nkNilLit: 
     result = copyNode(n)
   of nkIfExpr: 
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 601072833..0cf5086a8 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -130,13 +130,50 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
       s.ast.sons[genericParamsPos].kind == nkEmpty:
     c.threadEntries.add(s)
 
+proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PType =
+  InternalAssert invocation.kind == tyGenericInvokation
+  
+  let cacheHit = searchInstTypes(invocation)
+  if cacheHit != nil:
+    result = cacheHit
+  else:
+    let s = invocation.sons[0].sym
+    let oldScope = c.currentScope
+    c.currentScope = s.typScope
+    openScope(c)
+    pushInfoContext(info)
+    for i in 0 .. <s.typ.n.sons.len:
+      let genericParam = s.typ.n[i].sym
+      let symKind = if genericParam.typ.kind == tyExpr: skConst
+                    else: skType
+
+      var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info)
+      boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr})
+      boundSym.ast = invocation.sons[i+1].n
+      addDecl(c, boundSym)
+    # XXX: copyTree would have been unnecessary here if semTypeNode
+    # didn't modify its input parameters. Currently, it does modify
+    # at least the record lists of the passed object and tuple types
+    var instantiated = semTypeNode(c, copyTree(s.ast[2]), nil)
+    popInfoContext()
+    closeScope(c)
+    c.currentScope = oldScope
+    if instantiated != nil:
+      result = invocation
+      result.kind = tyGenericInst
+      result.sons.add instantiated
+      cacheTypeInst result
+
 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)
+  when oUseLateInstantiation:
+    lateInstantiateGeneric(c, header, info)
+  else:
+    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)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 41c379133..b9ef8b008 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -40,7 +40,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
     (typArg.kind == skParam and typArg.typ.sonsLen > 0):
     # This is either a type known to sem or a typedesc
     # param to a regular proc (again, known at instantiation)
-    result = evalTypeTrait(n, GetCurrOwner())
+    result = evalTypeTrait(n[0], n[1], GetCurrOwner())
   else:
     # a typedesc variable, pass unmodified to evals
     result = n
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 33c0adac1..a15b3e10a 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -729,12 +729,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       # like: mydata.seq
       rawAddSon(s.typ, newTypeS(tyEmpty, c))
       s.ast = a
-      inc c.InGenericContext
-      var body = semTypeNode(c, a.sons[2], nil)
-      dec c.InGenericContext
-      if body != nil:
-        body.sym = s
-        body.size = -1 # could not be computed properly
+      when oUseLateInstantiation:
+        var body: PType = nil
+        s.typScope = c.currentScope.parent
+      else:
+        inc c.InGenericContext
+        var body = semTypeNode(c, a.sons[2], nil)
+        dec c.InGenericContext
+        if body != nil:
+          body.sym = s
+          body.size = -1 # could not be computed properly
       s.typ.sons[sonsLen(s.typ) - 1] = body
       popOwner()
       closeScope(c)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 8ae23f851..b02fa7c31 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -156,7 +156,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
     LocalError(n.Info, errRangeIsEmpty)
   var a = semConstExpr(c, n[1])
   var b = semConstExpr(c, n[2])
-  if not sameType(a.typ, b.typ): 
+  if not sameType(a.typ, b.typ):
     LocalError(n.info, errPureTypeMismatch)
   elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,
                          tyFloat..tyFloat128,tyUInt8..tyUInt32}:
@@ -195,17 +195,19 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
     else:
       let e = semExprWithType(c, n.sons[1], {efDetermineType})
       if e.kind in {nkIntLit..nkUInt64Lit}:
-        indx = newTypeS(tyRange, c)
-        indx.n = newNodeI(nkRange, n.info)
-        addSon(indx.n, newIntTypeNode(e.kind, 0, e.typ))
-        addSon(indx.n, newIntTypeNode(e.kind, e.intVal-1, e.typ))
-        addSonSkipIntLit(indx, e.typ)
+        indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
+      elif e.kind == nkSym and e.typ.kind == tyExpr:
+        if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
+        InternalAssert c.InGenericContext > 0
+        if not isOrdinalType(e.typ.lastSon):
+          localError(n[1].info, errOrdinalTypeExpected)
+        indx = e.typ
       else:
         indx = e.typ.skipTypes({tyTypeDesc})
     addSonSkipIntLit(result, indx)
     if indx.kind == tyGenericInst: indx = lastSon(indx)
-    if indx.kind != tyGenericParam: 
-      if not isOrdinalType(indx): 
+    if indx.kind notin {tyGenericParam, tyExpr}:
+      if not isOrdinalType(indx):
         LocalError(n.sons[1].info, errOrdinalTypeExpected)
       elif enumHasHoles(indx): 
         LocalError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
@@ -587,6 +589,8 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
   else:
     if sfGenSym notin param.flags: addDecl(c, param)
 
+let typedescId = getIdent"typedesc"
+
 proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                    paramType: PType, paramName: string,
                    info: TLineInfo, anon = false): PType =
@@ -634,6 +638,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
   of tyTypeDesc:
     if tfUnresolved notin paramType.flags:
+      # naked typedescs are not bindOnce types
+      if paramType.sonsLen == 0 and paramTypId != nil and
+         paramTypId.id == typedescId.id: paramTypId = nil
       result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
   of tyDistinct:
     if paramType.sonsLen == 1:
@@ -760,7 +767,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         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)
@@ -846,7 +853,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
         LocalError(n.info, errCannotInstantiateX, s.name.s)
         result = newOrPrevType(tyError, prev, c)
       else:
-        result = instGenericContainer(c, n, result)
+        when oUseLateInstantiation:
+          result = lateInstantiateGeneric(c, result, n.info)
+        else:
+          result = instGenericContainer(c, n, result)
 
 proc semTypeExpr(c: PContext, n: PNode): PType =
   var n = semExprWithType(c, n, {efDetermineType})
@@ -1073,8 +1083,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
     if constraint.kind != nkEmpty:
       typ = semTypeNode(c, constraint, nil)
       if typ.kind != tyExpr or typ.len == 0:
-        if typ.len == 0 and typ.kind == tyTypeDesc:
-          typ = newTypeS(tyGenericParam, c)
+        if typ.kind == tyTypeDesc:
+          if typ.len == 0:
+            typ = newTypeS(tyTypeDesc, c)
         else:
           typ = semGenericConstraints(c, typ)
     
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 31fbc33e1..0c15c7248 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -31,7 +31,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
       if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: 
         localError(info, errInheritanceOnlyWithNonFinalObjects)
 
-proc searchInstTypes(key: PType): PType =
+proc searchInstTypes*(key: PType): PType =
   let genericTyp = key.sons[0]
   InternalAssert genericTyp.kind == tyGenericBody and
                  key.sons[0] == genericTyp and
@@ -55,7 +55,7 @@ proc searchInstTypes(key: PType): PType =
       
       return inst
 
-proc cacheTypeInst(inst: PType) =
+proc cacheTypeInst*(inst: PType) =
   # XXX: add to module's generics
   #      update the refcount
   let genericTyp = inst.sons[0]
@@ -208,6 +208,12 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   of tyInt:
     result = skipIntLit(t)
   else:
+    if t.kind == tyArray:
+      let idxt = t.sons[0]
+      if idxt.kind == tyExpr 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 = copyType(t, t.owner, false)
       incl(result.flags, tfFromGeneric)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 27c780391..a37b47366 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -626,7 +626,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyGenericParam, tyTypeClass:
     var x = PType(idTableGet(c.bindings, f))
     if x == nil:
-      if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
+      if c.calleeSym != nil and c.calleeSym.kind == skType and
+         f.kind == tyGenericParam and not c.typedescMatched:
         # XXX: The fact that generic types currently use tyGenericParam for 
         # their parameters is really a misnomer. tyGenericParam means "match
         # any value" and what we need is "match any type", which can be encoded
@@ -670,7 +671,9 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         result = isNone
     else:
       InternalAssert prev.sonsLen == 1
-      result = typeRel(c, prev.sons[0], a)
+      let toMatch = if tfUnresolved in f.flags: a
+                    else: a.sons[0]
+      result = typeRel(c, prev.sons[0], toMatch)
   of tyExpr, tyStmt:
     result = isGeneric
   of tyProxy:
@@ -772,6 +775,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
         if evaluated != nil:
           r = isGeneric
           arg.typ = newTypeS(tyExpr, c)
+          arg.typ.sons = @[evaluated.typ]
           arg.typ.n = evaluated
         
     if r == isGeneric: