diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e4ae60aba..ee6329125 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -86,9 +86,32 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode = result.add(filename) 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 = - let typ = operand.skipTypes({tyTypeDesc}) - case trait.sym.name.s.normalize + var typ = operand.skipTypes({tyTypeDesc}) + case trait.sym.name.s of "name": result = newStrNode(nkStrLit, typ.typeToString(preferName)) 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.typ = newType(tyInt, context) 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: internalAssert false diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9e0d9b633..204641b74 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1226,6 +1226,13 @@ proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) = result.sym = prev.sym 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 = result = nil when defined(nimsuggest): @@ -1316,7 +1323,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semTypeNode(c, whenResult, prev) of nkBracketExpr: 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 of mArray: result = semArray(c, n, prev) of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 2c3d872df..cc7fb9f72 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -19,7 +19,7 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".} ## ## import typetraits ## - ## proc `$`*[T](some:typedesc[T]): string = name(T) + ## proc `$`*(T: typedesc): string = name(T) ## ## template test(x): stmt = ## echo "type: ", type(x), ", value: ", x @@ -31,6 +31,21 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".} ## test(@['A','B']) ## # --> type: seq[char], value: @[A, B] - proc arity*(t: typedesc): int {.magic: "TypeTrait".} ## 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 +