mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
handle arbitrary expressions dependent on static input params in proc signatures
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 == {}:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
line: 1855
|
||||
line: 1912
|
||||
file: "system.nim"
|
||||
errormsg: "can raise an unlisted exception: ref EIO"
|
||||
"""
|
||||
|
||||
16
tests/generics/tlateboundstatic.nim
Normal file
16
tests/generics/tlateboundstatic.nim
Normal 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
msg: 'type mismatch: got (PTest)'
|
||||
msg: "type mismatch: got (PTest)"
|
||||
"""
|
||||
|
||||
type
|
||||
|
||||
Reference in New Issue
Block a user