handle arbitrary expressions dependent on static input params in proc signatures

This commit is contained in:
Zahary Karadjov
2014-03-16 17:12:30 +02:00
parent da5d88f04e
commit f0953db3ba
10 changed files with 60 additions and 18 deletions

View File

@@ -432,8 +432,9 @@ type
tfFromGeneric, # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural
# type equality has to be used
tfUnresolved, # marks unresolved typedesc params: e.g.
tfUnresolved, # marks unresolved typedesc/static params: e.g.
# proc foo(T: typedesc, list: seq[T]): var T
# proc foo(L: static[int]): array[L, int]
tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference)
tfCapturesEnv, # whether proc really captures some environment

View File

@@ -87,9 +87,10 @@ proc getUniqueType*(key: PType): PType =
gCanonicalTypes[k] = key
result = key
of tyTypeDesc, tyTypeClasses, tyGenericParam,
tyFromExpr, tyStatic, tyFieldAccessor:
tyFromExpr, tyFieldAccessor:
internalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
tyConst, tyIter, tyStatic:
result = getUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,

View File

@@ -612,7 +612,19 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
if result.isNil: result = n
else: return result
result.typ = semfold.getIntervalType(callee.magic, call)
block maybeLabelAsStatic:
# XXX: temporary work-around needed for tlateboundstatic.
# This is certainly not correct, but it will get the job
# done until we have a more robust infrastructure for
# implicit statics.
if n.len > 1:
for i in 1 .. <n.len:
if n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags:
break maybeLabelAsStatic
n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
n.typ.flags.incl tfUnresolved
# optimization pass: not necessary for correctness of the semantic pass
if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
{sfForward, sfImportc} * callee.flags == {}:

View File

@@ -704,11 +704,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
of tyStatic:
# proc(a: expr{string}, b: expr{nkLambda})
# overload on compile time values and AST trees
if paramType.n != nil: return # this is a concrete type
if tfUnresolved in paramType.flags: return # already lifted
let base = paramType.base.maybeLift
if base.isMetaType and procKind == skMacro:
localError(info, errMacroBodyDependsOnGenericTypes, paramName)
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
result.flags.incl tfHasStatic
result.flags.incl({tfHasStatic, tfUnresolved})
of tyTypeDesc:
if tfUnresolved notin paramType.flags:
@@ -911,7 +913,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if genericParams != nil:
for n in genericParams:
if tfUnresolved in n.sym.typ.flags:
if tfWildcard in n.sym.typ.flags:
n.sym.kind = skType
n.sym.typ.flags.excl tfWildcard
@@ -981,7 +983,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
if containsGenericType(typ): isConcrete = false
addToResult(typ)
if isConcrete:
if s.ast == nil:
localError(n.info, errCannotInstantiateX, s.name.s)

View File

@@ -96,8 +96,11 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
checkMetaInvariants(cl, result)
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
let t = replaceTypeVarsT(cl, n.typ)
if t != nil and t.kind == tyStatic and t.n != nil:
return t.n
result = copyNode(n)
result.typ = replaceTypeVarsT(cl, n.typ)
result.typ = t
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
let isCall = result.kind in nkCallKinds
for i in 0 .. <n.safeLen:
@@ -197,10 +200,10 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
result = copySym(s, false)
incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result)
result.typ = replaceTypeVarsT(cl, s.typ)
result.owner = s.owner
result.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:

View File

@@ -1053,11 +1053,15 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
# and finally start using tyTypedesc for generic types properly.
if argType.kind == tyGenericParam and tfWildcard in argType.flags:
argType.assignType(f)
argType.flags.incl tfUnresolved
# put(m.bindings, f, argType)
return argSemantized
if argType.kind != tyStatic:
if argType.kind == tyStatic:
if m.calleeSym.kind == skType:
result = newNodeI(nkType, argOrig.info)
result.typ = makeTypeFromExpr(c, arg)
return
else:
var evaluated = c.semTryConstExpr(c, arg)
if evaluated != nil:
arg.typ = newTypeS(tyStatic, c)

View File

@@ -1255,15 +1255,18 @@ proc getSize(typ: PType): BiggestInt =
if result < 0: internalError("getSize: " & $typ.kind)
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}:
return true
if t.kind == tyStatic:
return t.n == nil
if t.kind == tyTypeDesc:
if t.base.kind == tyNone: return true
if containsGenericTypeIter(t.base, closure): return true
return false
return t.kind == tyStatic and t.n == nil
if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}:
return true
return false
proc containsGenericType*(t: PType): bool =
result = iterOverType(t, containsGenericTypeIter, nil)

View File

@@ -1,5 +1,5 @@
discard """
line: 1855
line: 1912
file: "system.nim"
errormsg: "can raise an unlisted exception: ref EIO"
"""

View File

@@ -0,0 +1,16 @@
discard """
msg: "array[0..3, int]"
"""
type
KK[I: static[int]] = object
x: array[I, int]
proc foo(a: static[string]): KK[a.len] =
result.x[0] = 12
var x = foo "test"
import typetraits
static: echo x.x.type.name

View File

@@ -1,5 +1,5 @@
discard """
msg: 'type mismatch: got (PTest)'
msg: "type mismatch: got (PTest)"
"""
type