new type traits: GenericHead and StripGenericParams
This commit is contained in:
parent
fe48dd1cbe
commit
52b241fd57
3 changed files with 62 additions and 5 deletions
|
|
@ -86,9 +86,32 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||||
result.add(filename)
|
result.add(filename)
|
||||||
result.add(line)
|
result.add(line)
|
||||||
|
|
||||||
|
proc toNode(t: PType, i: TLineInfo): PNode =
|
||||||
|
result = newNodeIT(nkType, i, t)
|
||||||
|
|
||||||
|
const
|
||||||
|
# these are types that use the bracket syntax for instantiation
|
||||||
|
# they can be subjected to the type traits `GenericHead` and
|
||||||
|
# `Uninstantiated`
|
||||||
|
tyUserDefinedGenerics* = {tyGenericInst, tyGenericInvocation,
|
||||||
|
tyUserTypeClassInst}
|
||||||
|
|
||||||
|
tyMagicGenerics* = {tySet, tySequence, tyArray, tyOpenArray}
|
||||||
|
|
||||||
|
tyGenericLike* = tyUserDefinedGenerics +
|
||||||
|
tyMagicGenerics +
|
||||||
|
{tyCompositeTypeClass}
|
||||||
|
|
||||||
|
proc uninstantiate(t: PType): PType =
|
||||||
|
result = case t.kind
|
||||||
|
of tyMagicGenerics: t
|
||||||
|
of tyUserDefinedGenerics: t.base
|
||||||
|
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
||||||
|
else: t
|
||||||
|
|
||||||
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
||||||
let typ = operand.skipTypes({tyTypeDesc})
|
var typ = operand.skipTypes({tyTypeDesc})
|
||||||
case trait.sym.name.s.normalize
|
case trait.sym.name.s
|
||||||
of "name":
|
of "name":
|
||||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||||
result.typ = newType(tyString, context)
|
result.typ = newType(tyString, context)
|
||||||
|
|
@ -97,6 +120,16 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
||||||
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
|
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
|
||||||
result.typ = newType(tyInt, context)
|
result.typ = newType(tyInt, context)
|
||||||
result.info = trait.info
|
result.info = trait.info
|
||||||
|
of "GenericHead":
|
||||||
|
var res = uninstantiate(typ)
|
||||||
|
if res == typ and res.kind notin tyMagicGenerics:
|
||||||
|
localError(trait.info,
|
||||||
|
"GenericHead expects a generic type. The given type was " &
|
||||||
|
typeToString(typ))
|
||||||
|
return newType(tyError, context).toNode(trait.info)
|
||||||
|
result = res.base.toNode(trait.info)
|
||||||
|
of "StripGenericParams":
|
||||||
|
result = uninstantiate(typ).toNode(trait.info)
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1226,6 +1226,13 @@ proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
|
||||||
result.sym = prev.sym
|
result.sym = prev.sym
|
||||||
assignType(prev, result)
|
assignType(prev, result)
|
||||||
|
|
||||||
|
proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
|
||||||
|
if n.kind == nkType:
|
||||||
|
result = symFromType(n.typ, n.info)
|
||||||
|
else:
|
||||||
|
localError(n.info, "xx")
|
||||||
|
result = errorSym(c, n)
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
|
|
@ -1316,7 +1323,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = semTypeNode(c, whenResult, prev)
|
result = semTypeNode(c, whenResult, prev)
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
var s = semTypeIdent(c, n.sons[0])
|
var head = n.sons[0]
|
||||||
|
var s = if head.kind notin nkCallKinds: semTypeIdent(c, head)
|
||||||
|
else: symFromExpectedTypeNode(c, semExpr(c, head))
|
||||||
case s.magic
|
case s.magic
|
||||||
of mArray: result = semArray(c, n, prev)
|
of mArray: result = semArray(c, n, prev)
|
||||||
of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev)
|
of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".}
|
||||||
##
|
##
|
||||||
## import typetraits
|
## import typetraits
|
||||||
##
|
##
|
||||||
## proc `$`*[T](some:typedesc[T]): string = name(T)
|
## proc `$`*(T: typedesc): string = name(T)
|
||||||
##
|
##
|
||||||
## template test(x): stmt =
|
## template test(x): stmt =
|
||||||
## echo "type: ", type(x), ", value: ", x
|
## echo "type: ", type(x), ", value: ", x
|
||||||
|
|
@ -31,6 +31,21 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".}
|
||||||
## test(@['A','B'])
|
## test(@['A','B'])
|
||||||
## # --> type: seq[char], value: @[A, B]
|
## # --> type: seq[char], value: @[A, B]
|
||||||
|
|
||||||
|
|
||||||
proc arity*(t: typedesc): int {.magic: "TypeTrait".}
|
proc arity*(t: typedesc): int {.magic: "TypeTrait".}
|
||||||
## Returns the arity of the given type
|
## Returns the arity of the given type
|
||||||
|
|
||||||
|
proc GenericHead*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
||||||
|
## Accepts an instantiated generic type and returns its
|
||||||
|
## uninstantiated form.
|
||||||
|
##
|
||||||
|
## For example:
|
||||||
|
## seq[int].GenericHead will be just seq
|
||||||
|
## seq[int].GenericHead[float] will be seq[float]
|
||||||
|
##
|
||||||
|
## A compile-time error will be produced if the supplied type
|
||||||
|
## is not generic
|
||||||
|
|
||||||
|
proc StripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
||||||
|
## This trait is similar to `GenericHead`, but instead of producing
|
||||||
|
## error for non-generic types, it will just return them unmodified
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue