diff options
-rw-r--r-- | changelog.md | 2 | ||||
-rw-r--r-- | compiler/semmagic.nim | 16 | ||||
-rw-r--r-- | lib/pure/sugar.nim | 23 | ||||
-rw-r--r-- | lib/pure/typetraits.nim | 17 | ||||
-rw-r--r-- | tests/metatype/ttypetraits.nim | 49 | ||||
-rw-r--r-- | tests/stdlib/tstring.nim | 17 | ||||
-rw-r--r-- | tests/stdlib/tsugar.nim | 37 |
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) |