progress towards fixing tgenericshardcases
This commit is contained in:
parent
789ba107cf
commit
1ffae7cbaf
9 changed files with 146 additions and 43 deletions
|
|
@ -418,6 +418,7 @@ type
|
||||||
tfHasGCedMem, # type contains GC'ed memory
|
tfHasGCedMem, # type contains GC'ed memory
|
||||||
tfHasStatic
|
tfHasStatic
|
||||||
tfGenericTypeParam
|
tfGenericTypeParam
|
||||||
|
tfImplicitTypeParam
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,16 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||||
result = newTypeS(tyFromExpr, c)
|
result = newTypeS(tyFromExpr, c)
|
||||||
result.n = n
|
result.n = n
|
||||||
|
|
||||||
|
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
||||||
|
sons: seq[PType]): PType =
|
||||||
|
result = newType(kind, getCurrOwner())
|
||||||
|
result.sons = sons
|
||||||
|
|
||||||
|
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
|
||||||
|
result = newNodeI(nkStaticExpr, n.info)
|
||||||
|
result.sons = @[n]
|
||||||
|
result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
|
||||||
|
|
||||||
proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
||||||
result = newTypeS(tyAnd, c)
|
result = newTypeS(tyAnd, c)
|
||||||
result.sons = @[t1, t2]
|
result.sons = @[t1, t2]
|
||||||
|
|
@ -238,11 +248,6 @@ proc makeNotType*(c: PContext, t1: PType): PType =
|
||||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||||
result = newType(kind, getCurrOwner())
|
result = newType(kind, getCurrOwner())
|
||||||
|
|
||||||
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
|
||||||
sons: seq[PType]): PType =
|
|
||||||
result = newType(kind, getCurrOwner())
|
|
||||||
result.sons = sons
|
|
||||||
|
|
||||||
proc errorType*(c: PContext): PType =
|
proc errorType*(c: PContext): PType =
|
||||||
## creates a type representing an error state
|
## creates a type representing an error state
|
||||||
result = newTypeS(tyError, c)
|
result = newTypeS(tyError, c)
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
localError(n.info, errXExpectsTypeOrValue, opToStr[m])
|
localError(n.info, errXExpectsTypeOrValue, opToStr[m])
|
||||||
else:
|
else:
|
||||||
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
|
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
|
||||||
var typ = skipTypes(n.sons[1].typ, abstractVarRange)
|
var typ = skipTypes(n.sons[1].typ, abstractVarRange+{tyTypeDesc})
|
||||||
case typ.kind
|
case typ.kind
|
||||||
of tySequence, tyString, tyOpenArray, tyVarargs:
|
of tySequence, tyString, tyOpenArray, tyVarargs:
|
||||||
n.typ = getSysType(tyInt)
|
n.typ = getSysType(tyInt)
|
||||||
|
|
@ -249,8 +249,10 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
# do not skip the range!
|
# do not skip the range!
|
||||||
n.typ = n.sons[1].typ.skipTypes(abstractVar)
|
n.typ = n.sons[1].typ.skipTypes(abstractVar)
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
# leave it for now, it will be resolved in semtypinst
|
# prepare this for resolving in semtypinst:
|
||||||
n.typ = getSysType(tyInt)
|
# we must use copyTree here in order to avoid creating a cycle
|
||||||
|
# that could easily turn into an infinite recursion in semtypinst
|
||||||
|
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errInvalidArgForX, opToStr[m])
|
localError(n.info, errInvalidArgForX, opToStr[m])
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
result.ast = n
|
result.ast = n
|
||||||
pushOwner(result)
|
pushOwner(result)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
internalAssert n.sons[genericParamsPos].kind != nkEmpty
|
||||||
internalError(n.info, "generateInstance")
|
|
||||||
n.sons[namePos] = newSymNode(result)
|
n.sons[namePos] = newSymNode(result)
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
var entry = TInstantiation.new
|
var entry = TInstantiation.new
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,11 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||||
localError(n.info, errXExpectsOneTypeParam, "range")
|
localError(n.info, errXExpectsOneTypeParam, "range")
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
|
||||||
|
proc nMinusOne(n: PNode): PNode =
|
||||||
|
result = newNode(nkCall, n.info, @[
|
||||||
|
newSymNode(getSysMagic("<", mUnaryLt)),
|
||||||
|
n])
|
||||||
|
|
||||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var indx, base: PType
|
var indx, base: PType
|
||||||
result = newOrPrevType(tyArray, prev, c)
|
result = newOrPrevType(tyArray, prev, c)
|
||||||
|
|
@ -194,7 +199,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if isRange(n[1]): indx = semRangeAux(c, n[1], nil)
|
if isRange(n[1]): indx = semRangeAux(c, n[1], nil)
|
||||||
else:
|
else:
|
||||||
let e = semExprWithType(c, n.sons[1], {efDetermineType})
|
let e = semExprWithType(c, n.sons[1], {efDetermineType})
|
||||||
if e.kind in {nkIntLit..nkUInt64Lit}:
|
if e.typ.kind == tyFromExpr:
|
||||||
|
indx = e.typ
|
||||||
|
elif e.kind in {nkIntLit..nkUInt64Lit}:
|
||||||
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
|
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
|
||||||
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
||||||
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
|
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
|
||||||
|
|
@ -202,11 +209,25 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if not isOrdinalType(e.typ.lastSon):
|
if not isOrdinalType(e.typ.lastSon):
|
||||||
localError(n[1].info, errOrdinalTypeExpected)
|
localError(n[1].info, errOrdinalTypeExpected)
|
||||||
indx = e.typ
|
indx = e.typ
|
||||||
|
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
||||||
|
if not isOrdinalType(e.typ):
|
||||||
|
localError(n[1].info, errOrdinalTypeExpected)
|
||||||
|
# This is an int returning call, depending on an
|
||||||
|
# yet unknown generic param (see tgenericshardcases).
|
||||||
|
# We are going to construct a range type that will be
|
||||||
|
# properly filled-out in semtypinst (see how tyStaticExpr
|
||||||
|
# is handled there).
|
||||||
|
let intType = getSysType(tyInt)
|
||||||
|
indx = newTypeS(tyRange, c)
|
||||||
|
indx.sons = @[intType]
|
||||||
|
indx.n = newNode(nkRange, n.info, @[
|
||||||
|
newIntTypeNode(nkIntLit, 0, intType),
|
||||||
|
makeStaticExpr(c, e.nMinusOne)])
|
||||||
else:
|
else:
|
||||||
indx = e.typ.skipTypes({tyTypeDesc})
|
indx = e.typ.skipTypes({tyTypeDesc})
|
||||||
addSonSkipIntLit(result, indx)
|
addSonSkipIntLit(result, indx)
|
||||||
if indx.kind == tyGenericInst: indx = lastSon(indx)
|
if indx.kind == tyGenericInst: indx = lastSon(indx)
|
||||||
if indx.kind notin {tyGenericParam, tyStatic}:
|
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||||
if not isOrdinalType(indx):
|
if not isOrdinalType(indx):
|
||||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||||
elif enumHasHoles(indx):
|
elif enumHasHoles(indx):
|
||||||
|
|
@ -619,6 +640,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
var s = newSym(skType, finalTypId, owner, info)
|
var s = newSym(skType, finalTypId, owner, info)
|
||||||
if typId == nil: s.flags.incl(sfAnon)
|
if typId == nil: s.flags.incl(sfAnon)
|
||||||
s.linkTo(typeClass)
|
s.linkTo(typeClass)
|
||||||
|
typeClass.flags.incl tfImplicitTypeParam
|
||||||
s.position = genericParams.len
|
s.position = genericParams.len
|
||||||
genericParams.addSon(newSymNode(s))
|
genericParams.addSon(newSymNode(s))
|
||||||
result = typeClass
|
result = typeClass
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,50 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
result.typ = replaceTypeVarsT(cl, n.typ)
|
result.typ = replaceTypeVarsT(cl, n.typ)
|
||||||
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
|
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
|
||||||
for i in 0 .. safeLen(n)-1:
|
let isCall = result.kind in nkCallKinds
|
||||||
|
for i in 0 .. <n.safeLen:
|
||||||
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
|
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
|
||||||
if i == 0: result.add(n[i])
|
if isCall and i == 0: result.add(n[i])
|
||||||
else: result.add(prepareNode(cl, n[i]))
|
else: result.add(prepareNode(cl, n[i]))
|
||||||
|
|
||||||
|
proc isTypeParam(n: PNode): bool =
|
||||||
|
# XXX: generic params should use skGenericParam instead of skType
|
||||||
|
return n.kind == nkSym and
|
||||||
|
(n.sym.kind == skGenericParam or
|
||||||
|
(n.sym.kind == skType and sfFromGeneric in n.sym.flags))
|
||||||
|
|
||||||
|
proc hasGenericArguments*(n: PNode): bool =
|
||||||
|
if n.kind == nkSym:
|
||||||
|
return n.sym.kind == skGenericParam or
|
||||||
|
(n.sym.kind == skType and
|
||||||
|
n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
|
||||||
|
else:
|
||||||
|
for s in n.sons:
|
||||||
|
if hasGenericArguments(s): return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
|
# This is needed fo tgenericshardcases
|
||||||
|
# It's possible that a generic param will be used in a proc call to a
|
||||||
|
# typedesc accepting proc. After generic param substitution, such procs
|
||||||
|
# should be optionally instantiated with the correct type. In order to
|
||||||
|
# perform this instantiation, we need to re-run the generateInstance path
|
||||||
|
# in the compiler, but it's quite complicated to do so at the moment so we
|
||||||
|
# resort to a mild hack; the head symbol of the call is temporary reset and
|
||||||
|
# overload resolution is executed again (which may trigger generateInstance).
|
||||||
|
if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags:
|
||||||
|
var needsFixing = false
|
||||||
|
for i in 1 .. <n.safeLen:
|
||||||
|
if isTypeParam(n[i]): needsFixing = true
|
||||||
|
if needsFixing:
|
||||||
|
n.sons[0] = newSymNode(n.sons[0].sym.owner)
|
||||||
|
return cl.c.semOverloadedCall(cl.c, n, n, {skProc})
|
||||||
|
|
||||||
|
for i in 0 .. <n.safeLen:
|
||||||
|
n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
|
||||||
|
|
||||||
|
return n
|
||||||
|
|
||||||
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
|
|
@ -135,6 +174,10 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
result = replaceTypeVarsN(cl, branch)
|
result = replaceTypeVarsN(cl, branch)
|
||||||
else:
|
else:
|
||||||
result = newNodeI(nkRecList, n.info)
|
result = newNodeI(nkRecList, n.info)
|
||||||
|
of nkStaticExpr:
|
||||||
|
var n = prepareNode(cl, n)
|
||||||
|
n = reResolveCallsWithTypedescParams(cl, n)
|
||||||
|
result = cl.c.semExpr(cl.c, n)
|
||||||
else:
|
else:
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
if length > 0:
|
if length > 0:
|
||||||
|
|
@ -273,10 +316,6 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
|
|
||||||
#if t.kind == tyStatic and t.sym != nil and t.sym.kind == skGenericParam:
|
|
||||||
# let s = lookupTypeVar(cl, t)
|
|
||||||
# return if s != nil: s else: t
|
|
||||||
|
|
||||||
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
||||||
let lookup = PType(idTableGet(cl.typeMap, t))
|
let lookup = PType(idTableGet(cl.typeMap, t))
|
||||||
if lookup != nil: return lookup
|
if lookup != nil: return lookup
|
||||||
|
|
@ -284,34 +323,51 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyGenericInvokation:
|
of tyGenericInvokation:
|
||||||
result = handleGenericInvokation(cl, t)
|
result = handleGenericInvokation(cl, t)
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
internalError(cl.info, "ReplaceTypeVarsT: tyGenericBody" )
|
internalError(cl.info, "ReplaceTypeVarsT: tyGenericBody" )
|
||||||
result = replaceTypeVarsT(cl, lastSon(t))
|
result = replaceTypeVarsT(cl, lastSon(t))
|
||||||
|
|
||||||
of tyFromExpr:
|
of tyFromExpr:
|
||||||
var n = prepareNode(cl, t.n)
|
var n = prepareNode(cl, t.n)
|
||||||
n = cl.c.semExpr(cl.c, n, {})
|
n = cl.c.semConstExpr(cl.c, n)
|
||||||
|
if n.typ.kind == tyTypeDesc:
|
||||||
|
# XXX: sometimes, chained typedescs enter here.
|
||||||
|
# It may be worth investigating why this is happening,
|
||||||
|
# because it may cause other bugs elsewhere.
|
||||||
result = n.typ.skipTypes({tyTypeDesc})
|
result = n.typ.skipTypes({tyTypeDesc})
|
||||||
|
# result = n.typ.base
|
||||||
|
else:
|
||||||
|
if n.typ.kind != tyStatic:
|
||||||
|
# XXX: In the future, semConstExpr should
|
||||||
|
# return tyStatic values to let anyone make
|
||||||
|
# use of this knowledge. The patching here
|
||||||
|
# won't be necessary then.
|
||||||
|
result = newTypeS(tyStatic, cl.c)
|
||||||
|
result.sons = @[n.typ]
|
||||||
|
result.n = n
|
||||||
|
else:
|
||||||
|
result = n.typ
|
||||||
|
|
||||||
of tyInt:
|
of tyInt:
|
||||||
result = skipIntLit(t)
|
result = skipIntLit(t)
|
||||||
# XXX now there are also float literals
|
# XXX now there are also float literals
|
||||||
|
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
|
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
|
||||||
if lookup != nil:
|
if lookup != nil:
|
||||||
result = lookup
|
result = lookup
|
||||||
if tfUnresolved in t.flags: result = result.base
|
if tfUnresolved in t.flags: result = result.base
|
||||||
|
elif t.sonsLen > 0:
|
||||||
|
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
||||||
|
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
result = instCopyType(cl, t)
|
result = instCopyType(cl, t)
|
||||||
for i in 1 .. <result.sonsLen:
|
for i in 1 .. <result.sonsLen:
|
||||||
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
|
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
|
||||||
propagateToOwner(result, result.lastSon)
|
propagateToOwner(result, result.lastSon)
|
||||||
else:
|
|
||||||
if t.kind == tyArray:
|
|
||||||
let idxt = t.sons[0]
|
|
||||||
if idxt.kind == tyStatic and
|
|
||||||
idxt.sym != nil and idxt.sym.kind == skGenericParam:
|
|
||||||
let value = lookupTypeVar(cl, idxt).n
|
|
||||||
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
|
|
||||||
|
|
||||||
|
else:
|
||||||
if containsGenericType(t):
|
if containsGenericType(t):
|
||||||
result = instCopyType(cl, t)
|
result = instCopyType(cl, t)
|
||||||
result.size = -1 # needs to be recomputed
|
result.size = -1 # needs to be recomputed
|
||||||
|
|
@ -328,11 +384,23 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# localError(cl.info, errCannotInstantiateX, typeToString(t, preferName))
|
# localError(cl.info, errCannotInstantiateX, typeToString(t, preferName))
|
||||||
|
|
||||||
case result.kind
|
case result.kind
|
||||||
|
of tyArray:
|
||||||
|
let idx = result.sons[0]
|
||||||
|
if idx.kind == tyStatic:
|
||||||
|
if idx.n == nil:
|
||||||
|
let lookup = lookupTypeVar(cl, idx)
|
||||||
|
internalAssert lookup != nil
|
||||||
|
idx.n = lookup.n
|
||||||
|
|
||||||
|
result.sons[0] = makeRangeType(cl.c, 0, idx.n.intVal - 1, idx.n.info)
|
||||||
|
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
propagateFieldFlags(result, result.n)
|
propagateFieldFlags(result, result.n)
|
||||||
|
|
||||||
of tyProc:
|
of tyProc:
|
||||||
eraseVoidParams(result)
|
eraseVoidParams(result)
|
||||||
skipIntLiteralParams(result)
|
skipIntLiteralParams(result)
|
||||||
|
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||||
|
|
|
||||||
|
|
@ -1231,7 +1231,7 @@ proc getSize(typ: PType): BiggestInt =
|
||||||
if result < 0: internalError("getSize: " & $typ.kind)
|
if result < 0: internalError("getSize: " & $typ.kind)
|
||||||
|
|
||||||
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
|
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
|
||||||
result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc} or
|
result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc,tyFromExpr} or
|
||||||
t.kind == tyStatic and t.n == nil
|
t.kind == tyStatic and t.n == nil
|
||||||
|
|
||||||
proc containsGenericType*(t: PType): bool =
|
proc containsGenericType*(t: PType): bool =
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
||||||
## be called before any possible `object branch transition`:idx:.
|
## be called before any possible `object branch transition`:idx:.
|
||||||
|
|
||||||
# for low and high the return type T may not be correct, but
|
# for low and high the return type T may not be correct, but
|
||||||
# we handle that with compiler magic in SemLowHigh()
|
# we handle that with compiler magic in semLowHigh()
|
||||||
proc high*[T](x: T): T {.magic: "High", noSideEffect.}
|
proc high*[T](x: T): T {.magic: "High", noSideEffect.}
|
||||||
## returns the highest possible index of an array, a sequence, a string or
|
## returns the highest possible index of an array, a sequence, a string or
|
||||||
## the highest possible value of an ordinal value `x`. As a special
|
## the highest possible value of an ordinal value `x`. As a special
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tgenericshardcases.nim"
|
file: "tgenericshardcases.nim"
|
||||||
output: "int\nfloat\nint\nstring"
|
output: "2\n5\n126\n3"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typetraits
|
import typetraits
|
||||||
|
|
@ -13,18 +13,24 @@ macro selectType(a, b: typedesc): typedesc =
|
||||||
|
|
||||||
type
|
type
|
||||||
Foo[T] = object
|
Foo[T] = object
|
||||||
data1: array[high(T), int]
|
data1: array[T.high, int]
|
||||||
data2: array[1..typeNameLen(T), selectType(float, string)]
|
data2: array[typeNameLen(T), float] # data3: array[0..T.typeNameLen, selectType(float, int)]
|
||||||
|
|
||||||
MyEnum = enum A, B, C,D
|
MyEnum = enum A, B, C, D
|
||||||
|
|
||||||
var f1: Foo[MyEnum]
|
var f1: Foo[MyEnum]
|
||||||
var f2: Foo[int8]
|
var f2: Foo[int8]
|
||||||
|
|
||||||
static:
|
echo high(f1.data1) # (D = 3) - 1 == 2
|
||||||
assert high(f1.data1) == D
|
echo high(f1.data2) # (MyEnum.len = 6) - 1 == 5
|
||||||
assert high(f1.data2) == 6 # length of MyEnum
|
|
||||||
|
|
||||||
assert high(f2.data1) == 127
|
echo high(f2.data1) # 127 - 1 == 126
|
||||||
assert high(f2.data2) == 4 # length of int8
|
echo high(f2.data2) # int8.len - 1 == 3
|
||||||
|
|
||||||
|
#static:
|
||||||
|
# assert high(f1.data1) == ord(D)
|
||||||
|
# assert high(f1.data2) == 6 # length of MyEnum
|
||||||
|
|
||||||
|
# assert high(f2.data1) == 127
|
||||||
|
# assert high(f2.data2) == 4 # length of int8
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue