Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #8519 T.distinctBase to reverse T = distinct A #8531

Merged
merged 9 commits into from
Aug 10, 2018
3 changes: 2 additions & 1 deletion doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1673,7 +1673,8 @@ A ``distinct`` type is new type derived from a `base type`:idx: that is
incompatible with its base type. In particular, it is an essential property
of a distinct type that it **does not** imply a subtype relation between it
and its base type. Explicit type conversions from a distinct type to its
base type and vice versa are allowed.
base type and vice versa are allowed. See also ``distinctBase`` to get the
reverse operation.


Modelling currencies
Expand Down
38 changes: 38 additions & 0 deletions lib/pure/sugar.nim
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,41 @@ macro dump*(x: typed): untyped =
let r = quote do:
debugEcho `s`, " = ", `x`
return r

# TODO: consider exporting this in macros.nim
proc freshIdentNodes(ast: NimNode): NimNode =
# Replace NimIdent and NimSym by a fresh ident node
# see also https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
proc inspect(node: NimNode): NimNode =
case node.kind:
of nnkIdent, nnkSym:
result = ident($node)
of nnkEmpty, nnkLiterals:
result = node
else:
result = node.kind.newTree()
for child in node:
result.add inspect(child)
result = inspect(ast)

macro distinctBase*(T: typedesc): untyped =
## 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
29 changes: 29 additions & 0 deletions tests/stdlib/tsugar.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
discard """
file: "tsugar.nim"
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]