Skip to content

Conversation

@isVoid
Copy link
Collaborator

@isVoid isVoid commented Jan 27, 2026

This is a demo PR that shows a "Parent-Child" pattern that shows an end-to-end use case of class template instantiation, template argument deduction and overload selection working hand in hand.

  • Add templated member-function bindings for class template specializations with overload selection and arg_intent support.
  • Generate templated-method shims with explicit argument formatting (array-ref/pointer handling) and intent-aware returns.
  • Improve template specialization metadata and typing (qualified/specialized names, enum NTTP names, CCCL NullType/opaque fallback, quieter parse defaults).
  • Add class-template unit tests and CCCL integration tests; run CCCL tests in conda and wheels CI.

Summary by CodeRabbit

  • New Features

    • Templated-method support for class templates with per-method argument-intent overrides
  • Improvements

    • Enum-aware rendering of template arguments
    • Reduced default parsing verbosity
    • Looser type deduction for opaque mappings
    • More consistent qualified template-name handling
    • Device-shim and templated-method shim enhancements
  • Tests

    • New CCCL (CUB) test suite and CI step to run it
    • Expanded templated-class method tests
  • Chores

    • Updated CI/test scripts and pre-commit codespell ignores
  • Documentation

    • Added SPDX headers to third-party test modules

…cialization inherit, but instead own an instantiation object
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

Implements per-method templated-method binding with arg_intent propagation, enum-aware rendering of integral template arguments, CCCL type mappings and new CCCL tests, CI wiring to run CCCL tests, and multiple API/shim-generation and test updates across ast_canopy and numbast. (34 words)

Changes

Cohort / File(s) Summary
CI / Workflow
\.github/workflows/wheels-test.yaml, ci/run_tests.py, ci/test_conda_python.sh
Added CI step to run CCCL tests, new --cccl CLI flag and wiring, and updated local CI test invocation to include --cccl.
Pre-commit
.pre-commit-config.yaml
Extended codespell ignore-words-list to include thirdparty.
AST Canopy — API
ast_canopy/ast_canopy/api.py
Changed parse_declarations_from_source(verbose: bool) default from True to False.
AST Canopy — Declarations & Instantiation
ast_canopy/ast_canopy/decl.py, ast_canopy/ast_canopy/instantiations.py
Refactored ClassTemplateSpecialization to use an internal ClassInstantiation; added templated_member_functions, specialized_name and qual_name properties; extended get_instantiated_c_stmt to accept use_qual_name and propagate it into nested instantiations.
AST Canopy — C++ renderer
ast_canopy/cpp/src/class_template_specialization.cpp
NTTP (integral) handling now recognizes enum types and attempts to render enumerator names (qualified/plain), falling back to numeric strings when no enum match exists.
AST Canopy — Tests
ast_canopy/tests/test_class_template_specialization.py
Test updated to assert on specialized_name instead of name.
Numbast — Class Template & Templated Methods
numbast/src/numbast/class_template.py
Large feature addition: per-method arg_intent resolution, templated-method binding/lowering with caching, templated-method shim generation, MetaFunctionType, and propagation of arg_intent through binding and caching paths.
Numbast — Types, Deduction & Utils
numbast/src/numbast/types.py, numbast/src/numbast/deduction.py, numbast/src/numbast/utils.py
Added CCCL type mapping (cub::NullType → nbtypes.void), unknown-type fallback to nbtypes.Opaque, allow Opaque in deduction matching, and extended make_struct_regular_method_shim() signature to accept explicit arg strings or params with validation.
Numbast — Tests & Test Data
numbast/tests/data/sample_class_template.cuh, numbast/tests/data/sample_class_template_templated_method.cuh, numbast/tests/test_class_template.py
Added templated-method test headers/data and extensive tests/fixtures exercising templated member functions, arg-intent variants, shim argument generation, and behaviour of templated-method lowering.
CCCL — Test infra & tests
numbast_extensions/tests/thirdparty/__init__.py, numbast_extensions/tests/thirdparty/CCCL/__init__.py, .../CCCL/conftest.py, .../CCCL/test_block_scan.py, .../CCCL/test_block_load_store.py
Added SPDX headers, conftest fixtures enforcing CUDA≥13 and locating CCCL includes, and new functional CCCL tests for BlockScan and BlockLoad/Store that compile and run CUDA kernels.
Test-only metadata
numbast_extensions/tests/thirdparty/CCCL/__init__.py, numbast_extensions/tests/thirdparty/__init__.py
Added SPDX license header lines (no behavioral changes).

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Runner
    participant Binder as Binding Layer (numbast)
    participant Shim as ShimWriter / Shim Generator
    participant NVRTC as CUDA Compiler
    participant GPU as Device Runtime

    Test->>Binder: request templated-method binding (with arg_intent)
    Binder->>Binder: normalize arg_intent, resolve per-method overrides
    Binder->>Binder: select templated overload(s) / create AbstractTemplate
    Binder->>Shim: generate shim & kernel source for selected specialization
    Shim->>NVRTC: compile CUDA module
    NVRTC->>GPU: load/launch kernel
    Test->>GPU: prepare buffers and invoke kernel via compiled module
    GPU-->>Test: return results
    Test->>Test: validate outputs (assert correctness)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

"I hopped through headers, shims, and name,
Matched enums to tokens, tuned templated frame,
Tests queued and CI set to run,
Shims stitched up, kernels hum — what fun! 🥕"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Class Template - Method Template (Parent-Child pattern) Binding Generation' accurately and concisely describes the main feature being implemented—support for templated member functions within class template specializations with overload selection and argument intent handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@isVoid isVoid marked this pull request as ready for review January 27, 2026 18:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ast_canopy/ast_canopy/instantiations.py (1)

60-68: Missing @property decorators on abstract methods.

base_name (line 60) and qual_name (line 65) are accessed as properties via self.base_name and self.qual_name at lines 42-44, but they lack @property decorators. This causes self.base_name to return the method object instead of raising NotImplementedError.

🐛 Proposed fix
+    `@property`
     def base_name(self):
         raise NotImplementedError(
             "BaseInstantiation.base_name is not implemented"
         )

+    `@property`
     def qual_name(self):
         raise NotImplementedError(
             "BaseInstantiation.qual_name is not implemented"
         )
🤖 Fix all issues with AI agents
In @.github/workflows/wheels-test.yaml:
- Around line 136-138: The CI step named "Run a specific set of
numbast_extensions tests" is too vague—update the step's name field (the string
currently set to that value in the workflow step) to a more descriptive title
that clearly identifies what is executed, for example mentioning
"numbast_extensions", "thirdparty", and "CCCL" so logs show something like "Run
numbast_extensions third-party CCCL tests"; keep the command (python -m pytest
numbast_extensions/tests/thirdparty/CCCL/) unchanged.

In `@ast_canopy/ast_canopy/decl.py`:
- Line 303: Fix the typo in the docstring that reads "Struct/class method who's
name may include template parameters." — change "who's" to the possessive
"whose" in the triple-quoted docstring in decl.py (the docstring that begins
with "Struct/class method who's name may include template parameters.") so it
reads "Struct/class method whose name may include template parameters."

In `@numbast_extensions/tests/thirdparty/CCCL/test_block_scan.py`:
- Around line 16-28: Extract the duplicated helper make_bindings into a shared
test utility (e.g., add it to conftest.py or test_utils.py) and update both
test_block_scan.py and test_block_load_store.py to import and call that shared
make_bindings instead of defining it locally; ensure the extracted function
preserves the same signature and behavior (uses
ast_canopy.parse_declarations_from_source and bind_cxx_class_templates, returns
the matching class by ct.__name__) so tests continue to work unchanged.

In `@numbast/src/numbast/class_template.py`:
- Around line 127-128: Remove the debug print statements in class_template.py
(e.g., the print(f"CTOR SHIM: {shim}") and the other prints around lines 605,
683, 811-813); replace them with proper logging calls such as logging.debug(...)
or simply delete them if not needed, ensuring you import and use the
module-level logger (via import logging and logging.getLogger(__name__)) and
reference the same contextual variables (like shim) in the debug message so
runtime stdout is not polluted.
- Line 59: The declared type hint for ConcreteTypeCache is incorrect: the cache
holds nbtypes.TypeRef objects returned by struct_type_from_instantiation, not
nbtypes.Type. Update the annotation for ConcreteTypeCache to use nbtypes.TypeRef
(or a suitable union including TypeRef) instead of nbtypes.Type so the hint
matches the actual stored values (refer to ConcreteTypeCache and
struct_type_from_instantiation to locate the code).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ast_canopy/ast_canopy/decl.py (1)

545-552: Validate template-argument count to avoid silent truncation.
zip will drop extra actual template arguments without warning, which can produce an incorrect specialization. Add a length check before building kwargs.

✅ Suggested fix
         targ_names: list[str] = [
             tp.name for tp in class_template.template_parameters
         ]
         targ_values: list[str] = actual_template_arguments
+        if len(targ_values) != len(targ_names):
+            raise ValueError(
+                f"Expected {len(targ_names)} template arguments, got {len(targ_values)}"
+            )
 
         kwargs = dict(zip(targ_names, targ_values))
 
         self._instantiation.instantiate(**kwargs)
🤖 Fix all issues with AI agents
In `@numbast/src/numbast/class_template.py`:
- Around line 917-928: generic_resolve currently checks method_templates before
templated_method_to_template causing templated overloads to be silently
shadowed; update generic_resolve to detect a name collision between
method_templates and templated_method_to_template (e.g. attr present in both)
before returning a resolved type and raise a clear error (ValueError or custom)
that includes the attribute name and both sources; reference the existing
helpers _templated_method_ty and _method_ty so the detection runs prior to
calling them and ensure tests cover the collision path.
- Around line 689-789: The regex _CXX_ARRAY_TYPE_RE only matches numeric extents
so array-ref types like T(&)[N] or T(&)[Enum::k] aren't recognized; update the
pattern (used by _make_templated_method_shim_arg_strings) to accept any non-]
content inside brackets (e.g. change (\[\d+\])+ to (\[[^\]]+\])+) so
identifiers, scoped names and expressions are captured as sizes, keep the same
"base" and "sizes" group semantics, and ensure downstream logic (base/sizes
extraction and comparisons around base_norm/nb_base) still works with the
broader sizes token (no further parsing of sizes required for this shim logic).

…s in concrete method and templated method, (2) handle fixed sized array reference inputs
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@numbast/src/numbast/class_template.py`:
- Around line 675-686: The error currently conflates "no match" and "ambiguous"
when len(candidates) != 1; update the branching around candidates, overrides,
and intent_errors to produce distinct messages: first keep the existing
overrides-specific TypeError when overrides is not None and not candidates and
intent_errors, then if not candidates raise a TypeError like "No matching
overload found for {qualname} with {arity} args. Overload arities:
{[len(m.function.params) for m in overloads]}", else if len(candidates) > 1
raise a TypeError like "Ambiguous overload for {qualname} with {arity} args.
Matching overload arities: {[len(m.function.params) for m in candidates]}" and
finally return candidates[0].
- Around line 532-626: The code registers a lowering in generic() with
`@lower`(qualname, recvr, *param_types) each time generic() runs, causing
duplicate registrations (and duplicate mangled names via deduplicate_overloads)
for identical signatures; fix by adding a cache keyed by (qualname, recvr,
tuple(param_types)) that records when a lowering has already been registered and
skip re-registering if present. Locate the lowering site in the generic()
function where `@lower`(...) is applied and use a module-level or class-level dict
(or functools.lru_cache-style set) to track registrations before calling
deduplicate_overloads/shim creation and the `@lower` wrapper, so subsequent calls
with the same key return the already-registered FunctionCallConv or no-op
instead of re-decorating.

@isVoid isVoid enabled auto-merge (squash) January 29, 2026 00:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@numbast/src/numbast/class_template.py`:
- Around line 566-596: The pass_ptr_mask misalignment comes from using two
iterators (visible_iter and visible_mask_iter) that can get out of sync when
out-params are lifted; replace the iterator approach with an explicit index over
the visible parameters: keep a visible_idx integer and, when iterating orig_idx
over method_plan.intents, if orig_idx is an out-return use
out_return_types[out_pos] and append False to pass_ptr_mask_for_shim_list,
otherwise read param_types_inner[visible_idx] and
method_plan.pass_ptr_mask[visible_idx], append them and then increment
visible_idx; update the block using param_types_inner, visible_iter, and
visible_mask_iter to use visible_idx and method_plan.pass_ptr_mask indexing
instead to ensure masks align with visible params.

@isVoid isVoid disabled auto-merge January 29, 2026 01:18
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@numbast/tests/test_class_template.py`:
- Around line 172-176: The class docstring in test_class_template.py mentions
"Those tests are xfail to document the gap without implementing it" but no
`@pytest.mark.xfail` tests exist; either add xfail-marked test stubs (e.g., create
tests named test_templated_method_missing_api_xfail and
test_templated_method_paramization_xfail decorated with pytest.mark.xfail and a
short reason) to document the missing user-facing API for templated-method
parameters, or update the docstring to remove or reword that sentence to
accurately state that only default-parameter scenarios (like the "defaults
exist" and arg_intent tests) are covered.

@isVoid isVoid enabled auto-merge (squash) February 2, 2026 21:45
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@numbast/tests/test_class_template.py`:
- Around line 39-51: The _sample_class_template_templated_methods fixture
centralizes setup that is only used by a few tests; remove this fixture and
inline its setup directly into each test that currently depends on it by copying
the logic that calls parse_declarations_from_source(...), constructs
MemoryShimWriter(...), and invokes bind_cxx_class_templates(...); update those
tests to return or assign the resulting apis and shim_writer locally instead of
relying on the fixture, and delete the now-unused
_sample_class_template_templated_methods fixture to keep tests independent and
easier to evolve.

Comment on lines +39 to +51
@pytest.fixture
def _sample_class_template_templated_methods():
"""Bindings fixture for class-template + templated-method unit tests."""
DATA_FOLDER = os.path.join(os.path.dirname(__file__), "data")
p = os.path.join(DATA_FOLDER, "sample_class_template_templated_method.cuh")
decls = parse_declarations_from_source(p, [p], "sm_80", verbose=True)
shim_writer = MemoryShimWriter(f'#include "{p}"')

apis = bind_cxx_class_templates(
decls.class_templates, header_path=p, shim_writer=shim_writer
)

return apis, shim_writer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Prefer inlining setup in tests over a shared fixture here.

This fixture is only used by a small set of tests and can make independent evolution harder. Consider inlining the setup in each test unless there’s a strong DRY benefit.

Based on learnings: In Python tests under numbast/tests, prefer duplicating setup within individual test cases instead of extracting shared fixtures when the goal is to allow independent evolution of tests.

🤖 Prompt for AI Agents
In `@numbast/tests/test_class_template.py` around lines 39 - 51, The
_sample_class_template_templated_methods fixture centralizes setup that is only
used by a few tests; remove this fixture and inline its setup directly into each
test that currently depends on it by copying the logic that calls
parse_declarations_from_source(...), constructs MemoryShimWriter(...), and
invokes bind_cxx_class_templates(...); update those tests to return or assign
the resulting apis and shim_writer locally instead of relying on the fixture,
and delete the now-unused _sample_class_template_templated_methods fixture to
keep tests independent and easier to evolve.

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.

1 participant