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,
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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