summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md3
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/semtypes.nim16
-rw-r--r--lib/pure/collections/sequtils.nim22
-rw-r--r--lib/system.nim9
5 files changed, 47 insertions, 4 deletions
diff --git a/changelog.md b/changelog.md
index 9a5671757..e9e48d035 100644
--- a/changelog.md
+++ b/changelog.md
@@ -27,6 +27,9 @@
 
 - Added `or` for `NimNode` in `macros`.
 
+- Added `system.typeof` for more control over how `type` expressions
+  can be deduced.
+
 ### Library changes
 
 
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 13e0d0d11..648dcd8c4 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -84,6 +84,7 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimNoNilSeqs2")
   defineSymbol("nimHasUserErrors")
   defineSymbol("nimUncheckedArrayTyp")
+  defineSymbol("nimHasTypeof")
 
   defineSymbol("nimHasNilSeqs")
   for f in low(Feature)..high(Feature):
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index bbd966b38..f3ad46a9d 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1414,6 +1414,20 @@ proc semTypeof(c: PContext; n: PNode; prev: PType): PType =
   fixupTypeOf(c, prev, t)
   result = t.typ
 
+proc semTypeof2(c: PContext; n: PNode; prev: PType): PType =
+  openScope(c)
+  var m = BiggestInt 1 # typeOfIter
+  if n.len == 3:
+    let mode = semConstExpr(c, n[2])
+    if mode.kind != nkIntLit:
+      localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
+    else:
+      m = mode.intVal
+  let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
+  closeScope(c)
+  fixupTypeOf(c, prev, t)
+  result = t.typ
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   inc c.inTypeContext
@@ -1494,6 +1508,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       elif op.id == ord(wType):
         checkSonsLen(n, 2, c.config)
         result = semTypeof(c, n[1], prev)
+      elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeof:
+        result = semTypeOf2(c, n, prev)
       else:
         if c.inGenericContext > 0 and n.kind == nkCall:
           result = makeTypeFromExpr(c, n.copyTree)
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 2e21786bb..e8ea675f5 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -673,10 +673,16 @@ template mapIt*(s: typed, op: untyped): untyped =
   ##     nums = @[1, 2, 3, 4]
   ##     strings = nums.mapIt($(4 * it))
   ##   assert strings == @["4", "8", "12", "16"]
-  type outType = type((
-    block:
-      var it{.inject.}: type(items(s));
-      op))
+  when defined(nimHasTypeof):
+    type outType = typeof((
+      block:
+        var it{.inject.}: typeof(items(s), typeOfIter);
+        op), typeOfProc)
+  else:
+    type outType = type((
+      block:
+        var it{.inject.}: type(items(s));
+        op))
   when compiles(s.len):
     block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580
 
@@ -1135,5 +1141,13 @@ when isMainModule:
       A, B
     doAssert mapIt(X, $it) == @["A", "B"]
 
+  block:
+    # bug #9093
+    let inp = "a:b,c:d"
+
+    let outp = inp.split(",").mapIt(it.split(":"))
+    doAssert outp == @[@["a", "b"], @["c", "d"]]
+
+
   when not defined(testing):
     echo "Finished doc tests"
diff --git a/lib/system.nim b/lib/system.nim
index 469f5cebe..5ff9ffbeb 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -180,6 +180,15 @@ else:
     ## Cannot be overloaded.
     discard
 
+when defined(nimHasTypeof):
+  type
+    TypeOfMode* = enum ## Possible modes of `typeof`.
+      typeOfProc,      ## Prefer the interpretation that means `x` is a proc call.
+      typeOfIter       ## Prefer the interpretation that means `x` is an iterator call.
+  proc typeof*(x: untyped; mode = typeOfIter): typeDesc {.magic: "TypeOf", noSideEffect, compileTime.} =
+    ## Builtin 'typeof' operation for accessing the type of an expression. Since version 0.20.0.
+    discard
+
 proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.}
   ## Boolean not; returns true iff ``x == false``.