summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/semmagic.nim16
-rw-r--r--lib/pure/sugar.nim23
-rw-r--r--lib/pure/typetraits.nim17
-rw-r--r--tests/metatype/ttypetraits.nim49
-rw-r--r--tests/stdlib/tstring.nim17
-rw-r--r--tests/stdlib/tsugar.nim37
7 files changed, 91 insertions, 70 deletions
diff --git a/changelog.md b/changelog.md
index 429d0bfe0..b3e5745c6 100644
--- a/changelog.md
+++ b/changelog.md
@@ -17,6 +17,8 @@
   backends, and it is compatible with Python's behavior,
   e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`.
 - Global variable `lc` has been removed from sugar.nim.
+- `distinctBase` has been moved from sugar.nim to typetraits and now implemented as
+  compiler type trait instead of macro. `distinctBase` in sugar module is now deprecated.
 
 ### Breaking changes in the compiler
 
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 307e21ec6..990538096 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -172,6 +172,22 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     let complexObj = containsGarbageCollectedRef(t) or
                      hasDestructor(t)
     result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.graph)
+  of "isNamedTuple":
+    let cond = operand.kind == tyTuple and operand.n != nil
+    result = newIntNodeT(toInt128(ord(cond)), traitCall, c.graph)
+  of "distinctBase":
+    var arg = operand.skipTypes({tyGenericInst})
+    if arg.kind == tyDistinct:
+      while arg.kind == tyDistinct:
+        arg = arg.base
+        arg = arg.skipTypes(skippedTypes + {tyGenericInst})
+      var resType = newType(tyTypeDesc, operand.owner)
+      rawAddSon(resType, arg)
+      result = toNode(resType, traitCall.info)
+    else:
+      localError(c.config, traitCall.info,
+        "distinctBase expects a distinct type as argument. The given type was " & typeToString(operand))
+      result = newType(tyError, context).toNode(traitCall.info)
   else:
     localError(c.config, traitCall.info, "unknown trait: " & s)
     result = newNodeI(nkEmpty, traitCall.info)
diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim
index a084d4e00..e7ef63309 100644
--- a/lib/pure/sugar.nim
+++ b/lib/pure/sugar.nim
@@ -13,6 +13,7 @@
 include system/inclrtl
 
 import macros
+import typetraits
 
 proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
   #echo treeRepr(p)
@@ -160,27 +161,9 @@ proc freshIdentNodes(ast: NimNode): NimNode =
         result.add inspect(child)
   result = inspect(ast)
 
-macro distinctBase*(T: typedesc): untyped =
+template distinctBase*(T: typedesc): typedesc {.deprecated: "use distinctBase from typetraits instead".} =
   ## reverses ``type T = distinct A``; works recursively.
-  runnableExamples:
-    type T = distinct int
-    doAssert distinctBase(T) is int
-    doAssert: not compiles(distinctBase(int))
-    type T2 = distinct T
-    doAssert distinctBase(T2) is int
-
-  let typeNode = getTypeImpl(T)
-  expectKind(typeNode, nnkBracketExpr)
-  if typeNode[0].typeKind != ntyTypeDesc:
-    error "expected typeDesc, got " & $typeNode[0]
-  var typeSym = typeNode[1]
-  typeSym = getTypeImpl(typeSym)
-  if typeSym.typeKind != ntyDistinct:
-    error "type is not distinct"
-  typeSym = typeSym[0]
-  while typeSym.typeKind == ntyDistinct:
-    typeSym = getTypeImpl(typeSym)[0]
-  typeSym.freshIdentNodes
+  typetraits.distinctBase(T)
 
 macro capture*(locals: openArray[typed], body: untyped): untyped {.since: (1, 1).} =
   ## Useful when creating a closure in a loop to capture some local loop variables
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index 24aed52b0..7a493cb6c 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -63,19 +63,12 @@ proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
   ##
   ## Other languages name a type like these `blob`:idx:.
 
-proc isNamedTuple*(T: typedesc): bool =
+proc isNamedTuple*(T: typedesc): bool {.magic: "TypeTrait".}
   ## Return true for named tuples, false for any other type.
-  when T isnot tuple: result = false
-  else:
-    var t: T
-    for name, _ in t.fieldPairs:
-      when name == "Field0":
-        return compiles(t.Field0)
-      else:
-        return true
-    # empty tuple should be un-named,
-    # see https://github.com/nim-lang/Nim/issues/8861#issue-356631191
-    return false
+
+proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".}
+  ## Returns base type for distinct types, works only for distinct types.
+  ## compile time error otherwise
 
 
 when isMainModule:
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index 8c92122af..3215a21b0 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -1,4 +1,5 @@
 import typetraits
+import macros
 
 block: # isNamedTuple
   type Foo1 = (a:1,).type
@@ -9,6 +10,7 @@ block: # isNamedTuple
   doAssert (a:1,).type.isNamedTuple
   doAssert Foo1.isNamedTuple
   doAssert Foo2.isNamedTuple
+  doAssert isNamedTuple(tuple[key: int])
   doAssert not Foo3.isNamedTuple
   doAssert not Foo4.isNamedTuple
   doAssert not (1,).type.isNamedTuple
@@ -42,3 +44,50 @@ block: # typeToString
   doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 ==
     "tuple[a: C2b{C}[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]"
 
+
+#----------------------------------------------------
+
+block distinctBase:
+  block:
+    type
+      Foo[T] = distinct seq[T]
+    var a: Foo[int]
+    doAssert a.type.distinctBase is seq[int]
+
+  block:
+    # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
+    macro uintImpl(bits: static[int]): untyped =
+      if bits >= 128:
+        let inner = getAST(uintImpl(bits div 2))
+        result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
+      else:
+        result = ident("uint64")
+
+    type
+      BaseUint = UintImpl or SomeUnsignedInt
+      UintImpl[Baseuint] = object
+      Uint[bits: static[int]] = distinct uintImpl(bits)
+
+    doAssert Uint[128].distinctBase is UintImpl[uint64]
+
+    block:
+      type
+        AA = distinct seq[int]
+        BB = distinct string
+        CC = distinct int
+        AAA = AA
+
+      static:
+        var a2: AAA
+        var b2: BB
+        var c2: CC
+
+        doAssert(a2 is distinct)
+        doAssert(b2 is distinct)
+        doAssert(c2 is distinct)
+
+        doAssert($distinctBase(typeof(a2)) == "seq[int]")
+        doAssert($distinctBase(typeof(b2)) == "string")
+        doAssert($distinctBase(typeof(c2)) == "int")
+
+
diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim
index 852ff4fb7..36a2e9800 100644
--- a/tests/stdlib/tstring.nim
+++ b/tests/stdlib/tstring.nim
@@ -1,5 +1,7 @@
 discard """
-  output: "OK"
+  output: '''OK
+@[@[], @[], @[], @[], @[]]
+'''
 """
 const characters = "abcdefghijklmnopqrstuvwxyz"
 const numbers = "1234567890"
@@ -76,3 +78,16 @@ proc test_string_cmp() =
 
 test_string_slice()
 test_string_cmp()
+
+
+#--------------------------
+# bug #7816
+import sugar
+import sequtils
+
+proc tester[T](x: T) =
+  let test = toSeq(0..4).map(i => newSeq[int]())
+  echo test
+
+tester(1)
+
diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim
deleted file mode 100644
index 5006cf52b..000000000
--- a/tests/stdlib/tsugar.nim
+++ /dev/null
@@ -1,37 +0,0 @@
-discard """
-  output: "@[@[], @[], @[], @[], @[]]"
-"""
-import sugar
-import macros
-
-block distinctBase:
-  block:
-    type
-      Foo[T] = distinct seq[T]
-    var a: Foo[int]
-    doAssert a.type.distinctBase is seq[int]
-
-  block:
-    # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
-    macro uintImpl(bits: static[int]): untyped =
-      if bits >= 128:
-        let inner = getAST(uintImpl(bits div 2))
-        result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
-      else:
-        result = ident("uint64")
-
-    type
-      BaseUint = UintImpl or SomeUnsignedInt
-      UintImpl[Baseuint] = object
-      Uint[bits: static[int]] = distinct uintImpl(bits)
-
-    doAssert Uint[128].distinctBase is UintImpl[uint64]
-
-# bug #7816
-import sequtils
-
-proc tester[T](x: T) =
-  let test = toSeq(0..4).map(i => newSeq[int]())
-  echo test
-
-tester(1)