summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-03-02 20:23:56 +0100
committerAraq <rumpf_a@web.de>2013-03-02 20:23:56 +0100
commiteebee0eff2360219d02d4cf40675734f3361090a (patch)
tree2d53a720b7a17854e1d1d23f7a8ce7d270687080 /compiler
parentdc07732daa71d0868dd4c5901fa1a23c0dcd382d (diff)
downloadNim-eebee0eff2360219d02d4cf40675734f3361090a.tar.gz
lazy operand sem'checking (beware)
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/sem.nim16
-rwxr-xr-xcompiler/semdata.nim7
-rwxr-xr-xcompiler/semexprs.nim22
-rwxr-xr-xcompiler/semstmts.nim16
-rwxr-xr-xcompiler/sigmatch.nim63
5 files changed, 81 insertions, 43 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 555f5e7b7..f20ab9a05 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -19,13 +19,9 @@ import
 
 # implementation
 
-type 
-  TExprFlag = enum 
-    efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
-  TExprFlags = set[TExprFlag]
-
-proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
-proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
+proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
+  procvar.}
 proc semExprNoType(c: PContext, n: PNode): PNode
 proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semProcBody(c: PContext, n: PNode): PNode
@@ -200,14 +196,12 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
         addSon(n, prc.ast)
   c.lastGenericIdx = c.generics.len
 
-proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} = 
-  result = semExpr(c, n, {})
-
 proc myOpen(module: PSym): PPassContext =
   var c = newContext(module)
   if c.p != nil: InternalError(module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
-  c.semExpr = semExprNoFlags
+  c.semExpr = semExpr
+  c.semExprWithType = semExprWithType
   c.semConstBoolExpr = semConstBoolExpr
   c.semOverloadedCall = semOverloadedCall
   c.semTypeNode = semTypeNode
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index f5d5a9604..dd5f76172 100755
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -39,6 +39,10 @@ type
   TInstantiationPair* = object
     genericSym*: PSym
     inst*: PInstantiation
+
+  TExprFlag* = enum 
+    efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
+  TExprFlags* = set[TExprFlag]
     
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
@@ -64,7 +68,8 @@ type
                                # to some new symbol in a generic instantiation
     libs*: TLinkedList         # all libs used by this module
     semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
-    semExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}      # for the pragmas
+    semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
+    semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
     semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
     semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
                               filter: TSymKinds): PNode {.nimcall.}
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 1fcd7105d..b6e328926 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -31,10 +31,6 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
 
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 
-proc newDeref(n: PNode): PNode {.inline.} =  
-  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
-  addSon(result, n)
-
 proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
   result = semExpr(c, n, flags)
   if result.kind == nkEmpty: 
@@ -319,7 +315,7 @@ proc semIs(c: PContext, n: PNode): PNode =
   
 proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
-  for i in countup(1, n.sonsLen- 1):
+  for i in countup(1, n.sonsLen-1):
     var a = n.sons[i]
     if a.kind == nkExprEqExpr and sonsLen(a) == 2: 
       var info = a.sons[0].info
@@ -328,7 +324,7 @@ proc semOpAux(c: PContext, n: PNode) =
       a.typ = a.sons[1].typ
     else:
       n.sons[i] = semExprWithType(c, a, flags)
-    
+
 proc overloadedCallOpr(c: PContext, n: PNode): PNode = 
   # quick check if there is *any* () operator overloaded:
   var par = getIdent("()")
@@ -694,7 +690,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
   # this seems to be a hotspot in the compiler!
   let nOrig = n.copyTree
-  semOpAux(c, n)
+  #semLazyOpAux(c, n)
   result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
   if result == nil:
     result = overloadedCallOpr(c, n)
@@ -706,6 +702,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   of skMacro: result = semMacroExpr(c, result, nOrig, callee)
   of skTemplate: result = semTemplateExpr(c, result, callee)
   else:
+    semFinishOperands(c, n)
     activate(c, n)
     fixAbstractType(c, result)
     analyseIfAddressTakenInCall(c, result)
@@ -845,16 +842,17 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     return semSym(c, n, s, flags)
 
   n.sons[0] = semExprWithType(c, n.sons[0], flags)
-  restoreOldStyleType(n.sons[0])
+  #restoreOldStyleType(n.sons[0])
   var i = considerAcc(n.sons[1])
   var ty = n.sons[0].typ
   var f: PSym = nil
   result = nil
-  if isTypeExpr(n.sons[0]):
+  if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.len == 1:
+    if ty.kind == tyTypeDesc: ty = ty.sons[0]
     case ty.kind
-    of tyEnum: 
+    of tyEnum:
       # look up if the identifier belongs to the enum:
-      while ty != nil: 
+      while ty != nil:
         f = getSymFromList(ty.n, i)
         if f != nil: break 
         ty = ty.sons[0]         # enum inheritance
@@ -881,7 +879,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # XXX: This is probably not relevant any more
     # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
     ty = n.sons[0].Typ
-      
+    
   ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
   var check: PNode = nil
   if ty.kind == tyObject: 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 63e632eca..dacd397a2 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -484,10 +484,17 @@ proc semForVars(c: PContext, n: PNode): PNode =
   n.sons[length-1] = SemStmt(c, n.sons[length-1])
   Dec(c.p.nestedLoopCounter)
 
+proc newDeref(n: PNode): PNode {.inline.} =  
+  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
+  addSon(result, n)
+
 proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
   result = newNodeI(nkCall, arg.info)
   result.add(newIdentNode(it.getIdent, arg.info))
-  result.add(arg)
+  if arg.typ != nil and arg.typ.kind == tyVar: 
+    result.add newDeref(arg)
+  else:
+    result.add arg
   result = semExprNoDeref(c, result, {efWantIterator})
 
 proc semFor(c: PContext, n: PNode): PNode = 
@@ -776,8 +783,7 @@ proc activate(c: PContext, n: PNode) =
   # XXX: This proc is part of my plan for getting rid of
   # forward declarations. stay tuned.
   when false:
-    # well for now it breaks code ... I added the test case in main.nim of the
-    # compiler itself to break bootstrapping :P
+    # well for now it breaks code ...
     case n.kind
     of nkLambdaKinds:
       discard semLambda(c, n, {})
@@ -1142,8 +1148,8 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
   else:
     return false
 
-proc insertDestructors(c: PContext, varSection: PNode):
-  tuple[outer: PNode, inner: PNode] =
+proc insertDestructors(c: PContext,
+                       varSection: PNode): tuple[outer, inner: PNode] =
   # Accepts a var or let section.
   #
   # When a var section has variables with destructors
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 2159abecd..896d08665 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -799,6 +799,28 @@ proc setSon(father: PNode, at: int, son: PNode) =
   if sonsLen(father) <= at: setlen(father.sons, at + 1)
   father.sons[at] = son
 
+# we are allowed to modify the calling node in the 'prepare*' procs:
+proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
+  if formal.kind == tyExpr and formal.len != 1:
+    # {tyTypeDesc, tyExpr, tyStmt, tyProxy}:
+    # a.typ == nil is valid
+    result = a
+  elif a.typ.isNil:
+    result = c.semExprWithType(c, a, {efDetermineType})
+  else:
+    result = a
+
+proc prepareOperand(c: PContext; a: PNode): PNode =
+  if a.typ.isNil:
+    result = c.semExprWithType(c, a, {efDetermineType})
+  else:
+    result = a
+
+proc prepareNamedParam(a: PNode) =
+  if a.sons[0].kind != nkIdent:
+    var info = a.sons[0].info
+    a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
+
 proc matchesAux(c: PContext, n, nOrig: PNode,
                 m: var TCandidate, marker: var TIntSet) = 
   template checkConstraint(n: expr) {.immediate, dirty.} =
@@ -823,6 +845,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
     if n.sons[a].kind == nkExprEqExpr:
       # named param
       # check if m.callee has such a param:
+      prepareNamedParam(n.sons[a])
       if n.sons[a].sons[0].kind != nkIdent: 
         LocalError(n.sons[a].info, errNamedParamHasToBeIdent)
         m.state = csNoMatch
@@ -838,9 +861,11 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         m.state = csNoMatch
         return 
       m.baseTypeMatch = false
+      n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
+      n.sons[a].typ = n.sons[a].sons[1].typ
       var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
                                 n.sons[a].sons[1], nOrig.sons[a].sons[1])
-      if arg == nil: 
+      if arg == nil:
         m.state = csNoMatch
         return
       checkConstraint(n.sons[a].sons[1])
@@ -852,30 +877,33 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         if f != formalLen - 1: container = nil
       else: 
         setSon(m.call, formal.position + 1, arg)
-    else: 
+    else:
       # unnamed param
-      if f >= formalLen: 
+      if f >= formalLen:
         # too many arguments?
-        if tfVarArgs in m.callee.flags: 
+        if tfVarArgs in m.callee.flags:
           # is ok... but don't increment any counters...
-          if skipTypes(n.sons[a].typ, abstractVar).kind == tyString: 
-            addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString), 
+          # we have no formal here to snoop at:
+          n.sons[a] = prepareOperand(c, n.sons[a])
+          if skipTypes(n.sons[a].typ, abstractVar).kind == tyString:
+            addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
                                         copyTree(n.sons[a]), m, c))
-          else: 
+          else:
             addSon(m.call, copyTree(n.sons[a]))
         elif formal != nil:
           m.baseTypeMatch = false
+          n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
           var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
                                     n.sons[a], nOrig.sons[a])
-          if (arg != nil) and m.baseTypeMatch and (container != nil): 
+          if (arg != nil) and m.baseTypeMatch and (container != nil):
             addSon(container, arg)
-          else: 
+          else:
             m.state = csNoMatch
-            return 
-        else: 
+            return
+        else:
           m.state = csNoMatch
-          return 
-      else: 
+          return
+      else:
         if m.callee.n.sons[f].kind != nkSym: 
           InternalError(n.sons[a].info, "matches")
           return
@@ -886,6 +914,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.state = csNoMatch
           return 
         m.baseTypeMatch = false
+        n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
         var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
                                   n.sons[a], nOrig.sons[a])
         if arg == nil:
@@ -898,12 +927,18 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           setSon(m.call, formal.position + 1, 
                  implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
           if f != formalLen - 1: container = nil
-        else: 
+        else:
           setSon(m.call, formal.position + 1, arg)
       checkConstraint(n.sons[a])
     inc(a)
     inc(f)
 
+proc semFinishOperands*(c: PContext, n: PNode) =
+  # this needs to be called to ensure that after overloading resolution every
+  # argument has been sem'checked:
+  for i in 1 .. <n.len:
+    n.sons[i] = prepareOperand(c, n.sons[i])
+
 proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
   # for 'suggest' support:
   var marker = initIntSet()