summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-05-06 18:30:54 +0200
committerAraq <rumpf_a@web.de>2013-05-06 18:30:54 +0200
commit6c0425d574bc45417e126bb2712fb42ddf9e553c (patch)
treebc1c175c9025425f5239ac8c32afe4b7600ecc73 /compiler
parent23bd3ccd8bc1b6aae931a3754ad478849c3be82d (diff)
downloadNim-6c0425d574bc45417e126bb2712fb42ddf9e553c.tar.gz
'result/return' triggers a void context
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ccgexprs.nim16
-rw-r--r--compiler/semstmts.nim67
2 files changed, 60 insertions, 23 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index a50b39d47..2f7804384 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1799,10 +1799,20 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
      nkCallStrLit:
     genLineDir(p, n)
-    if n.sons[0].kind == nkSym and n.sons[0].sym.magic != mNone:
-      genMagicExpr(p, n, d, n.sons[0].sym.magic)
+    let op = n.sons[0]
+    if n.typ.isNil:
+      # discard the value:
+      var a: TLoc
+      if op.kind == nkSym and op.sym.magic != mNone:
+        genMagicExpr(p, n, a, op.sym.magic)
+      else:
+        genCall(p, n, a)
     else:
-      genCall(p, n, d)
+      # load it into 'd':
+      if op.kind == nkSym and op.sym.magic != mNone:
+        genMagicExpr(p, n, d, op.sym.magic)
+      else:
+        genCall(p, n, d)
   of nkCurly:
     if isDeepConstExpr(n) and n.len != 0:
       putIntoDest(p, d, n.typ, genSetNode(p, n))
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index bca77e06a..c8fc3e3d3 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -10,6 +10,8 @@
 ## this module does the semantic checking of statements
 #  included from sem.nim
 
+var EnforceVoidContext = PType(kind: tyStmt)
+
 proc semCommand(c: PContext, n: PNode): PNode =
   result = semExprNoType(c, n)
   
@@ -56,6 +58,8 @@ proc semWhile(c: PContext, n: PNode): PNode =
   n.sons[1] = semStmt(c, n.sons[1])
   dec(c.p.nestedLoopCounter)
   closeScope(c.tab)
+  if n.sons[1].typ == EnforceVoidContext:
+    result.typ = EnforceVoidContext
 
 proc toCover(t: PType): biggestInt = 
   var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
@@ -121,19 +125,21 @@ proc fixNilType(n: PNode) =
     if n.kind != nkNilLit and n.typ != nil:
       localError(n.info, errDiscardValue)
   elif n.kind in {nkStmtList, nkStmtListExpr}:
+    n.kind = nkStmtList
     for it in n: fixNilType(it)
   n.typ = nil
 
-var EnforceVoidContext = PType(kind: tyStmt)
-
 proc discardCheck(result: PNode) =
   if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
     if result.kind == nkNilLit:
-      # XXX too much work and fixing would break bootstrapping:
-      #Message(n.info, warnNilStatement)
       result.typ = nil
-    elif not ImplicitlyDiscardable(result) and result.typ.kind != tyError and
-        gCmd != cmdInteractive:
+    elif ImplicitlyDiscardable(result):
+      var n = result
+      result.typ = nil
+      while n.kind == nkStmtListExpr:
+        n = n.lastSon
+        n.typ = nil
+    elif result.typ.kind != tyError and gCmd != cmdInteractive:
       if result.typ.kind == tyNil:
         fixNilType(result)
       else:
@@ -157,16 +163,17 @@ proc semIf(c: PContext, n: PNode): PNode =
       it.sons[0] = semExprBranchScope(c, it.sons[0])
       typ = commonType(typ, it.sons[0].typ)
     else: illFormedAst(it)
-  if isEmptyType(typ) or not hasElse:
+  if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
     for it in n: discardCheck(it.lastSon)
     result.kind = nkIfStmt
+    # propagate any enforced VoidContext:
+    if typ == EnforceVoidContext: result.typ = EnforceVoidContext
   else:
     for it in n:
       let j = it.len-1
       it.sons[j] = fitNode(c, typ, it.sons[j])
     result.kind = nkIfExpr
-  # propagate any enforced VoidContext:
-  result.typ = typ
+    result.typ = typ
 
 proc semCase(c: PContext, n: PNode): PNode =
   result = n
@@ -211,20 +218,25 @@ proc semCase(c: PContext, n: PNode): PNode =
       hasElse = true
     else:
       illFormedAst(x)
-  if chckCovered and (covered != toCover(n.sons[0].typ)): 
-    localError(n.info, errNotAllCasesCovered)
+  if chckCovered:
+    if covered == toCover(n.sons[0].typ):
+      hasElse = true
+    else:
+      localError(n.info, errNotAllCasesCovered)
   closeScope(c.tab)
-  if isEmptyType(typ) or not hasElse:
+  if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
     for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
+    # propagate any enforced VoidContext:
+    if typ == EnforceVoidContext:
+      result.typ = EnforceVoidContext
   else:
     for i in 1..n.len-1:
       var it = n.sons[i]
       let j = it.len-1
       it.sons[j] = fitNode(c, typ, it.sons[j])
-  # propagate any enforced VoidContext:
-  result.typ = typ
+    result.typ = typ
 
-proc semTry(c: PContext, n: PNode): PNode = 
+proc semTry(c: PContext, n: PNode): PNode =
   result = n
   inc c.p.inTryStmt
   checkMinSonsLen(n, 2)
@@ -257,17 +269,18 @@ proc semTry(c: PContext, n: PNode): PNode =
     a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
     typ = commonType(typ, a.sons[length-1].typ)
   dec c.p.inTryStmt
-  if isEmptyType(typ):
+  if isEmptyType(typ) or typ.kind == tyNil:
     discardCheck(n.sons[0])
     for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
+    if typ == EnforceVoidContext:
+      result.typ = EnforceVoidContext
   else:
     n.sons[0] = fitNode(c, typ, n.sons[0])
     for i in 1..n.len-1:
       var it = n.sons[i]
       let j = it.len-1
       it.sons[j] = fitNode(c, typ, it.sons[j])
-  # propagate any enforced VoidContext:
-  result.typ = typ
+    result.typ = typ
   
 proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = 
   result = fitNode(c, typ, n)
@@ -627,7 +640,8 @@ proc semFor(c: PContext, n: PNode): PNode =
   else:
     result = semForVars(c, n)
   # propagate any enforced VoidContext:
-  result.typ = n.sons[length-1].typ
+  if n.sons[length-1].typ == EnforceVoidContext:
+    result.typ = EnforceVoidContext
   closeScope(c.tab)
 
 proc semRaise(c: PContext, n: PNode): PNode = 
@@ -1076,11 +1090,24 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
     result = newNodeI(nkDiscardStmt, n.info, 1)
     result.sons[0] = emptyNode
 
+proc usesResult(n: PNode): bool =
+  # nkStmtList(expr) properly propagates the void context,
+  # so we don't need to process that all over again:
+  if n.kind notin {nkStmtList, nkStmtListExpr}:
+    if isAtom(n):
+      result = n.kind == nkSym and n.sym.kind == skResult
+    elif n.kind == nkReturnStmt:
+      result = true
+    else:
+      for c in n:
+        if usesResult(c): return true
+
 proc semStmtList(c: PContext, n: PNode): PNode =
   # these must be last statements in a block:
   const
     LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
   result = n
+  result.kind = nkStmtList
   var length = sonsLen(n)
   var voidContext = false
   var last = length-1
@@ -1113,7 +1140,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
       return
     else:
       n.sons[i] = semExpr(c, n.sons[i])
-      if n.sons[i].typ == EnforceVoidContext:
+      if n.sons[i].typ == EnforceVoidContext or usesResult(n.sons[i]):
         voidContext = true
         n.typ = EnforceVoidContext
       elif i != last or voidContext: