mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
* Ast no transformation * Add getImplNoTransform to the macros module * progress on delaying transf * Fix methods tranformation * Fix lazy lambdalifting * fix create thread wrapper * transform for lambda lifting * improve getImplTransformed * Fix destructor tests * try to fix nimprof for linux
616 lines
22 KiB
Nim
616 lines
22 KiB
Nim
#
|
|
#
|
|
# The Nim Compiler
|
|
# (c) Copyright 2015 Andreas Rumpf
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
# This module does the instantiation of generic types.
|
|
|
|
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options,
|
|
lineinfos
|
|
|
|
const
|
|
tfInstClearedFlags = {tfHasMeta, tfUnresolved}
|
|
|
|
proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
|
|
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
|
localError(conf, info, "invalid pragma: acyclic")
|
|
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
|
|
localError(conf, info, "type 'var var' is not allowed")
|
|
|
|
proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
|
|
var t = typ.skipTypes({tyDistinct})
|
|
if t.kind in tyTypeClasses: discard
|
|
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
|
localError(conf, info, "invalid pragma: acyclic")
|
|
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
|
|
localError(conf, info, "type 'var var' is not allowed")
|
|
elif computeSize(conf, t) == szIllegalRecursion:
|
|
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
|
|
|
|
t = typ.skipTypes({tyGenericInst})
|
|
if t.kind == tyArray and tfUncheckedArray in t.flags:
|
|
t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked
|
|
|
|
when false:
|
|
if t.kind == tyObject and t.sons[0] != nil:
|
|
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
|
|
localError(info, errInheritanceOnlyWithNonFinalObjects)
|
|
|
|
proc searchInstTypes*(key: PType): PType =
|
|
let genericTyp = key.sons[0]
|
|
if not (genericTyp.kind == tyGenericBody and
|
|
key.sons[0] == genericTyp and genericTyp.sym != nil): return
|
|
|
|
when not defined(nimNoNilSeqs):
|
|
if genericTyp.sym.typeInstCache == nil: return
|
|
|
|
for inst in genericTyp.sym.typeInstCache:
|
|
if inst.id == key.id: return inst
|
|
if inst.sons.len < key.sons.len:
|
|
# XXX: This happens for prematurely cached
|
|
# types such as Channel[empty]. Why?
|
|
# See the notes for PActor in handleGenericInvocation
|
|
return
|
|
if not sameFlags(inst, key):
|
|
continue
|
|
|
|
block matchType:
|
|
for j in 1 .. high(key.sons):
|
|
# XXX sameType is not really correct for nested generics?
|
|
if not compareTypes(inst.sons[j], key.sons[j],
|
|
flags = {ExactGenericParams}):
|
|
break matchType
|
|
|
|
return inst
|
|
|
|
proc cacheTypeInst*(inst: PType) =
|
|
# XXX: add to module's generics
|
|
# update the refcount
|
|
let gt = inst.sons[0]
|
|
let t = if gt.kind == tyGenericBody: gt.lastSon else: gt
|
|
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
|
return
|
|
gt.sym.typeInstCache.add(inst)
|
|
|
|
|
|
type
|
|
LayeredIdTable* = object
|
|
topLayer*: TIdTable
|
|
nextLayer*: ptr LayeredIdTable
|
|
|
|
TReplTypeVars* = object
|
|
c*: PContext
|
|
typeMap*: ptr LayeredIdTable # map PType to PType
|
|
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
|
|
allowMetaTypes*: bool # allow types such as seq[Number]
|
|
# i.e. the result contains unresolved generics
|
|
skipTypedesc*: bool # wether we should skip typeDescs
|
|
owner*: PSym # where this instantiation comes from
|
|
recursionLimit: int
|
|
|
|
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
|
|
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
|
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode
|
|
|
|
proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable =
|
|
copyIdTable(result.topLayer, pt)
|
|
|
|
proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable =
|
|
result.nextLayer = cl.typeMap
|
|
initIdTable(result.topLayer)
|
|
|
|
proc lookup(typeMap: ptr LayeredIdTable, key: PType): PType =
|
|
var tm = typeMap
|
|
while tm != nil:
|
|
result = PType(idTableGet(tm.topLayer, key))
|
|
if result != nil: return
|
|
tm = tm.nextLayer
|
|
|
|
template put(typeMap: ptr LayeredIdTable, key, value: PType) =
|
|
idTablePut(typeMap.topLayer, key, value)
|
|
|
|
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()
|
|
|
|
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
|
result = replaceTypeVarsTAux(cl, t)
|
|
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 if tfUnresolved in t.flags: prepareNode(cl, t.n)
|
|
else: t.n
|
|
result = copyNode(n)
|
|
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:
|
|
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
|
|
if isCall and i == 0: result.add(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 reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
|
# This is needed for 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, skFunc}, {})
|
|
|
|
for i in 0 ..< n.safeLen:
|
|
n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
|
|
|
|
return n
|
|
|
|
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
|
|
if n == nil: return
|
|
result = copyNode(n)
|
|
if n.typ != nil:
|
|
result.typ = replaceTypeVarsT(cl, n.typ)
|
|
checkMetaInvariants(cl, result.typ)
|
|
case n.kind
|
|
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
|
|
discard
|
|
of nkSym:
|
|
result.sym = replaceTypeVarsS(cl, n.sym)
|
|
if result.sym.typ.kind == tyVoid:
|
|
# don't add the 'void' field
|
|
result = newNode(nkRecList, n.info)
|
|
of nkRecWhen:
|
|
var branch: PNode = nil # the branch to take
|
|
for i in countup(0, sonsLen(n) - 1):
|
|
var it = n.sons[i]
|
|
if it == nil: illFormedAst(n, cl.c.config)
|
|
case it.kind
|
|
of nkElifBranch:
|
|
checkSonsLen(it, 2, cl.c.config)
|
|
var cond = prepareNode(cl, it.sons[0])
|
|
var e = cl.c.semConstExpr(cl.c, cond)
|
|
if e.kind != nkIntLit:
|
|
internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
|
|
if e.intVal != 0 and branch == nil: branch = it.sons[1]
|
|
of nkElse:
|
|
checkSonsLen(it, 1, cl.c.config)
|
|
if branch == nil: branch = it.sons[0]
|
|
else: illFormedAst(n, cl.c.config)
|
|
if branch != nil:
|
|
result = replaceTypeVarsN(cl, branch)
|
|
else:
|
|
result = newNodeI(nkRecList, n.info)
|
|
of nkStaticExpr:
|
|
var n = prepareNode(cl, n)
|
|
n = reResolveCallsWithTypedescParams(cl, n)
|
|
result = if cl.allowMetaTypes: n
|
|
else: cl.c.semExpr(cl.c, n)
|
|
else:
|
|
var length = sonsLen(n)
|
|
if length > 0:
|
|
newSons(result, length)
|
|
if start > 0:
|
|
result.sons[0] = n.sons[0]
|
|
for i in countup(start, length - 1):
|
|
result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
|
|
|
|
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
|
if s == nil: return nil
|
|
# symbol is not our business:
|
|
if cl.owner != nil and s.owner != cl.owner:
|
|
return s
|
|
|
|
# XXX: Bound symbols in default parameter expressions may reach here.
|
|
# We cannot process them, becase `sym.n` may point to a proc body with
|
|
# cyclic references that will lead to an infinite recursion.
|
|
# Perhaps we should not use a black-list here, but a whitelist instead
|
|
# (e.g. skGenericParam and skType).
|
|
# Note: `s.magic` may be `mType` in an example such as:
|
|
# proc foo[T](a: T, b = myDefault(type(a)))
|
|
if s.kind == skProc or s.magic != mNone:
|
|
return s
|
|
|
|
#result = PSym(idTableGet(cl.symMap, s))
|
|
#if result == nil:
|
|
result = copySym(s, false)
|
|
incl(result.flags, sfFromGeneric)
|
|
#idTablePut(cl.symMap, s, result)
|
|
result.owner = s.owner
|
|
result.typ = replaceTypeVarsT(cl, s.typ)
|
|
result.ast = replaceTypeVarsN(cl, s.ast)
|
|
|
|
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
|
result = cl.typeMap.lookup(t)
|
|
if result == nil:
|
|
if cl.allowMetaTypes or tfRetType in t.flags: return
|
|
localError(cl.c.config, t.sym.info, "cannot instantiate: '" & typeToString(t) & "'")
|
|
result = errorType(cl.c)
|
|
# In order to prevent endless recursions, we must remember
|
|
# this bad lookup and replace it with errorType everywhere.
|
|
# These code paths are only active in "nim check"
|
|
cl.typeMap.put(t, result)
|
|
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
|
internalError(cl.c.config, cl.info, "substitution with generic parameter")
|
|
|
|
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
|
# XXX: relying on allowMetaTypes is a kludge
|
|
result = copyType(t, t.owner, cl.allowMetaTypes)
|
|
if cl.allowMetaTypes: return
|
|
result.flags.incl tfFromGeneric
|
|
if not (t.kind in tyMetaTypes or
|
|
(t.kind == tyStatic and t.n == nil)):
|
|
result.flags.excl tfInstClearedFlags
|
|
when false:
|
|
if newDestructors:
|
|
result.assignment = nil
|
|
#result.destructor = nil
|
|
result.sink = nil
|
|
|
|
template typeBound(c, newty, oldty, field, info) =
|
|
let opr = newty.field
|
|
if opr != nil and sfFromGeneric notin opr.flags:
|
|
# '=' needs to be instantiated for generics when the type is constructed:
|
|
newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
|
|
|
|
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
|
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
|
# is difficult to handle:
|
|
const eqFlags = eqTypeFlags + {tfGcSafe}
|
|
var body = t.sons[0]
|
|
if body.kind != tyGenericBody:
|
|
internalError(cl.c.config, cl.info, "no generic body")
|
|
var header: PType = t
|
|
# search for some instantiation here:
|
|
if cl.allowMetaTypes:
|
|
result = PType(idTableGet(cl.localCache, t))
|
|
else:
|
|
result = searchInstTypes(t)
|
|
|
|
if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
|
|
for i in countup(1, sonsLen(t) - 1):
|
|
var x = t.sons[i]
|
|
if x.kind in {tyGenericParam}:
|
|
x = lookupTypeVar(cl, x)
|
|
if x != nil:
|
|
if header == t: header = instCopyType(cl, t)
|
|
header.sons[i] = x
|
|
propagateToOwner(header, x)
|
|
else:
|
|
propagateToOwner(header, x)
|
|
|
|
if header != t:
|
|
# search again after first pass:
|
|
result = searchInstTypes(header)
|
|
if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
|
|
else:
|
|
header = instCopyType(cl, t)
|
|
|
|
result = newType(tyGenericInst, t.sons[0].owner)
|
|
result.flags = header.flags
|
|
# 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)
|
|
# we need to add the candidate here, before it's fully instantiated for
|
|
# recursive instantions:
|
|
if not cl.allowMetaTypes:
|
|
cacheTypeInst(result)
|
|
else:
|
|
idTablePut(cl.localCache, t, result)
|
|
|
|
let oldSkipTypedesc = cl.skipTypedesc
|
|
cl.skipTypedesc = true
|
|
|
|
var typeMapLayer = newTypeMapLayer(cl)
|
|
cl.typeMap = addr(typeMapLayer)
|
|
|
|
for i in countup(1, sonsLen(t) - 1):
|
|
var x = replaceTypeVarsT(cl, t.sons[i])
|
|
assert x.kind != tyGenericInvocation
|
|
header.sons[i] = x
|
|
propagateToOwner(header, x)
|
|
cl.typeMap.put(body.sons[i-1], x)
|
|
|
|
for i in countup(1, sonsLen(t) - 1):
|
|
# if one of the params is not concrete, we cannot do anything
|
|
# but we already raised an error!
|
|
rawAddSon(result, header.sons[i])
|
|
|
|
let bbody = lastSon body
|
|
var newbody = replaceTypeVarsT(cl, bbody)
|
|
let bodyIsNew = newbody != bbody
|
|
cl.skipTypedesc = oldSkipTypedesc
|
|
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
|
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
|
|
|
cl.typeMap = cl.typeMap.nextLayer
|
|
|
|
# This is actually wrong: tgeneric_closure fails with this line:
|
|
#newbody.callConv = body.callConv
|
|
# This type may be a generic alias and we want to resolve it here.
|
|
# One step is enough, because the recursive nature of
|
|
# handleGenericInvocation will handle the alias-to-alias-to-alias case
|
|
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
|
rawAddSon(result, newbody)
|
|
checkPartialConstructedType(cl.c.config, cl.info, newbody)
|
|
let dc = newbody.deepCopy
|
|
if cl.allowMetaTypes == false:
|
|
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
|
# 'deepCopy' needs to be instantiated for
|
|
# generics *when the type is constructed*:
|
|
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
|
attachedDeepCopy, 1)
|
|
if bodyIsNew and newbody.typeInst == nil:
|
|
#doassert newbody.typeInst == nil
|
|
newbody.typeInst = result
|
|
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
|
|
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
|
|
# need to look into this issue later
|
|
assert newbody.kind in {tyRef, tyPtr}
|
|
if newbody.lastSon.typeInst != nil:
|
|
#internalError(cl.c.config, cl.info, "ref already has a 'typeInst' field")
|
|
discard
|
|
else:
|
|
newbody.lastSon.typeInst = result
|
|
cl.c.typesWithOps.add((newbody, result))
|
|
let mm = skipTypes(bbody, abstractPtrs)
|
|
if tfFromGeneric notin mm.flags:
|
|
# bug #5479, prevent endless recursions here:
|
|
incl mm.flags, tfFromGeneric
|
|
let methods = mm.methods
|
|
for col, meth in items(methods):
|
|
# we instantiate the known methods belonging to that type, this causes
|
|
# them to be registered and that's enough, so we 'discard' the result.
|
|
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
|
|
attachedAsgn, col)
|
|
excl mm.flags, tfFromGeneric
|
|
|
|
proc eraseVoidParams*(t: PType) =
|
|
# transform '(): void' into '()' because old parts of the compiler really
|
|
# don't deal with '(): void':
|
|
if t.sons[0] != nil and t.sons[0].kind == tyVoid:
|
|
t.sons[0] = nil
|
|
|
|
for i in 1 ..< t.sonsLen:
|
|
# don't touch any memory unless necessary
|
|
if t.sons[i].kind == tyVoid:
|
|
var pos = i
|
|
for j in i+1 ..< t.sonsLen:
|
|
if t.sons[j].kind != tyVoid:
|
|
t.sons[pos] = t.sons[j]
|
|
t.n.sons[pos] = t.n.sons[j]
|
|
inc pos
|
|
setLen t.sons, pos
|
|
setLen t.n.sons, pos
|
|
return
|
|
|
|
proc skipIntLiteralParams*(t: PType) =
|
|
for i in 0 ..< t.sonsLen:
|
|
let p = t.sons[i]
|
|
if p == nil: continue
|
|
let skipped = p.skipIntLit
|
|
if skipped != p:
|
|
t.sons[i] = skipped
|
|
if i > 0: t.n.sons[i].sym.typ = skipped
|
|
|
|
# when the typeof operator is used on a static input
|
|
# param, the results gets infected with static as well:
|
|
if t.sons[0] != nil and t.sons[0].kind == tyStatic:
|
|
t.sons[0] = t.sons[0].base
|
|
|
|
proc propagateFieldFlags(t: PType, n: PNode) =
|
|
# This is meant for objects and tuples
|
|
# The type must be fully instantiated!
|
|
if n.isNil:
|
|
return
|
|
#internalAssert n.kind != nkRecWhen
|
|
case n.kind
|
|
of nkSym:
|
|
propagateToOwner(t, n.sym.typ)
|
|
of nkRecList, nkRecCase, nkOfBranch, nkElse:
|
|
for son in n:
|
|
propagateFieldFlags(t, son)
|
|
else: discard
|
|
|
|
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|
template bailout =
|
|
if cl.recursionLimit > 100:
|
|
# bail out, see bug #2509. But note this caching is in general wrong,
|
|
# look at this example where TwoVectors should not share the generic
|
|
# instantiations (bug #3112):
|
|
|
|
# type
|
|
# Vector[N: static[int]] = array[N, float64]
|
|
# TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
|
|
result = PType(idTableGet(cl.localCache, t))
|
|
if result != nil: return result
|
|
inc cl.recursionLimit
|
|
|
|
result = t
|
|
if t == nil: return
|
|
|
|
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
|
let lookup = cl.typeMap.lookup(t)
|
|
if lookup != nil: return lookup
|
|
|
|
case t.kind
|
|
of tyGenericInvocation:
|
|
result = handleGenericInvocation(cl, t)
|
|
if result.lastSon.kind == tyUserTypeClass:
|
|
result.kind = tyUserTypeClassInst
|
|
|
|
of tyGenericBody:
|
|
localError(cl.c.config, cl.info, "cannot instantiate: '" & typeToString(t) & "'")
|
|
result = errorType(cl.c)
|
|
#result = replaceTypeVarsT(cl, lastSon(t))
|
|
|
|
of tyFromExpr:
|
|
if cl.allowMetaTypes: return
|
|
# This assert is triggered when a tyFromExpr was created in a cyclic
|
|
# way. You should break the cycle at the point of creation by introducing
|
|
# a call such as: `n.typ = makeTypeFromExpr(c, n.copyTree)`
|
|
# Otherwise, the cycle will be fatal for the prepareNode call below
|
|
assert t.n.typ != t
|
|
var n = prepareNode(cl, t.n)
|
|
if n.kind != nkEmpty:
|
|
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.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, tyFloat:
|
|
result = skipIntLit(t)
|
|
|
|
of tyTypeDesc:
|
|
let lookup = cl.typeMap.lookup(t)
|
|
if lookup != nil:
|
|
result = lookup
|
|
if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
|
|
elif t.sons[0].kind != tyNone:
|
|
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
|
|
|
of tyUserTypeClass, tyStatic:
|
|
result = t
|
|
|
|
of tyGenericInst, tyUserTypeClassInst:
|
|
bailout()
|
|
result = instCopyType(cl, t)
|
|
idTablePut(cl.localCache, t, result)
|
|
for i in 1 ..< result.sonsLen:
|
|
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
|
propagateToOwner(result, result.lastSon)
|
|
|
|
else:
|
|
if containsGenericType(t):
|
|
#if not cl.allowMetaTypes:
|
|
bailout()
|
|
result = instCopyType(cl, t)
|
|
result.size = -1 # needs to be recomputed
|
|
#if not cl.allowMetaTypes:
|
|
idTablePut(cl.localCache, t, result)
|
|
|
|
for i in countup(0, sonsLen(result) - 1):
|
|
if result.sons[i] != nil:
|
|
var r = replaceTypeVarsT(cl, result.sons[i])
|
|
if result.kind == tyObject:
|
|
# carefully coded to not skip the precious tyGenericInst:
|
|
let r2 = r.skipTypes({tyAlias, tySink})
|
|
if r2.kind in {tyPtr, tyRef}:
|
|
r = skipTypes(r2, {tyPtr, tyRef})
|
|
result.sons[i] = r
|
|
if result.kind != tyArray or i != 0:
|
|
propagateToOwner(result, r)
|
|
# bug #4677: Do not instantiate effect lists
|
|
result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
|
|
case result.kind
|
|
of tyArray:
|
|
let idx = result.sons[0]
|
|
internalAssert cl.c.config, idx.kind != tyStatic
|
|
|
|
of tyObject, tyTuple:
|
|
propagateFieldFlags(result, result.n)
|
|
|
|
of tyProc:
|
|
eraseVoidParams(result)
|
|
skipIntLiteralParams(result)
|
|
|
|
else: discard
|
|
|
|
proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) =
|
|
var i = 0
|
|
while i < c.typesWithOps.len:
|
|
let (newty, oldty) = c.typesWithOps[i]
|
|
typeBound(c, newty, oldty, destructor, info)
|
|
typeBound(c, newty, oldty, sink, info)
|
|
typeBound(c, newty, oldty, assignment, info)
|
|
inc i
|
|
setLen(c.typesWithOps, 0)
|
|
|
|
proc initTypeVars*(p: PContext, typeMap: ptr LayeredIdTable, info: TLineInfo;
|
|
owner: PSym): TReplTypeVars =
|
|
initIdTable(result.symMap)
|
|
initIdTable(result.localCache)
|
|
result.typeMap = typeMap
|
|
result.info = info
|
|
result.c = p
|
|
result.owner = owner
|
|
|
|
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
|
owner: PSym, allowMetaTypes = false): PNode =
|
|
var typeMap = initLayeredTypeMap(pt)
|
|
var cl = initTypeVars(p, addr(typeMap), n.info, owner)
|
|
cl.allowMetaTypes = allowMetaTypes
|
|
pushInfoContext(p.config, n.info)
|
|
result = replaceTypeVarsN(cl, n)
|
|
popInfoContext(p.config)
|
|
|
|
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
|
|
original, new: PSym): PNode =
|
|
var typeMap = initLayeredTypeMap(pt)
|
|
var cl = initTypeVars(p, addr(typeMap), n.info, original)
|
|
idTablePut(cl.symMap, original, new)
|
|
pushInfoContext(p.config, n.info)
|
|
result = replaceTypeVarsN(cl, n)
|
|
popInfoContext(p.config)
|
|
|
|
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
|
t: PType): PType =
|
|
var typeMap = initLayeredTypeMap(pt)
|
|
var cl = initTypeVars(p, addr(typeMap), info, nil)
|
|
pushInfoContext(p.config, info)
|
|
result = replaceTypeVarsT(cl, t)
|
|
popInfoContext(p.config)
|
|
|
|
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
|
t: PType): PType =
|
|
var typeMap = initLayeredTypeMap(pt)
|
|
var cl = initTypeVars(p, addr(typeMap), info, nil)
|
|
cl.allowMetaTypes = true
|
|
pushInfoContext(p.config, info)
|
|
result = replaceTypeVarsT(cl, t)
|
|
popInfoContext(p.config)
|
|
|
|
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
|
t: PType): untyped =
|
|
generateTypeInstance(p, pt, arg.info, t)
|
|
|