distinctBase type trait for distinct types (#13031)

This commit is contained in:
cooldome 2020-01-07 23:36:57 +00:00 • committed by Andreas Rumpf
commit 871d5e79b1
7 changed files with 91 additions and 70 deletions

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

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

View file

@ -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)

View file

@ -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)