Static[T] fixes (#7333)
* fix the usage of unresolved static[T] parameters in proc signatures * fix tsametype and tmacrogenerics * Allow creating composite type classes with concepts and using them in type signatures * Allow integers to be used in ident concatenations * Support using imported C++ generic types in proc signatures * fixes #7230 * closes #7379 * re-enable some metatype tests
This commit is contained in:
parent
2e7a0e1cdd
commit
121b9e26fb
18 changed files with 265 additions and 26 deletions
|
|
@ -981,6 +981,7 @@ const
|
||||||
|
|
||||||
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
|
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
|
||||||
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
||||||
|
nkFloatLiterals* = {nkFloatLit..nkFloat128Lit}
|
||||||
nkLambdaKinds* = {nkLambda, nkDo}
|
nkLambdaKinds* = {nkLambda, nkDo}
|
||||||
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||||
procDefs* = nkLambdaKinds + declarativeDefs
|
procDefs* = nkLambdaKinds + declarativeDefs
|
||||||
|
|
@ -1476,7 +1477,7 @@ proc copyNode*(src: PNode): PNode =
|
||||||
echo "COMES FROM ", src.id
|
echo "COMES FROM ", src.id
|
||||||
case src.kind
|
case src.kind
|
||||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
of nkFloatLiterals: result.floatVal = src.floatVal
|
||||||
of nkSym: result.sym = src.sym
|
of nkSym: result.sym = src.sym
|
||||||
of nkIdent: result.ident = src.ident
|
of nkIdent: result.ident = src.ident
|
||||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||||
|
|
@ -1495,7 +1496,7 @@ proc shallowCopy*(src: PNode): PNode =
|
||||||
echo "COMES FROM ", src.id
|
echo "COMES FROM ", src.id
|
||||||
case src.kind
|
case src.kind
|
||||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
of nkFloatLiterals: result.floatVal = src.floatVal
|
||||||
of nkSym: result.sym = src.sym
|
of nkSym: result.sym = src.sym
|
||||||
of nkIdent: result.ident = src.ident
|
of nkIdent: result.ident = src.ident
|
||||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||||
|
|
@ -1515,7 +1516,7 @@ proc copyTree*(src: PNode): PNode =
|
||||||
echo "COMES FROM ", src.id
|
echo "COMES FROM ", src.id
|
||||||
case src.kind
|
case src.kind
|
||||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
of nkFloatLiterals: result.floatVal = src.floatVal
|
||||||
of nkSym: result.sym = src.sym
|
of nkSym: result.sym = src.sym
|
||||||
of nkIdent: result.ident = src.ident
|
of nkIdent: result.ident = src.ident
|
||||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||||
|
|
@ -1564,7 +1565,7 @@ proc getInt*(a: PNode): BiggestInt =
|
||||||
|
|
||||||
proc getFloat*(a: PNode): BiggestFloat =
|
proc getFloat*(a: PNode): BiggestFloat =
|
||||||
case a.kind
|
case a.kind
|
||||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal
|
of nkFloatLiterals: result = a.floatVal
|
||||||
else:
|
else:
|
||||||
internalError(a.info, "getFloat")
|
internalError(a.info, "getFloat")
|
||||||
result = 0.0
|
result = 0.0
|
||||||
|
|
|
||||||
|
|
@ -842,6 +842,13 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
# always call for sideeffects:
|
# always call for sideeffects:
|
||||||
assert t.kind != tyTuple
|
assert t.kind != tyTuple
|
||||||
discard getRecordDesc(m, t, result, check)
|
discard getRecordDesc(m, t, result, check)
|
||||||
|
# The resulting type will include commas and these won't play well
|
||||||
|
# with the C macros for defining procs such as N_NIMCALL. We must
|
||||||
|
# create a typedef for the type and use it in the proc signature:
|
||||||
|
let typedefName = ~"TY" & $sig
|
||||||
|
addf(m.s[cfsTypes], "typedef $1 $2;$n", [result, typedefName])
|
||||||
|
m.typeCache[sig] = typedefName
|
||||||
|
result = typedefName
|
||||||
else:
|
else:
|
||||||
when false:
|
when false:
|
||||||
if t.sym != nil and t.sym.name.s == "KeyValuePair":
|
if t.sym != nil and t.sym.name.s == "KeyValuePair":
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
|
||||||
case x.kind
|
case x.kind
|
||||||
of nkIdent: id.add(x.ident.s)
|
of nkIdent: id.add(x.ident.s)
|
||||||
of nkSym: id.add(x.sym.name.s)
|
of nkSym: id.add(x.sym.name.s)
|
||||||
|
of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
|
||||||
else: handleError(n, origin)
|
else: handleError(n, origin)
|
||||||
result = getIdent(id)
|
result = getIdent(id)
|
||||||
of nkOpenSymChoice, nkClosedSymChoice:
|
of nkOpenSymChoice, nkClosedSymChoice:
|
||||||
|
|
@ -456,4 +457,4 @@ proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
|
||||||
a = nextOverloadIter(o, c, n)
|
a = nextOverloadIter(o, c, n)
|
||||||
|
|
||||||
proc isInfixAs*(n: PNode): bool =
|
proc isInfixAs*(n: PNode): bool =
|
||||||
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"
|
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"
|
||||||
|
|
|
||||||
|
|
@ -884,6 +884,9 @@ const
|
||||||
|
|
||||||
proc readTypeParameter(c: PContext, typ: PType,
|
proc readTypeParameter(c: PContext, typ: PType,
|
||||||
paramName: PIdent, info: TLineInfo): PNode =
|
paramName: PIdent, info: TLineInfo): PNode =
|
||||||
|
# Note: This function will return emptyNode when attempting to read
|
||||||
|
# a static type parameter that is not yet resolved (e.g. this may
|
||||||
|
# happen in proc signatures such as `proc(x: T): array[T.sizeParam, U]`
|
||||||
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
|
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
|
||||||
for statement in typ.n:
|
for statement in typ.n:
|
||||||
case statement.kind
|
case statement.kind
|
||||||
|
|
@ -914,7 +917,10 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||||
if tParam.sym.name.id == paramName.id:
|
if tParam.sym.name.id == paramName.id:
|
||||||
let rawTyp = ty.sons[s + 1]
|
let rawTyp = ty.sons[s + 1]
|
||||||
if rawTyp.kind == tyStatic:
|
if rawTyp.kind == tyStatic:
|
||||||
return rawTyp.n
|
if rawTyp.n != nil:
|
||||||
|
return rawTyp.n
|
||||||
|
else:
|
||||||
|
return emptyNode
|
||||||
else:
|
else:
|
||||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||||
|
|
@ -1079,21 +1085,43 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
template tryReadingGenericParam(t: PType) =
|
template tryReadingGenericParam(t: PType) =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyTypeParamsHolders:
|
of tyTypeParamsHolders:
|
||||||
return readTypeParameter(c, t, i, n.info)
|
result = readTypeParameter(c, t, i, n.info)
|
||||||
|
if result == emptyNode:
|
||||||
|
result = n
|
||||||
|
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||||
|
return
|
||||||
of tyUserTypeClasses:
|
of tyUserTypeClasses:
|
||||||
if t.isResolvedUserTypeClass:
|
if t.isResolvedUserTypeClass:
|
||||||
return readTypeParameter(c, t, i, n.info)
|
return readTypeParameter(c, t, i, n.info)
|
||||||
else:
|
else:
|
||||||
n.typ = makeTypeFromExpr(c, copyTree(n))
|
n.typ = makeTypeFromExpr(c, copyTree(n))
|
||||||
return n
|
return n
|
||||||
of tyGenericParam:
|
of tyGenericParam, tyAnything:
|
||||||
n.typ = makeTypeFromExpr(c, copyTree(n))
|
n.typ = makeTypeFromExpr(c, copyTree(n))
|
||||||
return n
|
return n
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
|
var argIsType = false
|
||||||
if ty.kind == tyTypeDesc: ty = ty.base
|
|
||||||
|
if ty.kind == tyTypeDesc:
|
||||||
|
if ty.base.kind == tyNone:
|
||||||
|
# This is a still unresolved typedesc parameter.
|
||||||
|
# If this is a regular proc, then all bets are off and we must return
|
||||||
|
# tyFromExpr, but when this happen in a macro this is not a built-in
|
||||||
|
# field access and we leave the compiler to compile a normal call:
|
||||||
|
if getCurrOwner(c).kind != skMacro:
|
||||||
|
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||||
|
return n
|
||||||
|
else:
|
||||||
|
return nil
|
||||||
|
else:
|
||||||
|
ty = ty.base
|
||||||
|
argIsType = true
|
||||||
|
else:
|
||||||
|
argIsType = isTypeExpr(n.sons[0])
|
||||||
|
|
||||||
|
if argIsType:
|
||||||
ty = ty.skipTypes(tyDotOpTransparent)
|
ty = ty.skipTypes(tyDotOpTransparent)
|
||||||
case ty.kind
|
case ty.kind
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
|
|
@ -2186,7 +2214,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
# because of the changed symbol binding, this does not mean that we
|
# because of the changed symbol binding, this does not mean that we
|
||||||
# don't have to check the symbol for semantics here again!
|
# don't have to check the symbol for semantics here again!
|
||||||
result = semSym(c, n, n.sym, flags)
|
result = semSym(c, n, n.sym, flags)
|
||||||
of nkEmpty, nkNone, nkCommentStmt:
|
of nkEmpty, nkNone, nkCommentStmt, nkType:
|
||||||
discard
|
discard
|
||||||
of nkNilLit:
|
of nkNilLit:
|
||||||
if result.typ == nil: result.typ = getSysType(tyNil)
|
if result.typ == nil: result.typ = getSysType(tyNil)
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,8 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
allowMetaTypes = false): PType =
|
allowMetaTypes = false): PType =
|
||||||
|
internalAssert header.kind == tyGenericInvocation
|
||||||
|
|
||||||
var
|
var
|
||||||
typeMap: LayeredIdTable
|
typeMap: LayeredIdTable
|
||||||
cl: TReplTypeVars
|
cl: TReplTypeVars
|
||||||
|
|
@ -185,7 +187,35 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
cl.info = info
|
cl.info = info
|
||||||
cl.c = c
|
cl.c = c
|
||||||
cl.allowMetaTypes = allowMetaTypes
|
cl.allowMetaTypes = allowMetaTypes
|
||||||
|
|
||||||
|
# We must add all generic params in scope, because the generic body
|
||||||
|
# may include tyFromExpr nodes depending on these generic params.
|
||||||
|
# XXX: This looks quite similar to the code in matchUserTypeClass,
|
||||||
|
# perhaps the code can be extracted in a shared function.
|
||||||
|
openScope(c)
|
||||||
|
let genericTyp = header.base
|
||||||
|
for i in 0 .. (genericTyp.len - 2):
|
||||||
|
let genParam = genericTyp[i]
|
||||||
|
var param: PSym
|
||||||
|
|
||||||
|
template paramSym(kind): untyped =
|
||||||
|
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
|
||||||
|
|
||||||
|
if genParam.kind == tyStatic:
|
||||||
|
param = paramSym skConst
|
||||||
|
param.ast = header[i+1].n
|
||||||
|
param.typ = header[i+1]
|
||||||
|
else:
|
||||||
|
param = paramSym skType
|
||||||
|
param.typ = makeTypeDesc(c, header[i+1])
|
||||||
|
|
||||||
|
# this scope was not created by the user,
|
||||||
|
# unused params shoudn't be reported.
|
||||||
|
param.flags.incl sfUsed
|
||||||
|
addDecl(c, param)
|
||||||
|
|
||||||
result = replaceTypeVarsT(cl, header)
|
result = replaceTypeVarsT(cl, header)
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
proc instantiateProcType(c: PContext, pt: TIdTable,
|
proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
prc: PSym, info: TLineInfo) =
|
prc: PSym, info: TLineInfo) =
|
||||||
|
|
|
||||||
|
|
@ -1397,7 +1397,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
fixupTypeOf(c, prev, typExpr)
|
fixupTypeOf(c, prev, typExpr)
|
||||||
result = typExpr.typ
|
result = typExpr.typ
|
||||||
else:
|
else:
|
||||||
result = semTypeExpr(c, n, prev)
|
if c.inGenericContext > 0 and n.kind == nkCall:
|
||||||
|
result = makeTypeFromExpr(c, n.copyTree)
|
||||||
|
else:
|
||||||
|
result = semTypeExpr(c, n, prev)
|
||||||
of nkWhenStmt:
|
of nkWhenStmt:
|
||||||
var whenResult = semWhen(c, n, false)
|
var whenResult = semWhen(c, n, false)
|
||||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||||
|
|
|
||||||
|
|
@ -460,6 +460,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
of tyFromExpr:
|
of tyFromExpr:
|
||||||
if cl.allowMetaTypes: return
|
if cl.allowMetaTypes: return
|
||||||
|
# This assert is triggered when a tyFromExpr was created in a cyclic
|
||||||
|
# way. You should break the cycle at the point of creation by introducing
|
||||||
|
# a call such as: `n.typ = makeTypeFromExpr(c, n.copyTree)`
|
||||||
|
# Otherwise, the cycle will be fatal for the prepareNode call below
|
||||||
assert t.n.typ != t
|
assert t.n.typ != t
|
||||||
var n = prepareNode(cl, t.n)
|
var n = prepareNode(cl, t.n)
|
||||||
if n.kind != nkEmpty:
|
if n.kind != nkEmpty:
|
||||||
|
|
|
||||||
|
|
@ -1884,7 +1884,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
return arg
|
return arg
|
||||||
elif f.kind == tyTypeDesc:
|
elif f.kind == tyTypeDesc:
|
||||||
return arg
|
return arg
|
||||||
elif f.kind == tyStatic:
|
elif f.kind == tyStatic and arg.typ.n != nil:
|
||||||
return arg.typ.n
|
return arg.typ.n
|
||||||
else:
|
else:
|
||||||
return argSemantized # argOrig
|
return argSemantized # argOrig
|
||||||
|
|
|
||||||
|
|
@ -1136,6 +1136,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
of tyTypeClasses:
|
of tyTypeClasses:
|
||||||
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
|
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
|
||||||
discard
|
discard
|
||||||
|
elif t.isResolvedUserTypeClass:
|
||||||
|
result = typeAllowedAux(marker, t.lastSon, kind, flags)
|
||||||
elif kind notin {skParam, skResult}:
|
elif kind notin {skParam, skResult}:
|
||||||
result = t
|
result = t
|
||||||
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
||||||
|
|
|
||||||
19
tests/concepts/tseqofconcept.nim
Normal file
19
tests/concepts/tseqofconcept.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
discard """
|
||||||
|
output: "1\n2\n3"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
MyConcept = concept x
|
||||||
|
someProc(x)
|
||||||
|
|
||||||
|
SomeSeq = seq[MyConcept]
|
||||||
|
|
||||||
|
proc someProc(x:int) = echo x
|
||||||
|
|
||||||
|
proc work (s: SomeSeq) =
|
||||||
|
for item in s:
|
||||||
|
someProc item
|
||||||
|
|
||||||
|
var s = @[1, 2, 3]
|
||||||
|
work s
|
||||||
|
|
||||||
|
|
@ -300,7 +300,7 @@ reject wantsVarPointer2(pcat)
|
||||||
|
|
||||||
# covariance may be allowed for certain extern types
|
# covariance may be allowed for certain extern types
|
||||||
|
|
||||||
{.emit: """
|
{.emit: """/*TYPESECTION*/
|
||||||
template <class T> struct FN { typedef void (*type)(T); };
|
template <class T> struct FN { typedef void (*type)(T); };
|
||||||
template <class T> struct ARR { typedef T DataType[2]; DataType data; };
|
template <class T> struct ARR { typedef T DataType[2]; DataType data; };
|
||||||
""".}
|
""".}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ discard """
|
||||||
targets: "cpp"
|
targets: "cpp"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.emit: """
|
{.emit: """/*TYPESECTION*/
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct Vector {
|
struct Vector {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ AST b
|
||||||
20Test
|
20Test
|
||||||
20
|
20
|
||||||
'''
|
'''
|
||||||
disabled: true
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
|
@ -26,7 +25,7 @@ type
|
||||||
|
|
||||||
const data: Tconfig = (@["aa", "bb"], @[11, 22])
|
const data: Tconfig = (@["aa", "bb"], @[11, 22])
|
||||||
|
|
||||||
macro mymacro(data: static[TConfig]) =
|
macro mymacro(data: static[TConfig]): untyped =
|
||||||
echo "letters"
|
echo "letters"
|
||||||
for s in items(data.letters):
|
for s in items(data.letters):
|
||||||
echo s
|
echo s
|
||||||
|
|
@ -44,10 +43,10 @@ const
|
||||||
a : Ta = @[(11, 22), (33, 44)]
|
a : Ta = @[(11, 22), (33, 44)]
|
||||||
b : Tb = (@[55,66], @[77, 88])
|
b : Tb = (@[55,66], @[77, 88])
|
||||||
|
|
||||||
macro mA(data: static[Ta]) =
|
macro mA(data: static[Ta]): untyped =
|
||||||
echo "AST a \n", repr(data)
|
echo "AST a \n", repr(data)
|
||||||
|
|
||||||
macro mB(data: static[Tb]) =
|
macro mB(data: static[Tb]): untyped =
|
||||||
echo "AST b \n", repr(data)
|
echo "AST b \n", repr(data)
|
||||||
echo data.e[0]
|
echo data.e[0]
|
||||||
|
|
||||||
|
|
@ -57,13 +56,15 @@ mB(b)
|
||||||
type
|
type
|
||||||
Foo[N: static[int], Z: static[string]] = object
|
Foo[N: static[int], Z: static[string]] = object
|
||||||
|
|
||||||
macro staticIntMacro(f: static[int]) = echo f
|
macro staticIntMacro(f: static[int]): untyped =
|
||||||
|
echo f
|
||||||
|
|
||||||
staticIntMacro 10
|
staticIntMacro 10
|
||||||
|
|
||||||
var
|
var
|
||||||
x: Foo[20, "Test"]
|
x: Foo[20, "Test"]
|
||||||
|
|
||||||
macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12) =
|
macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): untyped =
|
||||||
echo N, Z
|
echo N, Z
|
||||||
|
|
||||||
genericMacro x
|
genericMacro x
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
import macros
|
discard """
|
||||||
|
output: "8\n8\n4"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import
|
||||||
|
macros, typetraits
|
||||||
|
|
||||||
template selectType(x: int): typeDesc =
|
template selectType(x: int): typeDesc =
|
||||||
when x < 10:
|
when x < 10:
|
||||||
|
|
@ -11,6 +16,9 @@ template simpleTypeTempl: typeDesc =
|
||||||
|
|
||||||
macro typeFromMacro: typedesc = string
|
macro typeFromMacro: typedesc = string
|
||||||
|
|
||||||
|
# The tests below check that the result variable of the
|
||||||
|
# selected type matches the literal types in the code:
|
||||||
|
|
||||||
proc t1*(x: int): simpleTypeTempl() =
|
proc t1*(x: int): simpleTypeTempl() =
|
||||||
result = "test"
|
result = "test"
|
||||||
|
|
||||||
|
|
@ -37,3 +45,57 @@ proc t6*(x: type(t3(0))): type(t1(0)) =
|
||||||
proc t7*(x: int): type($x) =
|
proc t7*(x: int): type($x) =
|
||||||
result = "test"
|
result = "test"
|
||||||
|
|
||||||
|
# This is a more compicated example involving a type
|
||||||
|
# selection through a macro:
|
||||||
|
# https://github.com/nim-lang/Nim/issues/7230
|
||||||
|
|
||||||
|
macro getBase*(bits: static[int]): untyped =
|
||||||
|
if bits >= 128:
|
||||||
|
result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64"))
|
||||||
|
else:
|
||||||
|
result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32"))
|
||||||
|
|
||||||
|
type
|
||||||
|
BaseUint* = SomeUnsignedInt or MpUintBase
|
||||||
|
|
||||||
|
MpUintBase*[T] = object
|
||||||
|
lo*, hi*: T
|
||||||
|
|
||||||
|
## This gets type mismatch
|
||||||
|
MpUint*[bits: static[int]] = getBase(bits)
|
||||||
|
|
||||||
|
var m1: MpUint[128]
|
||||||
|
var m2: MpUint[64]
|
||||||
|
var m3: getBase(32)
|
||||||
|
|
||||||
|
static:
|
||||||
|
# assert m1.type.name == "MpUintBase[uint64]"
|
||||||
|
assert m1.lo.type.name == "uint64"
|
||||||
|
assert m2.lo.type.name == "uint32"
|
||||||
|
assert m3.type.name == "MpUintBase[system.uint32]"
|
||||||
|
|
||||||
|
# https://github.com/nim-lang/Nim/issues/7379
|
||||||
|
|
||||||
|
import macros, typetraits
|
||||||
|
|
||||||
|
macro works(): untyped =
|
||||||
|
result = getType(int64)
|
||||||
|
|
||||||
|
macro fails(bits: static[int]): untyped =
|
||||||
|
if bits > 64:
|
||||||
|
result = getType(int64)
|
||||||
|
else:
|
||||||
|
result = getType(int32)
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo*[bits: static[int]] = works()
|
||||||
|
Bar*[bits: static[int]] = fails(bits)
|
||||||
|
|
||||||
|
var a: Foo[16]
|
||||||
|
var b: Bar[256]
|
||||||
|
var c: Bar[32]
|
||||||
|
|
||||||
|
echo sizeof(a)
|
||||||
|
echo sizeof(b)
|
||||||
|
echo sizeof(c)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "type mismatch: got <string> but expected 'ptr'"
|
errormsg: "type mismatch: got <string> but expected 'ptr'"
|
||||||
line: 20
|
line: 20
|
||||||
disabled: true
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typetraits
|
import typetraits
|
||||||
|
|
@ -12,7 +11,7 @@ type
|
||||||
var x = Vec([1, 2, 3])
|
var x = Vec([1, 2, 3])
|
||||||
|
|
||||||
static:
|
static:
|
||||||
assert x.type.name == "Vec[static[int](3), int]"
|
assert x.type.name == "Vec[3, system.int]"
|
||||||
|
|
||||||
var str1: string = "hello, world!"
|
var str1: string = "hello, world!"
|
||||||
var ptr1: ptr = addr(str1)
|
var ptr1: ptr = addr(str1)
|
||||||
|
|
|
||||||
32
tests/misc/tidentconcatenations.nim
Normal file
32
tests/misc/tidentconcatenations.nim
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
type
|
||||||
|
Hash*[bits: static[int]] = object
|
||||||
|
data*: array[bits div 8, uint8]
|
||||||
|
|
||||||
|
{.emit: """
|
||||||
|
|
||||||
|
void sha_256(void* input, int input_len, void* output, int output_len) {}
|
||||||
|
void sha_512(void* input, int input_len, void* output, int output_len) {}
|
||||||
|
|
||||||
|
void keccak_256(void* input, int input_len, void* output, int output_len) {}
|
||||||
|
void keccak_512(void* input, int input_len, void* output, int output_len) {}
|
||||||
|
|
||||||
|
""".}
|
||||||
|
|
||||||
|
template defineKeccak(bits: untyped) =
|
||||||
|
proc `extKeccak bits`(output: pointer, outSize: csize, input: pointer, inputSize: csize) {.nodecl, importc: "keccak_" & astToStr(bits).}
|
||||||
|
|
||||||
|
template defineSha(bits: static[int]) =
|
||||||
|
proc `extSha bits`(output: pointer, outSize: csize, input: pointer, inputSize: csize) {.nodecl, importc: "sha_" & astToStr(bits).}
|
||||||
|
|
||||||
|
template defineHashProcs(bits) =
|
||||||
|
defineSha(bits)
|
||||||
|
defineKeccak(bits)
|
||||||
|
|
||||||
|
defineHashProcs(256)
|
||||||
|
defineHashProcs(512)
|
||||||
|
|
||||||
|
extSha256(nil, 0, nil, 0)
|
||||||
|
extSha512(nil, 0, nil, 0)
|
||||||
|
extKeccak256(nil, 0, nil, 0)
|
||||||
|
extKeccak512(nil, 0, nil, 0)
|
||||||
|
|
||||||
44
tests/statictypes/tcryptodigest.nim
Normal file
44
tests/statictypes/tcryptodigest.nim
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
discard """
|
||||||
|
output: "Digest[128]\nDigest[256]"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type
|
||||||
|
Digest[bits: static[int]] = object
|
||||||
|
data: array[bits div 8, byte]
|
||||||
|
|
||||||
|
ContextKind = enum
|
||||||
|
A, B, C
|
||||||
|
|
||||||
|
HashingContext[bits: static[int], kind: static[ContextKind]] = object
|
||||||
|
ctx: array[bits div 8, byte]
|
||||||
|
|
||||||
|
Hash128 = HashingContext[128, A]
|
||||||
|
Hash256 = HashingContext[256, B]
|
||||||
|
|
||||||
|
HMAC[HashType] = object
|
||||||
|
h: HashType
|
||||||
|
|
||||||
|
proc init(c: var HashingContext) = discard
|
||||||
|
proc update(c: var HashingContext, data: ptr byte, dataLen: uint) = discard
|
||||||
|
proc finish(c: var HashingContext): Digest[c.bits] = discard
|
||||||
|
|
||||||
|
proc digest(T: typedesc, data: ptr byte, dataLen: uint): Digest[T.bits] =
|
||||||
|
mixin init, update, finish
|
||||||
|
|
||||||
|
var ctx: T
|
||||||
|
ctx.init()
|
||||||
|
ctx.update(data, dataLen)
|
||||||
|
result = ctx.finish()
|
||||||
|
|
||||||
|
var h = Hash128.digest(nil, 0)
|
||||||
|
echo h.type.name
|
||||||
|
|
||||||
|
proc finish(hmac: var HMAC): Digest[HMAC.HashType.bits] =
|
||||||
|
discard
|
||||||
|
|
||||||
|
var hm: HMAC[Hash256]
|
||||||
|
var d = hm.finish
|
||||||
|
echo d.type.name
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
targets: "cpp"
|
targets: "cpp"
|
||||||
output: "[0, 0, 10, 0]\n5\n1.2\n15\ntest"
|
output: "[0, 0, 10, 0]\n5\n1.2\n15\ntest\n[0, 0, 20, 0]"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.emit: """
|
{.emit: """/*TYPESECTION*/
|
||||||
|
|
||||||
template <int N, class T>
|
template <int N, class T>
|
||||||
struct GenericIntType {
|
struct GenericIntType {
|
||||||
|
|
@ -51,3 +51,9 @@ echo c.field
|
||||||
echo d.field
|
echo d.field
|
||||||
echo e.field
|
echo e.field
|
||||||
|
|
||||||
|
proc plus(a, b: GenInt4): GenInt4 =
|
||||||
|
for i in 0 ..< result.data.len:
|
||||||
|
result.data[i] = a.data[i] + b.data[i]
|
||||||
|
|
||||||
|
echo plus(a, a).data
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue