From 92d0c097e56991f193884c1019bdc3843435eac7 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 28 Apr 2026 00:47:45 +0800 Subject: [PATCH] fixes #25140; Cannot resolve pragmas when new type is defined from typeof expression (#25764) fixes #25140 --- lib/core/macros.nim | 21 +++++++++++++++++++-- tests/pragmas/tcustom_pragma.nim | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 793ae75a13..4a08bf559f 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1559,6 +1559,8 @@ macro expandMacros*(body: typed): untyped = echo body.toStrLit result = body +proc getTypeInstSkipAlias(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} + proc extractTypeImpl(n: NimNode): NimNode = ## attempts to extract the type definition of the given symbol case n.kind @@ -1573,11 +1575,17 @@ proc extractTypeImpl(n: NimNode): NimNode = result = n[0].getImpl() of nnkTypeDef: result = n[2] + if result.kind notin {nnkSym, nnkObjectTy, nnkRefTy, nnkPtrTy, nnkBracketExpr}: + # Handle typeof() and similar unresolvable type expressions + let typSym = if n[0].kind == nnkPragmaExpr: n[0][0] else: n[0] + if typSym.kind == nnkSym: + let resolved = typSym.getTypeInstSkipAlias() + if resolved.kind == nnkSym: + return resolved.getImpl.extractTypeImpl() + error("Invalid node to retrieve type implementation of: " & $result.kind) else: error("Invalid node to retrieve type implementation of: " & $n.kind) -proc getTypeInstSkipAlias(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} - proc customPragmaNode(n: NimNode): NimNode = result = nil expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkType, nnkCheckedFieldExpr}) @@ -1618,6 +1626,15 @@ proc customPragmaNode(n: NimNode): NimNode = var typDef = getImpl(typInst) while typDef != nil: typDef.expectKind(nnkTypeDef) + # Resolve typeof() and similar unresolvable type expressions + if typDef[2].kind notin {nnkSym, nnkObjectTy, nnkRefTy, nnkPtrTy, nnkBracketExpr}: + let typSym = if typDef[0].kind == nnkPragmaExpr: typDef[0][0] else: typDef[0] + if typSym.kind == nnkSym: + let resolved = typSym.getTypeInstSkipAlias() + if resolved.kind == nnkSym: + typDef = getImpl(resolved) + continue + break let typ = typDef[2].extractTypeImpl() if typ.kind notin {nnkRefTy, nnkPtrTy, nnkObjectTy}: break let isRef = typ.kind in {nnkRefTy, nnkPtrTy} diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 3d6032e605..092d59bc74 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -549,3 +549,20 @@ block: type X {.p.} = object doAssert foo(X()) + +block: # typeof() type alias preserves field pragmas + template myFieldPragma {.pragma.} + type Orig = object + x {.myFieldPragma.}: int + + var orig: Orig + + # Direct typeof alias + type TAlias = typeof(orig) + var a: TAlias + doAssert a.x.hasCustomPragma(myFieldPragma) + + # Indirect alias of typeof alias + type TAlias2 = TAlias + var b: TAlias2 + doAssert b.x.hasCustomPragma(myFieldPragma)