* getType now works with tyInferred (concepts); refs #18220 * avoid cast * add more docs
This commit is contained in:
parent
2ca6169ba1
commit
897e50d5fe
2 changed files with 79 additions and 23 deletions
|
|
@ -289,7 +289,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
|
||||||
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
|
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
|
||||||
of tyIterable: result = mapTypeToBracket("iterable", mIterableType, t, info)
|
of tyIterable: result = mapTypeToBracket("iterable", mIterableType, t, info)
|
||||||
of tyAnything: result = atomicType("anything", mNone)
|
of tyAnything: result = atomicType("anything", mNone)
|
||||||
of tyInferred: assert false
|
of tyInferred: result = mapTypeToAstX(cache, t.lastSon, info, idgen, inst, allowRecursion)
|
||||||
of tyStatic, tyFromExpr:
|
of tyStatic, tyFromExpr:
|
||||||
if inst:
|
if inst:
|
||||||
if t.n != nil: result = t.n.copyTree
|
if t.n != nil: result = t.n.copyTree
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,85 @@
|
||||||
discard """
|
import std/macros
|
||||||
output: '''
|
import stdtest/testutils
|
||||||
(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))
|
|
||||||
(BracketExpr (Sym "typeDesc") (Sym "User"))
|
|
||||||
'''
|
|
||||||
"""
|
|
||||||
import macros
|
|
||||||
|
|
||||||
type
|
# getType
|
||||||
Model = object of RootObj
|
|
||||||
User = object of Model
|
|
||||||
name : string
|
|
||||||
password : string
|
|
||||||
|
|
||||||
macro testUser: string =
|
block:
|
||||||
result = newLit(User.getType.lispRepr)
|
type
|
||||||
|
Model = object of RootObj
|
||||||
|
User = object of Model
|
||||||
|
name : string
|
||||||
|
password : string
|
||||||
|
|
||||||
macro testGeneric(T: typedesc[Model]): string=
|
macro testUser: string =
|
||||||
result = newLit(T.getType.lispRepr)
|
result = newLit(User.getType.lispRepr)
|
||||||
|
|
||||||
echo testUser
|
macro testGeneric(T: typedesc[Model]): string=
|
||||||
echo User.testGeneric
|
result = newLit(T.getType.lispRepr)
|
||||||
|
|
||||||
macro assertVoid(e: typed): untyped =
|
doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))"""
|
||||||
assert(getTypeInst(e).typeKind == ntyVoid)
|
doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))"""
|
||||||
|
|
||||||
proc voidProc() = discard
|
macro assertVoid(e: typed): untyped =
|
||||||
|
assert(getTypeInst(e).typeKind == ntyVoid)
|
||||||
|
|
||||||
assertVoid voidProc()
|
proc voidProc() = discard
|
||||||
|
|
||||||
|
assertVoid voidProc()
|
||||||
|
|
||||||
|
block:
|
||||||
|
# refs #18220; not an actual solution (yet) but at least shows what's currently
|
||||||
|
# possible
|
||||||
|
|
||||||
|
type Callable1[R, T, U] = concept fn
|
||||||
|
fn(default(T)) is R
|
||||||
|
fn is U
|
||||||
|
|
||||||
|
# note that typetraits.arity doesn't work
|
||||||
|
macro arity(a: typed): int =
|
||||||
|
# number of params
|
||||||
|
# this is not production code!
|
||||||
|
let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false``
|
||||||
|
newLit a2.len - 1
|
||||||
|
|
||||||
|
type Callable2[R, T, U] = concept fn
|
||||||
|
fn(default(T)) is R
|
||||||
|
fn is U
|
||||||
|
arity(U) == 2
|
||||||
|
|
||||||
|
proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R =
|
||||||
|
let fn = U(fn)
|
||||||
|
# `cast[U](fn)` would also work;
|
||||||
|
# this is currently needed otherwise, sigmatch errors with:
|
||||||
|
# Error: attempting to call routine: 'fn'
|
||||||
|
# found 'fn' [param declared in tgettype.nim(53, 28)]
|
||||||
|
# this can be fixed in future work
|
||||||
|
fn(a)
|
||||||
|
|
||||||
|
proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R =
|
||||||
|
let fn = U(fn)
|
||||||
|
fn(a)
|
||||||
|
|
||||||
|
proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1")
|
||||||
|
proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2")
|
||||||
|
proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3")
|
||||||
|
proc fn4(a: int): string {.inline.} = $(a, "fn4")
|
||||||
|
proc fn5(a: int): string = $(a, "fn5")
|
||||||
|
|
||||||
|
assertAll:
|
||||||
|
# Callable1
|
||||||
|
1.map1(fn1) == """(1, 'x', "fn1")"""
|
||||||
|
1.map1(fn2) == """(1, "zoo", "fn2")"""
|
||||||
|
1.map1(fn3) == """(1, "zoo", "fn3")"""
|
||||||
|
# fn3's optional param is not honored, because fn3 and fn2 yield same
|
||||||
|
# generic instantiation; this is a caveat with this approach
|
||||||
|
# There are several possible ways to improve things in future work.
|
||||||
|
1.map1(fn4) == """(1, "fn4")"""
|
||||||
|
1.map1(fn5) == """(1, "fn5")"""
|
||||||
|
|
||||||
|
# Callable2; prevents passing procs with optional params to avoid above
|
||||||
|
# mentioned caveat, but more restrictive
|
||||||
|
not compiles(1.map2(fn1))
|
||||||
|
not compiles(1.map2(fn2))
|
||||||
|
not compiles(1.map2(fn3))
|
||||||
|
1.map2(fn4) == """(1, "fn4")"""
|
||||||
|
1.map2(fn5) == """(1, "fn5")"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue