compilation cache: various bugfixes; works for the compiler itself
This commit is contained in:
parent
9fb36bd20c
commit
90db9171a2
13 changed files with 307 additions and 148 deletions
|
|
@ -293,7 +293,10 @@ type
|
||||||
tfAcyclic, # type is acyclic (for GC optimization)
|
tfAcyclic, # type is acyclic (for GC optimization)
|
||||||
tfEnumHasHoles, # enum cannot be mapped into a range
|
tfEnumHasHoles, # enum cannot be mapped into a range
|
||||||
tfShallow, # type can be shallow copied on assignment
|
tfShallow, # type can be shallow copied on assignment
|
||||||
tfThread # proc type is marked as ``thread``
|
tfThread, # proc type is marked as ``thread``
|
||||||
|
tfFromGeneric # type is an instantiation of a generic; this is needed
|
||||||
|
# because for instantiations of objects, structural
|
||||||
|
# type equality has to be used
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
@ -487,14 +490,14 @@ type
|
||||||
# same id; there may be multiple copies of a type
|
# same id; there may be multiple copies of a type
|
||||||
# in memory!
|
# in memory!
|
||||||
kind*: TTypeKind # kind of type
|
kind*: TTypeKind # kind of type
|
||||||
|
callConv*: TCallingConvention # for procs
|
||||||
|
flags*: TTypeFlags # flags of the type
|
||||||
sons*: TTypeSeq # base types, etc.
|
sons*: TTypeSeq # base types, etc.
|
||||||
n*: PNode # node for types:
|
n*: PNode # node for types:
|
||||||
# for range types a nkRange node
|
# for range types a nkRange node
|
||||||
# for record types a nkRecord node
|
# for record types a nkRecord node
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# else: unused
|
# else: unused
|
||||||
flags*: TTypeFlags # flags of the type
|
|
||||||
callConv*: TCallingConvention # for procs
|
|
||||||
owner*: PSym # the 'owner' of the type
|
owner*: PSym # the 'owner' of the type
|
||||||
sym*: PSym # types have the sym associated with them
|
sym*: PSym # types have the sym associated with them
|
||||||
# it is used for converting types to strings
|
# it is used for converting types to strings
|
||||||
|
|
|
||||||
|
|
@ -1395,8 +1395,7 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
|
||||||
toRope(magic)]))
|
toRope(magic)]))
|
||||||
|
|
||||||
proc genConv(p: BProc, e: PNode, d: var TLoc) =
|
proc genConv(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if equalOrDistinctOf(e.typ, e.sons[1].typ) or
|
if compareTypes(e.typ, e.sons[1].typ, dcEqIgnoreDistinct):
|
||||||
equalOrDistinctOf(e.sons[1].typ, e.typ):
|
|
||||||
expr(p, e.sons[1], d)
|
expr(p, e.sons[1], d)
|
||||||
else:
|
else:
|
||||||
genCast(p, e, d)
|
genCast(p, e, d)
|
||||||
|
|
|
||||||
|
|
@ -56,35 +56,70 @@ proc hashString*(s: string): biggestInt =
|
||||||
a = a +% `shl`(a, 15'i32)
|
a = a +% `shl`(a, 15'i32)
|
||||||
result = a
|
result = a
|
||||||
|
|
||||||
var gTypeTable: array[TTypeKind, TIdTable]
|
var
|
||||||
|
gTypeTable: array[TTypeKind, TIdTable]
|
||||||
|
gCanonicalTypes: array[TTypeKind, PType]
|
||||||
|
|
||||||
proc initTypeTables() =
|
proc initTypeTables() =
|
||||||
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
|
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc echoStats*() =
|
||||||
|
for i in countup(low(TTypeKind), high(TTypeKind)):
|
||||||
|
echo i, " ", gTypeTable[i].counter
|
||||||
|
|
||||||
proc GetUniqueType*(key: PType): PType =
|
proc GetUniqueType*(key: PType): PType =
|
||||||
# this is a hotspot in the compiler!
|
# this is a hotspot in the compiler!
|
||||||
result = key
|
|
||||||
if key == nil: return
|
if key == nil: return
|
||||||
var k = key.kind
|
var k = key.kind
|
||||||
case k
|
case k
|
||||||
of tyObject, tyEnum:
|
of tyNone, tyBool, tyChar, tyEmpty,
|
||||||
|
tyNil, tyExpr, tyStmt, tyTypeDesc, tyPointer, tyString, tyCString,
|
||||||
|
tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
|
||||||
|
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||||
|
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, tyBigNum:
|
||||||
|
result = gCanonicalTypes[k]
|
||||||
|
if result == nil:
|
||||||
|
gCanonicalTypes[k] = key
|
||||||
|
result = key
|
||||||
|
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
||||||
|
result = GetUniqueType(lastSon(key))
|
||||||
|
of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyGenericParam,
|
||||||
|
tyOpenArray, tyArray, tyTuple, tySet, tyRange,
|
||||||
|
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy:
|
||||||
|
# we have to do a slow linear search because types may need
|
||||||
|
# to be compared by their structure:
|
||||||
|
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||||
|
for h in countup(0, high(gTypeTable[k].data)):
|
||||||
|
var t = PType(gTypeTable[k].data[h].key)
|
||||||
|
if t != nil and sameType(t, key):
|
||||||
|
return t
|
||||||
|
IdTablePut(gTypeTable[k], key, key)
|
||||||
|
result = key
|
||||||
|
of tyObject:
|
||||||
|
if tfFromGeneric notin key.flags:
|
||||||
|
# fast case; lookup per id suffices:
|
||||||
result = PType(IdTableGet(gTypeTable[k], key))
|
result = PType(IdTableGet(gTypeTable[k], key))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
IdTablePut(gTypeTable[k], key, key)
|
IdTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
|
|
||||||
result = GetUniqueType(lastSon(key))
|
|
||||||
of tyProc:
|
|
||||||
nil
|
|
||||||
else:
|
else:
|
||||||
# we have to do a slow linear search because types may need
|
# ugly slow case: need to compare by structure
|
||||||
# to be compared by their structure:
|
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||||
if IdTableHasObjectAsKey(gTypeTable[k], key): return
|
|
||||||
for h in countup(0, high(gTypeTable[k].data)):
|
for h in countup(0, high(gTypeTable[k].data)):
|
||||||
var t = PType(gTypeTable[k].data[h].key)
|
var t = PType(gTypeTable[k].data[h].key)
|
||||||
if (t != nil) and sameType(t, key):
|
if t != nil and sameType(t, key):
|
||||||
return t
|
return t
|
||||||
IdTablePut(gTypeTable[k], key, key)
|
IdTablePut(gTypeTable[k], key, key)
|
||||||
|
result = key
|
||||||
|
of tyEnum:
|
||||||
|
result = PType(IdTableGet(gTypeTable[k], key))
|
||||||
|
if result == nil:
|
||||||
|
IdTablePut(gTypeTable[k], key, key)
|
||||||
|
result = key
|
||||||
|
of tyProc, tyVar:
|
||||||
|
# tyVar is not 100% correct, but speeds things up a little:
|
||||||
|
result = key
|
||||||
|
|
||||||
proc TableGetType*(tab: TIdTable, key: PType): PObject =
|
proc TableGetType*(tab: TIdTable, key: PType): PObject =
|
||||||
# returns nil if we need to declare this type
|
# returns nil if we need to declare this type
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,5 @@ const
|
||||||
VersionPatch* = 13
|
VersionPatch* = 13
|
||||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
||||||
|
|
||||||
|
RodFileVersion* = "1030" # modify this if the rod-format changes!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,16 +56,17 @@ proc SearchForProc(c: PContext, fn: PSym, tos: int): PSym =
|
||||||
nil
|
nil
|
||||||
result = NextIdentIter(it, c.tab.stack[tos])
|
result = NextIdentIter(it, c.tab.stack[tos])
|
||||||
|
|
||||||
proc paramsFitBorrow(a, b: PNode): bool =
|
proc paramsFitBorrow(child, parent: PNode): bool =
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(child)
|
||||||
result = false
|
result = false
|
||||||
if length == sonsLen(b):
|
if length == sonsLen(parent):
|
||||||
for i in countup(1, length - 1):
|
for i in countup(1, length - 1):
|
||||||
var m = a.sons[i].sym
|
var m = child.sons[i].sym
|
||||||
var n = b.sons[i].sym
|
var n = parent.sons[i].sym
|
||||||
assert((m.kind == skParam) and (n.kind == skParam))
|
assert((m.kind == skParam) and (n.kind == skParam))
|
||||||
if not equalOrDistinctOf(m.typ, n.typ): return
|
if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return
|
||||||
if not equalOrDistinctOf(a.sons[0].typ, b.sons[0].typ): return
|
if not compareTypes(child.sons[0].typ, parent.sons[0].typ,
|
||||||
|
dcEqOrDistinctOf): return
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc SearchForBorrowProc(c: PContext, fn: PSym, tos: int): PSym =
|
proc SearchForBorrowProc(c: PContext, fn: PSym, tos: int): PSym =
|
||||||
|
|
|
||||||
|
|
@ -141,9 +141,6 @@ type
|
||||||
|
|
||||||
PRodReader* = ref TRodReader
|
PRodReader* = ref TRodReader
|
||||||
|
|
||||||
const
|
|
||||||
FileVersion* = "1026" # modify this if the rod-format changes!
|
|
||||||
|
|
||||||
var rodCompilerprocs*: TStrTable
|
var rodCompilerprocs*: TStrTable
|
||||||
|
|
||||||
proc handleSymbolFile*(module: PSym, filename: string): PRodReader
|
proc handleSymbolFile*(module: PSym, filename: string): PRodReader
|
||||||
|
|
@ -376,7 +373,6 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||||
if r.s[r.pos] == '@':
|
if r.s[r.pos] == '@':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
result.magic = TMagic(decodeVInt(r.s, r.pos))
|
result.magic = TMagic(decodeVInt(r.s, r.pos))
|
||||||
if r.s[r.pos] == '(': result.ast = decodeNode(r, result.info)
|
|
||||||
if r.s[r.pos] == '!':
|
if r.s[r.pos] == '!':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
result.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
|
result.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
|
||||||
|
|
@ -395,6 +391,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||||
result.offset = - 1
|
result.offset = - 1
|
||||||
decodeLoc(r, result.loc, result.info)
|
decodeLoc(r, result.loc, result.info)
|
||||||
result.annex = decodeLib(r, info)
|
result.annex = decodeLib(r, info)
|
||||||
|
if r.s[r.pos] == '(': result.ast = decodeNode(r, result.info)
|
||||||
#echo "decoded: ", ident.s, "}"
|
#echo "decoded: ", ident.s, "}"
|
||||||
|
|
||||||
proc skipSection(r: PRodReader) =
|
proc skipSection(r: PRodReader) =
|
||||||
|
|
@ -618,7 +615,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||||
add(version, r.s[r.pos])
|
add(version, r.s[r.pos])
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
if r.s[r.pos] == '\x0A': inc(r.pos)
|
if r.s[r.pos] == '\x0A': inc(r.pos)
|
||||||
if version == FileVersion:
|
if version == RodFileVersion:
|
||||||
# since ROD files are only for caching, no backwarts compatibility is
|
# since ROD files are only for caching, no backwarts compatibility is
|
||||||
# needed
|
# needed
|
||||||
processRodFile(r, crc)
|
processRodFile(r, crc)
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,6 @@ proc addInterfaceSym(w: PRodWriter, s: PSym)
|
||||||
proc addStmt(w: PRodWriter, n: PNode)
|
proc addStmt(w: PRodWriter, n: PNode)
|
||||||
proc writeRod(w: PRodWriter)
|
proc writeRod(w: PRodWriter)
|
||||||
|
|
||||||
proc processStacks(w: PRodWriter)
|
|
||||||
|
|
||||||
proc getDefines(): string =
|
proc getDefines(): string =
|
||||||
var it: TTabIter
|
var it: TTabIter
|
||||||
var s = InitTabIter(it, gSymbols)
|
var s = InitTabIter(it, gSymbols)
|
||||||
|
|
@ -282,6 +280,19 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
if s.magic != mNone:
|
if s.magic != mNone:
|
||||||
result.add('@')
|
result.add('@')
|
||||||
encodeVInt(ord(s.magic), result)
|
encodeVInt(ord(s.magic), result)
|
||||||
|
if s.options != w.options:
|
||||||
|
result.add('!')
|
||||||
|
encodeVInt(cast[int32](s.options), result)
|
||||||
|
if s.position != 0:
|
||||||
|
result.add('%')
|
||||||
|
encodeVInt(s.position, result)
|
||||||
|
if s.offset != - 1:
|
||||||
|
result.add('`')
|
||||||
|
encodeVInt(s.offset, result)
|
||||||
|
encodeLoc(w, s.loc, result)
|
||||||
|
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||||
|
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||||
|
# the last entry of a symbol:
|
||||||
if s.ast != nil:
|
if s.ast != nil:
|
||||||
# we used to attempt to save space here by only storing a dummy AST if
|
# we used to attempt to save space here by only storing a dummy AST if
|
||||||
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
||||||
|
|
@ -297,17 +308,6 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
if codeAst != nil:
|
if codeAst != nil:
|
||||||
# resore the AST:
|
# resore the AST:
|
||||||
s.ast.sons[codePos] = codeAst
|
s.ast.sons[codePos] = codeAst
|
||||||
if s.options != w.options:
|
|
||||||
result.add('!')
|
|
||||||
encodeVInt(cast[int32](s.options), result)
|
|
||||||
if s.position != 0:
|
|
||||||
result.add('%')
|
|
||||||
encodeVInt(s.position, result)
|
|
||||||
if s.offset != - 1:
|
|
||||||
result.add('`')
|
|
||||||
encodeVInt(s.offset, result)
|
|
||||||
encodeLoc(w, s.loc, result)
|
|
||||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
|
||||||
|
|
||||||
proc addToIndex(w: var TIndex, key, val: int) =
|
proc addToIndex(w: var TIndex, key, val: int) =
|
||||||
if key - w.lastIdxKey == 1:
|
if key - w.lastIdxKey == 1:
|
||||||
|
|
@ -327,11 +327,14 @@ const debugWrittenIds = false
|
||||||
when debugWrittenIds:
|
when debugWrittenIds:
|
||||||
var debugWritten = initIntSet()
|
var debugWritten = initIntSet()
|
||||||
|
|
||||||
proc symStack(w: PRodWriter) =
|
proc symStack(w: PRodWriter): int =
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(w.sstack):
|
while i < len(w.sstack):
|
||||||
var s = w.sstack[i]
|
var s = w.sstack[i]
|
||||||
if IiTableGet(w.index.tab, s.id) == invalidKey:
|
if sfForward in s.flags:
|
||||||
|
w.sstack[result] = s
|
||||||
|
inc result
|
||||||
|
elif IiTableGet(w.index.tab, s.id) == invalidKey:
|
||||||
var m = getModule(s)
|
var m = getModule(s)
|
||||||
if m == nil: InternalError("symStack: module nil: " & s.name.s)
|
if m == nil: InternalError("symStack: module nil: " & s.name.s)
|
||||||
if (m.id == w.module.id) or (sfFromGeneric in s.flags):
|
if (m.id == w.module.id) or (sfFromGeneric in s.flags):
|
||||||
|
|
@ -367,29 +370,40 @@ proc symStack(w: PRodWriter) =
|
||||||
debug(s)
|
debug(s)
|
||||||
debug(s.owner)
|
debug(s.owner)
|
||||||
debug(m)
|
debug(m)
|
||||||
InternalError("BUG!!!!")
|
InternalError("Symbol referred to but never written")
|
||||||
inc(i)
|
inc(i)
|
||||||
setlen(w.sstack, 0)
|
setlen(w.sstack, result)
|
||||||
|
|
||||||
proc typeStack(w: PRodWriter) =
|
proc typeStack(w: PRodWriter): int =
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(w.tstack):
|
while i < len(w.tstack):
|
||||||
if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey:
|
var t = w.tstack[i]
|
||||||
|
if t.kind == tyForward:
|
||||||
|
w.tstack[result] = t
|
||||||
|
inc result
|
||||||
|
elif IiTableGet(w.index.tab, t.id) == invalidKey:
|
||||||
var L = w.data.len
|
var L = w.data.len
|
||||||
addToIndex(w.index, w.tstack[i].id, L)
|
addToIndex(w.index, t.id, L)
|
||||||
encodeType(w, w.tstack[i], w.data)
|
encodeType(w, t, w.data)
|
||||||
add(w.data, rodNL)
|
add(w.data, rodNL)
|
||||||
inc(i)
|
inc(i)
|
||||||
setlen(w.tstack, 0)
|
setlen(w.tstack, result)
|
||||||
|
|
||||||
proc processStacks(w: PRodWriter) =
|
proc processStacks(w: PRodWriter, finalPass: bool) =
|
||||||
while (len(w.tstack) > 0) or (len(w.sstack) > 0):
|
var oldS = 0
|
||||||
symStack(w)
|
var oldT = 0
|
||||||
typeStack(w)
|
while true:
|
||||||
|
var slen = symStack(w)
|
||||||
|
var tlen = typeStack(w)
|
||||||
|
if slen == oldS and tlen == oldT: break
|
||||||
|
oldS = slen
|
||||||
|
oldT = tlen
|
||||||
|
if finalPass and (oldS != 0 or oldT != 0):
|
||||||
|
InternalError("could not serialize some forwarded symbols/types")
|
||||||
|
|
||||||
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
|
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
|
||||||
pushSym(w, s)
|
pushSym(w, s)
|
||||||
processStacks(w)
|
processStacks(w, false)
|
||||||
|
|
||||||
proc addInterfaceSym(w: PRodWriter, s: PSym) =
|
proc addInterfaceSym(w: PRodWriter, s: PSym) =
|
||||||
if w == nil: return
|
if w == nil: return
|
||||||
|
|
@ -402,17 +416,17 @@ proc addStmt(w: PRodWriter, n: PNode) =
|
||||||
add(w.init, rodNL)
|
add(w.init, rodNL)
|
||||||
encodeNode(w, UnknownLineInfo(), n, w.data)
|
encodeNode(w, UnknownLineInfo(), n, w.data)
|
||||||
add(w.data, rodNL)
|
add(w.data, rodNL)
|
||||||
processStacks(w)
|
processStacks(w, false)
|
||||||
|
|
||||||
proc writeRod(w: PRodWriter) =
|
proc writeRod(w: PRodWriter) =
|
||||||
processStacks(w)
|
processStacks(w, true)
|
||||||
var f: TFile
|
var f: TFile
|
||||||
if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")),
|
if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")),
|
||||||
fmWrite):
|
fmWrite):
|
||||||
return
|
return
|
||||||
# write header:
|
# write header:
|
||||||
f.write("NIM:")
|
f.write("NIM:")
|
||||||
f.write(FileVersion)
|
f.write(RodFileVersion)
|
||||||
f.write(rodNL)
|
f.write(rodNL)
|
||||||
var id = "ID:"
|
var id = "ID:"
|
||||||
encodeVInt(w.module.id, id)
|
encodeVInt(w.module.id, id)
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,7 @@ proc checkConvertible(info: TLineInfo, castDest, src: PType) =
|
||||||
# we use d, s here to speed up that operation a bit:
|
# we use d, s here to speed up that operation a bit:
|
||||||
case cmpTypes(d, s)
|
case cmpTypes(d, s)
|
||||||
of isNone, isGeneric:
|
of isNone, isGeneric:
|
||||||
if not equalOrDistinctOf(castDest, src) and
|
if not compareTypes(castDest, src, dcEqIgnoreDistinct):
|
||||||
not equalOrDistinctOf(src, castDest):
|
|
||||||
GlobalError(info, errGenerated, `%`(
|
GlobalError(info, errGenerated, `%`(
|
||||||
MsgKindToString(errIllegalConvFromXtoY),
|
MsgKindToString(errIllegalConvFromXtoY),
|
||||||
[typeToString(src), typeToString(castDest)]))
|
[typeToString(src), typeToString(castDest)]))
|
||||||
|
|
@ -381,8 +380,7 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||||
# Object and tuple conversions are still addressable, so we skip them
|
# Object and tuple conversions are still addressable, so we skip them
|
||||||
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
|
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
|
||||||
result = isAssignable(c, n.sons[1])
|
result = isAssignable(c, n.sons[1])
|
||||||
elif equalOrDistinctOf(n.typ, n.sons[1].typ) or
|
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
|
||||||
equalOrDistinctOf(n.sons[1].typ, n.typ):
|
|
||||||
# types that are equal modulo distinction preserve l-value:
|
# types that are equal modulo distinction preserve l-value:
|
||||||
result = isAssignable(c, n.sons[1])
|
result = isAssignable(c, n.sons[1])
|
||||||
of nkHiddenDeref, nkDerefExpr:
|
of nkHiddenDeref, nkDerefExpr:
|
||||||
|
|
|
||||||
|
|
@ -502,7 +502,14 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
s.typ.kind = tyGenericBody
|
s.typ.kind = tyGenericBody
|
||||||
if s.typ.containerID != 0:
|
if s.typ.containerID != 0:
|
||||||
InternalError(a.info, "semTypeSection: containerID")
|
InternalError(a.info, "semTypeSection: containerID")
|
||||||
s.typ.containerID = getID()
|
s.typ.containerID = s.typ.id
|
||||||
|
# XXX for generic type aliases this is not correct! We need the
|
||||||
|
# underlying Id really:
|
||||||
|
#
|
||||||
|
# type
|
||||||
|
# TGObj[T] = object
|
||||||
|
# TAlias[T] = TGObj[T]
|
||||||
|
#
|
||||||
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
||||||
s.typ.size = -1 # could not be computed properly
|
s.typ.size = -1 # could not be computed properly
|
||||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ proc searchInstTypes(tab: TIdTable, key: PType): PType =
|
||||||
for h in countup(0, high(tab.data)):
|
for h in countup(0, high(tab.data)):
|
||||||
var t = PType(tab.data[h].key)
|
var t = PType(tab.data[h].key)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
if key.containerId == t.containerID:
|
if key.containerId == t.containerId:
|
||||||
var match = true
|
var match = true
|
||||||
for j in countup(0, sonsLen(t) - 1):
|
for j in countup(0, sonsLen(t) - 1):
|
||||||
# XXX sameType is not really correct for nested generics?
|
# XXX sameType is not really correct for nested generics?
|
||||||
|
|
@ -184,6 +184,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
else:
|
else:
|
||||||
if containsGenericType(t):
|
if containsGenericType(t):
|
||||||
result = copyType(t, t.owner, false)
|
result = copyType(t, t.owner, false)
|
||||||
|
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])
|
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||||
|
|
||||||
proc isObjectSubtype(a, f: PType): bool =
|
proc isObjectSubtype(a, f: PType): bool =
|
||||||
var t = a
|
var t = a
|
||||||
while t != nil and t.id != f.id: t = base(t)
|
while t != nil and not sameObjectTypes(f, t): t = t.sons[0]
|
||||||
result = t != nil
|
result = t != nil
|
||||||
|
|
||||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||||
|
|
@ -240,8 +240,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
return typeRel(mapping, f, a.sons[0])
|
return typeRel(mapping, f, a.sons[0])
|
||||||
case f.kind
|
case f.kind
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
if a.kind == f.kind and a.id == f.id: result = isEqual
|
if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
|
||||||
elif skipTypes(a, {tyRange}).id == f.id: result = isSubtype
|
elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype
|
||||||
of tyBool, tyChar:
|
of tyBool, tyChar:
|
||||||
if a.kind == f.kind: result = isEqual
|
if a.kind == f.kind: result = isEqual
|
||||||
elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
|
elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
|
||||||
|
|
@ -328,10 +328,10 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
if a.kind == tyTuple: result = tupleRel(mapping, f, a)
|
if a.kind == tyTuple: result = tupleRel(mapping, f, a)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
if a.kind == tyObject:
|
if a.kind == tyObject:
|
||||||
if a.id == f.id: result = isEqual
|
if sameObjectTypes(f, a): result = isEqual
|
||||||
elif isObjectSubtype(a, f): result = isSubtype
|
elif isObjectSubtype(a, f): result = isSubtype
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if (a.kind == tyDistinct) and (a.id == f.id): result = isEqual
|
if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
|
||||||
of tySet:
|
of tySet:
|
||||||
if a.kind == tySet:
|
if a.kind == tySet:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,7 @@ proc IterOverType*(t: PType, iter: TTypeIter, closure: PObject): bool
|
||||||
# Returns result of `iter`.
|
# Returns result of `iter`.
|
||||||
proc mutateType*(t: PType, iter: TTypeMutator, closure: PObject): PType
|
proc mutateType*(t: PType, iter: TTypeMutator, closure: PObject): PType
|
||||||
# Returns result of `iter`.
|
# Returns result of `iter`.
|
||||||
proc SameType*(x, y: PType): bool
|
|
||||||
proc SameTypeOrNil*(a, b: PType): bool
|
|
||||||
proc equalOrDistinctOf*(x, y: PType): bool
|
|
||||||
type
|
type
|
||||||
TParamsEquality* = enum # they are equal, but their
|
TParamsEquality* = enum # they are equal, but their
|
||||||
# identifiers or their return
|
# identifiers or their return
|
||||||
|
|
@ -544,6 +542,53 @@ proc lengthOrd(t: PType): biggestInt =
|
||||||
of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
|
of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
|
||||||
else: result = lastOrd(t) - firstOrd(t) + 1
|
else: result = lastOrd(t) - firstOrd(t) + 1
|
||||||
|
|
||||||
|
# -------------- type equality -----------------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
TDistinctCompare* = enum ## how distinct types are to be compared
|
||||||
|
dcEq, ## a and b should be the same type
|
||||||
|
dcEqIgnoreDistinct, ## compare symetrically: (distinct a) == b, a == b
|
||||||
|
## or a == (distinct b)
|
||||||
|
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||||
|
|
||||||
|
TSameTypeClosure = object {.pure.}
|
||||||
|
cmp: TDistinctCompare
|
||||||
|
initSets: bool
|
||||||
|
recCheck: int
|
||||||
|
a: TIntSet
|
||||||
|
b: TIntSet
|
||||||
|
|
||||||
|
proc initSameTypeClosure: TSameTypeClosure =
|
||||||
|
# we do the initialization lazy for performance (avoids memory allocations)
|
||||||
|
nil
|
||||||
|
|
||||||
|
proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
|
||||||
|
result = c.initSets and c.a.contains(a.id) and c.b.contains(b.id)
|
||||||
|
if not result:
|
||||||
|
if not c.initSets:
|
||||||
|
c.initSets = true
|
||||||
|
c.a = initIntSet()
|
||||||
|
c.b = initIntSet()
|
||||||
|
c.a.incl(a.id)
|
||||||
|
c.b.incl(b.id)
|
||||||
|
|
||||||
|
proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool
|
||||||
|
proc SameTypeOrNilAux(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
|
if a == b:
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
if a == nil or b == nil: result = false
|
||||||
|
else: result = SameTypeAux(a, b, c)
|
||||||
|
|
||||||
|
proc SameTypeOrNil*(a, b: PType): bool =
|
||||||
|
if a == b:
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
if a == nil or b == nil: result = false
|
||||||
|
else:
|
||||||
|
var c = initSameTypeClosure()
|
||||||
|
result = SameTypeAux(a, b, c)
|
||||||
|
|
||||||
proc equalParam(a, b: PSym): TParamsEquality =
|
proc equalParam(a, b: PSym): TParamsEquality =
|
||||||
if SameTypeOrNil(a.typ, b.typ):
|
if SameTypeOrNil(a.typ, b.typ):
|
||||||
if a.ast == b.ast:
|
if a.ast == b.ast:
|
||||||
|
|
@ -587,13 +632,6 @@ proc equalParams(a, b: PNode): TParamsEquality =
|
||||||
result = paramsIncompatible # overloading by different
|
result = paramsIncompatible # overloading by different
|
||||||
# result types does not work
|
# result types does not work
|
||||||
|
|
||||||
proc SameTypeOrNil(a, b: PType): bool =
|
|
||||||
if a == b:
|
|
||||||
result = true
|
|
||||||
else:
|
|
||||||
if a == nil or b == nil: result = false
|
|
||||||
else: result = SameType(a, b)
|
|
||||||
|
|
||||||
proc SameLiteral(x, y: PNode): bool =
|
proc SameLiteral(x, y: PNode): bool =
|
||||||
if x.kind == y.kind:
|
if x.kind == y.kind:
|
||||||
case x.kind
|
case x.kind
|
||||||
|
|
@ -606,15 +644,14 @@ proc SameRanges(a, b: PNode): bool =
|
||||||
result = SameLiteral(a.sons[0], b.sons[0]) and
|
result = SameLiteral(a.sons[0], b.sons[0]) and
|
||||||
SameLiteral(a.sons[1], b.sons[1])
|
SameLiteral(a.sons[1], b.sons[1])
|
||||||
|
|
||||||
proc sameTuple(a, b: PType, DistinctOf: bool): bool =
|
proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
# two tuples are equivalent iff the names, types and positions are the same;
|
# two tuples are equivalent iff the names, types and positions are the same;
|
||||||
# however, both types may not have any field names (t.n may be nil) which
|
# however, both types may not have any field names (t.n may be nil) which
|
||||||
# complicates the matter a bit.
|
# complicates the matter a bit.
|
||||||
if sonsLen(a) == sonsLen(b):
|
if sonsLen(a) == sonsLen(b):
|
||||||
result = true
|
result = true
|
||||||
for i in countup(0, sonsLen(a) - 1):
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
if DistinctOf: result = equalOrDistinctOf(a.sons[i], b.sons[i])
|
result = SameTypeAux(a.sons[i], b.sons[i], c)
|
||||||
else: result = SameType(a.sons[i], b.sons[i])
|
|
||||||
if not result: return
|
if not result: return
|
||||||
if a.n != nil and b.n != nil:
|
if a.n != nil and b.n != nil:
|
||||||
for i in countup(0, sonsLen(a.n) - 1):
|
for i in countup(0, sonsLen(a.n) - 1):
|
||||||
|
|
@ -628,73 +665,137 @@ proc sameTuple(a, b: PType, DistinctOf: bool): bool =
|
||||||
else:
|
else:
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc SameType(x, y: PType): bool =
|
template IfFastObjectTypeCheckFailed(a, b: PType, body: stmt) =
|
||||||
|
if tfFromGeneric notin a.flags + b.flags:
|
||||||
|
# fast case: id comparison suffices:
|
||||||
|
result = a.id == b.id
|
||||||
|
else:
|
||||||
|
# expensive structural equality test; however due to the way generic and
|
||||||
|
# objects work, if one of the types does **not** contain tfFromGeneric,
|
||||||
|
# they cannot be equal. The check ``a.sym.Id == b.sym.Id`` checks
|
||||||
|
# for the same origin and is essential because we don't want "pure"
|
||||||
|
# structural type equivalence:
|
||||||
|
#
|
||||||
|
# type
|
||||||
|
# TA[T] = object
|
||||||
|
# TB[T] = object
|
||||||
|
# --> TA[int] != TB[int]
|
||||||
|
if tfFromGeneric in a.flags * b.flags and a.sym.Id == b.sym.Id:
|
||||||
|
# ok, we need the expensive structural check
|
||||||
|
body
|
||||||
|
|
||||||
|
proc sameObjectTypes*(a, b: PType): bool =
|
||||||
|
# specialized for efficiency (sigmatch uses it)
|
||||||
|
IfFastObjectTypeCheckFailed(a, b):
|
||||||
|
var c = initSameTypeClosure()
|
||||||
|
result = sameTypeAux(a, b, c)
|
||||||
|
|
||||||
|
proc sameDistinctTypes*(a, b: PType): bool {.inline.} =
|
||||||
|
result = sameObjectTypes(a, b)
|
||||||
|
|
||||||
|
proc sameEnumTypes*(a, b: PType): bool {.inline.} =
|
||||||
|
result = a.id == b.id
|
||||||
|
|
||||||
|
proc SameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
|
||||||
|
if a == b:
|
||||||
|
result = true
|
||||||
|
elif (a != nil) and (b != nil) and (a.kind == b.kind):
|
||||||
|
if sameTypeOrNilAux(a.typ, b.typ, c):
|
||||||
|
case a.kind
|
||||||
|
of nkSym:
|
||||||
|
# same symbol as string is enough:
|
||||||
|
result = a.sym.name.id == b.sym.name.id
|
||||||
|
of nkIdent: result = a.ident.id == b.ident.id
|
||||||
|
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
|
||||||
|
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||||
|
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||||
|
of nkEmpty, nkNilLit, nkType: result = true
|
||||||
|
else:
|
||||||
|
if sonsLen(a) == sonsLen(b):
|
||||||
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
|
if not SameObjectTree(a.sons[i], b.sons[i], c): return
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
|
# check base types:
|
||||||
|
if sonsLen(a) != sonsLen(b): return
|
||||||
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
|
if not SameTypeOrNilAux(a.sons[i], b.sons[i], c): return
|
||||||
|
if not SameObjectTree(a.n, b.n, c): return
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
|
template CycleCheck() =
|
||||||
|
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
|
||||||
|
# increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat
|
||||||
|
# again: Since the recursion check is only to not get caught in an endless
|
||||||
|
# recursion, we use a counter and only if it's value is over some
|
||||||
|
# threshold we perform the expansive exact cycle check:
|
||||||
|
if c.recCheck < 20:
|
||||||
|
inc c.recCheck
|
||||||
|
else:
|
||||||
|
if containsOrIncl(c, a, b): return true
|
||||||
|
|
||||||
if x == y: return true
|
if x == y: return true
|
||||||
var a = skipTypes(x, {tyGenericInst})
|
var a = skipTypes(x, {tyGenericInst})
|
||||||
var b = skipTypes(y, {tyGenericInst})
|
var b = skipTypes(y, {tyGenericInst})
|
||||||
assert(a != nil)
|
assert(a != nil)
|
||||||
assert(b != nil)
|
assert(b != nil)
|
||||||
if a.kind != b.kind:
|
if a.kind != b.kind:
|
||||||
return false
|
case c.cmp
|
||||||
|
of dcEq: return false
|
||||||
|
of dcEqIgnoreDistinct:
|
||||||
|
while a.kind == tyDistinct: a = a.sons[0]
|
||||||
|
while b.kind == tyDistinct: b = b.sons[0]
|
||||||
|
if a.kind != b.kind: return false
|
||||||
|
of dcEqOrDistinctOf:
|
||||||
|
while a.kind == tyDistinct: a = a.sons[0]
|
||||||
|
if a.kind != b.kind: return false
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||||
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc:
|
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc:
|
||||||
result = true
|
result = true
|
||||||
of tyEnum, tyForward, tyObject, tyDistinct, tyProxy: result = (a.id == b.id)
|
of tyObject:
|
||||||
of tyTuple: result = sameTuple(a, b, false)
|
IfFastObjectTypeCheckFailed(a, b):
|
||||||
of tyGenericInst: result = sameType(lastSon(a), lastSon(b))
|
CycleCheck()
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
|
result = sameObjectStructures(a, b, c)
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc,
|
of tyDistinct:
|
||||||
tyConst, tyMutable, tyVarargs, tyIter:
|
CycleCheck()
|
||||||
|
result = sameTypeAux(a.sons[0], b.sons[0], c)
|
||||||
|
of tyEnum, tyForward, tyProxy:
|
||||||
|
# XXX generic enums do not make much sense, but require structural checking
|
||||||
|
result = a.id == b.id
|
||||||
|
of tyTuple:
|
||||||
|
CycleCheck()
|
||||||
|
result = sameTuple(a, b, c)
|
||||||
|
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
|
||||||
|
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
||||||
|
tyOrdinal, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||||
|
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter:
|
||||||
if sonsLen(a) == sonsLen(b):
|
if sonsLen(a) == sonsLen(b):
|
||||||
|
CycleCheck()
|
||||||
result = true
|
result = true
|
||||||
for i in countup(0, sonsLen(a) - 1):
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
result = SameTypeOrNil(a.sons[i], b.sons[i]) # BUGFIX
|
result = SameTypeOrNilAux(a.sons[i], b.sons[i], c)
|
||||||
if not result: return
|
if not result: return
|
||||||
if result and (a.kind == tyProc):
|
if result and (a.kind == tyProc):
|
||||||
result = a.callConv == b.callConv # BUGFIX
|
result = a.callConv == b.callConv
|
||||||
else:
|
|
||||||
result = false
|
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = SameTypeOrNil(a.sons[0], b.sons[0]) and
|
CycleCheck()
|
||||||
|
result = SameTypeOrNilAux(a.sons[0], b.sons[0], c) and
|
||||||
SameValue(a.n.sons[0], b.n.sons[0]) and
|
SameValue(a.n.sons[0], b.n.sons[0]) and
|
||||||
SameValue(a.n.sons[1], b.n.sons[1])
|
SameValue(a.n.sons[1], b.n.sons[1])
|
||||||
of tyNone: result = false
|
of tyNone: result = false
|
||||||
|
|
||||||
proc equalOrDistinctOf(x, y: PType): bool =
|
proc SameType*(x, y: PType): bool =
|
||||||
if x == y: return true
|
var c = initSameTypeClosure()
|
||||||
if x == nil or y == nil: return false
|
result = sameTypeAux(x, y, c)
|
||||||
var a = skipTypes(x, {tyGenericInst})
|
|
||||||
var b = skipTypes(y, {tyGenericInst})
|
proc compareTypes*(x, y: PType, cmp: TDistinctCompare): bool =
|
||||||
assert(a != nil)
|
## compares two type for equality (modulo type distinction)
|
||||||
assert(b != nil)
|
var c = initSameTypeClosure()
|
||||||
if a.kind != b.kind:
|
c.cmp = cmp
|
||||||
if a.kind == tyDistinct: a = a.sons[0]
|
result = sameTypeAux(x, y, c)
|
||||||
if a.kind != b.kind:
|
|
||||||
return false
|
|
||||||
case a.Kind
|
|
||||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
|
||||||
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc:
|
|
||||||
result = true
|
|
||||||
of tyEnum, tyForward, tyObject, tyDistinct, tyProxy: result = (a.id == b.id)
|
|
||||||
of tyTuple: result = sameTuple(a, b, true)
|
|
||||||
of tyGenericInst: result = equalOrDistinctOf(lastSon(a), lastSon(b))
|
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
|
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc,
|
|
||||||
tyConst, tyMutable, tyVarargs, tyIter:
|
|
||||||
if sonsLen(a) == sonsLen(b):
|
|
||||||
result = true
|
|
||||||
for i in countup(0, sonsLen(a) - 1):
|
|
||||||
result = equalOrDistinctOf(a.sons[i], b.sons[i])
|
|
||||||
if not result: return
|
|
||||||
if result and (a.kind == tyProc): result = a.callConv == b.callConv
|
|
||||||
else:
|
|
||||||
result = false
|
|
||||||
of tyRange:
|
|
||||||
result = equalOrDistinctOf(a.sons[0], b.sons[0]) and
|
|
||||||
SameValue(a.n.sons[0], b.n.sons[0]) and
|
|
||||||
SameValue(a.n.sons[1], b.n.sons[1])
|
|
||||||
of tyNone: result = false
|
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool
|
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool
|
||||||
proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
||||||
|
|
@ -927,8 +1028,9 @@ proc computeSize(typ: PType): biggestInt =
|
||||||
|
|
||||||
proc getReturnType*(s: PSym): PType =
|
proc getReturnType*(s: PSym): PType =
|
||||||
# Obtains the return type of a iterator/proc/macro/template
|
# Obtains the return type of a iterator/proc/macro/template
|
||||||
assert s.kind in { skProc, skTemplate, skMacro, skIterator }
|
assert s.kind in {skProc, skTemplate, skMacro, skIterator}
|
||||||
result = s.typ.n.sons[0].typ
|
# XXX ask Zahary if this change broke something
|
||||||
|
result = s.typ.sons[0]
|
||||||
|
|
||||||
proc getSize(typ: PType): biggestInt =
|
proc getSize(typ: PType): biggestInt =
|
||||||
result = computeSize(typ)
|
result = computeSize(typ)
|
||||||
|
|
|
||||||
6
todo.txt
6
todo.txt
|
|
@ -16,11 +16,11 @@ Version 0.8.14
|
||||||
incremental compilation
|
incremental compilation
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
- object types need to be compared by container ID!
|
- fix DLL interfacing!
|
||||||
|
- the loading has to be MUCH more lazy! --> next version: We should re-load
|
||||||
|
symbol.ast lazily
|
||||||
- adapt thread var implementation to care about the new merge operation
|
- adapt thread var implementation to care about the new merge operation
|
||||||
- write test cases: needs test script support
|
- write test cases: needs test script support
|
||||||
- stress test with whole compiler
|
|
||||||
- test DLL interfacing!
|
|
||||||
- test thread var
|
- test thread var
|
||||||
|
|
||||||
- automate tests:
|
- automate tests:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue