Skip to content

Commit

Permalink
give type macro pragmas unary type section with experimental switch
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Oct 5, 2024
1 parent 7dfadb8 commit 1ffc5a5
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 7 deletions.
22 changes: 22 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@

## Language changes

- With the experimental option `--experimental:typedTypeMacroPragma`,
macro pragmas in type definitions now receive a unary `nnkTypeSection` as
the argument instead of `nnkTypeDef`, which means `typed` arguments are now
possible for these macros.

```nim
{.experimental: "typedTypeMacroPragma".}
import macros
macro foo(def: typed) =
assert def.kind == nnkTypeSection # previously nnkTypeDef
assert def.len == 1
assert def[0].kind == nnkTypeDef
result = def
type Obj {.foo.} = object
x, y: int
let obj = Obj(x: 1, y: 2)
```


## Compiler changes

Expand Down
1 change: 1 addition & 0 deletions compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ type
# alternative to above:
genericsOpenSym
vtables
typedTypeMacroPragma

LegacyFeature* = enum
allowSemcheckedAstModification,
Expand Down
9 changes: 6 additions & 3 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,10 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
s.typ = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas:
if name.kind == nkPragmaExpr:
let rewritten = applyTypeSectionPragmas(c, name[1], typeDef)
var macroArg = typeDef
if typedTypeMacroPragma in c.features:
macroArg = newTreeI(nkTypeSection, typeDef.info, typeDef)
let rewritten = applyTypeSectionPragmas(c, name[1], macroArg)
if rewritten != nil:
case rewritten.kind
of nkTypeDef:
Expand Down Expand Up @@ -1712,8 +1715,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
obj.flags.incl sfPure
obj.typ = objTy
objTy.sym = obj
for sk in c.skipTypes:
discard semTypeNode(c, sk, nil)
for i in 0..<c.skipTypes.len:
discard semTypeNode(c, c.skipTypes[i], nil)
c.skipTypes = @[]

proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
Expand Down
11 changes: 7 additions & 4 deletions doc/manual_experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,13 @@ side of the definition. The macro can return either a type section or
another `nnkTypeDef` node, both of which will replace the original row
in the type section.

In the future, this `nnkTypeDef` argument may be replaced with a unary
type section node containing the type definition, or some other node that may
be more convenient to work with. The ability to return nodes other than type
definitions may also be supported, however currently this is not convenient
With the experimental option `--experimental:typedTypeMacroPragma`,
this `nnkTypeDef` argument is replaced with a unary type section node
containing the type definition, which allows macros to receive the node
as a `typed` argument.

In the future, the ability to return nodes other than type definitions may
also be supported, however currently this is not convenient
when dealing with mutual type recursion. For now, macros can return an unused
type definition where the right-hand node is of kind `nnkStmtListType`.
Declarations in this node will be attached to the same scope as
Expand Down
49 changes: 49 additions & 0 deletions tests/pragmas/ttypedef_macro_typed.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
discard """
nimout: '''
TypeSection
TypeDef
PragmaExpr
Sym "X"
Pragma
Empty
ObjectTy
Empty
Empty
Empty
'''
"""

import macros

{.experimental: "typedTypeMacroPragma".}

block: # changelog entry
macro foo(def: typed) =
assert def.kind == nnkTypeSection # previously nnkTypeDef
assert def.len == 1
assert def[0].kind == nnkTypeDef
result = def

type Obj {.foo.} = object
x, y: int

let obj = Obj(x: 1, y: 2)

block: # issue #18864
macro test(n: typed): untyped =
echo n.treeRepr
result = n

type
X {.test.} = object
var x = X()

block: # issue #15334
macro entity(entityType: typed) =
result = entityType

type
RootEntity = ref object of RootObj
Player {.entity.} = ref object of RootEntity
x, y: int
var foo = Player()

0 comments on commit 1ffc5a5

Please sign in to comment.