Skip to content

Conversation

@elijahr
Copy link
Contributor

@elijahr elijahr commented Jan 1, 2026

This PR implements deferred pragma expressions for the size pragma, and establishes infrastructure for deferred evaluation of expressions for other pragmas in generic types.

Summary

  1. Deferred evaluation infrastructure: New DeferredPragmaExpr type and accessors for storing pragma expressions that reference generic type parameters
  2. Size pragma enhancement: The size pragma now accepts expressions like sizeof(T) that are evaluated during generic instantiation
  3. Feature detection: Use defined(nimHasDeferredPragmas) to check for this feature

Use Cases

Proper C++ Template Type Wrapping

The primary motivation: correctly wrapping C++ template types whose size depends on template parameters.

# Before:
type
  Atomic*[T] {.importcpp: "std::atomic", completeStruct.} = object
    raw: T  # Fake field as workaround

# After: 
type
  Atomic*[T] {.importcpp: "std::atomic", size: sizeof(T), completeStruct.} = object

Platform-Independent FFI

Cross-platform bindings where size may vary by architecture:

type
  PlatformInt {.importc: "intptr_t", size: sizeof(pointer), completeStruct.} = object

Implementation

AST extensions (astdef.nim, ast.nim):

  • DeferredPragmaExpr type pairs pragma word with unevaluated expression
  • deferredExprsImpl field on TType and TSym
  • sfHasDeferredPragmas / tfHasDeferredPragmas flags
  • Accessor procs: setDeferredExpr, clearDeferredExpr, deferredPragmas iterator

Pragma processing (pragmas.nim):

  • containsUnresolvedIdent: Detects expressions with unresolved generic identifiers
  • deferOrEvaluate: Generic helper for defer-or-evaluate decision
  • Modified wSize handler to defer when expression contains generic params

Instantiation (semtypinst.nim):

  • replaceIdentsWithTypes: Substitutes generic param names with concrete types
  • applyDeferredPragma: Evaluates deferred pragmas after instantiation
  • evaluateDeferredPragmas: Orchestrates evaluation of all deferred type pragmas

IC serialization (ic/enum2nif.nim):

  • Added serialization for new sfHasDeferredPragmas and tfHasDeferredPragmas flags

Tests

  • tests/pragmas/tdeferred_size.nim - Size pragma with sizeof(T) expressions

Prior Art

PR #24204 addresses the same problem for the size pragma. Key differences in our approach:

Aspect PR #24204 This PR
Scope size pragma size pragma (with extensible infrastructure)
Storage Retrieves from symbol's pragma AST Dedicated deferredExprsImpl field with typed accessors
Detection tfHasMeta flag Scope lookup via containsUnresolvedIdent
Extensibility Single pragma Generic system designed for additional pragmas

This PR uses a dedicated storage mechanism rather than mining symbol AST (which the #24204 author noted "seems dubious"). The DeferredPragmaExpr type and accessor API make it straightforward to add deferred support to additional pragmas in follow-up PRs.

Related Work

I have submtited a follow-up PRs to supportalign pragma with generic expressions (#25404).

If the changeset is accepted, I also have branches ready for PR to support:

  • importc/importcpp pragmas with generic expressions
  • header pragma with generic expressions

Enables the size pragma to accept expressions involving type parameters
for generic imported types. The expression is deferred and evaluated
when the generic type is instantiated.

Example:
  type
    CppAtomic[T] {.importcpp, size: sizeof(T).} = object
@Araq
Copy link
Member

Araq commented Jan 17, 2026

Sorry for this late feedback. The feature itself is fine but I don't like the fact that now every symbol/type takes up more memory (16 bytes if I'm not mistaken). We need a more general mechanism for symbol/type extensions, maybe based on a in-memory representation of NIF, maybe something else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants