diff options
-rw-r--r-- | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 87 | ||||
-rw-r--r-- | compiler/cgen.nim | 18 | ||||
-rw-r--r-- | compiler/cgendata.nim | 1 | ||||
-rw-r--r-- | compiler/debuginfo.nim | 17 | ||||
-rw-r--r-- | compiler/rodwrite.nim | 4 | ||||
-rw-r--r-- | compiler/sighashes.nim | 137 | ||||
-rw-r--r-- | compiler/types.nim | 14 |
9 files changed, 226 insertions, 56 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 00a60fe1b..88ae8c7bd 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1953,7 +1953,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of skMethod: if {sfDispatcher, sfForward} * sym.flags != {}: # we cannot produce code for the dispatcher yet: - fillProcLoc(sym) + fillProcLoc(p.module, sym) genProcPrototype(p.module, sym) else: genProc(p.module, sym) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 10b5641c5..a1ec73e5c 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -970,7 +970,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = if r == nil: # if no name has already been given, # it doesn't matter much: - r = mangleName(sym) + r = mangleName(p.module, sym) sym.loc.r = r # but be consequent! res.add($r) else: internalError(t.sons[i].info, "genAsmOrEmitStmt()") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index bd2e2cdda..f7f0d9f5a 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -11,7 +11,7 @@ # ------------------------- Name Mangling -------------------------------- -import debuginfo +import debuginfo, sighashes proc isKeyword(w: PIdent): bool = # Nim and C++ share some keywords @@ -29,14 +29,27 @@ proc mangleField(name: PIdent): string = # Mangling makes everything lowercase, # but some identifiers are C keywords -proc hashOwner(s: PSym): FilenameHash = +proc hashOwner(s: PSym): SigHash = var m = s while m.kind != skModule: m = m.owner let p = m.owner assert p.kind == skPackage result = gDebugInfo.register(p.name.s, m.name.s) -proc mangleName(s: PSym): Rope = +proc idOrSig(m: BModule; s: PSym): BiggestInt = + if s.kind in routineKinds and s.typ != nil and sfExported in s.flags: + # signatures for exported routines are reliable enough to + # produce a unique name and this means produced C++ is more stable wrt + # Nim changes: + let h = hashType(s.typ, {considerParamNames}) + if m.hashConflicts.containsOrIncl(cast[int](h)): + result = s.id + else: + result = BiggestInt(h) + else: + result = s.id + +proc mangleName(m: BModule; s: PSym): Rope = result = s.loc.r if result == nil: let keepOrigName = s.kind in skLocalVars - {skForVar} and @@ -86,7 +99,7 @@ proc mangleName(s: PSym): Rope = result.add "0" else: add(result, ~"_") - add(result, rope(s.id)) + add(result, rope(m.idOrSig(s))) add(result, ~"_") add(result, rope(hashOwner(s).BiggestInt)) s.loc.r = result @@ -95,12 +108,22 @@ proc typeName(typ: PType): Rope = result = if typ.sym != nil: typ.sym.name.s.mangle.rope else: ~"TY" -proc getTypeName(typ: PType): Rope = +proc getTypeName(m: BModule; typ: PType): Rope = if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}: result = typ.sym.loc.r else: if typ.loc.r == nil: - typ.loc.r = typ.typeName & typ.id.rope + when false: + # doesn't work yet and would require bigger rewritings + let h = hashType(typ, {considerParamNames}) + let sig = + if m.hashConflicts.containsOrIncl(cast[int](h)): + BiggestInt typ.id + else: + BiggestInt h + else: + let sig = BiggestInt typ.id + typ.loc.r = typ.typeName & sig.rope result = typ.loc.r if result == nil: internalError("getTypeName: " & $typ.kind) @@ -235,9 +258,9 @@ proc fillResult(param: PSym) = incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown -proc typeNameOrLiteral(t: PType, literal: string): Rope = +proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope = if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone: - result = getTypeName(t) + result = getTypeName(m, t) else: result = rope(literal) @@ -249,16 +272,16 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = "NU", "NU8", "NU16", "NU32", "NU64"] case typ.kind of tyPointer: - result = typeNameOrLiteral(typ, "void*") + result = typeNameOrLiteral(m, typ, "void*") of tyString: discard cgsym(m, "NimStringDesc") - result = typeNameOrLiteral(typ, "NimStringDesc*") - of tyCString: result = typeNameOrLiteral(typ, "NCSTRING") - of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL") - of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR") - of tyNil: result = typeNameOrLiteral(typ, "0") + result = typeNameOrLiteral(m, typ, "NimStringDesc*") + of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING") + of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL") + of tyChar: result = typeNameOrLiteral(m, typ, "NIM_CHAR") + of tyNil: result = typeNameOrLiteral(m, typ, "0") of tyInt..tyUInt64: - result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) + result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) of tyStatic: if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) @@ -290,7 +313,7 @@ proc getTypeForward(m: BModule, typ: PType): Rope = if result != nil: return case typ.kind of tySequence, tyTuple, tyObject: - result = getTypeName(typ) + result = getTypeName(m, typ) if not isImportedType(typ): addf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(typ), result]) @@ -336,7 +359,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, var param = t.n.sons[i].sym if isCompileTimeOnly(param.typ): continue if params != nil: add(params, ~", ") - fillLoc(param.loc, locParam, param.typ, mangleName(param), + fillLoc(param.loc, locParam, param.typ, mangleName(m, param), param.paramStorageLoc) if ccgIntroducedPtr(param): add(params, getTypeDescWeak(m, param.typ, check)) @@ -583,7 +606,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = let t = if t.kind == tyRange: t.lastSon else: t result = cacheGetType(m.typeCache, t) if result == nil: - result = getTypeName(t) + result = getTypeName(m, t) if not (isImportedCppType(t) or (sfImportc in t.sym.flags and t.sym.magic == mNone)): idTablePut(m.typeCache, t, result) @@ -609,7 +632,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id, name: t.sym.name.s, values: vals)) of tyProc: - result = getTypeName(t) + result = getTypeName(m, t) idTablePut(m.typeCache, t, result) var rettype, desc: Rope genProcParams(m, t, rettype, desc, check, true, true) @@ -627,7 +650,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = # with the name of the struct, not with the pointer to the struct: result = cacheGetType(m.forwTypeCache, t) if result == nil: - result = getTypeName(t) + result = getTypeName(m, t) if not isImportedType(t): addf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(t), result]) @@ -650,7 +673,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = of tyArrayConstr, tyArray: var n: BiggestInt = lengthOrd(t) if n <= 0: n = 1 # make an array of at least one element - result = getTypeName(t) + result = getTypeName(m, t) idTablePut(m.typeCache, t, result) if not isImportedType(t): let foo = getTypeDescAux(m, t.sons[1], check) @@ -660,7 +683,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = if isImportedCppType(t) and typ.kind == tyGenericInst: # for instantiated templates we do not go through the type cache as the # the type cache is not aware of 'tyGenericInst'. - let cppName = getTypeName(t) + let cppName = getTypeName(m, t) var i = 0 var chunkStart = 0 while i < cppName.data.len: @@ -693,7 +716,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = else: result = cacheGetType(m.forwTypeCache, t) if result == nil: - result = getTypeName(t) + result = getTypeName(m, t) if not isImportedType(t): addf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(t), result]) @@ -703,7 +726,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = else: getTupleDesc(m, t, result, check) if not isImportedType(t): add(m.s[cfsTypes], recdesc) of tySet: - result = getTypeName(t.lastSon) & "Set" + result = getTypeName(m, t.lastSon) & "Set" idTablePut(m.typeCache, t, result) if not isImportedType(t): let s = int(getSize(t)) @@ -764,7 +787,7 @@ proc genProcHeader(m: BModule, prc: PSym): Rope = elif prc.typ.callConv == ccInline: result.add "static " var check = initIntSet() - fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown) + fillLoc(prc.loc, locProc, prc.typ, mangleName(m, prc), OnUnknown) genProcParams(m, prc.typ, rettype, params, check) # careful here! don't access ``prc.ast`` as that could reload large parts of # the object graph! @@ -810,7 +833,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) = proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) = var base: Rope - if (sonsLen(typ) > 0) and (typ.sons[0] != nil): + if sonsLen(typ) > 0 and typ.sons[0] != nil: var x = typ.sons[0] if typ.kind == tyObject: x = x.skipTypes(skipPtrs) base = genTypeInfo(m, x) @@ -1005,7 +1028,17 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) = proc genTypeInfo(m: BModule, t: PType): Rope = let origType = t var t = getUniqueType(t) - result = "NTI$1" % [rope(t.id)] + + when false: + let h = hashType(t, {considerParamNames}) + let tid = if m.hashConflicts.containsOrIncl(cast[int](h)): + BiggestInt t.id + else: + BiggestInt h + else: + let tid = t.id + + result = "NTI$1" % [rope(tid)] if containsOrIncl(m.typeInfoMarker, t.id): return "(&".rope & result & ")".rope diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 6e18c8389..a4e6a4e51 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -359,7 +359,7 @@ proc localDebugInfo(p: BProc, s: PSym) = proc localVarDecl(p: BProc; s: PSym): Rope = if s.loc.k == locNone: - fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) + fillLoc(s.loc, locLocalVar, s.typ, mangleName(p.module, s), OnStack) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) result = getTypeDesc(p.module, s.loc.t) if s.constraint.isNil: @@ -387,7 +387,7 @@ proc mangleDynLibProc(sym: PSym): Rope proc assignGlobalVar(p: BProc, s: PSym) = if s.loc.k == locNone: - fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap) + fillLoc(s.loc, locGlobalVar, s.typ, mangleName(p.module, s), OnHeap) if lfDynamicLib in s.loc.flags: var q = findPendingModule(p.module, s) @@ -426,9 +426,9 @@ proc assignParam(p: BProc, s: PSym) = assert(s.loc.r != nil) localDebugInfo(p, s) -proc fillProcLoc(sym: PSym) = +proc fillProcLoc(m: BModule; sym: PSym) = if sym.loc.k == locNone: - fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack) + fillLoc(sym.loc, locProc, sym.typ, mangleName(m, sym), OnStack) proc getLabel(p: BProc): TLabel = inc(p.labels) @@ -729,7 +729,7 @@ proc genProcPrototype(m: BModule, sym: PSym) = add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) proc genProcNoForward(m: BModule, prc: PSym) = - fillProcLoc(prc) + fillProcLoc(m, prc) useHeader(m, prc) if lfImportCompilerProc in prc.loc.flags: # dependency to a compilerproc: @@ -757,7 +757,7 @@ proc requestConstImpl(p: BProc, sym: PSym) = var m = p.module useHeader(m, sym) if sym.loc.k == locNone: - fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnStatic) + fillLoc(sym.loc, locData, sym.typ, mangleName(p.module, sym), OnStatic) if lfNoDecl in sym.loc.flags: return # declare implementation: var q = findPendingModule(m, sym) @@ -778,7 +778,7 @@ proc isActivated(prc: PSym): bool = prc.typ != nil proc genProc(m: BModule, prc: PSym) = if sfBorrow in prc.flags or not isActivated(prc): return - fillProcLoc(prc) + fillProcLoc(m, prc) if sfForward in prc.flags: addForwardedProc(m, prc) else: genProcNoForward(m, prc) @@ -792,7 +792,7 @@ proc genProc(m: BModule, prc: PSym) = proc genVarPrototypeAux(m: BModule, sym: PSym) = #assert(sfGlobal in sym.flags) useHeader(m, sym) - fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap) + fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(m, sym), OnHeap) if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id): return if sym.owner.id != m.module.id: @@ -1107,6 +1107,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = result.forwardedProcs = @[] result.typeNodesName = getTempName(result) result.nimTypesName = getTempName(result) + result.hashConflicts = initIntSet() # no line tracing for the init sections of the system module so that we # don't generate a TFrame which can confuse the stack botton initialization: if sfSystemModule in module.flags: @@ -1140,6 +1141,7 @@ proc resetModule*(m: BModule) = nullify m.s m.typeNodes = 0 m.nimTypes = 0 + m.hashConflicts = initIntSet() nullify m.extensionLoaders # indicate that this is now cached module diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index a94950029..c6b93ad06 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -127,6 +127,7 @@ type extensionLoaders*: array['0'..'9', Rope] # special procs for the # OpenGL wrapper injectStmt*: Rope + hashConflicts*: IntSet var mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope diff --git a/compiler/debuginfo.nim b/compiler/debuginfo.nim index 8589730b9..32e95d1eb 100644 --- a/compiler/debuginfo.nim +++ b/compiler/debuginfo.nim @@ -11,14 +11,15 @@ ## to Nim. The data structure has been designed to produce something useful with Nim's marshal ## module. +import sighashes + type - FilenameHash* = uint32 FilenameMapping* = object package*, file*: string - mangled*: FilenameHash + mangled*: SigHash EnumDesc* = object size*: int - owner*: FilenameHash + owner*: SigHash id*: int name*: string values*: seq[(string, int)] @@ -28,11 +29,7 @@ type enums*: seq[EnumDesc] conflicts*: bool -proc sdbmHash(hash: FilenameHash, c: char): FilenameHash {.inline.} = - return FilenameHash(c) + (hash shl 6) + (hash shl 16) - hash - -proc sdbmHash(package, file: string): FilenameHash = - template `&=`(x, c) = x = sdbmHash(x, c) +proc sdbmHash(package, file: string): SigHash = result = 0 for i in 0..<package.len: result &= package[i] @@ -40,7 +37,7 @@ proc sdbmHash(package, file: string): FilenameHash = for i in 0..<file.len: result &= file[i] -proc register*(self: var DebugInfo; package, file: string): FilenameHash = +proc register*(self: var DebugInfo; package, file: string): SigHash = result = sdbmHash(package, file) for f in self.files: if f.mangled == result: @@ -49,7 +46,7 @@ proc register*(self: var DebugInfo; package, file: string): FilenameHash = break self.files.add(FilenameMapping(package: package, file: file, mangled: result)) -proc hasEnum*(self: DebugInfo; ename: string; id: int; owner: FilenameHash): bool = +proc hasEnum*(self: DebugInfo; ename: string; id: int; owner: SigHash): bool = for en in self.enums: if en.owner == owner and en.name == ename and en.id == id: return true diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index f2422f947..4ce9e616a 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -385,9 +385,9 @@ proc symStack(w: PRodWriter): int = inc result elif iiTableGet(w.index.tab, s.id) == InvalidKey: var m = getModule(s) - if m == nil and s.kind != skPackage: + if m == nil and s.kind != skPackage and sfGenSym notin s.flags: internalError("symStack: module nil: " & s.name.s) - if s.kind == skPackage or m.id == w.module.id or sfFromGeneric in s.flags: + if s.kind == skPackage or {sfFromGeneric, sfGenSym} * s.flags != {} or m.id == w.module.id: # put definition in here var L = w.data.len addToIndex(w.index, s.id, L) diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim new file mode 100644 index 000000000..9653b0e52 --- /dev/null +++ b/compiler/sighashes.nim @@ -0,0 +1,137 @@ +# +# +# The Nim Compiler +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Computes hash values for routine (proc, method etc) signatures. + +import ast + +type + SigHash* = uint32 ## a hash good enough for a filename or a proc signature + +proc sdbmHash(hash: SigHash, c: char): SigHash {.inline.} = + return SigHash(c) + (hash shl 6) + (hash shl 16) - hash + +template `&=`*(x: var SigHash, c: char) = x = sdbmHash(x, c) +template `&=`*(x: var SigHash, s: string) = + for c in s: x = sdbmHash(x, c) + +proc hashSym(c: var SigHash, s: PSym) = + if sfAnon in s.flags or s.kind == skGenericParam: + c &= ":anon" + else: + var it = s + while it != nil: + c &= it.name.s + c &= "." + it = it.owner + +proc hashTree(c: var SigHash, n: PNode) = + template lowlevel(v) = + for i in 0..<sizeof(v): c = sdbmHash(c, cast[cstring](unsafeAddr(v))[i]) + + if n == nil: + c &= "\255" + return + let k = n.kind + c &= char(k) + # we really must not hash line information. 'n.typ' is debatable but + # shouldn't be necessary for now and avoids potential infinite recursions. + case n.kind + of nkEmpty, nkNilLit, nkType: discard + of nkIdent: + c &= n.ident.s + of nkSym: + hashSym(c, n.sym) + of nkCharLit..nkUInt64Lit: + let v = n.intVal + lowlevel v + of nkFloatLit..nkFloat64Lit: + let v = n.floatVal + lowlevel v + of nkStrLit..nkTripleStrLit: + c &= n.strVal + else: + for i in 0.. <n.len: hashTree(c, n.sons[i]) + +type + ConsiderFlag* = enum + considerParamNames + +proc hashType(c: var SigHash, t: PType; flags: set[ConsiderFlag]) = + # modelled after 'typeToString' + if t == nil: + c &= "\254" + return + + c &= char(t.kind) + + # Every cyclic type in Nim need to be constructed via some 't.sym', so this + # is actually safe without an infinite recursion check: + if t.sym != nil and sfAnon notin t.sym.flags: + # t.n for literals, but not for e.g. objects! + if t.kind in {tyFloat, tyInt}: c.hashTree(t.n) + c.hashSym(t.sym) + return + + case t.kind + of tyGenericBody, tyGenericInst, tyGenericInvocation: + for i in countup(0, sonsLen(t) - 1 - ord(t.kind != tyGenericInvocation)): + c.hashType t.sons[i], flags + of tyUserTypeClass: + if t.sym != nil and t.sym.owner != nil: + c &= t.sym.owner.name.s + else: + c &= "unknown typeclass" + of tyUserTypeClassInst: + let body = t.sons[0] + c.hashSym body.sym + for i in countup(1, sonsLen(t) - 2): + c.hashType t.sons[i], flags + of tyFromExpr, tyFieldAccessor: + c.hashTree(t.n) + of tyArrayConstr: + c.hashTree(t.sons[0].n) + c.hashType(t.sons[1], flags) + of tyTuple: + if t.n != nil: + assert(sonsLen(t.n) == sonsLen(t)) + for i in countup(0, sonsLen(t.n) - 1): + assert(t.n.sons[i].kind == nkSym) + c &= t.n.sons[i].sym.name.s + c &= ':' + c.hashType(t.sons[i], flags) + c &= ',' + else: + for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i], flags + of tyRange: + c.hashTree(t.n) + c.hashType(t.sons[0], flags) + of tyProc: + c &= (if tfIterator in t.flags: "iterator " else: "proc ") + if considerParamNames in flags and t.n != nil: + let params = t.n + for i in 1..<params.len: + let param = params[i].sym + c &= param.name.s + c &= ':' + c.hashType(param.typ, flags) + c &= ',' + c.hashType(t.sons[0], flags) + else: + for i in 0.. <t.len: c.hashType(t.sons[i], flags) + c &= char(t.callConv) + if tfNoSideEffect in t.flags: c &= ".noSideEffect" + if tfThread in t.flags: c &= ".thread" + else: + for i in 0.. <t.len: c.hashType(t.sons[i], flags) + if tfNotNil in t.flags: c &= "not nil" + +proc hashType*(t: PType; flags: set[ConsiderFlag]): SigHash = + result = 0 + hashType result, t, flags diff --git a/compiler/types.nim b/compiler/types.nim index fc50449ec..ebbc7ee69 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -20,8 +20,11 @@ type preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string -proc base*(t: PType): PType - # ------------------- type iterator: ---------------------------------------- + +proc base*(t: PType): PType = + result = t.sons[0] + +# ------------------- type iterator: ---------------------------------------- type TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it @@ -444,8 +447,8 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = add(result, typeToString(t.sons[i], preferGenericArg)) add(result, ']') of tyTypeDesc: - if t.base.kind == tyNone: result = "typedesc" - else: result = "typedesc[" & typeToString(t.base) & "]" + if t.sons[0].kind == tyNone: result = "typedesc" + else: result = "typedesc[" & typeToString(t.sons[0]) & "]" of tyStatic: internalAssert t.len > 0 if prefer == preferGenericArg and t.n != nil: @@ -572,9 +575,6 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = typeToStr[t.kind] result.addTypeFlags(t) -proc base(t: PType): PType = - result = t.sons[0] - proc firstOrd(t: PType): BiggestInt = case t.kind of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: |