From 38b62d5db70c51a0ab4af2fae445cdf83ca0d897 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 11 Nov 2025 14:29:33 +0100 Subject: [PATCH] more IC related refactorings --- compiler/ast.nim | 368 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 265 insertions(+), 103 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 92b34cf087..fcd248b203 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -721,7 +721,7 @@ type hasUserSpecifiedTypeImpl*: bool # used for determining whether to display inlay type hints ownerFieldImpl: PSym flagsImpl*: TSymFlags - astImpl*: PNode # syntax tree of proc, iterator, etc.: + astImpl*: PNode # syntax tree of proc, iterator, etc.: # the whole proc including header; this is used # for easy generation of proper error messages # for variant record fields the discriminant @@ -730,7 +730,7 @@ type # generated code that will be appended to the # module after the sem pass (see appendToModule) optionsImpl*: TOptions - positionImpl*: int # used for many different things: + positionImpl*: int # used for many different things: # for enum fields its position; # for fields its offset # for parameters its position (starting with 0) @@ -740,16 +740,16 @@ type # for modules, an unique index corresponding # to the module's fileIdx # for variables a slot index for the evaluator - offsetImpl*: int32 # offset of record field + offsetImpl*: int32 # offset of record field disamb*: int32 # disambiguation number; the basic idea is that # `___` is unique locImpl*: TLoc - annexImpl*: PLib # additional fields (seldom used, so we use a + annexImpl*: PLib # additional fields (seldom used, so we use a # reference to another object to save space) when hasFFI: - cnameImpl*: string # resolved C declaration name in importc decl, e.g.: + cnameImpl*: string # resolved C declaration name in importc decl, e.g.: # proc fun() {.importc: "$1aux".} => cname = funaux - constraintImpl*: PNode # additional constraints like 'lit|result'; also + constraintImpl*: PNode # additional constraints like 'lit|result'; also # misused for the codegenDecl and virtual pragmas in the hope # it won't cause problems # for skModule the string literal to output for @@ -777,10 +777,12 @@ type itemId*: ItemId kind*: TTypeKind # kind of type state*: ItemState - callConv*: TCallingConvention # for procs - flags*: TTypeFlags # flags of the type - sons: TTypeSeq # base types, etc. - n*: PNode # node for types: + uniqueId*: ItemId # due to a design mistake, we need to keep the real ID here as it + # is required by the --incremental:on mode. + callConvImpl*: TCallingConvention # for procs + flagsImpl*: TTypeFlags # flags of the type + sonsImpl: TTypeSeq # base types, etc. + nImpl*: PNode # node for types: # for range types a nkRange node # for record types a nkRecord node # for enum types a list of symbols @@ -789,18 +791,16 @@ type # formal param list # for concepts, the concept body # else: unused - ownerField: PSym # the 'owner' of the type - sym*: PSym # types have the sym associated with them + ownerFieldImpl: PSym # the 'owner' of the type + symImpl*: PSym # types have the sym associated with them # it is used for converting types to strings - size*: BiggestInt # the size of the type in bytes + sizeImpl*: BiggestInt # the size of the type in bytes # -1 means that the size is unknown - align*: int16 # the type's alignment requirements - paddingAtEnd*: int16 # - loc*: TLoc - typeInst*: PType # for generic instantiations the tyGenericInst that led to this + alignImpl*: int16 # the type's alignment requirements + paddingAtEndImpl*: int16 # + locImpl*: TLoc + typeInstImpl*: PType # for generic instantiations the tyGenericInst that led to this # type. - uniqueId*: ItemId # due to a design mistake, we need to keep the real ID here as it - # is required by the --incremental:on mode. TPair* = object key*, val*: RootRef @@ -846,16 +846,26 @@ proc loadSym*(s: PSym) {.inline.} = ## This is a forward declaration - implementation should be provided elsewhere. discard +proc loadType*(t: PType) {.inline.} = + ## Loads a type from NIF file if it's in Partial state. + ## This is a forward declaration - implementation should be provided elsewhere. + discard + proc ensureMutable*(s: PSym) {.inline.} = assert s.state != Sealed if s.state == Partial: loadSym(s) +proc ensureMutable*(t: PType) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + proc owner*(s: PSym|PType): PSym {.inline.} = when s is PSym: if s.state == Partial: loadSym(s) result = s.ownerFieldImpl else: - result = s.ownerField + if s.state == Partial: loadType(s) + result = s.ownerFieldImpl proc setOwner*(s: PSym|PType, owner: PSym) {.inline.} = when s is PSym: @@ -863,7 +873,9 @@ proc setOwner*(s: PSym|PType, owner: PSym) {.inline.} = if s.state == Partial: loadSym(s) s.ownerFieldImpl = owner else: - s.ownerField = owner + assert s.state != Sealed + if s.state == Partial: loadType(s) + s.ownerFieldImpl = owner # Accessor procs for TSym fields # Note: kind is kept as a direct field for case statement compatibility @@ -1094,6 +1106,112 @@ when defined(nimsuggest): if s.state == Partial: loadSym(s) s.allUsagesImpl = val +# Accessor procs for TType fields +proc callConv*(t: PType): TCallingConvention {.inline.} = + if t.state == Partial: loadType(t) + result = t.callConvImpl + +proc `callConv=`*(t: PType, val: TCallingConvention) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.callConvImpl = val + +proc flags*(t: PType): TTypeFlags {.inline.} = + if t.state == Partial: loadType(t) + result = t.flagsImpl + +proc `flags=`*(t: PType, val: TTypeFlags) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.flagsImpl = val + +proc sons*(t: PType): TTypeSeq {.inline.} = + if t.state == Partial: loadType(t) + result = t.sonsImpl + +proc `sons=`*(t: PType, val: TTypeSeq) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.sonsImpl = val + +proc n*(t: PType): PNode {.inline.} = + if t.state == Partial: loadType(t) + result = t.nImpl + +proc `n=`*(t: PType, val: PNode) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.nImpl = val + +proc sym*(t: PType): PSym {.inline.} = + if t.state == Partial: loadType(t) + result = t.symImpl + +proc `sym=`*(t: PType, val: PSym) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.symImpl = val + +proc size*(t: PType): BiggestInt {.inline.} = + if t.state == Partial: loadType(t) + result = t.sizeImpl + +proc `size=`*(t: PType, val: BiggestInt) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.sizeImpl = val + +proc align*(t: PType): int16 {.inline.} = + if t.state == Partial: loadType(t) + result = t.alignImpl + +proc `align=`*(t: PType, val: int16) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.alignImpl = val + +proc paddingAtEnd*(t: PType): int16 {.inline.} = + if t.state == Partial: loadType(t) + result = t.paddingAtEndImpl + +proc `paddingAtEnd=`*(t: PType, val: int16) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.paddingAtEndImpl = val + +proc loc*(t: PType): TLoc {.inline.} = + if t.state == Partial: loadType(t) + result = t.locImpl + +proc `loc=`*(t: PType, val: TLoc) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.locImpl = val + +proc typeInst*(t: PType): PType {.inline.} = + if t.state == Partial: loadType(t) + result = t.typeInstImpl + +proc `typeInst=`*(t: PType, val: PType) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.typeInstImpl = val + +proc incl*(t: PType; flag: TTypeFlag) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.flagsImpl.incl(flag) + +proc incl*(t: PType; flags: set[TTypeFlag]) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.flagsImpl.incl(flags) + +proc excl*(t: PType; flag: TTypeFlag) {.inline.} = + assert t.state != Sealed + if t.state == Partial: loadType(t) + t.flagsImpl.excl(flag) + type Gconfig = object # we put comments in a side channel to avoid increasing `sizeof(TNode)`, which # reduces memory usage given that `PNode` is the most allocated type by far. @@ -1291,13 +1409,20 @@ template `[]=`*(n: PNode, i: BackwardsIndex; x: PNode) = n[n.len - i.int] = x proc add*(father, son: PType) = assert son != nil - father.sons.add(son) + var s = father.sons() + s.add(son) + father.sonsImpl = s proc addAllowNil*(father, son: PType) {.inline.} = - father.sons.add(son) + var s = father.sons() + s.add(son) + father.sonsImpl = s -template `[]`*(n: PType, i: int): PType = n.sons[i] -template `[]=`*(n: PType, i: int; x: PType) = n.sons[i] = x +template `[]`*(n: PType, i: int): PType = n.sons()[i] +template `[]=`*(n: PType, i: int; x: PType) = + var s = n.sons() + s[i] = x + n.sonsImpl = s template `[]`*(n: PType, i: BackwardsIndex): PType = n[n.len - i.int] template `[]=`*(n: PType, i: BackwardsIndex; x: PType) = n[n.len - i.int] = x @@ -1604,27 +1729,33 @@ proc replaceFirstSon*(n, newson: PNode) {.inline.} = proc replaceSon*(n: PNode; i: int; newson: PNode) {.inline.} = n.sons[i] = newson -proc last*(n: PType): PType {.inline.} = n.sons[^1] +proc last*(n: PType): PType {.inline.} = n.sons()[^1] -proc elementType*(n: PType): PType {.inline.} = n.sons[^1] -proc skipModifier*(n: PType): PType {.inline.} = n.sons[^1] +proc elementType*(n: PType): PType {.inline.} = n.sons()[^1] +proc skipModifier*(n: PType): PType {.inline.} = n.sons()[^1] -proc indexType*(n: PType): PType {.inline.} = n.sons[0] -proc baseClass*(n: PType): PType {.inline.} = n.sons[0] +proc indexType*(n: PType): PType {.inline.} = n.sons()[0] +proc baseClass*(n: PType): PType {.inline.} = n.sons()[0] proc base*(t: PType): PType {.inline.} = - result = t.sons[0] + result = t.sons()[0] -proc returnType*(n: PType): PType {.inline.} = n.sons[0] -proc setReturnType*(n, r: PType) {.inline.} = n.sons[0] = r -proc setIndexType*(n, idx: PType) {.inline.} = n.sons[0] = idx +proc returnType*(n: PType): PType {.inline.} = n.sons()[0] +proc setReturnType*(n, r: PType) {.inline.} = + var s = n.sons() + s[0] = r + n.sonsImpl = s +proc setIndexType*(n, idx: PType) {.inline.} = + var s = n.sons() + s[0] = idx + n.sonsImpl = s -proc firstParamType*(n: PType): PType {.inline.} = n.sons[1] -proc firstGenericParam*(n: PType): PType {.inline.} = n.sons[1] +proc firstParamType*(n: PType): PType {.inline.} = n.sons()[1] +proc firstGenericParam*(n: PType): PType {.inline.} = n.sons()[1] -proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons[^1] +proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons()[^1] -proc genericHead*(n: PType): PType {.inline.} = n.sons[0] +proc genericHead*(n: PType): PType {.inline.} = n.sons()[0] proc skipTypes*(t: PType, kinds: TTypeKinds): PType = ## Used throughout the compiler code to test whether a type tree contains or @@ -1700,112 +1831,138 @@ when false: when true: proc len*(n: PType): int {.inline.} = - result = n.sons.len + result = n.sons().len proc sameTupleLengths*(a, b: PType): bool {.inline.} = - result = a.sons.len == b.sons.len + result = a.sons().len == b.sons().len iterator tupleTypePairs*(a, b: PType): (int, PType, PType) = - for i in 0 ..< a.sons.len: - yield (i, a.sons[i], b.sons[i]) + let sa = a.sons() + let sb = b.sons() + for i in 0 ..< sa.len: + yield (i, sa[i], sb[i]) iterator underspecifiedPairs*(a, b: PType; start = 0; without = 0): (PType, PType) = # XXX Figure out with what typekinds this is called. - for i in start ..< min(a.sons.len, b.sons.len) + without: - yield (a.sons[i], b.sons[i]) + let sa = a.sons() + let sb = b.sons() + for i in start ..< min(sa.len, sb.len) + without: + yield (sa[i], sb[i]) proc signatureLen*(t: PType): int {.inline.} = - result = t.sons.len + result = t.sons().len proc paramsLen*(t: PType): int {.inline.} = - result = t.sons.len - 1 + result = t.sons().len - 1 proc genericParamsLen*(t: PType): int {.inline.} = assert t.kind == tyGenericInst - result = t.sons.len - 2 # without 'head' and 'body' + result = t.sons().len - 2 # without 'head' and 'body' proc genericInvocationParamsLen*(t: PType): int {.inline.} = assert t.kind == tyGenericInvocation - result = t.sons.len - 1 # without 'head' + result = t.sons().len - 1 # without 'head' proc kidsLen*(t: PType): int {.inline.} = - result = t.sons.len + result = t.sons().len -proc genericParamHasConstraints*(t: PType): bool {.inline.} = t.sons.len > 0 +proc genericParamHasConstraints*(t: PType): bool {.inline.} = t.sons().len > 0 -proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0 -proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0 -proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1 +proc hasElementType*(t: PType): bool {.inline.} = t.sons().len > 0 +proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons().len == 0 +proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons().len == 1 -proc genericConstraint*(t: PType): PType {.inline.} = t.sons[0] +proc genericConstraint*(t: PType): PType {.inline.} = t.sons()[0] iterator genericInstParams*(t: PType): (bool, PType) = - for i in 1..= b.sons.len: + let sa = a.sons() + let sb = b.sons() + for i in 1..= sb.len: yield (false, nil, nil) else: - yield (true, a.sons[i], b.sons[i]) + yield (true, sa[i], sb[i]) iterator genericBodyParams*(t: PType): (int, PType) = - for i in 0.. 1: - setLen(t.sons, 1) + var s = t.sons() + if s.len > 1: + setLen(s, 1) + t.sonsImpl = s proc assignType*(dest, src: PType) = dest.kind = src.kind - dest.flags = src.flags - dest.callConv = src.callConv - dest.n = src.n - dest.size = src.size - dest.align = src.align + dest.flagsImpl = src.flags + dest.callConvImpl = src.callConv + dest.nImpl = src.n + dest.sizeImpl = src.size + dest.alignImpl = src.align # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: @@ -1841,21 +2002,22 @@ proc assignType*(dest, src: PType) = if dest.sym.annex == nil: dest.sym.annexImpl = src.sym.annex mergeLoc(dest.sym.locImpl, src.sym.loc) else: - dest.sym = src.sym - newSons(dest, src.sons.len) - for i in 0..