distinctBase type trait for distinct types (#13031)
This commit is contained in:
parent
8bcc7e8b9e
commit
871d5e79b1
7 changed files with 91 additions and 70 deletions
|
|
@ -17,6 +17,8 @@
|
||||||
backends, and it is compatible with Python's behavior,
|
backends, and it is compatible with Python's behavior,
|
||||||
e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`.
|
e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`.
|
||||||
- Global variable `lc` has been removed from sugar.nim.
|
- 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
|
### Breaking changes in the compiler
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,22 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
|
||||||
let complexObj = containsGarbageCollectedRef(t) or
|
let complexObj = containsGarbageCollectedRef(t) or
|
||||||
hasDestructor(t)
|
hasDestructor(t)
|
||||||
result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.graph)
|
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:
|
else:
|
||||||
localError(c.config, traitCall.info, "unknown trait: " & s)
|
localError(c.config, traitCall.info, "unknown trait: " & s)
|
||||||
result = newNodeI(nkEmpty, traitCall.info)
|
result = newNodeI(nkEmpty, traitCall.info)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
include system/inclrtl
|
include system/inclrtl
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
import typetraits
|
||||||
|
|
||||||
proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
|
proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
|
||||||
#echo treeRepr(p)
|
#echo treeRepr(p)
|
||||||
|
|
@ -160,27 +161,9 @@ proc freshIdentNodes(ast: NimNode): NimNode =
|
||||||
result.add inspect(child)
|
result.add inspect(child)
|
||||||
result = inspect(ast)
|
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.
|
## reverses ``type T = distinct A``; works recursively.
|
||||||
runnableExamples:
|
typetraits.distinctBase(T)
|
||||||
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
|
|
||||||
|
|
||||||
macro capture*(locals: openArray[typed], body: untyped): untyped {.since: (1, 1).} =
|
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
|
## Useful when creating a closure in a loop to capture some local loop variables
|
||||||
|
|
|
||||||
|
|
@ -63,19 +63,12 @@ proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
|
||||||
##
|
##
|
||||||
## Other languages name a type like these `blob`:idx:.
|
## 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.
|
## Return true for named tuples, false for any other type.
|
||||||
when T isnot tuple: result = false
|
|
||||||
else:
|
proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".}
|
||||||
var t: T
|
## Returns base type for distinct types, works only for distinct types.
|
||||||
for name, _ in t.fieldPairs:
|
## compile time error otherwise
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import typetraits
|
import typetraits
|
||||||
|
import macros
|
||||||
|
|
||||||
block: # isNamedTuple
|
block: # isNamedTuple
|
||||||
type Foo1 = (a:1,).type
|
type Foo1 = (a:1,).type
|
||||||
|
|
@ -9,6 +10,7 @@ block: # isNamedTuple
|
||||||
doAssert (a:1,).type.isNamedTuple
|
doAssert (a:1,).type.isNamedTuple
|
||||||
doAssert Foo1.isNamedTuple
|
doAssert Foo1.isNamedTuple
|
||||||
doAssert Foo2.isNamedTuple
|
doAssert Foo2.isNamedTuple
|
||||||
|
doAssert isNamedTuple(tuple[key: int])
|
||||||
doAssert not Foo3.isNamedTuple
|
doAssert not Foo3.isNamedTuple
|
||||||
doAssert not Foo4.isNamedTuple
|
doAssert not Foo4.isNamedTuple
|
||||||
doAssert not (1,).type.isNamedTuple
|
doAssert not (1,).type.isNamedTuple
|
||||||
|
|
@ -42,3 +44,50 @@ block: # typeToString
|
||||||
doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 ==
|
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]"
|
"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")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
output: "OK"
|
output: '''OK
|
||||||
|
@[@[], @[], @[], @[], @[]]
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
const characters = "abcdefghijklmnopqrstuvwxyz"
|
const characters = "abcdefghijklmnopqrstuvwxyz"
|
||||||
const numbers = "1234567890"
|
const numbers = "1234567890"
|
||||||
|
|
@ -76,3 +78,16 @@ proc test_string_cmp() =
|
||||||
|
|
||||||
test_string_slice()
|
test_string_slice()
|
||||||
test_string_cmp()
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue