first phase of tyGenericParam reforms needed for static params

This commit is contained in:
Zahary Karadjov 2014-03-15 19:23:20 +02:00
commit 37b199d34a
6 changed files with 79 additions and 47 deletions

View file

@ -383,6 +383,10 @@ type
# sons[1]: field type # sons[1]: field type
# .n: nkDotExpr storing the field name # .n: nkDotExpr storing the field name
static:
# remind us when TTypeKind stops to fit in a single 64-bit word
assert TTypeKind.high.ord <= 63
const const
tyPureObject* = tyTuple tyPureObject* = tyTuple
GcTypeKinds* = {tyRef, tySequence, tyString} GcTypeKinds* = {tyRef, tySequence, tyString}
@ -448,6 +452,10 @@ type
tfHasStatic tfHasStatic
tfGenericTypeParam tfGenericTypeParam
tfImplicitTypeParam tfImplicitTypeParam
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
# T and I here can bind to both typedesc and static types
# before this is determined, we'll consider them to be a
# wildcard type.
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]
@ -693,7 +701,7 @@ type
TSym* {.acyclic.} = object of TIdObj TSym* {.acyclic.} = object of TIdObj
# proc and type instantiations are cached in the generic symbol # proc and type instantiations are cached in the generic symbol
case kind*: TSymKind case kind*: TSymKind
of skType: of skType, skGenericParam:
typeInstCache*: seq[PType] typeInstCache*: seq[PType]
typScope*: PScope typScope*: PScope
of routineKinds: of routineKinds:
@ -1495,6 +1503,9 @@ proc hasPattern*(s: PSym): bool {.inline.} =
iterator items*(n: PNode): PNode = iterator items*(n: PNode): PNode =
for i in 0.. <n.len: yield n.sons[i] for i in 0.. <n.len: yield n.sons[i]
iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
for i in 0.. <n.len: yield (i, n.sons[i])
proc isAtom*(n: PNode): bool {.inline.} = proc isAtom*(n: PNode): bool {.inline.} =
result = n.kind >= nkNone and n.kind <= nkNilLit result = n.kind >= nkNone and n.kind <= nkNilLit

View file

@ -117,8 +117,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
elif s.ast != nil: elif s.ast != nil:
result = semExpr(c, s.ast) result = semExpr(c, s.ast)
else: else:
internalError(n.info, "no default for") n.typ = s.typ
result = emptyNode return n
of skType: of skType:
markUsed(n, s) markUsed(n, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)

View file

@ -15,8 +15,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
if n.kind != nkGenericParams: if n.kind != nkGenericParams:
internalError(n.info, "instantiateGenericParamList; no generic params") internalError(n.info, "instantiateGenericParamList; no generic params")
newSeq(entry.concreteTypes, n.len) newSeq(entry.concreteTypes, n.len)
for i in countup(0, n.len - 1): for i, a in n.pairs:
var a = n.sons[i]
if a.kind != nkSym: if a.kind != nkSym:
internalError(a.info, "instantiateGenericParamList; no symbol") internalError(a.info, "instantiateGenericParamList; no symbol")
var q = a.sym var q = a.sym
@ -149,7 +148,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym = info: TLineInfo): PSym =
# no need to instantiate generic templates/macros: # no need to instantiate generic templates/macros:
if fn.kind in {skTemplate, skMacro}: return fn if fn.kind in {skTemplate, skMacro}: return fn
# generates an instantiated proc # generates an instantiated proc
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep") if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
inc(c.instCounter) inc(c.instCounter)
@ -183,7 +181,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas) pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
if isNil(n.sons[bodyPos]): if isNil(n.sons[bodyPos]):
n.sons[bodyPos] = copyTree(fn.getBody) n.sons[bodyPos] = copyTree(fn.getBody)
if fn.kind != skTemplate:
instantiateBody(c, n, result) instantiateBody(c, n, result)
sideEffectsCheck(c, result) sideEffectsCheck(c, result)
paramsTypeCheck(c, result.typ) paramsTypeCheck(c, result.typ)

View file

@ -203,6 +203,14 @@ proc nMinusOne(n: PNode): PNode =
newSymNode(getSysMagic("<", mUnaryLt)), newSymNode(getSysMagic("<", mUnaryLt)),
n]) n])
proc makeRangeWithStaticExpr(c: PContext, n: PNode): PType =
let intType = getSysType tyInt
result = newTypeS(tyRange, c)
result.sons = @[intType]
result.n = newNode(nkRange, n.info, @[
newIntTypeNode(nkIntLit, 0, intType),
makeStaticExpr(c, n.nMinusOne)])
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)
@ -220,7 +228,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
internalAssert c.inGenericContext > 0 internalAssert c.inGenericContext > 0
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 = makeRangeWithStaticExpr(c, e)
elif e.kind in nkCallKinds and hasGenericArguments(e): elif e.kind in nkCallKinds and hasGenericArguments(e):
if not isOrdinalType(e.typ): if not isOrdinalType(e.typ):
localError(n[1].info, errOrdinalTypeExpected) localError(n[1].info, errOrdinalTypeExpected)
@ -229,12 +237,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
# We are going to construct a range type that will be # We are going to construct a range type that will be
# properly filled-out in semtypinst (see how tyStaticExpr # properly filled-out in semtypinst (see how tyStaticExpr
# is handled there). # is handled there).
let intType = getSysType(tyInt) indx = makeRangeWithStaticExpr(c, e)
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)
@ -283,6 +286,18 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
result = result.typ.sym.copySym result = result.typ.sym.copySym
result.typ = copyType(result.typ, result.typ.owner, true) result.typ = copyType(result.typ, result.typ.owner, true)
result.typ.flags.incl tfUnresolved result.typ.flags.incl tfUnresolved
if result.kind == skGenericParam:
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
tfWildcard in result.typ.flags:
# collapse the wild-card param to a type
result.kind = skType
result.typ.flags.excl tfWildcard
return
else:
localError(n.info, errTypeExpected)
return errorSym(c, n)
if result.kind != skType: if result.kind != skType:
# this implements the wanted ``var v: V, x: V`` feature ... # this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter var ov: TOverloadIter
@ -787,11 +802,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = addImplicitGeneric(newTypeS(tyAnything, c)) result = addImplicitGeneric(newTypeS(tyAnything, c))
of tyGenericParam: of tyGenericParam:
if tfGenericTypeParam in paramType.flags and false: if tfWildcard in paramType.flags:
if paramType.sonsLen > 0: paramType.flags.excl tfWildcard
result = liftingWalk(paramType.lastSon) paramType.sym.kind = skType
else:
result = addImplicitGeneric(newTypeS(tyAnything, c))
else: discard else: discard
@ -894,6 +907,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
result.sons[0] = r result.sons[0] = r
res.typ = r res.typ = r
if genericParams != nil:
for n in genericParams:
if tfUnresolved in n.sym.typ.flags:
n.sym.kind = skType
n.sym.typ.flags.excl tfWildcard
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var length = sonsLen(n) var length = sonsLen(n)
@ -944,7 +963,6 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
localError(n.info, errNoGenericParamsAllowedForX, s.name.s) localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
return newOrPrevType(tyError, prev, c) return newOrPrevType(tyError, prev, c)
else: else:
var m = newCandidate(c, s, n) var m = newCandidate(c, s, n)
matches(c, n, copyTree(n), m) matches(c, n, copyTree(n), m)
@ -1262,6 +1280,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if typ == nil: if typ == nil:
typ = newTypeS(tyGenericParam, c) typ = newTypeS(tyGenericParam, c)
if father == nil: typ.flags.incl tfWildcard
typ.flags.incl tfGenericTypeParam typ.flags.incl tfGenericTypeParam
@ -1272,8 +1291,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
# type for each generic param. the index # type for each generic param. the index
# of the parameter will be stored in the # of the parameter will be stored in the
# attached symbol. # attached symbol.
var s = case finalType.kind var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
of tyStatic:
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType) newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
else: else:
newSymG(skType, a.sons[j], c).linkTo(finalType) newSymG(skType, a.sons[j], c).linkTo(finalType)

View file

@ -395,20 +395,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result.n = replaceTypeVarsN(cl, result.n) result.n = replaceTypeVarsN(cl, result.n)
# XXX: This is not really needed?
# if result.kind in GenericTypes:
# localError(cl.info, errCannotInstantiateX, typeToString(t, preferName))
case result.kind case result.kind
of tyArray: of tyArray:
let idx = result.sons[0] let idx = result.sons[0]
if idx.kind == tyStatic: internalAssert 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)

View file

@ -620,8 +620,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else: else:
fRange = prev fRange = prev
result = typeRel(c, f.sons[1], a.sons[1]) result = typeRel(c, f.sons[1], a.sons[1])
if result < isGeneric: result = isNone if result < isGeneric:
elif lengthOrd(fRange) != lengthOrd(a): result = isNone result = isNone
elif lengthOrd(fRange) != lengthOrd(a):
result = isNone
else: discard else: discard
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
case a.kind case a.kind
@ -867,7 +869,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# any value" and what we need is "match any type", which can be encoded # any value" and what we need is "match any type", which can be encoded
# by a tyTypeDesc params. Unfortunately, this requires more substantial # by a tyTypeDesc params. Unfortunately, this requires more substantial
# changes in semtypinst and elsewhere. # changes in semtypinst and elsewhere.
if a.kind == tyTypeDesc: if a.kind == tyTypeDesc or tfWildcard in a.flags:
if f.sonsLen == 0: if f.sonsLen == 0:
result = isGeneric result = isGeneric
else: else:
@ -883,11 +885,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isGeneric result = isGeneric
if result == isGeneric: if result == isGeneric:
var concrete = concreteType(c, a) var concrete = a
if concrete == nil: if tfWildcard in a.flags:
result = isNone a.sym.kind = skType
a.flags.excl tfWildcard
else: else:
if doBind: put(c.bindings, f, concrete) concrete = concreteType(c, a)
if concrete == nil:
return isNone
if doBind:
put(c.bindings, f, concrete)
elif a.kind == tyEmpty: elif a.kind == tyEmpty:
result = isGeneric result = isGeneric
elif x.kind == tyGenericParam: elif x.kind == tyGenericParam:
@ -1030,6 +1037,15 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
# XXX: When implicit statics are the default # XXX: When implicit statics are the default
# this will be done earlier - we just have to # this will be done earlier - we just have to
# make sure that static types enter here # make sure that static types enter here
# XXX: weaken tyGenericParam and call it tyGenericPlaceholder
# 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
var evaluated = c.semTryConstExpr(c, arg) var evaluated = c.semTryConstExpr(c, arg)
if evaluated != nil: if evaluated != nil:
arg.typ = newTypeS(tyStatic, c) arg.typ = newTypeS(tyStatic, c)