summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2018-09-11 19:02:05 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-09-11 19:02:05 +0200
commit84d122b5c872d7d045516f62e4843189fbb12c9c (patch)
tree00e038d886543b1409fbe080a65d63cc5e86ac7a
parentf7d1902043c1bc70ba0bb159a3e8c71b78947ad7 (diff)
downloadNim-84d122b5c872d7d045516f62e4843189fbb12c9c.tar.gz
extended system.type/typeof to support an upcoming 'collect' macro that works much better than sugar.lc
-rw-r--r--compiler/sem.nim8
-rw-r--r--compiler/semexprs.nim24
-rw-r--r--compiler/semfields.nim4
-rw-r--r--compiler/semstmts.nim70
-rw-r--r--compiler/semtypes.nim17
5 files changed, 67 insertions, 56 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 7a83c3079..5e5205c20 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -37,7 +37,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
 
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
-proc semStmt(c: PContext, n: PNode): PNode
+proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode
 proc semOpAux(c: PContext, n: PNode)
 proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
 proc addParams(c: PContext, n: PNode, kind: TSymKind)
@@ -399,7 +399,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
   excl(result.flags, nfSem)
   #resetSemFlag n
   if s.typ.sons[0] == nil:
-    result = semStmt(c, result)
+    result = semStmt(c, result, flags)
   else:
     case s.typ.sons[0].kind
     of tyExpr:
@@ -408,7 +408,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
       # semExprWithType(c, result)
       result = semExpr(c, result, flags)
     of tyStmt:
-      result = semStmt(c, result)
+      result = semStmt(c, result, flags)
     of tyTypeDesc:
       if result.kind == nkStmtList: result.kind = nkStmtListType
       var typ = semTypeNode(c, result, nil)
@@ -557,7 +557,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
     result = semAllTypeSections(c, n)
   else:
     result = n
-  result = semStmt(c, result)
+  result = semStmt(c, result, {})
   when false:
     # Code generators are lazy now and can deal with undeclared procs, so these
     # steps are not required anymore and actually harmful for the upcoming
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index e527b06cc..43f04fc9f 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -918,7 +918,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
   let isPush = hintExtendedContext in c.config.notes
   if isPush: pushInfoContext(c.config, n.info)
   result = semExpr(c, n, {efWantStmt})
-  discardCheck(c, result)
+  discardCheck(c, result, {})
   if isPush: popInfoContext(c.config)
 
 proc isTypeExpr(n: PNode): bool =
@@ -1530,7 +1530,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
       # unfortunately we need to rewrite ``(x, y) = foo()`` already here so
       # that overloading of the assignment operator still works. Usually we
       # prefer to do these rewritings in transf.nim:
-      return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner))
+      return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner), {})
     else:
       a = semExprWithType(c, a, {efLValue})
   else:
@@ -1614,7 +1614,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       a.sons[1] = result
       result = semAsgn(c, a)
   else:
-    discardCheck(c, result)
+    discardCheck(c, result, {})
 
   if c.p.owner.kind notin {skMacro, skTemplate} and
      c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
@@ -1990,7 +1990,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     var x = n.lastSon
     if x.kind == nkDo: x = x.sons[bodyPos]
     inc c.inParallelStmt
-    result.sons[1] = semStmt(c, x)
+    result.sons[1] = semStmt(c, x, {})
     dec c.inParallelStmt
   of mSpawn:
     result = setMs(n, s)
@@ -2241,7 +2241,7 @@ proc isTupleType(n: PNode): bool =
 
 include semobjconstr
 
-proc semBlock(c: PContext, n: PNode): PNode =
+proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   inc(c.p.nestedBlockCounter)
   checkSonsLen(n, 2, c.config)
@@ -2253,7 +2253,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
     n.sons[0] = newSymNode(labl, n.sons[0].info)
     suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
     styleCheckDef(c.config, labl)
-  n.sons[1] = semExpr(c, n.sons[1])
+  n.sons[1] = semExpr(c, n.sons[1], flags)
   n.typ = n.sons[1].typ
   if isEmptyType(n.typ): n.kind = nkBlockStmt
   else: n.kind = nkBlockExpr
@@ -2498,7 +2498,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     checkSonsLen(n, 1, c.config)
     n.sons[0] = semExpr(c, n.sons[0], flags)
   of nkCast: result = semCast(c, n)
-  of nkIfExpr, nkIfStmt: result = semIf(c, n)
+  of nkIfExpr, nkIfStmt: result = semIf(c, n, flags)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
     checkSonsLen(n, 2, c.config)
     considerGenSyms(c, n)
@@ -2519,7 +2519,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     discard
   of nkStaticExpr: result = semStaticExpr(c, n[0])
   of nkAsgn: result = semAsgn(c, n)
-  of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
+  of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
   of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
   of nkRaiseStmt: result = semRaise(c, n)
   of nkVarSection: result = semVarOrLet(c, n, skVar)
@@ -2527,11 +2527,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkConstSection: result = semConst(c, n)
   of nkTypeSection: result = semTypeSection(c, n)
   of nkDiscardStmt: result = semDiscard(c, n)
-  of nkWhileStmt: result = semWhile(c, n)
-  of nkTryStmt: result = semTry(c, n)
+  of nkWhileStmt: result = semWhile(c, n, flags)
+  of nkTryStmt: result = semTry(c, n, flags)
   of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
-  of nkForStmt, nkParForStmt: result = semFor(c, n)
-  of nkCaseStmt: result = semCase(c, n)
+  of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
+  of nkCaseStmt: result = semCase(c, n, flags)
   of nkReturnStmt: result = semReturn(c, n)
   of nkUsingStmt: result = semUsing(c, n)
   of nkAsmStmt: result = semAsm(c, n)
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
index 869f5ae74..07321f477 100644
--- a/compiler/semfields.nim
+++ b/compiler/semfields.nim
@@ -70,7 +70,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
     openScope(c.c)
     inc c.c.inUnrolledContext
     let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
-    father.add(semStmt(c.c, body))
+    father.add(semStmt(c.c, body, {}))
     dec c.c.inUnrolledContext
     closeScope(c.c)
   of nkNilLit: discard
@@ -145,7 +145,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
       fc.replaceByFieldName = m == mFieldPairs
       var body = instFieldLoopBody(fc, loopBody, n)
       inc c.inUnrolledContext
-      stmts.add(semStmt(c, body))
+      stmts.add(semStmt(c, body, {}))
       dec c.inUnrolledContext
       closeScope(c)
   else:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 9a218f225..c032932b8 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -76,17 +76,19 @@ proc semAsm(c: PContext, n: PNode): PNode =
   if marker == '\0': marker = '`' # default marker
   result = semAsmOrEmit(c, n, marker)
 
-proc semWhile(c: PContext, n: PNode): PNode =
+proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   checkSonsLen(n, 2, c.config)
   openScope(c)
   n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
   inc(c.p.nestedLoopCounter)
-  n.sons[1] = semStmt(c, n.sons[1])
+  n.sons[1] = semStmt(c, n.sons[1], flags)
   dec(c.p.nestedLoopCounter)
   closeScope(c)
   if n.sons[1].typ == c.enforceVoidContext:
     result.typ = c.enforceVoidContext
+  elif efInTypeof in flags:
+    result.typ = n[1].typ
 
 proc toCover(c: PContext, t: PType): BiggestInt =
   let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
@@ -97,8 +99,8 @@ proc toCover(c: PContext, t: PType): BiggestInt =
 
 proc semProc(c: PContext, n: PNode): PNode
 
-proc semExprBranch(c: PContext, n: PNode): PNode =
-  result = semExpr(c, n)
+proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =
+  result = semExpr(c, n, flags)
   if result.typ != nil:
     # XXX tyGenericInst here?
     if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
@@ -130,8 +132,9 @@ proc fixNilType(c: PContext; n: PNode) =
     for it in n: fixNilType(c, it)
   n.typ = nil
 
-proc discardCheck(c: PContext, result: PNode) =
-  if c.matchedConcept != nil: return
+proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
+  if c.matchedConcept != nil or efInTypeof in flags: return
+
   if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
     if implicitlyDiscardable(result):
       var n = newNodeI(nkDiscardStmt, result.info, 1)
@@ -148,7 +151,7 @@ proc discardCheck(c: PContext, result: PNode) =
         s.add "; for a function call use ()"
       localError(c.config, n.info, s)
 
-proc semIf(c: PContext, n: PNode): PNode =
+proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   var typ = commonTypeBegin
   var hasElse = false
@@ -165,8 +168,9 @@ proc semIf(c: PContext, n: PNode): PNode =
       it.sons[0] = semExprBranchScope(c, it.sons[0])
       typ = commonType(typ, it.sons[0])
     else: illFormedAst(it, c.config)
-  if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
-    for it in n: discardCheck(c, it.lastSon)
+  if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
+      (not hasElse and efInTypeof notin flags):
+    for it in n: discardCheck(c, it.lastSon, flags)
     result.kind = nkIfStmt
     # propagate any enforced VoidContext:
     if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
@@ -178,8 +182,7 @@ proc semIf(c: PContext, n: PNode): PNode =
     result.kind = nkIfExpr
     result.typ = typ
 
-proc semTry(c: PContext, n: PNode): PNode =
-
+proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
   var check = initIntSet()
   template semExceptBranchType(typeNode: PNode): bool =
     # returns true if exception type is imported type
@@ -246,12 +249,12 @@ proc semTry(c: PContext, n: PNode): PNode =
 
   dec c.p.inTryStmt
   if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
-    discardCheck(c, n.sons[0])
-    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
+    discardCheck(c, n.sons[0], flags)
+    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
     if typ == c.enforceVoidContext:
       result.typ = c.enforceVoidContext
   else:
-    if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
+    if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
     n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
     for i in 1..last:
       var it = n.sons[i]
@@ -570,7 +573,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
   if n.kind == nkPragmaExpr:
     pragma(c, result, n.sons[1], forVarPragmas)
 
-proc semForVars(c: PContext, n: PNode): PNode =
+proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   var length = sonsLen(n)
   let iterBase = n.sons[length-2].typ
@@ -601,7 +604,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
         addForVarDecl(c, v)
   inc(c.p.nestedLoopCounter)
   openScope(c)
-  n.sons[length-1] = semExprBranch(c, n.sons[length-1])
+  n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
   closeScope(c)
   dec(c.p.nestedLoopCounter)
 
@@ -685,7 +688,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
   when false:
     result = handleStmtMacro(c, n, n[0], "CaseStmt")
 
-proc semFor(c: PContext, n: PNode): PNode =
+proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
   checkMinSonsLen(n, 3, c.config)
   var length = sonsLen(n)
   if forLoopMacros in c.features:
@@ -702,14 +705,14 @@ proc semFor(c: PContext, n: PNode): PNode =
   if isCallExpr and call[0].kind == nkSym and
       call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
     if call.sons[0].sym.magic == mOmpParFor:
-      result = semForVars(c, n)
+      result = semForVars(c, n, flags)
       result.kind = nkParForStmt
     else:
       result = semForFields(c, n, call.sons[0].sym.magic)
   elif isCallExpr and call.sons[0].typ.callConv == ccClosure and
       tfIterator in call.sons[0].typ.flags:
     # first class iterator:
-    result = semForVars(c, n)
+    result = semForVars(c, n, flags)
   elif not isCallExpr or call.sons[0].kind != nkSym or
       call.sons[0].sym.kind != skIterator:
     if length == 3:
@@ -718,15 +721,17 @@ proc semFor(c: PContext, n: PNode): PNode =
       n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
     else:
       localError(c.config, n.sons[length-2].info, "iterator within for loop context expected")
-    result = semForVars(c, n)
+    result = semForVars(c, n, flags)
   else:
-    result = semForVars(c, n)
+    result = semForVars(c, n, flags)
   # propagate any enforced VoidContext:
   if n.sons[length-1].typ == c.enforceVoidContext:
     result.typ = c.enforceVoidContext
+  elif efInTypeof in flags:
+    result.typ = result.lastSon.typ
   closeScope(c)
 
-proc semCase(c: PContext, n: PNode): PNode =
+proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   checkMinSonsLen(n, 2, c.config)
   openScope(c)
@@ -782,8 +787,9 @@ proc semCase(c: PContext, n: PNode): PNode =
     else:
       localError(c.config, n.info, "not all cases are covered")
   closeScope(c)
-  if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
-    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
+  if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
+      (not hasElse and efInTypeof notin flags):
+    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
     # propagate any enforced VoidContext:
     if typ == c.enforceVoidContext:
       result.typ = c.enforceVoidContext
@@ -1792,7 +1798,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
       if containsOrIncl(c.includedFiles, f.int):
         localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
       else:
-        addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f)))
+        addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
         excl(c.includedFiles, f.int)
 
 proc setLine(n: PNode, info: TLineInfo) =
@@ -1819,7 +1825,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
   #writeStackTrace()
   inc c.inStaticContext
   openScope(c)
-  let a = semStmt(c, n.sons[0])
+  let a = semStmt(c, n.sons[0], {})
   closeScope(c)
   dec c.inStaticContext
   n.sons[0] = a
@@ -1895,11 +1901,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]):
       voidContext = true
       n.typ = c.enforceVoidContext
-    if i == last and (length == 1 or efWantValue in flags):
+    if i == last and (length == 1 or ({efWantValue, efInTypeof} * flags != {})):
       n.typ = n.sons[i].typ
       if not isEmptyType(n.typ): n.kind = nkStmtListExpr
     elif i != last or voidContext:
-      discardCheck(c, n.sons[i])
+      discardCheck(c, n.sons[i], flags)
     else:
       n.typ = n.sons[i].typ
       if not isEmptyType(n.typ): n.kind = nkStmtListExpr
@@ -1928,6 +1934,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
       # it is an old-style comment statement: we replace it with 'discard ""':
       prettybase.replaceComment(result.info)
 
-proc semStmt(c: PContext, n: PNode): PNode =
-  # now: simply an alias:
-  result = semExprNoType(c, n)
+proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode =
+  if efInTypeof notin flags:
+    result = semExprNoType(c, n)
+  else:
+    result = semExpr(c, n, flags)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 86f3a17ab..a90a06150 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1161,7 +1161,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
   checkMinSonsLen(n, 1, c.config)
   var length = sonsLen(n)
   for i in countup(0, length - 2):
-    n.sons[i] = semStmt(c, n.sons[i])
+    n.sons[i] = semStmt(c, n.sons[i], {})
   if length > 0:
     result = semTypeNode(c, n.sons[length - 1], prev)
     n.typ = result
@@ -1406,6 +1406,13 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
   result.rawAddSon(base)
   result.flags.incl tfHasStatic
 
+proc semTypeof(c: PContext; n: PNode; prev: PType): PType =
+  openScope(c)
+  let t = semExprWithType(c, n, {efInTypeof})
+  closeScope(c)
+  fixupTypeOf(c, prev, t)
+  result = t.typ
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   inc c.inTypeContext
@@ -1416,9 +1423,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkTypeOfExpr:
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     checkSonsLen(n, 1, c.config)
-    let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
-    fixupTypeOf(c, prev, typExpr)
-    result = typExpr.typ
+    result = semTypeof(c, n.sons[0], prev)
     if result.kind == tyTypeDesc: result.flags.incl tfExplicit
   of nkPar:
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
@@ -1487,9 +1492,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = semAnyRef(c, n, tyRef, prev)
       elif op.id == ord(wType):
         checkSonsLen(n, 2, c.config)
-        let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
-        fixupTypeOf(c, prev, typExpr)
-        result = typExpr.typ
+        result = semTypeof(c, n[1], prev)
       else:
         if c.inGenericContext > 0 and n.kind == nkCall:
           result = makeTypeFromExpr(c, n.copyTree)