From cd7feabc97c53408c0f4a9fc915ec80fe124253c Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Jul 2026 20:28:49 +0200 Subject: [PATCH] refactorings: progress --- compiler/ast.nim | 15 ++-- compiler/lowerings.nim | 146 +++++++++++++++++++++++++------------- compiler/sem.nim | 3 +- compiler/semexprs.nim | 3 +- compiler/semfold.nim | 2 +- compiler/semmagic.nim | 3 +- compiler/semstmts.nim | 9 ++- compiler/semtypes.nim | 138 +++++++++++++++++++++++++---------- compiler/semtypinst.nim | 52 +++++++++----- compiler/sigmatch.nim | 6 +- compiler/typebuilders.nim | 98 +++++++++++++++++++++++++ compiler/types.nim | 8 ++- 12 files changed, 361 insertions(+), 122 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index a76a675240..1829c5e61f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -626,7 +626,14 @@ proc `[]`*(n: PType, i: int): PType {.inline.} = else: n.sonsImpl[i] -proc `[]=`*(n: PType, i: int; x: PType) {.inline.} = +proc replaceSon*(n: PType, i: int; x: PType) {.inline.} = + ## The single low-level "replace son `i` in place" primitive. All in-place son + ## mutation funnels through here -- call sites go via `TypeBuilder.setSon` + ## (`typebuilders.nim`, the reopen/mutable-staging seam); this is its backing. + ## The `PType.[]=` operators used to do this inline; they were removed so that + ## son replacement is named and greppable, and the PType->NifCursor swap (where + ## this becomes a token rewrite over a thawed cursor) touches one proc, not + ## every caller. if n.state == Partial: loadType(n) if n.kind == tyProc and i > 0: assert n.nImpl[i] != nil and n.nImpl[i].sym != nil @@ -638,9 +645,9 @@ proc `[]`*(n: PType, i: BackwardsIndex): PType {.inline.} = if n.state == Partial: loadType(n) n[n.sonsImpl.len - i.int] -proc `[]=`*(n: PType, i: BackwardsIndex; x: PType) {.inline.} = +proc replaceSon*(n: PType, i: BackwardsIndex; x: PType) {.inline.} = if n.state == Partial: loadType(n) - n[n.sonsImpl.len - i.int] = x + replaceSon(n, n.sonsImpl.len - i.int, x) proc getDeclPragma*(n: PNode): PNode = ## return the `nkPragma` node for declaration `n`, or `nil` if no pragma was found. @@ -1165,7 +1172,7 @@ proc assignType*(dest, src: PType) = dest.sonsImpl[0] = src.sonsImpl[0] else: newSons(dest, src.len) - for i in 0..child # heap leak the write-barrier surfaces. - result = newType(tyGenericInst, cl.c.idgen, cl.c.module, son = header.genericHead) - result.flags = header.flags + var rb = openPair(tyGenericInst, cl.c.idgen, cl.c.module, son = header.genericHead) + rb.setFlags header.flags # be careful not to propagate unnecessary flags here (don't use rawAddSon) # 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: + # recursive instantions: publish the instance's *identity* (`rb.pair`) while + # its body is still open, so recursive instantiations find it under its name. if not cl.allowMetaTypes: - cacheTypeInst(cl.c, result) + cacheTypeInst(cl.c, rb.pair) else: - cl.localCache[t.itemId] = result + cl.localCache[t.itemId] = rb.pair.decl let oldSkipTypedesc = cl.skipTypedesc cl.skipTypedesc = true @@ -516,17 +523,18 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = else: header[i] assert x.kind != tyGenericInvocation - header[i] = x + var hb = reopen(header) + hb.setSon(i, x) propagateToOwner(header, x) cl.typeMap.put(body[i-1], x) for i in FirstGenericParamAt.. 0: t.n[i].sym.typ = skipped # when the typeof operator is used on a static input @@ -769,11 +780,12 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false): bailout() result = instCopyType(cl, t) cl.localCache[t.itemId] = result + var b = reopen(result) for i in FirstGenericParamAt..