handle recursive types during the instantiation of meta types; propagate tfHasMeta more carefully
This commit is contained in:
parent
88873f7965
commit
7e24cf26de
4 changed files with 86 additions and 26 deletions
|
|
@ -404,8 +404,8 @@ type
|
||||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||||
# or other type classes
|
# or other type classes
|
||||||
tfHasGCedMem, # type contains GC'ed memory
|
tfHasGCedMem, # type contains GC'ed memory
|
||||||
tfGenericTypeParam
|
|
||||||
tfHasStatic
|
tfHasStatic
|
||||||
|
tfGenericTypeParam
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
@ -1229,6 +1229,10 @@ proc newSons(father: PNode, length: int) =
|
||||||
else:
|
else:
|
||||||
setLen(father.sons, length)
|
setLen(father.sons, length)
|
||||||
|
|
||||||
|
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||||
|
result = t
|
||||||
|
while result.kind in kinds: result = lastSon(result)
|
||||||
|
|
||||||
proc propagateToOwner*(owner, elem: PType) =
|
proc propagateToOwner*(owner, elem: PType) =
|
||||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
const HaveTheirOwnEmpty = {tySequence, tySet}
|
||||||
owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta,
|
owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta,
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
var cl: TReplTypeVars
|
var cl: TReplTypeVars
|
||||||
initIdTable(cl.symMap)
|
initIdTable(cl.symMap)
|
||||||
initIdTable(cl.typeMap)
|
initIdTable(cl.typeMap)
|
||||||
|
initIdTable(cl.localCache)
|
||||||
cl.info = info
|
cl.info = info
|
||||||
cl.c = c
|
cl.c = c
|
||||||
cl.allowMetaTypes = allowMetaTypes
|
cl.allowMetaTypes = allowMetaTypes
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
import ast, astalgo, msgs, types, magicsys, semdata, renderer
|
import ast, astalgo, msgs, types, magicsys, semdata, renderer
|
||||||
|
|
||||||
|
const
|
||||||
|
tfInstClearedFlags = {tfHasMeta}
|
||||||
|
|
||||||
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
||||||
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
||||||
localError(info, errInvalidPragmaX, "acyclic")
|
localError(info, errInvalidPragmaX, "acyclic")
|
||||||
|
|
@ -67,14 +70,30 @@ type
|
||||||
c*: PContext
|
c*: PContext
|
||||||
typeMap*: TIdTable # map PType to PType
|
typeMap*: TIdTable # map PType to PType
|
||||||
symMap*: TIdTable # map PSym to PSym
|
symMap*: TIdTable # map PSym to PSym
|
||||||
|
localCache*: TIdTable # local cache for remembering alraedy replaced
|
||||||
|
# types during instantiation of meta types
|
||||||
|
# (they are not stored in the global cache)
|
||||||
info*: TLineInfo
|
info*: TLineInfo
|
||||||
allowMetaTypes*: bool # allow types such as seq[Number]
|
allowMetaTypes*: bool # allow types such as seq[Number]
|
||||||
# i.e. the result contains unresolved generics
|
# i.e. the result contains unresolved generics
|
||||||
|
|
||||||
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
|
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
|
||||||
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||||
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
|
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
|
||||||
|
|
||||||
|
template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
|
||||||
|
when false:
|
||||||
|
if t != nil and tfHasMeta in t.flags and
|
||||||
|
cl.allowMetaTypes == false:
|
||||||
|
echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1)
|
||||||
|
debug t
|
||||||
|
writeStackTrace()
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
result = replaceTypeVarsTAux(cl, t)
|
||||||
|
checkMetaInvariants(cl, result)
|
||||||
|
|
||||||
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
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)
|
||||||
|
|
@ -87,7 +106,9 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
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)
|
||||||
result.typ = replaceTypeVarsT(cl, n.typ)
|
if n.typ != nil:
|
||||||
|
result.typ = replaceTypeVarsT(cl, n.typ)
|
||||||
|
checkMetaInvariants(cl, result.typ)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
|
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
discard
|
discard
|
||||||
|
|
@ -141,6 +162,11 @@ proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
||||||
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||||
internalError(cl.info, "substitution with generic parameter")
|
internalError(cl.info, "substitution with generic parameter")
|
||||||
|
|
||||||
|
proc instCopyType(t: PType): PType =
|
||||||
|
result = copyType(t, t.owner, false)
|
||||||
|
result.flags.incl tfFromGeneric
|
||||||
|
result.flags.excl tfInstClearedFlags
|
||||||
|
|
||||||
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
|
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
|
||||||
# is difficult to handle:
|
# is difficult to handle:
|
||||||
|
|
@ -148,14 +174,17 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
||||||
var header: PType = nil
|
var header: PType = nil
|
||||||
# search for some instantiation here:
|
# search for some instantiation here:
|
||||||
result = searchInstTypes(t)
|
if cl.allowMetaTypes:
|
||||||
|
result = PType(idTableGet(cl.localCache, t))
|
||||||
|
else:
|
||||||
|
result = searchInstTypes(t)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = t.sons[i]
|
var x = t.sons[i]
|
||||||
if x.kind == tyGenericParam:
|
if x.kind == tyGenericParam:
|
||||||
x = lookupTypeVar(cl, x)
|
x = lookupTypeVar(cl, x)
|
||||||
if x != nil:
|
if x != nil:
|
||||||
if header == nil: header = copyType(t, t.owner, false)
|
if header == nil: header = instCopyType(t)
|
||||||
header.sons[i] = x
|
header.sons[i] = x
|
||||||
propagateToOwner(header, x)
|
propagateToOwner(header, x)
|
||||||
|
|
||||||
|
|
@ -164,14 +193,18 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = searchInstTypes(header)
|
result = searchInstTypes(header)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
else:
|
else:
|
||||||
header = copyType(t, t.owner, false)
|
header = instCopyType(t)
|
||||||
|
|
||||||
|
result = newType(tyGenericInst, t.sons[0].owner)
|
||||||
|
# be careful not to propagate unnecessary flags here (don't use rawAddSon)
|
||||||
|
result.sons = @[header.sons[0]]
|
||||||
# ugh need another pass for deeply recursive generic types (e.g. PActor)
|
# ugh need another pass for deeply recursive generic types (e.g. PActor)
|
||||||
# we need to add the candidate here, before it's fully instantiated for
|
# we need to add the candidate here, before it's fully instantiated for
|
||||||
# recursive instantions:
|
# recursive instantions:
|
||||||
result = newType(tyGenericInst, t.sons[0].owner)
|
|
||||||
result.rawAddSon(header.sons[0])
|
|
||||||
if not cl.allowMetaTypes:
|
if not cl.allowMetaTypes:
|
||||||
cacheTypeInst(result)
|
cacheTypeInst(result)
|
||||||
|
else:
|
||||||
|
idTablePut(cl.localCache, t, result)
|
||||||
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = replaceTypeVarsT(cl, t.sons[i])
|
var x = replaceTypeVarsT(cl, t.sons[i])
|
||||||
|
|
@ -186,7 +219,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
rawAddSon(result, header.sons[i])
|
rawAddSon(result, header.sons[i])
|
||||||
|
|
||||||
var newbody = replaceTypeVarsT(cl, lastSon(body))
|
var newbody = replaceTypeVarsT(cl, lastSon(body))
|
||||||
newbody.flags = newbody.flags + t.flags + body.flags
|
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||||
result.flags = result.flags + newbody.flags
|
result.flags = result.flags + newbody.flags
|
||||||
newbody.callConv = body.callConv
|
newbody.callConv = body.callConv
|
||||||
# This type may be a generic alias and we want to resolve it here.
|
# This type may be a generic alias and we want to resolve it here.
|
||||||
|
|
@ -215,9 +248,22 @@ proc normalizeProcType(t: PType) =
|
||||||
setLen t.n.sons, pos
|
setLen t.n.sons, pos
|
||||||
return
|
return
|
||||||
|
|
||||||
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
proc propagateFieldFlags(t: PType, n: PNode) =
|
||||||
|
# This is meant for objects and tuples
|
||||||
|
# The type must be fully instantiated!
|
||||||
|
internalAssert n.kind != nkRecWhen
|
||||||
|
case n.kind
|
||||||
|
of nkSym:
|
||||||
|
propagateToOwner(t, n.sym.typ)
|
||||||
|
of nkRecList, nkRecCase, nkOfBranch, nkElse:
|
||||||
|
for son in n.sons:
|
||||||
|
propagateFieldFlags(t, son)
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
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:
|
if t.kind == tyStatic and t.sym != nil and t.sym.kind == skGenericParam:
|
||||||
let s = lookupTypeVar(cl, t)
|
let s = lookupTypeVar(cl, t)
|
||||||
return if s != nil: s else: t
|
return if s != nil: s else: t
|
||||||
|
|
@ -243,9 +289,10 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = lookup
|
result = lookup
|
||||||
if tfUnresolved in t.flags: result = result.base
|
if tfUnresolved in t.flags: result = result.base
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
result = copyType(t, t.owner, true)
|
result = instCopyType(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)
|
||||||
else:
|
else:
|
||||||
if t.kind == tyArray:
|
if t.kind == tyArray:
|
||||||
let idxt = t.sons[0]
|
let idxt = t.sons[0]
|
||||||
|
|
@ -253,22 +300,35 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
idxt.sym != nil and idxt.sym.kind == skGenericParam:
|
idxt.sym != nil and idxt.sym.kind == skGenericParam:
|
||||||
let value = lookupTypeVar(cl, idxt).n
|
let value = lookupTypeVar(cl, idxt).n
|
||||||
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
|
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
|
||||||
|
|
||||||
if containsGenericType(t):
|
if containsGenericType(t):
|
||||||
result = copyType(t, t.owner, false)
|
result = instCopyType(t)
|
||||||
incl(result.flags, tfFromGeneric)
|
|
||||||
result.size = -1 # needs to be recomputed
|
result.size = -1 # needs to be recomputed
|
||||||
|
|
||||||
for i in countup(0, sonsLen(result) - 1):
|
for i in countup(0, sonsLen(result) - 1):
|
||||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
if result.sons[i] != nil:
|
||||||
|
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||||
|
propagateToOwner(result, result.sons[i])
|
||||||
|
|
||||||
result.n = replaceTypeVarsN(cl, result.n)
|
result.n = replaceTypeVarsN(cl, result.n)
|
||||||
if result.kind in GenericTypes:
|
|
||||||
localError(cl.info, errCannotInstantiateX, typeToString(t, preferName))
|
# XXX: This is not really needed?
|
||||||
if result.kind == tyProc: normalizeProcType(result)
|
# if result.kind in GenericTypes:
|
||||||
|
# localError(cl.info, errCannotInstantiateX, typeToString(t, preferName))
|
||||||
|
|
||||||
|
case result.kind
|
||||||
|
of tyObject, tyTuple:
|
||||||
|
propagateFieldFlags(result, result.n)
|
||||||
|
of tyProc:
|
||||||
|
normalizeProcType(result)
|
||||||
|
else: discard
|
||||||
|
|
||||||
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||||
t: PType): PType =
|
t: PType): PType =
|
||||||
var cl: TReplTypeVars
|
var cl: TReplTypeVars
|
||||||
initIdTable(cl.symMap)
|
initIdTable(cl.symMap)
|
||||||
copyIdTable(cl.typeMap, pt)
|
copyIdTable(cl.typeMap, pt)
|
||||||
|
initIdTable(cl.localCache)
|
||||||
cl.info = info
|
cl.info = info
|
||||||
cl.c = p
|
cl.c = p
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ const
|
||||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||||
typedescInst* = abstractInst + {tyTypeDesc}
|
typedescInst* = abstractInst + {tyTypeDesc}
|
||||||
|
|
||||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType
|
|
||||||
proc containsObject*(t: PType): bool
|
proc containsObject*(t: PType): bool
|
||||||
proc containsGarbageCollectedRef*(typ: PType): bool
|
proc containsGarbageCollectedRef*(typ: PType): bool
|
||||||
proc containsHiddenPointer*(typ: PType): bool
|
proc containsHiddenPointer*(typ: PType): bool
|
||||||
|
|
@ -148,10 +147,6 @@ proc skipGeneric(t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
while result.kind == tyGenericInst: result = lastSon(result)
|
while result.kind == tyGenericInst: result = lastSon(result)
|
||||||
|
|
||||||
proc skipTypes(t: PType, kinds: TTypeKinds): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind in kinds: result = lastSon(result)
|
|
||||||
|
|
||||||
proc isOrdinalType(t: PType): bool =
|
proc isOrdinalType(t: PType): bool =
|
||||||
assert(t != nil)
|
assert(t != nil)
|
||||||
# caution: uint, uint64 are no ordinal types!
|
# caution: uint, uint64 are no ordinal types!
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue